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