smartmontools SVN Rev 5680
Utility to control and monitor storage systems with "S.M.A.R.T."
scsicmds.cpp
Go to the documentation of this file.
1/*
2 * scsicmds.cpp
3 *
4 * Home page of code is: https://www.smartmontools.org
5 *
6 * Copyright (C) 2002-8 Bruce Allen
7 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
8 * Copyright (C) 2003-2023 Douglas Gilbert <dgilbert@interlog.com>
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 *
13 * In the SCSI world "SMART" is a dead or withdrawn standard. In recent
14 * SCSI standards (since SCSI-3) it goes under the awkward name of
15 * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")].
16 * The relevant information is spread around several SCSI draft
17 * standards available at http://www.t10.org . Reference is made in the
18 * code to the following acronyms:
19 * - SAM [SCSI Architectural model, versions 2 or 3]
20 * - SPC [SCSI Primary commands, versions 2 or 3]
21 * - SBC [SCSI Block commands, versions 2]
22 *
23 * Some SCSI disk vendors have snippets of "SMART" information in their
24 * product manuals.
25 */
26
27#include <stdio.h>
28#include <string.h>
29#include <errno.h>
30#include <ctype.h>
31
32#include "config.h"
33
34#include "scsicmds.h"
35#include "dev_interface.h"
36#include "utility.h"
37#include "sg_unaligned.h"
38
39const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 5664 2025-02-24 14:20:16Z chrfranke $"
41
42static const char * logSenStr = "Log Sense";
43
44// Print SCSI debug messages?
45unsigned char scsi_debugmode = 0;
46
48
49#define RSOC_RESP_SZ 4096
50#define RSOC_ALL_CMDS_CTDP_0 8
51#define RSOC_ALL_CMDS_CTDP_1 20
52#define RSOC_1_CMD_CTDP_0 36
53
54// Check if LOG SENSE cdb supports changing the Subpage Code field
57{
58 int r_len = 0;
59 int err;
60 uint8_t rsoc_1cmd_rsp[RSOC_1_CMD_CTDP_0] = {};
61 uint8_t * rp = rsoc_1cmd_rsp;
62
63 err = scsiRSOCcmd(device, false /*rctd */ , 1 /* '1 cmd' format */,
64 LOG_SENSE, 0, rp, RSOC_1_CMD_CTDP_0, r_len);
65 if (err) {
67 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
68 return SC_NO_SUPPORT;
69 }
70 if (r_len < 8) {
72 pout("%s response to short [%d]\n", __func__, r_len);
73 return SC_NO_SUPPORT;
74 }
75 /* check the "subpage code" field in LOG SENSE cdb usage data */
76 return rp[7] ? SC_SUPPORT : SC_NO_SUPPORT; /* 4 + ls_cdb_byte3 */
77}
78
79bool
81{
82 bool res = true;
83 int k, err, cd_len, bump;
84 int r_len = 0;
85 uint8_t * rp = (uint8_t *)calloc(sizeof(uint8_t), RSOC_RESP_SZ);
86 const uint8_t * last_rp;
87 uint8_t * cmdp;
88 static const int max_bytes_of_cmds = RSOC_RESP_SZ - 4;
89
90 if (nullptr == rp)
91 return false;
92 rsoc_queried = true;
93 /* request 'all commands' format: 4 bytes header, 20 bytes per command */
94 err = scsiRSOCcmd(this, false /* rctd */, 0 /* 'all' format */, 0, 0,
95 rp, RSOC_RESP_SZ, r_len);
96 if (err) {
99 pout("%s Failed [%s]\n", __func__, scsiErrString(err));
100 res = false;
101 goto fini;
102 }
103 if (r_len < 4) {
104 pout("%s response too short\n", __func__);
105 res = false;
106 goto fini;
107 }
109 cd_len = sg_get_unaligned_be32(rp + 0);
110 if (cd_len > max_bytes_of_cmds) {
111 if (scsi_debugmode)
112 pout("%s: truncate %d byte response to %d bytes\n", __func__,
113 cd_len, max_bytes_of_cmds);
114 cd_len = max_bytes_of_cmds;
115 }
116 last_rp = rp + cd_len;
122
123 for (k = 0, cmdp = rp + 4; cmdp < last_rp; ++k, cmdp += bump) {
124 bool sa_valid = !! (0x1 & cmdp[5]);
125 bool ctdp = !! (0x2 & cmdp[5]);
126 uint8_t opcode = cmdp[0];
127 uint16_t sa;
128
130 sa = sa_valid ? sg_get_unaligned_be16(cmdp + 2) : 0;
131
132 switch (opcode) {
133 case LOG_SENSE:
136 break;
137 case READ_DEFECT_10:
139 break;
140 case READ_DEFECT_12:
142 break;
144 if (sa_valid && (SAI_READ_CAPACITY_16 == sa))
146 break;
147 default:
148 break;
149 }
150 }
151 if (scsi_debugmode > 3) {
152 pout("%s: decoded %d supported commands\n", __func__, k);
153 pout(" LOG SENSE %ssupported\n",
154 (SC_SUPPORT == logsense_sup) ? "" : "not ");
155 pout(" LOG SENSE subpage code %ssupported\n",
156 (SC_SUPPORT == logsense_spc_sup) ? "" : "not ");
157 pout(" READ DEFECT 10 %ssupported\n",
158 (SC_SUPPORT == rdefect10_sup) ? "" : "not ");
159 pout(" READ DEFECT 12 %ssupported\n",
160 (SC_SUPPORT == rdefect12_sup) ? "" : "not ");
161 pout(" READ CAPACITY 16 %ssupported\n",
162 (SC_SUPPORT == rcap16_sup) ? "" : "not ");
163 }
164
165fini:
166 free(rp);
167 return res;
168}
169
170/* May track more in the future */
173 uint16_t sa, bool for_lsense_spc) const
174{
176
177 switch (opcode) {
178 case LOG_SENSE: /* checking if LOG SENSE _subpages_ supported */
179 scs = for_lsense_spc ? logsense_spc_sup : logsense_sup;
180 break;
181 case READ_DEFECT_10:
182 scs = rdefect10_sup;
183 break;
184 case READ_DEFECT_12:
185 scs = rdefect12_sup;
186 break;
188 if (sa_valid && (SAI_READ_CAPACITY_16 == sa))
189 scs = rcap16_sup;
190 break;
192 if (sa_valid && (MI_REP_SUP_OPCODES == sa))
193 scs = rsoc_sup;
194 break;
195 default:
196 break;
197 }
198 return scs;
199}
200
202{
203 unsigned char b[0xfc] = {}; /* pre SPC-3 INQUIRY max response size */
204
205 if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES,
206 b, sizeof(b)))) {
208 int n = sizeof(b) - 4;
209 if (num_valid > n)
210 num_valid = n;
211 memcpy(pages, b + 4, num_valid);
212 }
213}
214
215bool
217{
218 /* Supported VPD pages numbers start at offset 4 and should be in
219 * ascending order but don't assume that. */
220 for (int k = 0; k < num_valid; ++k) {
221 if (vpd_page_num == pages[k])
222 return true;
223 }
224 return false;
225}
226
227/* Simple ASCII printable (does not use locale), includes space and excludes
228 * DEL (0x7f). Note all UTF-8 encoding apart from <= 0x7f have top bit set. */
229static inline int
230my_isprint(uint8_t ch)
231{
232 return ((ch >= ' ') && (ch < 0x7f));
233}
234
235static int
237{
238 int n = strlen(b);
239
240 while ((n > 0) && (' ' == b[n - 1]))
241 b[--n] = '\0';
242 return n;
243}
244
245/* Read binary starting at 'up' for 'len' bytes and output as ASCII
246 * hexadecimal to the passed function 'out'. See dStrHex() below for more. */
247static void
248dStrHexHelper(const uint8_t * up, int len, int no_ascii,
249 void (*out)(const char * s, void * ctx), void * ctx = nullptr)
250{
251 static const int line_len = 80;
252 static const int cpstart = 60; // offset of start of ASCII rendering
253 uint8_t c;
254 char buff[line_len + 2]; // room for trailing null
255 int a = 0;
256 int bpstart = 5;
257 int cpos = cpstart;
258 int bpos = bpstart;
259 int i, k, blen;
260 char e[line_len + 4];
261 static const int elen = sizeof(e);
262
263 if (len <= 0)
264 return;
265 blen = (int)sizeof(buff);
266 memset(buff, ' ', line_len);
267 buff[line_len] = '\0';
268 if (no_ascii < 0) {
269 bpstart = 0;
270 bpos = bpstart;
271 for (k = 0; k < len; k++) {
272 c = *up++;
273 if (bpos == (bpstart + (8 * 3)))
274 bpos++;
275 snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
276 buff[bpos + 2] = ' ';
277 if ((k > 0) && (0 == ((k + 1) % 16))) {
278 trimTrailingSpaces(buff);
279 if (no_ascii)
280 snprintf(e, elen, "%s\n", buff);
281 else
282 snprintf(e, elen, "%.76s\n", buff);
283 out(e, ctx);
284 bpos = bpstart;
285 memset(buff, ' ', line_len);
286 } else
287 bpos += 3;
288 }
289 if (bpos > bpstart) {
290 buff[bpos + 2] = '\0';
291 trimTrailingSpaces(buff);
292 snprintf(e, elen, "%s\n", buff);
293 out(e, ctx);
294 }
295 return;
296 }
297 /* no_ascii>=0, start each line with address (offset) */
298 k = snprintf(buff + 1, blen - 1, "%.2x", a);
299 buff[k + 1] = ' ';
300
301 for (i = 0; i < len; i++) {
302 c = *up++;
303 bpos += 3;
304 if (bpos == (bpstart + (9 * 3)))
305 bpos++;
306 snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(uint8_t)c);
307 buff[bpos + 2] = ' ';
308 if (no_ascii)
309 buff[cpos++] = ' ';
310 else {
311 if (! my_isprint(c))
312 c = '.';
313 buff[cpos++] = c;
314 }
315 if (cpos > (cpstart + 15)) {
316 if (no_ascii)
317 trimTrailingSpaces(buff);
318 if (no_ascii)
319 snprintf(e, elen, "%s\n", buff);
320 else
321 snprintf(e, elen, "%.76s\n", buff);
322 out(e, ctx);
323 bpos = bpstart;
324 cpos = cpstart;
325 a += 16;
326 memset(buff, ' ', line_len);
327 k = snprintf(buff + 1, blen - 1, "%.2x", a);
328 buff[k + 1] = ' ';
329 }
330 }
331 if (cpos > cpstart) {
332 buff[cpos] = '\0';
333 if (no_ascii)
334 trimTrailingSpaces(buff);
335 snprintf(e, elen, "%s\n", buff);
336 out(e, ctx);
337 }
338}
339
340/* Read binary starting at 'up' for 'len' bytes and output as ASCII
341 * hexadecimal into file pointer (fp). If fp is nullptr, then send to
342 * pout(). See dStrHex() below for more. */
343void
344dStrHexFp(const uint8_t * up, int len, int no_ascii, FILE * fp)
345{
346 /* N.B. Use of lamba requires C++11 or later. */
347 if ((nullptr == up) || (len < 1))
348 return;
349 else if (fp)
350 dStrHexHelper(up, len, no_ascii,
351 [](const char * s, void * ctx)
352 { fputs(s, reinterpret_cast<FILE *>(ctx)); },
353 fp);
354 else
355 dStrHexHelper(up, len, no_ascii,
356 [](const char * s, void *){ pout("%s", s); });
357}
358
359/* Read binary starting at 'up' for 'len' bytes and output as ASCII
360 * hexadecimal into pout(). 16 bytes per line are output with an
361 * additional space between 8th and 9th byte on each line (for readability).
362 * 'no_ascii' selects one of 3 output format types:
363 * > 0 each line has address then up to 16 ASCII-hex bytes
364 * = 0 in addition, the bytes are rendered in ASCII to the right
365 * of each line, non-printable characters shown as '.'
366 * < 0 only the ASCII-hex bytes are listed (i.e. without address) */
367void
368dStrHex(const uint8_t * up, int len, int no_ascii)
369{
370 /* N.B. Use of lamba requires C++11 or later. */
371 dStrHexHelper(up, len, no_ascii,
372 [](const char * s, void *){ pout("%s", s); });
373}
374
375/* This is a heuristic that takes into account the command bytes and length
376 * to decide whether the presented unstructured sequence of bytes could be
377 * a SCSI command. If so it returns true otherwise false. Vendor specific
378 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
379 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
380 * only SCSI commands considered above 16 bytes of length are the Variable
381 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
382 * Both have an inbuilt length field which can be cross checked with clen.
383 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
384 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
385 * structures that are sent across the wire. The FIS register structure is
386 * used to move a command from a SATA host to device, but the ATA 'command'
387 * is not the first byte. So it is harder to say what will happen if a
388 * FIS structure is presented as a SCSI command, hopefully there is a low
389 * probability this function will yield true in that case. */
390bool
391is_scsi_cdb(const uint8_t * cdbp, int clen)
392{
393 if (clen < 6)
394 return false;
395 uint8_t opcode = cdbp[0];
396 uint8_t top3bits = opcode >> 5;
397 if (0x3 == top3bits) { /* Opcodes 0x60 to 0x7f */
398 int ilen, sa;
399 if ((clen < 12) || (clen % 4))
400 return false; /* must be modulo 4 and 12 or more bytes */
401 switch (opcode) {
402 case 0x7e: /* Extended cdb (XCDB) */
403 ilen = 4 + sg_get_unaligned_be16(cdbp + 2);
404 return (ilen == clen);
405 case 0x7f: /* Variable Length cdb */
406 ilen = 8 + cdbp[7];
407 sa = sg_get_unaligned_be16(cdbp + 8);
408 /* service action (sa) 0x0 is reserved */
409 return ((ilen == clen) && sa);
410 default:
411 return false;
412 }
413 } else if (clen <= 16) {
414 switch (clen) {
415 case 6:
416 if (top3bits > 0x5) /* vendor */
417 return true;
418 return (0x0 == top3bits); /* 6 byte cdb */
419 case 10:
420 if (top3bits > 0x5) /* vendor */
421 return true;
422 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
423 case 16:
424 if (top3bits > 0x5) /* vendor */
425 return true;
426 return (0x4 == top3bits); /* 16 byte cdb */
427 case 12:
428 if (top3bits > 0x5) /* vendor */
429 return true;
430 return (0x5 == top3bits); /* 12 byte cdb */
431 default:
432 return false;
433 }
434 }
435 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
436 * opcode > 0x7f). */
437 return false;
438}
439
442 scsi_sa_b1b4n5, /* for cdb byte 1, bit 4, number 5 bits */
444};
445
447 uint8_t cdb0;
449};
450
451static struct scsi_sa_var_map sa_var_a[] = {
452 {0x3b, scsi_sa_b1b4n5}, /* Write buffer modes_s */
453 {0x3c, scsi_sa_b1b4n5}, /* Read buffer(10) modes_s */
454 {0x48, scsi_sa_b1b4n5}, /* Sanitize sa_s */
455 {0x5e, scsi_sa_b1b4n5}, /* Persistent reserve in sa_s */
456 {0x5f, scsi_sa_b1b4n5}, /* Persistent reserve out sa_s */
457 {0x7f, scsi_sa_b8b7n16}, /* Variable length commands */
458 {0x83, scsi_sa_b1b4n5}, /* Extended copy out/cmd sa_s */
459 {0x84, scsi_sa_b1b4n5}, /* Extended copy in sa_s */
460 {0x8c, scsi_sa_b1b4n5}, /* Read attribute sa_s */
461 {0x9b, scsi_sa_b1b4n5}, /* Read buffer(16) modes_s */
462 {0x9e, scsi_sa_b1b4n5}, /* Service action in (16) */
463 {0x9f, scsi_sa_b1b4n5}, /* Service action out (16) */
464 {0xa3, scsi_sa_b1b4n5}, /* Maintenance in */
465 {0xa4, scsi_sa_b1b4n5}, /* Maintenance out */
466 {0xa9, scsi_sa_b1b4n5}, /* Service action out (12) */
467 {0xab, scsi_sa_b1b4n5}, /* Service action in (12) */
468};
469
471 uint8_t opcode;
472 bool sa_valid; /* Service action (next field) valid */
473 uint16_t sa;
474 const char * name;
475};
476
477/* Array assumed to be sorted by opcode then service action (sa) */
479 /* in ascending opcode order */
480 {TEST_UNIT_READY, false, 0, "test unit ready"}, /* 0x00 */
481 {REQUEST_SENSE, false, 0, "request sense"}, /* 0x03 */
482 {INQUIRY, false, 0, "inquiry"}, /* 0x12 */
483 {MODE_SELECT_6, false, 0, "mode select(6)"}, /* 0x15 */
484 {MODE_SENSE_6, false, 0, "mode sense(6)"}, /* 0x1a */
485 {START_STOP_UNIT, false, 0, "start stop unit"}, /* 0x1b */
486 {RECEIVE_DIAGNOSTIC, false, 0, "receive diagnostic"}, /* 0x1c */
487 {SEND_DIAGNOSTIC, false, 0, "send diagnostic"}, /* 0x1d */
488 {READ_CAPACITY_10, false, 0, "read capacity(10)"}, /* 0x25 */
489 {READ_DEFECT_10, false, 0, "read defect list(10)"}, /* 0x37 */
490 {LOG_SELECT, false, 0, "log select"}, /* 0x4c */
491 {LOG_SENSE, false, 0, "log sense"}, /* 0x4d */
492 {MODE_SELECT_10, false, 0, "mode select(10)"}, /* 0x55 */
493 {MODE_SENSE_10, false, 0, "mode sense(10)"}, /* 0x5a */
494 {SAT_ATA_PASSTHROUGH_16, false, 0, "ata pass-through(16)"}, /* 0x85 */
495 {SERVICE_ACTION_IN_16, true, SAI_READ_CAPACITY_16, "read capacity(16)"},
496 /* 0x9e,0x10 */
498 "get physical element status"}, /* 0x9e,0x17 */
499 {REPORT_LUNS, false, 0, "report luns"}, /* 0xa0 */
500 {SAT_ATA_PASSTHROUGH_12, false, 0, "ata pass-through(12)"}, /* 0xa1 */
502 "report supported operation codes"}, /* 0xa3,0xc */
503 {READ_DEFECT_12, false, 0, "read defect list(12)"}, /* 0xb7 */
504};
505
506static const char * vendor_specific = "<vendor specific>";
507
508/* Need to expand to take service action into account. For commands
509 * of interest the service action is in the 2nd command byte */
510const char *
511scsi_get_opcode_name(const uint8_t * cdbp)
512{
513 uint8_t opcode = cdbp[0];
514 uint8_t cdb0;
515 enum scsi_sa_t sa_var = scsi_sa_none;
516 bool sa_valid = false;
517 uint16_t sa = 0;
518 int k;
519 static const int sa_var_len = sizeof(sa_var_a) /
520 sizeof(sa_var_a[0]);
521 static const int len = sizeof(opcode_name_arr) /
522 sizeof(opcode_name_arr[0]);
523
524 if (opcode >= 0xc0)
525 return vendor_specific;
526 for (k = 0; k < sa_var_len; ++k) {
527 cdb0 = sa_var_a[k].cdb0;
528 if (opcode == cdb0) {
529 sa_var = sa_var_a[k].sa_var;
530 break;
531 }
532 if (opcode < cdb0)
533 break;
534 }
535 switch (sa_var) {
536 case scsi_sa_none:
537 break;
538 case scsi_sa_b1b4n5:
539 sa_valid = true;
540 sa = cdbp[1] & 0x1f;
541 break;
542 case scsi_sa_b8b7n16:
543 sa_valid = true;
544 sa = sg_get_unaligned_be16(cdbp + 8);
545 break;
546 }
547 for (k = 0; k < len; ++k) {
548 struct scsi_opcode_name * onp = &opcode_name_arr[k];
549
550 if (opcode == onp->opcode) {
551 if ((! sa_valid) && (! onp->sa_valid))
552 return onp->name;
553 if (sa_valid && onp->sa_valid) {
554 if (sa == onp->sa)
555 return onp->name;
556 }
557 /* should not see sa_valid and ! onp->sa_valid (or vice versa) */
558 } else if (opcode < onp->opcode)
559 return nullptr;
560 }
561 return nullptr;
562}
563
564void
565scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
566 struct scsi_sense_disect * out)
567{
568 memset(out, 0, sizeof(struct scsi_sense_disect));
570 int resp_code = (io_buf->sensep[0] & 0x7f);
571 out->resp_code = resp_code;
572 if (resp_code >= 0x72) {
573 out->sense_key = (io_buf->sensep[1] & 0xf);
574 out->asc = io_buf->sensep[2];
575 out->ascq = io_buf->sensep[3];
576 } else if (resp_code >= 0x70) {
577 out->sense_key = (io_buf->sensep[2] & 0xf);
578 if (io_buf->resp_sense_len > 13) {
579 out->asc = io_buf->sensep[12];
580 out->ascq = io_buf->sensep[13];
581 }
582 }
583 }
584}
585
586int
588{
589 switch (sinfo->sense_key) {
590 case SCSI_SK_NO_SENSE:
593 return SIMPLE_NO_ERROR;
595 if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
597 else if (SCSI_ASC_NOT_READY == sinfo->asc) {
598 if (0x1 == sinfo->ascq)
600 else
602 } else
608 if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc)
610 else if (SCSI_ASC_INVALID_FIELD == sinfo->asc)
612 else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc)
614 else
615 return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */
624 default:
625 return SIMPLE_ERR_UNKNOWN;
626 }
627}
628
629const char *
630scsiErrString(int scsiErr)
631{
632 if (scsiErr < 0)
633 return strerror(-scsiErr);
634 switch (scsiErr) {
635 case SIMPLE_NO_ERROR:
636 return "no error";
638 return "device not ready";
640 return "unsupported scsi opcode";
642 return "unsupported field in scsi command";
644 return "badly formed scsi parameters";
646 return "scsi response fails sanity test";
648 return "no medium present";
650 return "device will be ready soon";
652 return "unit attention reported, try again";
654 return "medium or hardware error (serious)";
656 return "unknown error (unexpected sense key)";
658 return "aborted command";
660 return "data protection error";
662 return "miscompare";
663 default:
664 return "unknown error";
665 }
666}
667
668static const char * sense_key_desc[] = {
669 "No Sense", /* Filemark, ILI and/or EOM; progress
670 indication (during FORMAT); power
671 condition sensing (REQUEST SENSE) */
672 "Recovered Error", /* The last command completed successfully
673 but used error correction */
674 "Not Ready", /* The addressed target is not ready */
675 "Medium Error", /* Data error detected on the medium */
676 "Hardware Error", /* Controller or device failure */
677 "Illegal Request",
678 "Unit Attention", /* Removable medium was changed, or
679 the target has been reset */
680 "Data Protect", /* Access to the data is blocked */
681 "Blank Check", /* Reached unexpected written or unwritten
682 region of the medium */
683 "Vendor specific(9)", /* Vendor specific */
684 "Copy Aborted", /* COPY or COMPARE was aborted */
685 "Aborted Command", /* The target aborted the command */
686 "Equal", /* SEARCH DATA found data equal (obsolete) */
687 "Volume Overflow", /* Medium full with data to be written */
688 "Miscompare", /* Source data and data on the medium
689 do not agree */
690 "Completed" /* may occur for successful cmd (spc4r23) */
691};
692
693/* Yield string associated with sense_key value. Returns 'buff'. */
694char *
695scsi_get_sense_key_str(int sense_key, int buff_len, char * buff)
696{
697 if (1 == buff_len) {
698 buff[0] = '\0';
699 return buff;
700 }
701 if ((sense_key >= 0) && (sense_key < 16))
702 snprintf(buff, buff_len, "%s", sense_key_desc[sense_key]);
703 else
704 snprintf(buff, buff_len, "invalid value: 0x%x", sense_key);
705 return buff;
706}
707
708/* Iterates to next designation descriptor in the device identification
709 * VPD page. The 'initial_desig_desc' should point to start of first
710 * descriptor with 'page_len' being the number of valid bytes in that
711 * and following descriptors. To start, 'off' should point to a negative
712 * value, thereafter it should point to the value yielded by the previous
713 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
714 * descriptor; returns -1 if normal end condition and -2 for an abnormal
715 * termination. Matches association, designator_type and/or code_set when
716 * any of those values are greater than or equal to zero. */
717int
718scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len,
719 int * off, int m_assoc, int m_desig_type, int m_code_set)
720{
721 const unsigned char * ucp;
722 int k;
723
724 for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) {
725 k = (k < 0) ? 0 : (k + ucp[k + 3] + 4);
726 if ((k + 4) > page_len)
727 break;
728 int c_set = (ucp[k] & 0xf);
729 if ((m_code_set >= 0) && (m_code_set != c_set))
730 continue;
731 int assoc = ((ucp[k + 1] >> 4) & 0x3);
732 if ((m_assoc >= 0) && (m_assoc != assoc))
733 continue;
734 int desig_type = (ucp[k + 1] & 0xf);
735 if ((m_desig_type >= 0) && (m_desig_type != desig_type))
736 continue;
737 *off = k;
738 return 0;
739 }
740 return (k == page_len) ? -1 : -2;
741}
742
743/* Decode VPD page 0x83 logical unit designator into a string. If multiple
744 * designators are present, the order of preference is NAA, EUI-64, SCSI name
745 * string.
746 * Returns 0 on success, -1 on error with error string in s. */
747int
748scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
749 int * transport)
750{
751 if (transport)
752 *transport = -1;
753 if (slen < 32) {
754 if (slen > 0)
755 s[0] = '\0';
756 return -1;
757 }
758
759#define SLEN(a, b) ((a) > (b) ? ((a) - (b)) : 0)
760 s[0] = '\0';
761 int si = 0;
762 int have_scsi_ns = 0, have_eui_64 = 0, have_naa = 0;
763 int off = -1;
764 int u;
765 while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) {
766 const unsigned char * ucp = b + off;
767 int i_len = ucp[3];
768 if ((off + i_len + 4) > blen) {
769 snprintf(s+si, SLEN(slen, si), "error: designator length");
770 return -1;
771 }
772 int assoc = ((ucp[1] >> 4) & 0x3);
773 if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
774 *transport = (ucp[0] >> 4) & 0xf;
775 if (0 != assoc)
776 continue;
777 const unsigned char * ip = ucp + 4;
778 int c_set = (ucp[0] & 0xf);
779 int desig_type = (ucp[1] & 0xf);
780
781 int naa;
782 switch (desig_type) {
783 case 0: /* vendor specific */
784 case 1: /* T10 vendor identification */
785 break;
786 case 2: /* EUI-64 based */
787 if ((8 != i_len) && (12 != i_len) && (16 != i_len)) {
788 snprintf(s+si, SLEN(slen, si), "error: EUI-64 length");
789 return -1;
790 }
791 if (have_eui_64) {
792 snprintf(s+si, SLEN(slen, si), "error: Duplicate EUI-64 designator");
793 return -1;
794 }
795 if (have_naa)
796 continue;
797 if (have_scsi_ns)
798 si = 0;
799 si += snprintf(s+si, SLEN(slen, si), "0x");
800 for (int m = 0; m < i_len; ++m)
801 si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
802 have_eui_64++;
803 break;
804 case 3: /* NAA */
805 if (1 != c_set) {
806 snprintf(s+si, SLEN(slen, si), "error: NAA bad code_set");
807 return -1;
808 }
809 naa = (ip[0] >> 4) & 0xff;
810 if ((naa < 2) || (naa > 6) || (4 == naa)) {
811 snprintf(s+si, SLEN(slen, si), "error: unexpected NAA");
812 return -1;
813 }
814 if (have_naa) {
815 snprintf(s+si, SLEN(slen, si), "error: Duplicate NAA designator");
816 return -1;
817 }
818 if (have_eui_64 || have_scsi_ns)
819 si = 0;
820 if (2 == naa) { /* NAA IEEE Extended */
821 if (8 != i_len) {
822 snprintf(s+si, SLEN(slen, si), "error: NAA 2 length");
823 return -1;
824 }
825 si += snprintf(s+si, SLEN(slen, si), "0x");
826 for (int m = 0; m < 8; ++m)
827 si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
828 } else if ((3 == naa ) || (5 == naa)) {
829 /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
830 if (8 != i_len) {
831 snprintf(s+si, SLEN(slen, si), "error: NAA 3 or 5 length");
832 return -1;
833 }
834 si += snprintf(s+si, SLEN(slen, si), "0x");
835 for (int m = 0; m < 8; ++m)
836 si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
837 } else if (6 == naa) { /* NAA IEEE Registered extended */
838 if (16 != i_len) {
839 snprintf(s+si, SLEN(slen, si), "error: NAA 6 length");
840 return -1;
841 }
842 si += snprintf(s+si, SLEN(slen, si), "0x");
843 for (int m = 0; m < 16; ++m)
844 si += snprintf(s+si, SLEN(slen, si), "%02x", (unsigned int)ip[m]);
845 }
846 have_naa++;
847 break;
848 case 4: /* Relative target port */
849 case 5: /* (primary) Target port group */
850 case 6: /* Logical unit group */
851 case 7: /* MD5 logical unit identifier */
852 break;
853 case 8: /* SCSI name string */
854 if (3 != c_set) {
855 snprintf(s+si, SLEN(slen, si), "error: SCSI name string");
856 return -1;
857 }
858 if (have_scsi_ns) {
859 snprintf(s+si, SLEN(slen, si), "error: Duplicate SCSI name string designator");
860 return -1;
861 }
862 if (have_eui_64 || have_naa)
863 continue;
864 /* does %s print out UTF-8 ok?? */
865 si += snprintf(s+si, SLEN(slen, si), "%s", (const char *)ip);
866 ++have_scsi_ns;
867 break;
868 default: /* reserved */
869 break;
870 }
871 }
872 if (-2 == u) {
873 snprintf(s+si, SLEN(slen, si), "error: bad structure");
874 return -1;
875 }
876 return 0;
877#undef SLEN
878}
879
880/* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if
881 * command not supported, 3 if field (within command) not supported or
882 * returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a).
883 * N.B. Sets PC==1 to fetch "current cumulative" log pages.
884 * If known_resp_len > 0 then a single fetch is done for this response
885 * length. If known_resp_len == 0 then twin fetches are performed, the
886 * first to deduce the response length, then send the same command again
887 * requesting the deduced response length. This protects certain fragile
888 * HBAs. The twin fetch technique should not be used with the TapeAlert
889 * log page since it clears its state flags after each fetch. If
890 * known_resp_len < 0 then does single fetch for BufLen bytes. */
891int
892scsiLogSense(scsi_device * device, int pagenum, int subpagenum, uint8_t *pBuf,
893 int bufLen, int known_resp_len)
894{
895 int pageLen;
896 struct scsi_cmnd_io io_hdr = {};
897 struct scsi_sense_disect sinfo;
898 uint8_t cdb[10] = {};
899 uint8_t sense[32];
900
901 if (known_resp_len > bufLen)
902 return -EIO;
903 if (known_resp_len > 0)
904 pageLen = known_resp_len;
905 else if (known_resp_len < 0)
906 pageLen = bufLen;
907 else { /* 0 == known_resp_len */
908 /* Twin fetch strategy: first fetch to find response length */
909 pageLen = 4;
910 if (pageLen > bufLen)
911 return -EIO;
912 else
913 memset(pBuf, 0, pageLen);
914
916 io_hdr.dxfer_len = pageLen;
917 io_hdr.dxferp = pBuf;
918 cdb[0] = LOG_SENSE;
919 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
920 cdb[3] = subpagenum; /* 0 for no sub-page */
921 sg_put_unaligned_be16(pageLen, cdb + 7);
922 io_hdr.cmnd = cdb;
923 io_hdr.cmnd_len = sizeof(cdb);
924 io_hdr.sensep = sense;
925 io_hdr.max_sense_len = sizeof(sense);
927
928 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
929 return -device->get_errno();
930 int res;
931 if ((res = scsiSimpleSenseFilter(&sinfo)))
932 return res;
933 /* sanity check on response */
934 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
935 return SIMPLE_ERR_BAD_RESP;
936 uint16_t u = sg_get_unaligned_be16(pBuf + 2);
937 if (0 == u)
938 return SIMPLE_ERR_BAD_RESP;
939 pageLen = u + 4;
940 /* some SCSI HBA don't like "odd" length transfers */
941 if (pageLen % 2)
942 pageLen += 1;
943 if (pageLen > bufLen)
944 pageLen = bufLen;
945 }
946 memset(pBuf, 0, 4);
947 memset(&io_hdr, 0, sizeof(io_hdr));
948 memset(cdb, 0, sizeof(cdb));
950 io_hdr.dxfer_len = pageLen;
951 io_hdr.dxferp = pBuf;
952 cdb[0] = LOG_SENSE;
953 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
954 cdb[3] = subpagenum;
955 sg_put_unaligned_be16(pageLen, cdb + 7);
956 io_hdr.cmnd = cdb;
957 io_hdr.cmnd_len = sizeof(cdb);
958 io_hdr.sensep = sense;
959 io_hdr.max_sense_len = sizeof(sense);
961
962 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
963 return -device->get_errno();
964 int status = scsiSimpleSenseFilter(&sinfo);
965 if (0 != status)
966 return status;
967 /* sanity check on response */
968 if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum))
969 return SIMPLE_ERR_BAD_RESP;
970 if (0 == sg_get_unaligned_be16(pBuf + 2))
971 return SIMPLE_ERR_BAD_RESP;
972 return 0;
973}
974
975/* Sends a LOG SELECT command. Can be used to set log page values
976 * or reset one log page (or all of them) to its defaults (typically zero).
977 * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if
978 * field in command not supported, * 4 if bad parameter to command or
979 * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */
980int
981scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
982 int subpagenum, uint8_t *pBuf, int bufLen)
983{
984 struct scsi_cmnd_io io_hdr = {};
985 struct scsi_sense_disect sinfo;
986 uint8_t cdb[10] = {};
987 uint8_t sense[32];
988
989 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
990 io_hdr.dxfer_len = bufLen;
991 io_hdr.dxferp = pBuf;
992 cdb[0] = LOG_SELECT;
993 cdb[1] = (pcr ? 2 : 0) | (sp ? 1 : 0);
994 cdb[2] = ((pc << 6) & 0xc0) | (pagenum & 0x3f);
995 cdb[3] = (subpagenum & 0xff);
996 sg_put_unaligned_be16(bufLen, cdb + 7);
997 io_hdr.cmnd = cdb;
998 io_hdr.cmnd_len = sizeof(cdb);
999 io_hdr.sensep = sense;
1000 io_hdr.max_sense_len = sizeof(sense);
1002
1003 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1004 return -device->get_errno();
1005 return scsiSimpleSenseFilter(&sinfo);
1006}
1007
1008/* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
1009 * 2 if command not supported (then MODE SENSE(10) should be supported),
1010 * 3 if field in command not supported or returns negated errno.
1011 * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
1012int
1013scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
1014 uint8_t *pBuf, int bufLen)
1015{
1016 struct scsi_cmnd_io io_hdr = {};
1017 struct scsi_sense_disect sinfo;
1018 uint8_t cdb[6] = {};
1019 uint8_t sense[32];
1020
1021 if ((bufLen < 0) || (bufLen > 255))
1022 return -EINVAL;
1024 io_hdr.dxfer_len = bufLen;
1025 io_hdr.dxferp = pBuf;
1026 cdb[0] = MODE_SENSE_6;
1027 cdb[2] = (pc << 6) | (pagenum & 0x3f);
1028 cdb[3] = subpagenum;
1029 cdb[4] = bufLen;
1030 io_hdr.cmnd = cdb;
1031 io_hdr.cmnd_len = sizeof(cdb);
1032 io_hdr.sensep = sense;
1033 io_hdr.max_sense_len = sizeof(sense);
1035
1036 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1037 return -device->get_errno();
1038 int status = scsiSimpleSenseFilter(&sinfo);
1039 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
1040 int offset;
1041
1042 offset = scsiModePageOffset(pBuf, bufLen, 0);
1043 if (offset < 0)
1044 return SIMPLE_ERR_BAD_RESP;
1045 else if (pagenum != (pBuf[offset] & 0x3f))
1046 return SIMPLE_ERR_BAD_RESP;
1047 }
1048 return status;
1049}
1050
1051/* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response
1052 * from a corresponding 6 byte MODE SENSE command. Such a response should
1053 * have a 4 byte header followed by 0 or more 8 byte block descriptors
1054 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY,
1055 * 2 if command not supported (then MODE SELECT(10) may be supported),
1056 * 3 if field in command not supported, 4 if bad parameter to command
1057 * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
1058int
1059scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
1060{
1061 struct scsi_cmnd_io io_hdr = {};
1062 struct scsi_sense_disect sinfo;
1063 uint8_t cdb[6] = {};
1064 uint8_t sense[32];
1065 int pg_offset, pg_len, hdr_plus_1_pg;
1066
1067 pg_offset = 4 + pBuf[3];
1068 if (pg_offset + 2 >= bufLen)
1069 return -EINVAL;
1070 pg_len = pBuf[pg_offset + 1] + 2;
1071 hdr_plus_1_pg = pg_offset + pg_len;
1072 if (hdr_plus_1_pg > bufLen)
1073 return -EINVAL;
1074 pBuf[0] = 0; /* Length of returned mode sense data reserved for SELECT */
1075 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
1076 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
1077 io_hdr.dxfer_len = hdr_plus_1_pg;
1078 io_hdr.dxferp = pBuf;
1079 cdb[0] = MODE_SELECT_6;
1080 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
1081 cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */
1082 io_hdr.cmnd = cdb;
1083 io_hdr.cmnd_len = sizeof(cdb);
1084 io_hdr.sensep = sense;
1085 io_hdr.max_sense_len = sizeof(sense);
1087
1088 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1089 return -device->get_errno();
1090 return scsiSimpleSenseFilter(&sinfo);
1091}
1092
1093/* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
1094 * not supported (then MODE SENSE(6) might be supported), 3 if field in
1095 * command not supported or returns negated errno.
1096 * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
1097int
1098scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
1099 uint8_t *pBuf, int bufLen)
1100{
1101 struct scsi_cmnd_io io_hdr = {};
1102 struct scsi_sense_disect sinfo;
1103 uint8_t cdb[10] = {};
1104 uint8_t sense[32];
1105
1107 io_hdr.dxfer_len = bufLen;
1108 io_hdr.dxferp = pBuf;
1109 cdb[0] = MODE_SENSE_10;
1110 cdb[2] = (pc << 6) | (pagenum & 0x3f);
1111 cdb[3] = subpagenum;
1112 sg_put_unaligned_be16(bufLen, cdb + 7);
1113 io_hdr.cmnd = cdb;
1114 io_hdr.cmnd_len = sizeof(cdb);
1115 io_hdr.sensep = sense;
1116 io_hdr.max_sense_len = sizeof(sense);
1118
1119 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1120 return -device->get_errno();
1121 int status = scsiSimpleSenseFilter(&sinfo);
1122 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
1123 int offset;
1124
1125 offset = scsiModePageOffset(pBuf, bufLen, 1);
1126 if (offset < 0)
1127 return SIMPLE_ERR_BAD_RESP;
1128 else if (pagenum != (pBuf[offset] & 0x3f))
1129 return SIMPLE_ERR_BAD_RESP;
1130 }
1131 return status;
1132}
1133
1134/* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response
1135 * from a corresponding 10 byte MODE SENSE command. Such a response should
1136 * have a 8 byte header followed by 0 or more 8 byte block descriptors
1137 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
1138 * command not supported (then MODE SELECT(6) may be supported), 3 if field
1139 * in command not supported, 4 if bad parameter to command or returns
1140 * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
1141int
1142scsiModeSelect10(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
1143{
1144 struct scsi_cmnd_io io_hdr = {};
1145 struct scsi_sense_disect sinfo;
1146 uint8_t cdb[10] = {};
1147 uint8_t sense[32];
1148 int pg_offset, pg_len, hdr_plus_1_pg;
1149
1150 pg_offset = 8 + sg_get_unaligned_be16(pBuf + 6);
1151 if (pg_offset + 2 >= bufLen)
1152 return -EINVAL;
1153 pg_len = pBuf[pg_offset + 1] + 2;
1154 hdr_plus_1_pg = pg_offset + pg_len;
1155 if (hdr_plus_1_pg > bufLen)
1156 return -EINVAL;
1157 pBuf[0] = 0;
1158 pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */
1159 pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
1160 io_hdr.dxfer_dir = DXFER_TO_DEVICE;
1161 io_hdr.dxfer_len = hdr_plus_1_pg;
1162 io_hdr.dxferp = pBuf;
1163 cdb[0] = MODE_SELECT_10;
1164 cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */
1165 /* make sure only one page sent */
1166 sg_put_unaligned_be16(hdr_plus_1_pg, cdb + 7);
1167 io_hdr.cmnd = cdb;
1168 io_hdr.cmnd_len = sizeof(cdb);
1169 io_hdr.sensep = sense;
1170 io_hdr.max_sense_len = sizeof(sense);
1172
1173 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1174 return -device->get_errno();
1175 return scsiSimpleSenseFilter(&sinfo);
1176}
1177
1178/* Standard INQUIRY returns 0 for ok, anything else is a major problem.
1179 * bufLen should be 36 for unsafe devices (like USB mass storage stuff)
1180 * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
1181int
1182scsiStdInquiry(scsi_device * device, uint8_t *pBuf, int bufLen)
1183{
1184 struct scsi_sense_disect sinfo;
1185 struct scsi_cmnd_io io_hdr = {};
1186 int res;
1187 uint8_t cdb[6] = {};
1188 uint8_t sense[32];
1189
1190 if ((bufLen < 0) || (bufLen > 1023))
1191 return -EINVAL;
1192 if (bufLen >= 36) /* normal case */
1193 memset(pBuf, 0, 36);
1195 io_hdr.dxfer_len = bufLen;
1196 io_hdr.dxferp = pBuf;
1197 cdb[0] = INQUIRY;
1198 sg_put_unaligned_be16(bufLen, cdb + 3);
1199 io_hdr.cmnd = cdb;
1200 io_hdr.cmnd_len = sizeof(cdb);
1201 io_hdr.sensep = sense;
1202 io_hdr.max_sense_len = sizeof(sense);
1204
1205 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1206 return -device->get_errno();
1207 res = scsiSimpleSenseFilter(&sinfo);
1208 if ((SIMPLE_NO_ERROR == res) && (! device->is_spc4_or_higher())) {
1209 if (((bufLen - io_hdr.resid) >= 36) &&
1210 (pBuf[2] >= 6) && /* VERSION field >= SPC-4 */
1211 ((pBuf[3] & 0xf) == 2)) { /* RESPONSE DATA field == 2 */
1212 uint8_t pdt = pBuf[0] & 0x1f;
1213
1214 if ((SCSI_PT_DIRECT_ACCESS == pdt) ||
1215 (SCSI_PT_HOST_MANAGED == pdt) ||
1216 (SCSI_PT_SEQUENTIAL_ACCESS == pdt) ||
1217 (SCSI_PT_MEDIUM_CHANGER == pdt))
1218 device->set_spc4_or_higher();
1219 }
1220 }
1221 return res;
1222}
1223
1224/* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
1225 * (unlikely), 2 if command not supported, 3 if field in command not
1226 * supported, 5 if response indicates that EVPD bit ignored or returns
1227 * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
1228int
1229scsiInquiryVpd(scsi_device * device, int vpd_page, uint8_t *pBuf, int bufLen)
1230{
1231 struct scsi_cmnd_io io_hdr = {};
1232 struct scsi_sense_disect sinfo;
1233 uint8_t cdb[6] = {};
1234 uint8_t sense[32];
1235 int res;
1236
1237 /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */
1238 if ((SCSI_VPD_SUPPORTED_VPD_PAGES != vpd_page) &&
1240 (! supported_vpd_pages_p->is_supported(vpd_page)))
1241 return 3;
1242
1243 if ((bufLen < 0) || (bufLen > 1023))
1244 return -EINVAL;
1245try_again:
1246 if (bufLen > 1)
1247 pBuf[1] = 0x0;
1249 io_hdr.dxfer_len = bufLen;
1250 io_hdr.dxferp = pBuf;
1251 cdb[0] = INQUIRY;
1252 cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
1253 cdb[2] = vpd_page;
1254 sg_put_unaligned_be16(bufLen, cdb + 3);
1255 io_hdr.cmnd = cdb;
1256 io_hdr.cmnd_len = sizeof(cdb);
1257 io_hdr.sensep = sense;
1258 io_hdr.max_sense_len = sizeof(sense);
1260
1261 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1262 return -device->get_errno();
1263 if ((SCSI_STATUS_CHECK_CONDITION == io_hdr.scsi_status) &&
1265 (SCSI_ASC_INVALID_FIELD == sinfo.asc) &&
1266 (cdb[3] > 0)) {
1267 bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */
1268 goto try_again;
1269 }
1270
1271 if ((res = scsiSimpleSenseFilter(&sinfo)))
1272 return res;
1273 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
1274 if (bufLen > 1) {
1275 if (vpd_page == pBuf[1]) {
1276 if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2]))
1277 return SIMPLE_ERR_BAD_RESP;
1278 } else
1279 return SIMPLE_ERR_BAD_RESP;
1280 }
1281 return 0;
1282}
1283
1284/* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
1285 * SPC-3 section 6.27 (rev 22a) */
1286int
1287scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
1288{
1289 struct scsi_cmnd_io io_hdr = {};
1290 uint8_t cdb[6] = {};
1291 uint8_t sense[32];
1292 uint8_t buff[18] = {};
1293 bool ok;
1294 static const int sz_buff = sizeof(buff);
1295
1297 io_hdr.dxfer_len = sz_buff;
1298 io_hdr.dxferp = buff;
1299 cdb[0] = REQUEST_SENSE;
1300 cdb[4] = sz_buff;
1301 io_hdr.cmnd = cdb;
1302 io_hdr.cmnd_len = sizeof(cdb);
1303 io_hdr.sensep = sense;
1304 io_hdr.max_sense_len = sizeof(sense);
1306
1307 if (sense_info)
1308 ok = scsi_pass_through_yield_sense(device, &io_hdr, *sense_info);
1309 else {
1310 scsi_sense_disect dummy_sense;
1311 ok = scsi_pass_through_yield_sense(device, &io_hdr, dummy_sense);
1312 }
1313 if (! ok)
1314 return -device->get_errno();
1315 if (sense_info) {
1316 uint8_t resp_code = buff[0] & 0x7f;
1317 sense_info->resp_code = resp_code;
1318 sense_info->sense_key = buff[2] & 0xf;
1319 sense_info->asc = 0;
1320 sense_info->ascq = 0;
1321 if ((0x70 == resp_code) || (0x71 == resp_code)) {
1322 int len = buff[7] + 8;
1323 if (len > 13) {
1324 sense_info->asc = buff[12];
1325 sense_info->ascq = buff[13];
1326 }
1327 }
1328 // fill progress indicator, if available
1329 sense_info->progress = -1;
1330 switch (resp_code) {
1331 const unsigned char * ucp;
1332 int sk, sk_pr;
1333 case 0x70:
1334 case 0x71:
1335 sk = (buff[2] & 0xf);
1336 if (! ((SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk))) {
1337 break;
1338 }
1339 if (buff[15] & 0x80) { /* SKSV bit set */
1340 sense_info->progress = sg_get_unaligned_be16(buff + 16);
1341 break;
1342 } else {
1343 break;
1344 }
1345 case 0x72:
1346 case 0x73:
1347 /* sense key specific progress (0x2) or progress descriptor (0xa) */
1348 sk = (buff[1] & 0xf);
1349 sk_pr = (SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk);
1350 if (sk_pr && ((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 2))) &&
1351 (0x6 == ucp[1]) && (0x80 & ucp[4])) {
1352 sense_info->progress = sg_get_unaligned_be16(ucp + 5);
1353 break;
1354 } else if (((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 0xa))) &&
1355 ((0x6 == ucp[1]))) {
1356 sense_info->progress = sg_get_unaligned_be16(ucp + 6);
1357 break;
1358 } else
1359 break;
1360 default:
1361 return 0;
1362 }
1363 }
1364 return 0;
1365}
1366
1367/* Send Start Stop Unit command with power_condition setting and
1368 * Power condition command. Returns 0 if ok, anything else major problem.
1369 * If power_cond is 0, treat as SSU(START) as that is better than
1370 * SSU(STOP) which would be the case if byte 4 of the cdb was zero.
1371 * Ref: SBC-4 revision 22, section 4.20 SSU and power conditions.
1372 *
1373 * SCSI_POW_COND_ACTIVE 0x1
1374 * SCSI_POW_COND_IDLE 0x2
1375 * SCSI_POW_COND_STANDBY 0x3
1376 *
1377 */
1378
1379int
1380scsiSetPowerCondition(scsi_device * device, int power_cond, int pcond_modifier)
1381{
1382 struct scsi_cmnd_io io_hdr = {};
1383 struct scsi_sense_disect sinfo;
1384 uint8_t cdb[6] = {};
1385 uint8_t sense[32];
1386
1387 io_hdr.dxfer_dir = DXFER_NONE;
1388 cdb[0] = START_STOP_UNIT;
1389 /* IMMED bit (cdb[1] = 0x1) not set, therefore will wait */
1390 if (power_cond > 0) {
1391 cdb[3] = pcond_modifier & 0xf;
1392 cdb[4] = power_cond << 4;
1393 } else
1394 cdb[4] = 0x1; /* START */
1395 io_hdr.cmnd = cdb;
1396 io_hdr.cmnd_len = sizeof(cdb);
1397 io_hdr.sensep = sense;
1398 io_hdr.max_sense_len = sizeof(sense);
1400
1401 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1402 return -device->get_errno();
1403
1404 return scsiSimpleSenseFilter(&sinfo);
1405}
1406
1407/* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
1408 * not supported, 3 if field in command not supported or returns negated
1409 * errno. SPC-3 section 6.28 (rev 22a) */
1410int
1411scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf,
1412 int bufLen)
1413{
1414 struct scsi_cmnd_io io_hdr = {};
1415 struct scsi_sense_disect sinfo;
1416 uint8_t cdb[6] = {};
1417 uint8_t sense[32];
1418
1419 io_hdr.dxfer_dir = bufLen ? DXFER_TO_DEVICE: DXFER_NONE;
1420 io_hdr.dxfer_len = bufLen;
1421 io_hdr.dxferp = pBuf;
1422 cdb[0] = SEND_DIAGNOSTIC;
1423 if (SCSI_DIAG_DEF_SELF_TEST == functioncode)
1424 cdb[1] = 0x4; /* SelfTest bit */
1425 else if (SCSI_DIAG_NO_SELF_TEST != functioncode)
1426 cdb[1] = (functioncode & 0x7) << 5; /* SelfTest _code_ */
1427 else /* SCSI_DIAG_NO_SELF_TEST == functioncode */
1428 cdb[1] = 0x10; /* PF bit */
1429 sg_put_unaligned_be16(bufLen, cdb + 3);
1430 io_hdr.cmnd = cdb;
1431 io_hdr.cmnd_len = sizeof(cdb);
1432 io_hdr.sensep = sense;
1433 io_hdr.max_sense_len = sizeof(sense);
1434 /* worst case is an extended foreground self test on a big disk */
1436
1437 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1438 return -device->get_errno();
1439 return scsiSimpleSenseFilter(&sinfo);
1440}
1441
1442/* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
1443static int
1445{
1446 struct scsi_cmnd_io io_hdr = {};
1447 bool ok;
1448 uint8_t cdb[6] = {};
1449 uint8_t sense[32];
1450
1451 io_hdr.dxfer_dir = DXFER_NONE;
1452 io_hdr.dxfer_len = 0;
1453 io_hdr.dxferp = nullptr;
1454 cdb[0] = TEST_UNIT_READY;
1455 io_hdr.cmnd = cdb;
1456 io_hdr.cmnd_len = sizeof(cdb);
1457 io_hdr.sensep = sense;
1458 io_hdr.max_sense_len = sizeof(sense);
1460
1461 if (sinfop)
1462 ok = scsi_pass_through_yield_sense(device, &io_hdr, *sinfop);
1463 else {
1464 struct scsi_sense_disect dummy_si;
1465 ok = scsi_pass_through_yield_sense(device, &io_hdr, dummy_si);
1466 }
1467 if (! ok)
1468 return -device->get_errno();
1469 return 0;
1470}
1471
1472/* Returns 0 for device responds and media ready, 1 for device responds and
1473 media not ready, or returns a negated errno value */
1474int
1476{
1477 struct scsi_sense_disect sinfo;
1478 int status;
1479
1480 status = _testunitready(device, &sinfo);
1481 if (0 != status)
1482 return status;
1483 return scsiSimpleSenseFilter(&sinfo);
1484}
1485
1486/* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1487 * command not supported, 3 if field in command not supported, 101 if
1488 * defect list not found (e.g. SSD may not have defect list) or returns
1489 * negated errno. SBC-2 section 5.12 (rev 16) */
1490int
1491scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
1492 int dl_format, uint8_t *pBuf, int bufLen)
1493{
1494 struct scsi_cmnd_io io_hdr = {};
1495 struct scsi_sense_disect sinfo;
1496 uint8_t cdb[10] = {};
1497 uint8_t sense[32];
1498
1500 io_hdr.dxfer_len = bufLen;
1501 io_hdr.dxferp = pBuf;
1502 cdb[0] = READ_DEFECT_10;
1503 cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) |
1504 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
1505 sg_put_unaligned_be16(bufLen, cdb + 7);
1506 io_hdr.cmnd = cdb;
1507 io_hdr.cmnd_len = sizeof(cdb);
1508 io_hdr.sensep = sense;
1509 io_hdr.max_sense_len = sizeof(sense);
1511
1512 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1513 return -device->get_errno();
1514 /* Look for "(Primary|Grown) defect list not found" */
1515 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1516 return 101;
1517 return scsiSimpleSenseFilter(&sinfo);
1518}
1519
1520/* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if
1521 * command not supported, 3 if field in command not supported, 101 if
1522 * defect list not found (e.g. SSD may not have defect list) or returns
1523 * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */
1524int
1525scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
1526 int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
1527{
1528 struct scsi_cmnd_io io_hdr = {};
1529 struct scsi_sense_disect sinfo;
1530 uint8_t cdb[12] = {};
1531 uint8_t sense[32];
1532
1534 io_hdr.dxfer_len = bufLen;
1535 io_hdr.dxferp = pBuf;
1536 cdb[0] = READ_DEFECT_12;
1537 cdb[1] = (unsigned char)(((req_plist << 4) & 0x10) |
1538 ((req_glist << 3) & 0x8) | (dl_format & 0x7));
1539 sg_put_unaligned_be32(addrDescIndex, cdb + 2);
1540 sg_put_unaligned_be32(bufLen, cdb + 6);
1541 io_hdr.cmnd = cdb;
1542 io_hdr.cmnd_len = sizeof(cdb);
1543 io_hdr.sensep = sense;
1544 io_hdr.max_sense_len = sizeof(sense);
1546
1547 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1548 return -device->get_errno();
1549 /* Look for "(Primary|Grown) defect list not found" */
1550 if ((sinfo.resp_code >= 0x70) && (0x1c == sinfo.asc))
1551 return 101;
1552 return scsiSimpleSenseFilter(&sinfo);
1553}
1554
1555/* Call scsi_pass_through, and retry only if a UNIT_ATTENTION (UA) is raised.
1556 * When false returned, the caller should invoke device->get_error().
1557 * When true returned, the caller should check sinfo.
1558 * All SCSI commands can receive pending Unit Attentions, apart from:
1559 * INQUIRY, REPORT LUNS, REQUEST SENSE and NOTIFY DATA TRANSFER DEVICE
1560 * (ADC-3 spec). The first three are the important ones. */
1561bool
1563 /* OUT param */ scsi_sense_disect & sinfo)
1564{
1565 int k;
1566 uint32_t opcode = (iop->cmnd_len > 0) ? iop->cmnd[0] : 0xffff;
1567
1568 if (scsi_debugmode > 2) {
1569 bool dout = false;
1570 const char * ddir = "none";
1571 const char * np;
1572
1573 if (iop->dxfer_len > 0) {
1574 dout = (DXFER_TO_DEVICE == iop->dxfer_dir);
1575 ddir = dout ? "out" : "in";
1576 }
1577 np = scsi_get_opcode_name(iop->cmnd);
1578 pout(" [%s: ", np ? np : "<unknown opcode>");
1579 pout("SCSI opcode=0x%x, CDB length=%u, data length=0x%u, data "
1580 "dir=%s]\n", opcode, (unsigned int)iop->cmnd_len,
1581 (unsigned int)iop->dxfer_len, ddir);
1582 if (dout && (scsi_debugmode > 3)) /* output hex without address */
1583 dStrHexFp(iop->dxferp, iop->dxfer_len, -1, nullptr);
1584 }
1585
1586 if (! device->scsi_pass_through(iop))
1587 return false; // this will be missing device, timeout, etc
1588
1589 if (scsi_debugmode > 3) {
1590 unsigned int req_len = iop->dxfer_len;
1591 unsigned int act_len;
1592
1593 if ((req_len > 0) && (DXFER_FROM_DEVICE == iop->dxfer_dir) &&
1594 (iop->resid >= 0) && (req_len >= (unsigned int)iop->resid)) {
1595 act_len = req_len - (unsigned int)iop->resid;
1596 pout(" [data-in buffer: req_len=%u, resid=%d, gives %u "
1597 "bytes]\n", req_len, iop->resid, act_len);
1598 dStrHexFp(iop->dxferp, act_len, -1, nullptr);
1599 }
1600 }
1601 scsi_do_sense_disect(iop, &sinfo);
1602
1603 switch (opcode) {
1604 case INQUIRY:
1605 case REPORT_LUNS:
1606 case REQUEST_SENSE:
1607 return true; /* in these cases, it shouldn't be a UA */
1608 default:
1609 break; /* continue on for all other SCSI commands to check for UA */
1610 }
1611
1612 /* There can be multiple UAs pending, allow for three */
1613 for (k = 0; (k < 3) && (SCSI_SK_UNIT_ATTENTION == sinfo.sense_key); ++k) {
1614 if (scsi_debugmode > 0)
1615 pout("%s Unit Attention %d: asc/ascq=0x%x,0x%x, retrying\n",
1616 __func__, k + 1, sinfo.asc, sinfo.ascq);
1617 if (! device->scsi_pass_through(iop))
1618 return false;
1619 scsi_do_sense_disect(iop, &sinfo);
1620 }
1621 return true;
1622}
1623
1624/* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1625 * command not supported, 3 if field in command not supported or returns
1626 * negated errno. SBC-3 section 5.15 (rev 26) */
1627int
1628scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
1629 unsigned int * lb_sizep)
1630{
1631 int res;
1632 struct scsi_cmnd_io io_hdr = {};
1633 struct scsi_sense_disect sinfo;
1634 uint8_t cdb[10] = {};
1635 uint8_t sense[32];
1636 uint8_t resp[8] = {};
1637
1639 io_hdr.dxfer_len = sizeof(resp);
1640 io_hdr.dxferp = resp;
1641 cdb[0] = READ_CAPACITY_10;
1642 io_hdr.cmnd = cdb;
1643 io_hdr.cmnd_len = sizeof(cdb);
1644 io_hdr.sensep = sense;
1645 io_hdr.max_sense_len = sizeof(sense);
1647
1648 if (! scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1649 return -device->get_errno();
1650 res = scsiSimpleSenseFilter(&sinfo);
1651 if (res)
1652 return res;
1653 if (last_lbap)
1654 *last_lbap = sg_get_unaligned_be32(resp + 0);
1655 if (lb_sizep)
1656 *lb_sizep = sg_get_unaligned_be32(resp + 4);
1657 return 0;
1658}
1659
1660/* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0
1661 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command
1662 * not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */
1663int
1664scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen)
1665{
1666 struct scsi_cmnd_io io_hdr = {};
1667 struct scsi_sense_disect sinfo;
1668 uint8_t cdb[16] = {};
1669 uint8_t sense[32];
1670
1672 io_hdr.dxfer_len = bufLen;
1673 io_hdr.dxferp = pBuf;
1676 sg_put_unaligned_be32(bufLen, cdb + 10);
1677 io_hdr.cmnd = cdb;
1678 io_hdr.cmnd_len = sizeof(cdb);
1679 io_hdr.sensep = sense;
1680 io_hdr.max_sense_len = sizeof(sense);
1682
1683 if (!scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1684 return -device->get_errno();
1685 return scsiSimpleSenseFilter(&sinfo);
1686}
1687
1688/* REPORT SUPPORTED OPERATION CODES [RSOC] command. If SIMPLE_NO_ERROR is
1689 * returned then the response length is written to rspLen. */
1690int
1691scsiRSOCcmd(scsi_device * device, bool rctd, uint8_t rep_opt, uint8_t opcode,
1692 uint16_t serv_act, uint8_t *pBuf, int bufLen, int & rspLen)
1693{
1694 struct scsi_cmnd_io io_hdr = {};
1695 struct scsi_sense_disect sinfo;
1696 int res;
1697 uint8_t cdb[12] = {};
1698 uint8_t sense[32];
1699
1701 io_hdr.dxfer_len = bufLen;
1702 io_hdr.dxferp = pBuf;
1705 if (rctd)
1706 cdb[2] |= 0x80;
1707 if (rep_opt > 0)
1708 cdb[2] |= (0x7 & rep_opt);
1709 cdb[3] = opcode;
1710 sg_put_unaligned_be16(serv_act, cdb + 4);
1711 sg_put_unaligned_be32(bufLen, cdb + 6);
1712 io_hdr.cmnd = cdb;
1713 io_hdr.cmnd_len = sizeof(cdb);
1714 io_hdr.sensep = sense;
1715 io_hdr.max_sense_len = sizeof(sense);
1717
1718 if (!scsi_pass_through_yield_sense(device, &io_hdr, sinfo))
1719 return -device->get_errno();
1720 res = scsiSimpleSenseFilter(&sinfo);
1721 if (SIMPLE_NO_ERROR == res)
1722 rspLen = bufLen - io_hdr.resid;
1723 return res;
1724}
1725
1726/* Return number of bytes of storage in 'device' or 0 if error. If
1727 * successful and lb_sizep is not nullptr then the logical block size in bytes
1728 * is written to the location pointed to by lb_sizep. If the 'Logical Blocks
1729 * per Physical Block Exponent' pointer (lb_per_pb_expp,) is non-null then
1730 * the value is written. If 'Protection information Intervals Exponent'*/
1731uint64_t
1732scsiGetSize(scsi_device * device, bool avoid_rcap16,
1733 struct scsi_readcap_resp * srrp)
1734{
1735 bool try_16 = false;
1736 bool try_12 = false;
1737 unsigned int last_lba = 0, lb_size = 0;
1738 int res;
1739 uint64_t ret_val = 0;
1740 uint8_t rc16resp[32];
1741
1742 if (avoid_rcap16) {
1743 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1744 if (res) {
1745 if (scsi_debugmode)
1746 pout("%s: READ CAPACITY(10) failed, res=%d\n", __func__, res);
1747 try_16 = true;
1748 } else { /* rcap10 succeeded */
1749 if (0xffffffff == last_lba) {
1750 /* so number of blocks needs > 32 bits to represent */
1751 try_16 = true;
1752 device->set_rcap16_first();
1753 } else {
1754 ret_val = last_lba + 1;
1755 if (srrp) {
1756 memset(srrp, 0, sizeof(*srrp));
1757 srrp->num_lblocks = ret_val;
1758 srrp->lb_size = lb_size;
1759 }
1760 }
1761 }
1762 } else if (SC_SUPPORT ==
1765 try_16 = true;
1766
1767 if (try_16 || (! avoid_rcap16)) {
1768 res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
1769 if (res) {
1770 if (scsi_debugmode)
1771 pout("%s: READ CAPACITY(16) failed, res=%d\n", __func__, res);
1772 if (try_16) /* so already tried rcap10 */
1773 return 0;
1774 try_12 = true;
1775 } else { /* rcap16 succeeded */
1776 ret_val = sg_get_unaligned_be64(rc16resp + 0) + 1;
1777 lb_size = sg_get_unaligned_be32(rc16resp + 8);
1778 if (srrp) { /* writes to all fields */
1779 srrp->num_lblocks = ret_val;
1780 srrp->lb_size = lb_size;
1781 bool prot_en = !!(0x1 & rc16resp[12]);
1782 uint8_t p_type = ((rc16resp[12] >> 1) & 0x7);
1783 srrp->prot_type = prot_en ? (1 + p_type) : 0;
1784 srrp->p_i_exp = ((rc16resp[13] >> 4) & 0xf);
1785 srrp->lb_p_pb_exp = (rc16resp[13] & 0xf);
1786 srrp->lbpme = !!(0x80 & rc16resp[14]);
1787 srrp->lbprz = !!(0x40 & rc16resp[14]);
1788 srrp->l_a_lba = sg_get_unaligned_be16(rc16resp + 14) & 0x3fff;
1789 }
1790 }
1791 }
1792 if (try_12) { /* case where only rcap16 has been tried and failed */
1793 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1794 if (res) {
1795 if (scsi_debugmode)
1796 pout("%s: 2nd READ CAPACITY(10) failed, res=%d\n", __func__,
1797 res);
1798 return 0;
1799 } else { /* rcap10 succeeded */
1800 ret_val = (uint64_t)last_lba + 1;
1801 if (srrp) {
1802 memset(srrp, 0, sizeof(*srrp));
1803 srrp->num_lblocks = ret_val;
1804 srrp->lb_size = lb_size;
1805 }
1806 }
1807 }
1808 return (ret_val * lb_size);
1809}
1810
1811/* Offset into mode sense (6 or 10 byte) response that actual mode page
1812 * starts at (relative to resp[0]). Returns -1 if problem */
1813int
1814scsiModePageOffset(const uint8_t * resp, int len, int modese_len)
1815{
1816 int offset = -1;
1817
1818 if (resp) {
1819 int resp_len, bd_len;
1820 if (10 == modese_len) {
1821 resp_len = sg_get_unaligned_be16(resp + 0) + 2;
1822 bd_len = sg_get_unaligned_be16(resp + 6);
1823 offset = bd_len + 8;
1824 } else {
1825 resp_len = resp[0] + 1;
1826 bd_len = resp[3];
1827 offset = bd_len + 4;
1828 }
1829 if ((offset + 2) >= len) {
1830 pout("scsiModePageOffset: raw_curr too small, offset=%d "
1831 "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
1832 offset = -1;
1833 } else if ((offset + 2) >= resp_len) {
1834 if ((resp_len > 2) || scsi_debugmode)
1835 pout("scsiModePageOffset: response length too short, "
1836 "resp_len=%d offset=%d bd_len=%d\n", resp_len,
1837 offset, bd_len);
1838 offset = -1;
1839 }
1840 }
1841 return offset;
1842}
1843
1844/* IEC mode page byte 2 bit masks */
1845#define DEXCPT_ENABLE 0x08
1846#define EWASC_ENABLE 0x10
1847#define DEXCPT_DISABLE 0xf7
1848#define EWASC_DISABLE 0xef
1849#define TEST_DISABLE 0xfb
1850
1851/* Fetches the Informational Exceptions Control mode page. First tries
1852 * the 6 byte MODE SENSE command and if that fails with an illegal opcode
1853 * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
1854 * number if a known error (see SIMPLE_ERR_ ...) or a negative errno
1855 * value. */
1856int
1858 int modese_len)
1859{
1860 int err = 0;
1861
1862 memset(iecp, 0, sizeof(*iecp));
1863 iecp->modese_len = modese_len;
1864 iecp->requestedCurrent = 1;
1865 if (iecp->modese_len <= 6) {
1868 iecp->raw_curr, sizeof(iecp->raw_curr)))) {
1869 if (SIMPLE_ERR_BAD_OPCODE == err)
1870 iecp->modese_len = 10;
1871 else {
1872 iecp->modese_len = 0;
1873 return err;
1874 }
1875 } else if (0 == iecp->modese_len)
1876 iecp->modese_len = 6;
1877 }
1878 if (10 == iecp->modese_len) {
1881 iecp->raw_curr, sizeof(iecp->raw_curr));
1882 if (err) {
1883 iecp->modese_len = 0;
1884 return err;
1885 }
1886 }
1887 iecp->gotCurrent = 1;
1888 iecp->requestedChangeable = 1;
1889 if (10 == iecp->modese_len)
1892 iecp->raw_chg, sizeof(iecp->raw_chg));
1893 else if (6 == iecp->modese_len)
1896 iecp->raw_chg, sizeof(iecp->raw_chg));
1897 if (err)
1898 return err;
1899 iecp->gotChangeable = 1;
1900 return 0;
1901}
1902
1903int
1905{
1906 if (iecp && iecp->gotCurrent) {
1907 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1908 iecp->modese_len);
1909 if (offset >= 0)
1910 return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1911 else
1912 return 0;
1913 } else
1914 return 0;
1915}
1916
1917int
1919{
1920 if (iecp && iecp->gotCurrent) {
1921 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1922 iecp->modese_len);
1923 if (offset >= 0)
1924 return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1925 else
1926 return 0;
1927 } else
1928 return 0;
1929}
1930
1931/* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */
1932#define SCSI_IEC_MP_BYTE2_ENABLED 0x10
1933#define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
1934/* exception/warning via an unrequested REQUEST SENSE command */
1935#define SCSI_IEC_MP_MRIE 6
1936#define SCSI_IEC_MP_INTERVAL_T 0
1937#define SCSI_IEC_MP_REPORT_COUNT 1
1938
1939/* Try to set (or clear) both Exception Control and Warning in the IE
1940 * mode page subject to the "changeable" mask. The object pointed to
1941 * by iecp is (possibly) inaccurate after this call, therefore
1942 * scsiFetchIECmpage() should be called again if the IEC mode page
1943 * is to be re-examined.
1944 * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
1945 * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
1946int
1948 const struct scsi_iec_mode_page *iecp)
1949{
1950 int offset, resp_len;
1951 int err = 0;
1952 uint8_t rout[SCSI_IECMP_RAW_LEN];
1953
1954 if ((! iecp) || (! iecp->gotCurrent))
1955 return -EINVAL;
1956 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1957 iecp->modese_len);
1958 if (offset < 0)
1959 return -EINVAL;
1960 memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN);
1961 /* mask out DPOFUA device specific (disk) parameter bit */
1962 if (10 == iecp->modese_len) {
1963 resp_len = sg_get_unaligned_be16(rout + 0) + 2;
1964 rout[3] &= 0xef;
1965 } else {
1966 resp_len = rout[0] + 1;
1967 rout[2] &= 0xef;
1968 }
1969 int sp = !! (rout[offset] & 0x80); /* PS bit becomes 'SELECT's SP bit */
1970 if (enabled) {
1971 if ((offset + 12) > SCSI_IECMP_RAW_LEN)
1972 return -EINVAL;
1973 rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
1974 if (scsi_debugmode > 2)
1975 rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
1976 rout[offset + 3] = SCSI_IEC_MP_MRIE;
1979 if (iecp->gotChangeable) {
1980 uint8_t chg2 = iecp->raw_chg[offset + 2];
1981
1982 rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
1983 iecp->raw_curr[offset + 2];
1984 for (int k = 3; k < 12; ++k) {
1985 if (0 == iecp->raw_chg[offset + k])
1986 rout[offset + k] = iecp->raw_curr[offset + k];
1987 }
1988 }
1989 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
1990 if (scsi_debugmode > 0)
1991 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1992 return 0;
1993 }
1994 } else { /* disabling Exception Control and (temperature) Warnings */
1995 int eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1996 int wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1997 if ((! eCEnabled) && (! wEnabled)) {
1998 if (scsi_debugmode > 0)
1999 pout("scsiSetExceptionControlAndWarning: already disabled\n");
2000 return 0; /* nothing to do, leave other setting alone */
2001 }
2002 if (wEnabled)
2003 rout[offset + 2] &= EWASC_DISABLE;
2004 if (eCEnabled) {
2005 if (iecp->gotChangeable &&
2006 (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
2007 rout[offset + 2] |= DEXCPT_ENABLE;
2008 rout[offset + 2] &= TEST_DISABLE; /* clear TEST bit for spec */
2009 }
2010 }
2011 if (10 == iecp->modese_len)
2012 err = scsiModeSelect10(device, sp, rout, resp_len);
2013 else if (6 == iecp->modese_len)
2014 err = scsiModeSelect(device, sp, rout, resp_len);
2015 return err;
2016}
2017
2018int
2019scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp)
2020{
2021 uint8_t tBuf[252] = {};
2022 int err;
2023
2024 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
2025 sizeof(tBuf), 0))) {
2026 *currenttemp = 0;
2027 *triptemp = 0;
2028 pout("%s for temperature failed [%s]\n", logSenStr,
2029 scsiErrString(err));
2030 return err;
2031 }
2032 *currenttemp = tBuf[9];
2033 *triptemp = tBuf[15];
2034 return 0;
2035}
2036
2037/* Informational Exception conditions specified by spc6r06.pdf seem to be
2038 * associated with ASC values 0xb (warnings) and 0x5d (impending failures).
2039 * The asc/accq value 0x5d,0xff is reported in response to setting the TEST
2040 * bit in the Informationl Exception Control mode page. */
2041
2042/* Read informational exception log page or Request Sense response.
2043 * Fetching asc/ascq code potentially flagging an exception or warning.
2044 * Returns 0 if ok, else error number. A current temperature of 255
2045 * (Celsius) implies that the temperature not available. */
2046int
2047scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
2048 uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
2049 uint8_t *triptemp)
2050{
2051 uint8_t tBuf[252] = {};
2052 struct scsi_sense_disect sense_info;
2053 int err;
2054 uint8_t currTemp, trTemp;
2055
2056 memset(&sense_info, 0, sizeof(sense_info));
2057 *asc = 0;
2058 *ascq = 0;
2059 *currenttemp = 0;
2060 *triptemp = 0;
2061 if (hasIELogPage) {
2062 if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
2063 sizeof(tBuf), 0))) {
2064 pout("%s failed, IE page [%s]\n", logSenStr, scsiErrString(err));
2065 return err;
2066 }
2067 // pull out page size from response, don't forget to add 4
2068 unsigned short pagesize = sg_get_unaligned_be16(tBuf + 2) + 4;
2069 if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
2070 pout("%s failed, IE page, bad parameter code or length\n",
2071 logSenStr);
2072 return SIMPLE_ERR_BAD_PARAM;
2073 }
2074 if (tBuf[7] > 1) {
2075 sense_info.asc = tBuf[8];
2076 sense_info.ascq = tBuf[9];
2077 if (! hasTempLogPage) {
2078 if (tBuf[7] > 2)
2079 *currenttemp = tBuf[10];
2080 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
2081 *triptemp = tBuf[11];
2082 }
2083 }
2084 }
2085 if (0 == sense_info.asc) {
2086 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
2087 if ((err = scsiRequestSense(device, &sense_info))) {
2088 pout("Request Sense failed, [%s]\n", scsiErrString(err));
2089 return err;
2090 }
2091 }
2092 *asc = sense_info.asc;
2093 *ascq = sense_info.ascq;
2094 if (hasTempLogPage) {
2095 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
2096 *currenttemp = currTemp;
2097 *triptemp = trTemp;
2098 }
2099 }
2100 return 0;
2101}
2102
2103// The first character (W, C, I) tells the severity
2104static const char * TapeAlertsMessageTable[]= {
2105 " ",
2106 /* 0x01 */
2107 "W: The tape drive is having problems reading data. No data has been "
2108 "lost,\n"
2109 " but there has been a reduction in the performance of the tape.",
2110 /* 0x02 */
2111 "W: The tape drive is having problems writing data. No data has been "
2112 "lost,\n"
2113 " but there has been a reduction in the capacity of the tape.",
2114 /* 0x03 */
2115 "W: The operation has stopped because an error has occurred while "
2116 "reading\n"
2117 " or writing data that the drive cannot correct.",
2118 /* 0x04 */
2119 "C: Your data is at risk:\n"
2120 " 1. Copy any data you require from this tape. \n"
2121 " 2. Do not use this tape again.\n"
2122 " 3. Restart the operation with a different tape.",
2123 /* 0x05 */
2124 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
2125 " supplier helpline.",
2126 /* 0x06 */
2127 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
2128 " 1. Use a good tape to test the drive.\n"
2129 " 2. If problem persists, call the tape drive supplier helpline.",
2130 /* 0x07 */
2131 "W: The tape cartridge has reached the end of its calculated useful "
2132 "life:\n"
2133 " 1. Copy data you need to another tape.\n"
2134 " 2. Discard the old tape.",
2135 /* 0x08 */
2136 "W: The tape cartridge is not data-grade. Any data you back up to the "
2137 "tape\n"
2138 " is at risk. Replace the cartridge with a data-grade tape.",
2139 /* 0x09 */
2140 "C: You are trying to write to a write-protected cartridge. Remove the\n"
2141 " write-protection or use another tape.",
2142 /* 0x0a */
2143 "I: You cannot eject the cartridge because the tape drive is in use. "
2144 "Wait\n"
2145 " until the operation is complete before ejecting the cartridge.",
2146 /* 0x0b */
2147 "I: The tape in the drive is a cleaning cartridge.",
2148 /* 0x0c */
2149 "I: You have tried to load a cartridge of a type which is not supported\n"
2150 " by this drive.",
2151 /* 0x0d */
2152 "C: The operation has failed because the tape in the drive has "
2153 "experienced\n"
2154 " a mechanical failure:\n"
2155 " 1. Discard the old tape.\n"
2156 " 2. Restart the operation with a different tape.",
2157 /* 0x0e */
2158 "C: The operation has failed because the tape in the drive has "
2159 "experienced\n"
2160 " a mechanical failure:\n"
2161 " 1. Do not attempt to extract the tape cartridge\n"
2162 " 2. Call the tape drive supplier helpline.",
2163 /* 0x0f */
2164 "W: The memory in the tape cartridge has failed, which reduces\n"
2165 " performance. Do not use the cartridge for further write "
2166 "operations.",
2167 /* 0x10 */
2168 "C: The operation has failed because the tape cartridge was manually\n"
2169 " de-mounted while the tape drive was actively writing or reading.",
2170 /* 0x11 */
2171 "W: You have loaded a cartridge of a type that is read-only in this "
2172 "drive.\n"
2173 " The cartridge will appear as write-protected.",
2174 /* 0x12 */
2175 "W: The tape directory on the tape cartridge has been corrupted. File\n"
2176 " search performance will be degraded. The tape directory can be "
2177 "rebuilt\n"
2178 " by reading all the data on the cartridge.",
2179 /* 0x13 */
2180 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
2181 " recommended that you:\n"
2182 " 1. Use another tape cartridge for your next backup.\n"
2183 " 2. Store this tape in a safe place in case you need to restore "
2184 " data from it.",
2185 /* 0x14 */
2186 "C: The tape drive needs cleaning:\n"
2187 " 1. If the operation has stopped, eject the tape and clean the "
2188 "drive.\n"
2189 " 2. If the operation has not stopped, wait for it to finish and "
2190 "then\n"
2191 " clean the drive.\n"
2192 " Check the tape drive users manual for device specific cleaning "
2193 "instructions.",
2194 /* 0x15 */
2195 "W: The tape drive is due for routine cleaning:\n"
2196 " 1. Wait for the current operation to finish.\n"
2197 " 2. The use a cleaning cartridge.\n"
2198 " Check the tape drive users manual for device specific cleaning "
2199 "instructions.",
2200 /* 0x16 */
2201 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
2202 " 1. Discard the worn out cleaning cartridge.\n"
2203 " 2. Wait for the current operation to finish.\n"
2204 " 3. Then use a new cleaning cartridge.",
2205 /* 0x17 */
2206 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
2207 " type:\n"
2208 " 1. Do not use this cleaning cartridge in this drive.\n"
2209 " 2. Wait for the current operation to finish.\n"
2210 " 3. Then use a new cleaning cartridge.",
2211 /* 0x18 */
2212 "W: The tape drive has requested a retention operation",
2213 /* 0x19 */
2214 "W: A redundant interface port on the tape drive has failed",
2215 /* 0x1a */
2216 "W: A tape drive cooling fan has failed",
2217 /* 0x1b */
2218 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
2219 " Check the enclosure users manual for instructions on replacing "
2220 "the\n"
2221 " failed power supply.",
2222 /* 0x1c */
2223 "W: The tape drive power consumption is outside the specified range.",
2224 /* 0x1d */
2225 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
2226 " drive users manual for device specific preventive maintenance\n"
2227 " tasks or call the tape drive supplier helpline.",
2228 /* 0x1e */
2229 "C: The tape drive has a hardware fault:\n"
2230 " 1. Eject the tape or magazine.\n"
2231 " 2. Reset the drive.\n"
2232 " 3. Restart the operation.",
2233 /* 0x1f */
2234 "C: The tape drive has a hardware fault:\n"
2235 " 1. Turn the tape drive off and then on again.\n"
2236 " 2. Restart the operation.\n"
2237 " 3. If the problem persists, call the tape drive supplier helpline.",
2238 /* 0x20 */
2239 "W: The tape drive has a problem with the application client interface:\n"
2240 " 1. Check the cables and cable connections.\n"
2241 " 2. Restart the operation.",
2242 /* 0x21 */
2243 "C: The operation has failed:\n"
2244 " 1. Eject the tape or magazine.\n"
2245 " 2. Insert the tape or magazine again.\n"
2246 " 3. Restart the operation.",
2247 /* 0x22 */
2248 "W: The firmware download has failed because you have tried to use the\n"
2249 " incorrect firmware for this tape drive. Obtain the correct\n"
2250 " firmware and try again.",
2251 /* 0x23 */
2252 "W: Environmental conditions inside the tape drive are outside the\n"
2253 " specified humidity range.",
2254 /* 0x24 */
2255 "W: Environmental conditions inside the tape drive are outside the\n"
2256 " specified temperature range.",
2257 /* 0x25 */
2258 "W: The voltage supply to the tape drive is outside the specified range.",
2259 /* 0x26 */
2260 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
2261 " drive supplier helpline.",
2262 /* 0x27 */
2263 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
2264 " verify and diagnose the problem. Check the tape drive users manual "
2265 "for\n"
2266 " device specific instructions on running extended diagnostic tests.",
2267 /* 0x28 */
2268 "C: The changer mechanism is having difficulty communicating with the "
2269 "tape\n"
2270 " drive:\n"
2271 " 1. Turn the autoloader off then on.\n"
2272 " 2. Restart the operation.\n"
2273 " 3. If problem persists, call the tape drive supplier helpline.",
2274 /* 0x29 */
2275 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
2276 " 1. Insert an empty magazine to clear the fault.\n"
2277 " 2. If the fault does not clear, turn the autoloader off and then\n"
2278 " on again.\n"
2279 " 3. If the problem persists, call the tape drive supplier helpline.",
2280 /* 0x2a */
2281 "W: There is a problem with the autoloader mechanism.",
2282 /* 0x2b */
2283 "C: The operation has failed because the autoloader door is open:\n"
2284 " 1. Clear any obstructions from the autoloader door.\n"
2285 " 2. Eject the magazine and then insert it again.\n"
2286 " 3. If the fault does not clear, turn the autoloader off and then\n"
2287 " on again.\n"
2288 " 4. If the problem persists, call the tape drive supplier helpline.",
2289 /* 0x2c */
2290 "C: The autoloader has a hardware fault:\n"
2291 " 1. Turn the autoloader off and then on again.\n"
2292 " 2. Restart the operation.\n"
2293 " 3. If the problem persists, call the tape drive supplier helpline.\n"
2294 " Check the autoloader users manual for device specific instructions\n"
2295 " on turning the device power on and off.",
2296 /* 0x2d */
2297 "C: The autoloader cannot operate without the magazine,\n"
2298 " 1. Insert the magazine into the autoloader.\n"
2299 " 2. Restart the operation.",
2300 /* 0x2e */
2301 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
2302 " tape drive supplier helpline.",
2303 /* 0x2f */
2304 "I: Reserved.",
2305 /* 0x30 */
2306 "I: Reserved.",
2307 /* 0x31 */
2308 "I: Reserved.",
2309 /* 0x32 */
2310 "W: Media statistics have been lost at some time in the past",
2311 /* 0x33 */
2312 "W: The tape directory on the tape cartridge just unloaded has been\n"
2313 " corrupted. File search performance will be degraded. The tape\n"
2314 " directory can be rebuilt by reading all the data.",
2315 /* 0x34 */
2316 "C: The tape just unloaded could not write its system area successfully:\n"
2317 " 1. Copy data to another tape cartridge.\n"
2318 " 2. Discard the old cartridge.",
2319 /* 0x35 */
2320 "C: The tape system are could not be read successfully at load time:\n"
2321 " 1. Copy data to another tape cartridge.\n",
2322 /* 0x36 */
2323 "C: The start or data could not be found on the tape:\n"
2324 " 1. Check you are using the correct format tape.\n"
2325 " 2. Discard the tape or return the tape to your supplier",
2326 /* 0x37 */
2327 "C: The operation has failed because the media cannot be loaded\n"
2328 " and threaded.\n"
2329 " 1. Remove the cartridge, inspect it as specified in the product\n"
2330 " manual, and retry the operation.\n"
2331 " 2. If the problem persists, call the tape drive supplier help "
2332 "line.",
2333 /* 0x38 */
2334 "C: The operation has failed because the medium cannot be unloaded:\n"
2335 " 1. Do not attempt to extract the tape cartridge.\n"
2336 " 2. Call the tape driver supplier help line.",
2337 /* 0x39 */
2338 "C: The tape drive has a problem with the automation interface:\n"
2339 " 1. Check the power to the automation system.\n"
2340 " 2. Check the cables and cable connections.\n"
2341 " 3. Call the supplier help line if problem persists.",
2342 /* 0x3a */
2343 "W: The tape drive has reset itself due to a detected firmware\n"
2344 " fault. If problem persists, call the supplier help line.",
2345 };
2346
2347const char *
2348scsiTapeAlertsTapeDevice(unsigned short code)
2349{
2350 static const int num = sizeof(TapeAlertsMessageTable) /
2351 sizeof(TapeAlertsMessageTable[0]);
2352
2353 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
2354}
2355
2356// The first character (W, C, I) tells the severity
2357static const char * ChangerTapeAlertsMessageTable[]= {
2358 " ",
2359 /* 0x01 */
2360 "C: The library mechanism is having difficulty communicating with the\n"
2361 " drive:\n"
2362 " 1. Turn the library off then on.\n"
2363 " 2. Restart the operation.\n"
2364 " 3. If the problem persists, call the library supplier help line.",
2365 /* 0x02 */
2366 "W: There is a problem with the library mechanism. If problem persists,\n"
2367 " call the library supplier help line.",
2368 /* 0x03 */
2369 "C: The library has a hardware fault:\n"
2370 " 1. Reset the library.\n"
2371 " 2. Restart the operation.\n"
2372 " Check the library users manual for device specific instructions on "
2373 "resetting\n"
2374 " the device.",
2375 /* 0x04 */
2376 "C: The library has a hardware fault:\n"
2377 " 1. Turn the library off then on again.\n"
2378 " 2. Restart the operation.\n"
2379 " 3. If the problem persists, call the library supplier help line.\n"
2380 " Check the library users manual for device specific instructions on "
2381 "turning the\n"
2382 " device power on and off.",
2383 /* 0x05 */
2384 "W: The library mechanism may have a hardware fault.\n"
2385 " Run extended diagnostics to verify and diagnose the problem. "
2386 "Check the library\n"
2387 " users manual for device specific instructions on running extended "
2388 "diagnostic\n"
2389 " tests.",
2390 /* 0x06 */
2391 "C: The library has a problem with the host interface:\n"
2392 " 1. Check the cables and connections.\n"
2393 " 2. Restart the operation.",
2394 /* 0x07 */
2395 "W: A hardware failure of the library is predicted. Call the library\n"
2396 " supplier help line.",
2397 /* 0x08 */
2398 "W: Preventive maintenance of the library is required.\n"
2399 " Check the library users manual for device specific preventative "
2400 "maintenance\n"
2401 " tasks, or call your library supplier help line.",
2402 /* 0x09 */
2403 "C: General environmental conditions inside the library are outside the\n"
2404 " specified humidity range.",
2405 /* 0x0a */
2406 "C: General environmental conditions inside the library are outside the\n"
2407 " specified temperature range.",
2408 /* 0x0b */
2409 "C: The voltage supply to the library is outside the specified range.\n"
2410 " There is a potential problem with the power supply or failure of\n"
2411 " a redundant power supply.",
2412 /* 0x0c */
2413 "C: A cartridge has been left inside the library by a previous hardware\n"
2414 " fault:\n"
2415 " 1. Insert an empty magazine to clear the fault.\n"
2416 " 2. If the fault does not clear, turn the library off and then on "
2417 "again.\n"
2418 " 3. If the problem persists, call the library supplier help line.",
2419 /* 0x0d */
2420 "W: There is a potential problem with the drive ejecting cartridges or\n"
2421 " with the library mechanism picking a cartridge from a slot.\n"
2422 " 1. No action needs to be taken at this time.\n"
2423 " 2. If the problem persists, call the library supplier help line.",
2424 /* 0x0e */
2425 "W: There is a potential problem with the library mechanism placing a\n"
2426 " cartridge into a slot.\n"
2427 " 1. No action needs to be taken at this time.\n"
2428 " 2. If the problem persists, call the library supplier help line.",
2429 /* 0x0f */
2430 "W: There is a potential problem with the drive or the library mechanism\n"
2431 " loading cartridges, or an incompatible cartridge.",
2432 /* 0x10 */
2433 "C: The library has failed because the door is open:\n"
2434 " 1. Clear any obstructions from the library door.\n"
2435 " 2. Close the library door.\n"
2436 " 3. If the problem persists, call the library supplier help line.",
2437 /* 0x11 */
2438 "C: There is a mechanical problem with the library media import/export\n"
2439 " mailslot.",
2440 /* 0x12 */
2441 "C: The library cannot operate without the magazine.\n"
2442 " 1. Insert the magazine into the library.\n"
2443 " 2. Restart the operation.",
2444 /* 0x13 */
2445 "W: Library security has been compromised.",
2446 /* 0x14 */
2447 "I: The library security mode has been changed.\n"
2448 " The library has either been put into secure mode, or the library "
2449 "has exited\n"
2450 " the secure mode.\n"
2451 " This is for information purposes only. No action is required.",
2452 /* 0x15 */
2453 "I: The library has been manually turned offline and is unavailable for "
2454 "use.",
2455 /* 0x16 */
2456 "I: A drive inside the library has been taken offline.\n"
2457 " This is for information purposes only. No action is required.",
2458 /* 0x17 */
2459 "W: There is a potential problem with the bar code label or the scanner\n"
2460 " hardware in the library mechanism.\n"
2461 " 1. No action needs to be taken at this time.\n"
2462 " 2. If the problem persists, call the library supplier help line.",
2463 /* 0x18 */
2464 "C: The library has detected an inconsistency in its inventory.\n"
2465 " 1. Redo the library inventory to correct inconsistency.\n"
2466 " 2. Restart the operation.\n"
2467 " Check the applications users manual or the hardware users manual "
2468 "for\n"
2469 " specific instructions on redoing the library inventory.",
2470 /* 0x19 */
2471 "W: A library operation has been attempted that is invalid at this time.",
2472 /* 0x1a */
2473 "W: A redundant interface port on the library has failed.",
2474 /* 0x1b */
2475 "W: A library cooling fan has failed.",
2476 /* 0x1c */
2477 "W: A redundant power supply has failed inside the library. Check the\n"
2478 " library users manual for instructions on replacing the failed "
2479 "power supply.",
2480 /* 0x1d */
2481 "W: The library power consumption is outside the specified range.",
2482 /* 0x1e */
2483 "C: A failure has occurred in the cartridge pass-through mechanism "
2484 "between\n"
2485 " two library modules.",
2486 /* 0x1f */
2487 "C: A cartridge has been left in the pass-through mechanism from a\n"
2488 " previous hardware fault. Check the library users guide for "
2489 "instructions on\n"
2490 " clearing this fault.",
2491 /* 0x20 */
2492 "I: The library was unable to read the bar code on a cartridge.",
2493};
2494
2495const char *
2497{
2498 static const int num = sizeof(ChangerTapeAlertsMessageTable) /
2500
2501 return (code < num) ? ChangerTapeAlertsMessageTable[code] :
2502 "Unknown Alert";
2503}
2504
2505int
2507{
2508 int res;
2509
2510 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, nullptr, 0);
2511 if (res)
2512 pout("Default self test failed [%s]\n", scsiErrString(res));
2513 return res;
2514}
2515
2516int
2518{
2519 int res;
2520
2521 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, nullptr, 0);
2522 if (res)
2523 pout("Short offline self test failed [%s]\n", scsiErrString(res));
2524 return res;
2525}
2526
2527int
2529{
2530 int res;
2531
2532 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, nullptr, 0);
2533 if (res)
2534 pout("Long (extended) offline self test failed [%s]\n",
2535 scsiErrString(res));
2536 return res;
2537}
2538
2539int
2541{
2542 int res;
2543
2544 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, nullptr, 0);
2545 if (res)
2546 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2547 return res;
2548}
2549
2550int
2552{
2553 int res;
2554
2555 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, nullptr, 0);
2556 if (res)
2557 pout("Long (extended) foreground self test failed [%s]\n",
2558 scsiErrString(res));
2559 return res;
2560}
2561
2562int
2564{
2565 int res;
2566
2567 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, nullptr, 0);
2568 if (res)
2569 pout("Abort self test failed [%s]\n", scsiErrString(res));
2570 return res;
2571}
2572
2573/* Returns 0 and the expected duration of an extended self test (in seconds)
2574 if successful; any other return value indicates a failure. */
2575int
2576scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2577 int modese_len)
2578{
2579 int err, offset;
2580 uint8_t buff[64] = {};
2581
2582 if (modese_len <= 6) {
2583 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2585 buff, sizeof(buff)))) {
2586 if (SIMPLE_ERR_BAD_OPCODE == err)
2587 modese_len = 10;
2588 else
2589 return err;
2590 } else if (0 == modese_len)
2591 modese_len = 6;
2592 }
2593 if (10 == modese_len) {
2594 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2596 buff, sizeof(buff));
2597 if (err)
2598 return err;
2599 }
2600 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2601 if (offset < 0)
2602 return -EINVAL;
2603 if (buff[offset + 1] >= 0xa) {
2604 int res = sg_get_unaligned_be16(buff + offset + 10);
2605
2606 if (res < 0xffff) {
2607 *durationSec = res;
2608 return 0;
2609 }
2610 /* The value 0xffff (all bits set in 16 bit field) indicates that
2611 * the Extended Inquiry VPD page should be consulted, it has a
2612 * similarly named 16 bit field, but the unit is minutes. */
2613 uint8_t b[64];
2614
2616 b, sizeof(b))) &&
2617 ((sg_get_unaligned_be16(b + 2)) > 11)) {
2618 res = sg_get_unaligned_be16(b + 10);
2619 *durationSec = res * 60; /* VPD field is in minutes */
2620 return 0;
2621 } else
2622 return -EINVAL;
2623 } else
2624 return -EINVAL;
2625}
2626
2627void
2628scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp,
2629 int allocLen)
2630{
2631 memset(ecp, 0, sizeof(*ecp));
2632 int num = sg_get_unaligned_be16(resp + 2);
2633 unsigned char * ucp = &resp[0] + 4;
2634
2635 /* allocLen is length of whole log page including 4 byte log page header */
2636 num = num < allocLen - 4 ? num : allocLen - 4;
2637 while (num >= 4) { /* header of each parameter takes 4 bytes */
2638 int pc = sg_get_unaligned_be16(ucp + 0);
2639 int pl = ucp[3] + 4;
2640 uint64_t * ullp;
2641
2642 if (num < pl) /* remaining length less than a complete parameter */
2643 break;
2644 switch (pc) {
2645 case 0:
2646 case 1:
2647 case 2:
2648 case 3:
2649 case 4:
2650 case 5:
2651 case 6:
2652 ecp->gotPC[pc] = 1;
2653 ullp = &ecp->counter[pc];
2654 break;
2655 default:
2656 ecp->gotExtraPC = 1;
2657 ullp = &ecp->counter[7];
2658 break;
2659 }
2660 int k = pl - 4;
2661 unsigned char * xp = ucp + 4;
2662 if (k > (int)sizeof(*ullp)) {
2663 xp += (k - sizeof(*ullp));
2664 k = sizeof(*ullp);
2665 }
2666 *ullp = sg_get_unaligned_be(k, xp);
2667 num -= pl;
2668 ucp += pl;
2669 }
2670}
2671
2672void
2673scsiDecodeNonMediumErrPage(unsigned char *resp,
2674 struct scsiNonMediumError *nmep,
2675 int allocLen)
2676{
2677 memset(nmep, 0, sizeof(*nmep));
2678 int num = sg_get_unaligned_be16(resp + 2);
2679 unsigned char * ucp = &resp[0] + 4;
2680 static int szof = sizeof(nmep->counterPC0);
2681
2682 /* allocLen is length of whole log page including 4 byte log page header */
2683 num = num < allocLen - 4 ? num : allocLen - 4;
2684 while (num >= 4) { /* header of each parameter takes 4 bytes */
2685 int pc = sg_get_unaligned_be16(ucp + 0);
2686 int pl = ucp[3] + 4;
2687 int k;
2688 unsigned char * xp;
2689
2690 if (num < pl) /* remaining length less than a complete parameter */
2691 break;
2692 switch (pc) {
2693 case 0:
2694 nmep->gotPC0 = 1;
2695 k = pl - 4;
2696 xp = ucp + 4;
2697 if (k > szof) {
2698 xp += (k - szof);
2699 k = szof;
2700 }
2701 nmep->counterPC0 = sg_get_unaligned_be(k, xp + 0);
2702 break;
2703 case 0x8009:
2704 nmep->gotTFE_H = 1;
2705 k = pl - 4;
2706 xp = ucp + 4;
2707 if (k > szof) {
2708 xp += (k - szof);
2709 k = szof;
2710 }
2711 nmep->counterTFE_H = sg_get_unaligned_be(k, xp + 0);
2712 break;
2713 case 0x8015:
2714 nmep->gotPE_H = 1;
2715 k = pl - 4;
2716 xp = ucp + 4;
2717 if (k > szof) {
2718 xp += (k - szof);
2719 k = szof;
2720 }
2721 nmep->counterPE_H = sg_get_unaligned_be(k, xp + 0);
2722 break;
2723 default:
2724 nmep->gotExtraPC = 1;
2725 break;
2726 }
2727 num -= pl;
2728 ucp += pl;
2729 }
2730}
2731
2732/* Counts number of failed self-tests. Also encodes the poweron_hour
2733 of the most recent failed self-test. Return value is negative if
2734 this function has a problem (typically -1), otherwise the bottom 8
2735 bits are the number of failed self tests and the 16 bits above that
2736 are the poweron hour of the most recent failure. Note: aborted self
2737 tests (typically by the user) and self tests in progress are not
2738 considered failures. See Working Draft SCSI Primary Commands - 3
2739 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
2740int
2742{
2743 int num, k, err, fails, fail_hour;
2744 uint8_t * ucp;
2745 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2746
2747 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2749 if (noisy)
2750 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2751 return -1;
2752 }
2753 if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
2754 if (noisy)
2755 pout("Self-test %s Failed, page mismatch\n", logSenStr);
2756 return -1;
2757 }
2758 // compute page length
2759 num = sg_get_unaligned_be16(resp + 2);
2760 // Log sense page length 0x190 bytes
2761 if (num != 0x190) {
2762 if (noisy)
2763 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr,
2764 num);
2765 return -1;
2766 }
2767 fails = 0;
2768 fail_hour = 0;
2769 // loop through the twenty possible entries
2770 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2771
2772 // timestamp in power-on hours (or zero if test in progress)
2773 int n = sg_get_unaligned_be16(ucp + 6);
2774
2775 // The spec says "all 20 bytes will be zero if no test" but
2776 // DG has found otherwise. So this is a heuristic.
2777 if ((0 == n) && (0 == ucp[4]))
2778 break;
2779 int res = ucp[4] & 0xf;
2780 if ((res > 2) && (res < 8)) {
2781 fails++;
2782 if (1 == fails)
2783 fail_hour = sg_get_unaligned_be16(ucp + 6);
2784 }
2785 }
2786 return (fail_hour << 8) + fails;
2787}
2788
2789/* Returns 0 if able to read self test log page; then outputs 1 into
2790 *inProgress if self test still in progress, else outputs 0. */
2791int
2793{
2794 int num;
2795 uint8_t * ucp;
2796 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2797
2798 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2800 return -1;
2801 if (resp[0] != SELFTEST_RESULTS_LPAGE)
2802 return -1;
2803 // compute page length
2804 num = sg_get_unaligned_be16(resp + 2);
2805 // Log sense page length 0x190 bytes
2806 if (num != 0x190) {
2807 return -1;
2808 }
2809 ucp = resp + 4;
2810 if (inProgress)
2811 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2812 return 0;
2813}
2814
2815/* Returns a negative value if failed to fetch Control mode page or it was
2816 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2817 bit is set. Examines default mode page when current==0 else examines
2818 current mode page. */
2819int
2821{
2822 int err, offset;
2823 uint8_t buff[64] = {};
2824 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2825
2826 if (modese_len <= 6) {
2827 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc,
2828 buff, sizeof(buff)))) {
2829 if (SIMPLE_ERR_BAD_OPCODE == err)
2830 modese_len = 10;
2831 else
2832 return -EINVAL;
2833 } else if (0 == modese_len)
2834 modese_len = 6;
2835 }
2836 if (10 == modese_len) {
2837 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
2838 buff, sizeof(buff));
2839 if (err)
2840 return -EINVAL;
2841 }
2842 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2843 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2844 return (buff[offset + 2] & 2) ? 1 : 0;
2845 return -EINVAL;
2846}
2847
2848/* Returns a negative value on error, 0 if unknown and 1 if SSD,
2849 * otherwise the positive returned value is the speed in rpm. First checks
2850 * the Block Device Characteristics VPD page and if that fails it tries the
2851 * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page.
2852 * In SBC-4 the 2 bit ZONED field in this VPD page is written to *haw_zbcp
2853 * if haw_zbcp is non-nullptr. In SBC-5 the ZONED field is now obsolete,
2854 * the Zoned block device characteristics VPD page should be used instead. */
2855
2856int
2857scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
2858 int * haw_zbcp)
2859{
2860 int err, offset;
2861 uint8_t buff[64] = {};
2862 int pc = MPAGE_CONTROL_DEFAULT;
2863
2865 buff, sizeof(buff))) &&
2866 ((sg_get_unaligned_be16(buff + 2)) > 2)) {
2867 int speed = sg_get_unaligned_be16(buff + 4);
2868 if (form_factorp)
2869 *form_factorp = buff[7] & 0xf;
2870 if (haw_zbcp)
2871 *haw_zbcp = (buff[8] >> 4) & 0x3;
2872 return speed;
2873 }
2874 if (form_factorp)
2875 *form_factorp = 0;
2876 if (haw_zbcp)
2877 *haw_zbcp = 0;
2878 if (modese_len <= 6) {
2879 if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2880 buff, sizeof(buff)))) {
2881 if (SIMPLE_ERR_BAD_OPCODE == err)
2882 modese_len = 10;
2883 else
2884 return -EINVAL;
2885 } else if (0 == modese_len)
2886 modese_len = 6;
2887 }
2888 if (10 == modese_len) {
2890 buff, sizeof(buff));
2891 if (err)
2892 return -EINVAL;
2893 }
2894 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2895 return sg_get_unaligned_be16(buff + offset + 20);
2896}
2897
2898/* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2899 0 - clear bit, 1 - set bit */
2900
2901int
2902scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2903 short int * rcdp)
2904{
2905 int err, offset, resp_len, sp;
2906 uint8_t buff[64] = {};
2907 uint8_t ch_buff[64];
2908 short set_wce = *wcep;
2909 short set_rcd = *rcdp;
2910
2911 if (modese_len <= 6) {
2913 buff, sizeof(buff));
2914 if (err) {
2915 if (SIMPLE_ERR_BAD_OPCODE == err)
2916 modese_len = 10;
2917 else {
2918 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2919 return -EINVAL;
2920 }
2921 } else if (0 == modese_len)
2922 modese_len = 6;
2923 }
2924
2925 if (10 == modese_len) {
2927 buff, sizeof(buff));
2928 if (err) {
2929 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2930 return -EINVAL;
2931 }
2932 }
2933 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2934 if ((offset < 0) || (buff[offset + 1] < 0xa)) {
2935 device->set_err(EINVAL, "Bad response");
2936 return SIMPLE_ERR_BAD_RESP;
2937 }
2938
2939 *wcep = ((buff[offset + 2] & 0x04) != 0);
2940 *rcdp = ((buff[offset + 2] & 0x01) != 0);
2941
2942 if((*wcep == set_wce || set_wce == -1)
2943 && ((*rcdp == set_rcd) || set_rcd == -1))
2944 return 0; // no changes needed or nothing to set
2945
2946 if (modese_len == 6)
2947 err = scsiModeSense(device, CACHING_PAGE, 0,
2949 ch_buff, sizeof(ch_buff));
2950 else
2951 err = scsiModeSense10(device, CACHING_PAGE, 0,
2953 ch_buff, sizeof(ch_buff));
2954 if (err) {
2955 device->set_err(EINVAL, "WCE/RCD bits not changeable");
2956 return err;
2957 }
2958
2959 // set WCE bit
2960 if(set_wce >= 0 && *wcep != set_wce) {
2961 if (0 == (ch_buff[offset + 2] & 0x04)) {
2962 device->set_err(EINVAL, "WCE bit not changeable");
2963 return 1;
2964 }
2965 if(set_wce)
2966 buff[offset + 2] |= 0x04; // set bit
2967 else
2968 buff[offset + 2] &= 0xfb; // clear bit
2969 }
2970 // set RCD bit
2971 if(set_rcd >= 0 && *rcdp != set_rcd) {
2972 if (0 == (ch_buff[offset + 2] & 0x01)) {
2973 device->set_err(EINVAL, "RCD bit not changeable");
2974 return 1;
2975 }
2976 if(set_rcd)
2977 buff[offset + 2] |= 0x01; // set bit
2978 else
2979 buff[offset + 2] &= 0xfe; // clear bit
2980 }
2981
2982 /* mask out DPOFUA device specific (disk) parameter bit */
2983 if (10 == modese_len) {
2984 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2985 buff[3] &= 0xef;
2986 } else {
2987 resp_len = buff[0] + 1;
2988 buff[2] &= 0xef;
2989 }
2990 sp = 0; /* Do not change saved values */
2991 if (10 == modese_len)
2992 err = scsiModeSelect10(device, sp, buff, resp_len);
2993 else if (6 == modese_len)
2994 err = scsiModeSelect(device, sp, buff, resp_len);
2995 if(err)
2996 device->set_err(EINVAL, "MODE SELECT command failed");
2997 return err;
2998}
2999
3000
3001/* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
3002 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
3003 successful, negative if low level error, > 0 if higher level error (e.g.
3004 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
3005int
3006scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
3007{
3008 int err, offset, resp_len, sp;
3009 uint8_t buff[64] = {};
3010 uint8_t ch_buff[64];
3011
3012 if (modese_len <= 6) {
3013 if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
3015 buff, sizeof(buff)))) {
3016 if (SIMPLE_ERR_BAD_OPCODE == err)
3017 modese_len = 10;
3018 else
3019 return err;
3020 } else if (0 == modese_len)
3021 modese_len = 6;
3022 }
3023 if (10 == modese_len) {
3024 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3026 buff, sizeof(buff));
3027 if (err)
3028 return err;
3029 }
3030 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3031 if ((offset < 0) || (buff[offset + 1] < 0xa))
3032 return SIMPLE_ERR_BAD_RESP;
3033
3034 if (enabled)
3035 enabled = 2;
3036 if (enabled == (buff[offset + 2] & 2))
3037 return 0; /* GLTSD already in wanted state so nothing to do */
3038
3039 if (modese_len == 6)
3040 err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
3042 ch_buff, sizeof(ch_buff));
3043 else
3044 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
3046 ch_buff, sizeof(ch_buff));
3047 if (err)
3048 return err;
3049 if (0 == (ch_buff[offset + 2] & 2))
3050 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not changeable */
3051
3052 /* mask out DPOFUA device specific (disk) parameter bit */
3053 if (10 == modese_len) {
3054 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
3055 buff[3] &= 0xef;
3056 } else {
3057 resp_len = buff[0] + 1;
3058 buff[2] &= 0xef;
3059 }
3060 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
3061 if (enabled)
3062 buff[offset + 2] |= 0x2; /* set GLTSD bit */
3063 else
3064 buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
3065 if (10 == modese_len)
3066 err = scsiModeSelect10(device, sp, buff, resp_len);
3067 else if (6 == modese_len)
3068 err = scsiModeSelect(device, sp, buff, resp_len);
3069 return err;
3070}
3071
3072/* Returns a negative value if failed to fetch Protocol specific port mode
3073 page or it was malformed. Returns transport protocol identifier when
3074 value >= 0 . */
3075int
3077{
3078 int err, offset;
3079 uint8_t buff[64] {};
3080
3081 if (modese_len <= 6) {
3082 if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
3084 buff, sizeof(buff)))) {
3085 if (SIMPLE_ERR_BAD_OPCODE == err)
3086 modese_len = 10;
3087 else
3088 return -EINVAL;
3089 } else if (0 == modese_len)
3090 modese_len = 6;
3091 }
3092 if (10 == modese_len) {
3095 buff, sizeof(buff));
3096 if (err)
3097 return -EINVAL;
3098 }
3099 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
3100 if ((offset >= 0) && (buff[offset + 1] > 1)) {
3101 if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
3102 (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
3103 return (buff[offset + 2] & 0xf);
3104 }
3105 return -EINVAL;
3106}
3107
3108const unsigned char *
3109sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
3110 int desc_type)
3111{
3112 int add_sen_len;
3113 const unsigned char * descp;
3114
3115 if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
3116 return nullptr;
3117 if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
3118 return nullptr;
3119 add_sen_len = (add_sen_len < (sense_len - 8)) ?
3120 add_sen_len : (sense_len - 8);
3121 descp = &sensep[8];
3122 for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
3123 descp += desc_len;
3124 int add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
3125 desc_len = add_len + 2;
3126 if (descp[0] == desc_type)
3127 return descp;
3128 if (add_len < 0) /* short descriptor ?? */
3129 break;
3130 }
3131 return nullptr;
3132}
3133
3134// Convenience function for formatting strings from SCSI identify
3135void
3136scsi_format_id_string(char * out, const uint8_t * in, int n)
3137{
3138 char tmp[65];
3139 n = n > 64 ? 64 : n;
3140 strncpy(tmp, (const char *)in, n);
3141 tmp[n] = '\0';
3142
3143 // Find the first non-space character (maybe none).
3144 int first = -1;
3145 int i;
3146 for (i = 0; tmp[i]; i++)
3147 if (!isspace((int)tmp[i])) {
3148 first = i;
3149 break;
3150 }
3151
3152 if (first == -1) {
3153 // There are only space characters.
3154 out[0] = '\0';
3155 return;
3156 }
3157
3158 // Find the last non-space character.
3159 for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
3160 int last = i;
3161
3162 strncpy(out, tmp+first, last-first+1);
3163 out[last-first+1] = '\0';
3164}
3165
3166static const char * wn = "Warning";
3167
3168static const char * wn1_9[] = {
3169 "specified temperature exceeded",
3170 "enclosure degraded",
3171 "background self-test failed",
3172 "background pre-scan detected medium error",
3173 "background medium scan detected medium error",
3174 "non-volatile cache now volatile",
3175 "degraded power to non-volatile cache",
3176 "power loss expected",
3177 "device statistics notification active",
3178};
3179
3180static const char * five_d_t[] = {
3181 "Hardware",
3182 "Controller",
3183 "Data channel",
3184 "Servo",
3185 "Spindle",
3186 "Firmware",
3187};
3188
3189static const char * impfail = "impending failure";
3190
3191static const char * impending0_c[] = {
3192 "general hard drive failure",
3193 "drive error rate too high",
3194 "data error rate too high",
3195 "seek error rate too high",
3196 "too many block reassigns",
3197 "access times too high",
3198 "start unit times too high",
3199 "channel parametrics",
3200 "controller detected",
3201 "throughput performance",
3202 "seek time performance",
3203 "spin-up retry count",
3204 "drive calibration retry count",
3205};
3206
3207static const char * pred = "prediction threshold exceeded";
3208
3209/* The SCSI Informational Exceptions log page and various other mechanisms
3210 * yield an additional sense code (and its qualifier) [asc and ascq] when
3211 * triggered. It seems only two asc values are involved: 0xb and 0xd.
3212 * If asc,ascq strings are known (in spc6r06.pdf) for asc 0xb and 0x5d
3213 * then a pointer to that string is returned, else nullptr is returned. The
3214 * caller provides a buffer (b) and its length (blen) that a string (if
3215 * found) is placed in. So if a match is found b is returned. */
3216char *
3217scsiGetIEString(uint8_t asc, uint8_t ascq, char * b, int blen)
3218{
3219 if (asc == 0xb) {
3220 switch (ascq) {
3221 case 0:
3222 snprintf(b, blen, "%s", wn);
3223 return b;
3224 case 0x1:
3225 case 0x2:
3226 case 0x3:
3227 case 0x4:
3228 case 0x5:
3229 case 0x6:
3230 case 0x7:
3231 case 0x8:
3232 case 0x9:
3233 snprintf(b, blen, "%s - %s", wn, wn1_9[ascq - 1]);
3234 return b;
3235 case 0x12:
3236 snprintf(b, blen, "%s - microcode security at risk", wn);
3237 return b;
3238 case 0x13:
3239 snprintf(b, blen, "%s - microcode digital signature validation "
3240 "failure", wn);
3241 return b;
3242 case 0x14:
3243 snprintf(b, blen, "%s - physical element status change", wn);
3244 return b;
3245 default:
3246 if ((ascq >= 0xa) && (ascq <= 0x11)) {
3247 uint8_t q = ascq - 0xa;
3248
3249 snprintf(b, blen, "%s - %s %s %s limit exceeded", wn,
3250 (((q % 2) == 0) ? "high" : "low"),
3251 ((((q / 2) % 2) == 0) ? "critical" : "operating"),
3252 ((((q / 4) % 2) == 0) ? "temperature" : "humidity"));
3253 return b;
3254 } else
3255 return nullptr;
3256 }
3257 } else if (asc == 0x5d) {
3258 switch (ascq) {
3259 case 0:
3260 snprintf(b, blen, "Failure %s", pred);
3261 return b;
3262 case 1:
3263 snprintf(b, blen, "Media failure %s", pred);
3264 return b;
3265 case 2:
3266 snprintf(b, blen, "Logical unit failure %s", pred);
3267 return b;
3268 case 3:
3269 snprintf(b, blen, "spare area exhaustion failure %s", pred);
3270 return b;
3271 case 0x1d:
3272 snprintf(b, blen, "%s %s power loss protection circuit area "
3273 "exhaustion failure", five_d_t[0], impfail);
3274 return b;
3275 case 0x73:
3276 snprintf(b, blen, "Media %s endurance limit met", impfail);
3277 return b;
3278 case 0xff:
3279 snprintf(b, blen, "Failure %s (false)", pred);
3280 return b;
3281 default:
3282 if ((ascq >= 0x10) && (ascq <= 0x6c)) {
3283 uint8_t q = ascq - 0x10;
3284 uint8_t rem = q % 0x10;
3285
3286 if (rem <= 0xc) {
3287 snprintf(b, blen, "%s %s %s", five_d_t[q / 0x10], impfail,
3288 impending0_c[rem]);
3289 return b;
3290 } else
3291 return nullptr;
3292 } else
3293 return nullptr;
3294 }
3295 } else
3296 return nullptr;
3297}
SCSI device access.
scsi_cmd_support logsense_spc_sup
bool is_spc4_or_higher() const
scsi_cmd_support rdefect12_sup
void set_rcap16_first()
Always try READ CAPACITY(10) (rcap10) first but once we know rcap16 is needed, use it instead.
bool query_cmd_support()
Definition: scsicmds.cpp:80
scsi_cmd_support logsense_sup
scsi_cmd_support rsoc_sup
virtual bool scsi_pass_through(scsi_cmnd_io *iop)=0
SCSI pass through.
scsi_cmd_support rdefect10_sup
scsi_cmd_support rcap16_sup
enum scsi_cmd_support cmd_support_level(uint8_t opcode, bool sa_valid, uint16_t sa, bool for_lsense_spc=false) const
Definition: scsicmds.cpp:172
void set_spc4_or_higher()
int get_errno() const
Get last error number.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_supported(int vpd_page_num) const
Definition: scsicmds.cpp:216
unsigned char pages[256]
Definition: scsicmds.h:400
supported_vpd_pages(scsi_device *device)
Definition: scsicmds.cpp:201
scsi_cmd_support
@ SC_SUPPORT
@ SC_SUPPORT_UNKNOWN
@ SC_NO_SUPPORT
u8 sense_len
Definition: megaraid.h:2
uint8_t opcode
Definition: megaraid.h:0
u8 cdb[16]
Definition: megaraid.h:21
u8 b[12]
Definition: megaraid.h:17
u16 s[6]
Definition: megaraid.h:18
int scsiSetPowerCondition(scsi_device *device, int power_cond, int pcond_modifier)
Definition: scsicmds.cpp:1380
int scsiReadDefect12(scsi_device *device, int req_plist, int req_glist, int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1525
int scsiFetchExtendedSelfTestTime(scsi_device *device, int *durationSec, int modese_len)
Definition: scsicmds.cpp:2576
void scsiDecodeErrCounterPage(unsigned char *resp, struct scsiErrorCounter *ecp, int allocLen)
Definition: scsicmds.cpp:2628
int scsiModeSelect(scsi_device *device, int sp, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1059
int scsiSimpleSenseFilter(const struct scsi_sense_disect *sinfo)
Definition: scsicmds.cpp:587
#define SCSI_IEC_MP_BYTE2_ENABLED
Definition: scsicmds.cpp:1932
int scsiSetExceptionControlAndWarning(scsi_device *device, int enabled, const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1947
#define RSOC_ALL_CMDS_CTDP_0
Definition: scsicmds.cpp:50
static struct scsi_sa_var_map sa_var_a[]
Definition: scsicmds.cpp:451
int scsiSmartExtendCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2551
static const char * TapeAlertsMessageTable[]
Definition: scsicmds.cpp:2104
int scsiFetchIECmpage(scsi_device *device, struct scsi_iec_mode_page *iecp, int modese_len)
Definition: scsicmds.cpp:1857
int scsiGetTemp(scsi_device *device, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:2019
static const char * pred
Definition: scsicmds.cpp:3207
int scsiSmartShortCapSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2540
int scsiSmartSelfTestAbort(scsi_device *device)
Definition: scsicmds.cpp:2563
char * scsi_get_sense_key_str(int sense_key, int buff_len, char *buff)
Definition: scsicmds.cpp:695
static const char * ChangerTapeAlertsMessageTable[]
Definition: scsicmds.cpp:2357
static const char * wn
Definition: scsicmds.cpp:3166
static const char * impfail
Definition: scsicmds.cpp:3189
const char * scsiTapeAlertsTapeDevice(unsigned short code)
Definition: scsicmds.cpp:2348
int scsiFetchTransportProtocol(scsi_device *device, int modese_len)
Definition: scsicmds.cpp:3076
int scsi_decode_lu_dev_id(const unsigned char *b, int blen, char *s, int slen, int *transport)
Definition: scsicmds.cpp:748
bool is_scsi_cdb(const uint8_t *cdbp, int clen)
Definition: scsicmds.cpp:391
static const char * wn1_9[]
Definition: scsicmds.cpp:3168
void dStrHexFp(const uint8_t *up, int len, int no_ascii, FILE *fp)
Definition: scsicmds.cpp:344
int scsiTestUnitReady(scsi_device *device)
Definition: scsicmds.cpp:1475
int scsiModeSense10(scsi_device *device, int pagenum, int subpagenum, int pc, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1098
int scsiModePageOffset(const uint8_t *resp, int len, int modese_len)
Definition: scsicmds.cpp:1814
void scsi_do_sense_disect(const struct scsi_cmnd_io *io_buf, struct scsi_sense_disect *out)
Definition: scsicmds.cpp:565
#define RSOC_1_CMD_CTDP_0
Definition: scsicmds.cpp:52
#define RSOC_ALL_CMDS_CTDP_1
Definition: scsicmds.cpp:51
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1229
static void dStrHexHelper(const uint8_t *up, int len, int no_ascii, void(*out)(const char *s, void *ctx), void *ctx=nullptr)
Definition: scsicmds.cpp:248
#define SCSI_IEC_MP_REPORT_COUNT
Definition: scsicmds.cpp:1937
static scsi_cmd_support chk_lsense_spc(scsi_device *device)
Definition: scsicmds.cpp:56
static int trimTrailingSpaces(char *b)
Definition: scsicmds.cpp:236
int scsiSmartExtendSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2528
void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep, int allocLen)
Definition: scsicmds.cpp:2673
int scsiRequestSense(scsi_device *device, struct scsi_sense_disect *sense_info)
Definition: scsicmds.cpp:1287
int scsiCheckIE(scsi_device *device, int hasIELogPage, int hasTempLogPage, uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:2047
const char * scsicmds_c_cvsid
Definition: scsicmds.cpp:39
uint64_t scsiGetSize(scsi_device *device, bool avoid_rcap16, struct scsi_readcap_resp *srrp)
Definition: scsicmds.cpp:1732
int scsiSelfTestInProgress(scsi_device *fd, int *inProgress)
Definition: scsicmds.cpp:2792
static const char * sense_key_desc[]
Definition: scsicmds.cpp:668
#define DEXCPT_ENABLE
Definition: scsicmds.cpp:1845
char * scsiGetIEString(uint8_t asc, uint8_t ascq, char *b, int blen)
Definition: scsicmds.cpp:3217
static const char * vendor_specific
Definition: scsicmds.cpp:506
int scsiGetSetCache(scsi_device *device, int modese_len, short int *wcep, short int *rcdp)
Definition: scsicmds.cpp:2902
int scsiRSOCcmd(scsi_device *device, bool rctd, uint8_t rep_opt, uint8_t opcode, uint16_t serv_act, uint8_t *pBuf, int bufLen, int &rspLen)
Definition: scsicmds.cpp:1691
#define SCSI_IEC_MP_INTERVAL_T
Definition: scsicmds.cpp:1936
supported_vpd_pages * supported_vpd_pages_p
Definition: scsicmds.cpp:47
bool scsi_pass_through_yield_sense(scsi_device *device, scsi_cmnd_io *iop, scsi_sense_disect &sinfo)
Definition: scsicmds.cpp:1562
int scsiGetRPM(scsi_device *device, int modese_len, int *form_factorp, int *haw_zbcp)
Definition: scsicmds.cpp:2857
void scsi_format_id_string(char *out, const uint8_t *in, int n)
Definition: scsicmds.cpp:3136
#define EWASC_ENABLE
Definition: scsicmds.cpp:1846
int scsiReadCapacity16(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1664
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1182
#define SCSI_IEC_MP_MRIE
Definition: scsicmds.cpp:1935
scsi_sa_t
Definition: scsicmds.cpp:440
@ scsi_sa_b8b7n16
Definition: scsicmds.cpp:443
@ scsi_sa_b1b4n5
Definition: scsicmds.cpp:442
@ scsi_sa_none
Definition: scsicmds.cpp:441
int scsiModeSelect10(scsi_device *device, int sp, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1142
const unsigned char * sg_scsi_sense_desc_find(const unsigned char *sensep, int sense_len, int desc_type)
Definition: scsicmds.cpp:3109
static const char * logSenStr
Definition: scsicmds.cpp:42
#define SCSI_IEC_MP_BYTE2_TEST_MASK
Definition: scsicmds.cpp:1933
int scsiSmartDefaultSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2506
static int _testunitready(scsi_device *device, struct scsi_sense_disect *sinfop)
Definition: scsicmds.cpp:1444
void dStrHex(const uint8_t *up, int len, int no_ascii)
Definition: scsicmds.cpp:368
int scsiSendDiagnostic(scsi_device *device, int functioncode, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1411
const char * scsiErrString(int scsiErr)
Definition: scsicmds.cpp:630
const char * scsiTapeAlertsChangerDevice(unsigned short code)
Definition: scsicmds.cpp:2496
int scsiReadCapacity10(scsi_device *device, unsigned int *last_lbap, unsigned int *lb_sizep)
Definition: scsicmds.cpp:1628
int scsiFetchControlGLTSD(scsi_device *device, int modese_len, int current)
Definition: scsicmds.cpp:2820
static int my_isprint(uint8_t ch)
Definition: scsicmds.cpp:230
static struct scsi_opcode_name opcode_name_arr[]
Definition: scsicmds.cpp:478
#define SLEN(a, b)
int scsiModeSense(scsi_device *device, int pagenum, int subpagenum, int pc, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1013
int scsiCountFailedSelfTests(scsi_device *fd, int noisy)
Definition: scsicmds.cpp:2741
int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1918
int scsiSetControlGLTSD(scsi_device *device, int enabled, int modese_len)
Definition: scsicmds.cpp:3006
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1904
#define TEST_DISABLE
Definition: scsicmds.cpp:1849
int scsiSmartShortSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2517
int scsiLogSense(scsi_device *device, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen, int known_resp_len)
Definition: scsicmds.cpp:892
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45
#define EWASC_DISABLE
Definition: scsicmds.cpp:1848
const char * scsi_get_opcode_name(const uint8_t *cdbp)
Definition: scsicmds.cpp:511
#define RSOC_RESP_SZ
Definition: scsicmds.cpp:49
int scsiLogSelect(scsi_device *device, int pcr, int sp, int pc, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:981
static const char * five_d_t[]
Definition: scsicmds.cpp:3180
int scsiReadDefect10(scsi_device *device, int req_plist, int req_glist, int dl_format, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1491
static const char * impending0_c[]
Definition: scsicmds.cpp:3191
int scsi_vpd_dev_id_iter(const unsigned char *initial_desig_desc, int page_len, int *off, int m_assoc, int m_desig_type, int m_code_set)
Definition: scsicmds.cpp:718
#define REPORT_LUNS
Definition: scsicmds.h:76
#define SIMPLE_ERR_BECOMING_READY
Definition: scsicmds.h:354
#define SCSI_SK_MEDIUM_ERROR
Definition: scsicmds.h:326
#define SIMPLE_ERR_MEDIUM_HARDWARE
Definition: scsicmds.h:356
#define START_STOP_UNIT
Definition: scsicmds.h:73
#define MPAGE_CONTROL_CURRENT
Definition: scsicmds.h:301
#define SAI_READ_CAPACITY_16
Definition: scsicmds.h:85
#define SCSI_ASC_UNKNOWN_OPCODE
Definition: scsicmds.h:338
#define MODE_SENSE_6
Definition: scsicmds.h:43
#define SIMPLE_ERR_BAD_FIELD
Definition: scsicmds.h:350
#define SAI_GET_PHY_ELEM_STATUS
Definition: scsicmds.h:88
#define INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
Definition: scsicmds.h:292
#define READ_CAPACITY_10
Definition: scsicmds.h:79
#define MAINTENANCE_IN_12
Definition: scsicmds.h:94
#define SCSI_DIAG_DEF_SELF_TEST
Definition: scsicmds.h:365
#define SCSI_SK_UNIT_ATTENTION
Definition: scsicmds.h:329
#define MI_REP_SUP_OPCODES
Definition: scsicmds.h:97
#define SAT_ATA_PASSTHROUGH_12
Definition: scsicmds.h:101
#define DXFER_NONE
Definition: scsicmds.h:108
#define SCSICMDS_H_CVSID
Definition: scsicmds.h:22
#define SIMPLE_NO_ERROR
Definition: scsicmds.h:347
#define SEND_DIAGNOSTIC
Definition: scsicmds.h:64
#define SIMPLE_ERR_NOT_READY
Definition: scsicmds.h:348
#define RIGID_DISK_DRIVE_GEOMETRY_PAGE
Definition: scsicmds.h:276
#define SCSI_DIAG_BG_SHORT_SELF_TEST
Definition: scsicmds.h:366
#define SIMPLE_ERR_ABORTED_COMMAND
Definition: scsicmds.h:358
#define READ_DEFECT_12
Definition: scsicmds.h:70
#define SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS
Definition: scsicmds.h:315
#define READ_DEFECT_10
Definition: scsicmds.h:67
#define SCSI_DIAG_BG_EXTENDED_SELF_TEST
Definition: scsicmds.h:367
#define SIMPLE_ERR_TRY_AGAIN
Definition: scsicmds.h:355
#define SIMPLE_ERR_NO_MEDIUM
Definition: scsicmds.h:353
#define RECEIVE_DIAGNOSTIC
Definition: scsicmds.h:61
#define SCSI_ASC_INVALID_FIELD
Definition: scsicmds.h:339
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1229
#define CACHING_PAGE
Definition: scsicmds.h:279
#define SELFTEST_RESULTS_LPAGE
Definition: scsicmds.h:232
#define MODE_SELECT_10
Definition: scsicmds.h:52
#define LOG_SENSE
Definition: scsicmds.h:40
#define SIMPLE_ERR_PROTECTION
Definition: scsicmds.h:359
#define DXFER_FROM_DEVICE
Definition: scsicmds.h:109
#define SCSI_SK_ILLEGAL_REQUEST
Definition: scsicmds.h:328
#define SCSI_TIMEOUT_DEFAULT
Definition: scsicmds.h:379
#define SCSI_SK_ABORTED_COMMAND
Definition: scsicmds.h:331
#define SCSI_IECMP_RAW_LEN
Definition: scsicmds.h:143
#define SCSI_DIAG_ABORT_SELF_TEST
Definition: scsicmds.h:370
#define MODE_SELECT_6
Definition: scsicmds.h:49
#define SUPPORTED_LPAGES
Definition: scsicmds.h:218
#define SCSI_SK_COMPLETED
Definition: scsicmds.h:333
#define SAT_ATA_PASSTHROUGH_16
Definition: scsicmds.h:104
#define SCSI_DIAG_FG_SHORT_SELF_TEST
Definition: scsicmds.h:368
#define SIMPLE_ERR_BAD_OPCODE
Definition: scsicmds.h:349
#define SCSI_PT_MEDIUM_CHANGER
Definition: scsicmds.h:196
#define SCSI_ASC_UNKNOWN_PARAM
Definition: scsicmds.h:340
#define DXFER_TO_DEVICE
Definition: scsicmds.h:110
#define SCSI_PT_SEQUENTIAL_ACCESS
Definition: scsicmds.h:192
#define SCSI_SK_HARDWARE_ERROR
Definition: scsicmds.h:327
#define SCSI_STATUS_CHECK_CONDITION
Definition: scsicmds.h:320
#define MODE_SENSE_10
Definition: scsicmds.h:46
#define LOG_SELECT
Definition: scsicmds.h:37
#define SIMPLE_ERR_BAD_PARAM
Definition: scsicmds.h:351
#define SCSI_PT_HOST_MANAGED
Definition: scsicmds.h:199
#define MPAGE_CONTROL_DEFAULT
Definition: scsicmds.h:303
#define SCSI_VPD_EXTENDED_INQUIRY_DATA
Definition: scsicmds.h:310
#define SCSI_DIAG_NO_SELF_TEST
Definition: scsicmds.h:364
#define LOG_RESP_SELF_TEST_LEN
Definition: scsicmds.h:265
#define SCSI_VPD_SUPPORTED_VPD_PAGES
Definition: scsicmds.h:307
#define TEST_UNIT_READY
Definition: scsicmds.h:34
#define SIMPLE_ERR_MISCOMPARE
Definition: scsicmds.h:360
#define TEMPERATURE_LPAGE
Definition: scsicmds.h:229
#define MPAGE_CONTROL_CHANGEABLE
Definition: scsicmds.h:302
#define SIMPLE_ERR_BAD_RESP
Definition: scsicmds.h:352
#define SCSI_PT_DIRECT_ACCESS
Definition: scsicmds.h:191
#define SERVICE_ACTION_IN_16
Definition: scsicmds.h:82
#define SCSI_ASC_NOT_READY
Definition: scsicmds.h:336
#define SIMPLE_ERR_UNKNOWN
Definition: scsicmds.h:357
#define SCSI_SK_NO_SENSE
Definition: scsicmds.h:323
#define IE_LPAGE
Definition: scsicmds.h:241
#define ALL_MODE_PAGES
Definition: scsicmds.h:298
#define INQUIRY
Definition: scsicmds.h:55
#define SCSI_SK_RECOVERED_ERR
Definition: scsicmds.h:324
#define SCSI_SK_NOT_READY
Definition: scsicmds.h:325
#define REQUEST_SENSE
Definition: scsicmds.h:58
#define CONTROL_MODE_PAGE
Definition: scsicmds.h:282
#define SCSI_SK_DATA_PROTECT
Definition: scsicmds.h:330
#define SCSI_SK_MISCOMPARE
Definition: scsicmds.h:332
#define SCSI_DIAG_FG_EXTENDED_SELF_TEST
Definition: scsicmds.h:369
#define SCSI_TIMEOUT_SELF_TEST
Definition: scsicmds.h:382
#define SCSI_ASC_NO_MEDIUM
Definition: scsicmds.h:337
#define PROTOCOL_SPECIFIC_PORT_PAGE
Definition: scsicmds.h:290
static int modese_len
Definition: scsiprint.cpp:83
static void sg_put_unaligned_be32(uint32_t val, void *p)
Definition: sg_unaligned.h:279
static void sg_put_unaligned_be16(uint16_t val, void *p)
Definition: sg_unaligned.h:273
static uint64_t sg_get_unaligned_be64(const void *p)
Definition: sg_unaligned.h:267
static uint64_t sg_get_unaligned_be(int num_bytes, const void *p)
Definition: sg_unaligned.h:350
static uint16_t sg_get_unaligned_be16(const void *p)
Definition: sg_unaligned.h:256
static uint32_t sg_get_unaligned_be32(const void *p)
Definition: sg_unaligned.h:261
for(char *p=buf, *q;p &&*p;p=q)
Definition: smartd.cpp:1315
void pout(const char *fmt,...)
Definition: smartd.cpp:1335
uint8_t gotPC[7]
Definition: scsicmds.h:156
uint64_t counter[8]
Definition: scsicmds.h:158
uint8_t gotExtraPC
Definition: scsicmds.h:157
uint64_t counterTFE_H
Definition: scsicmds.h:167
uint64_t counterPE_H
Definition: scsicmds.h:169
uint8_t gotTFE_H
Definition: scsicmds.h:166
uint8_t gotExtraPC
Definition: scsicmds.h:164
uint64_t counterPC0
Definition: scsicmds.h:165
uint8_t * sensep
Definition: scsicmds.h:123
uint8_t * dxferp
Definition: scsicmds.h:121
int dxfer_dir
Definition: scsicmds.h:119
size_t cmnd_len
Definition: scsicmds.h:118
size_t resp_sense_len
Definition: scsicmds.h:127
size_t dxfer_len
Definition: scsicmds.h:122
size_t max_sense_len
Definition: scsicmds.h:125
uint8_t scsi_status
Definition: scsicmds.h:128
uint8_t * cmnd
Definition: scsicmds.h:117
unsigned timeout
Definition: scsicmds.h:126
uint8_t gotChangeable
Definition: scsicmds.h:148
uint8_t gotCurrent
Definition: scsicmds.h:146
uint8_t modese_len
Definition: scsicmds.h:149
uint8_t raw_curr[SCSI_IECMP_RAW_LEN]
Definition: scsicmds.h:150
uint8_t raw_chg[SCSI_IECMP_RAW_LEN]
Definition: scsicmds.h:151
uint8_t requestedChangeable
Definition: scsicmds.h:147
uint8_t requestedCurrent
Definition: scsicmds.h:145
const char * name
Definition: scsicmds.cpp:474
uint16_t l_a_lba
Definition: scsicmds.h:182
uint8_t lb_p_pb_exp
Definition: scsicmds.h:179
uint8_t prot_type
Definition: scsicmds.h:176
uint8_t p_i_exp
Definition: scsicmds.h:178
uint32_t lb_size
Definition: scsicmds.h:174
uint64_t num_lblocks
Definition: scsicmds.h:173
enum scsi_sa_t sa_var
Definition: scsicmds.cpp:448
uint8_t resp_code
Definition: scsicmds.h:135
uint8_t sense_key
Definition: scsicmds.h:136