4 * Home page of code is: http://www.smartmontools.org
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>
10 * SPDX-License-Identifier: GPL-2.0-or-later
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]
23 * Some SCSI disk vendors have snippets of "SMART" information in their
35 #include "atacmds.h" // FIXME: for smart_command_set only
36 #include "dev_interface.h"
38 #include "sg_unaligned.h"
40 const char *scsicmds_c_cvsid
="$Id: scsicmds.cpp 4842 2018-12-02 16:07:26Z chrfranke $"
43 static const char * logSenStr
= "Log Sense";
45 // Print SCSI debug messages?
46 unsigned char scsi_debugmode
= 0;
48 supported_vpd_pages
* supported_vpd_pages_p
= NULL
;
51 supported_vpd_pages::supported_vpd_pages(scsi_device
* device
) : num_valid(0)
53 unsigned char b
[0xfc]; /* pre SPC-3 INQUIRY max response size */
54 memset(b
, 0, sizeof(b
));
55 if (device
&& (0 == scsiInquiryVpd(device
, SCSI_VPD_SUPPORTED_VPD_PAGES
,
57 num_valid
= sg_get_unaligned_be16(b
+ 2);
58 int n
= sizeof(pages
);
61 memcpy(pages
, b
+ 4, num_valid
);
66 supported_vpd_pages::is_supported(int vpd_page_num
) const
68 /* Supported VPD pages numbers start at offset 4 and should be in
69 * ascending order but don't assume that. */
70 for (int k
= 0; k
< num_valid
; ++k
) {
71 if (vpd_page_num
== pages
[k
])
77 /* output binary in ASCII hex and optionally ASCII. Uses pout() for output. */
79 dStrHex(const uint8_t * up
, int len
, int no_ascii
)
81 const uint8_t * p
= up
;
84 const int bpstart
= 5;
85 const int cpstart
= 60;
93 k
= snprintf(buff
+1, sizeof(buff
)-1, "%.2x", a
);
95 if (bpos
>= ((bpstart
+ (9 * 3))))
98 for(i
= 0; i
< len
; i
++)
102 if (bpos
== (bpstart
+ (9 * 3)))
104 snprintf(buff
+bpos
, sizeof(buff
)-bpos
, "%.2x", (unsigned int)c
);
105 buff
[bpos
+ 2] = ' ';
109 if ((c
< ' ') || (c
>= 0x7f))
113 if (cpos
> (cpstart
+15))
115 while (cpos
> 0 && buff
[cpos
-1] == ' ')
123 k
= snprintf(buff
+1, sizeof(buff
)-1, "%.2x", a
);
129 while (cpos
> 0 && buff
[cpos
-1] == ' ')
136 /* This is a heuristic that takes into account the command bytes and length
137 * to decide whether the presented unstructured sequence of bytes could be
138 * a SCSI command. If so it returns true otherwise false. Vendor specific
139 * SCSI commands (i.e. opcodes from 0xc0 to 0xff), if presented, are assumed
140 * to follow SCSI conventions (i.e. length of 6, 10, 12 or 16 bytes). The
141 * only SCSI commands considered above 16 bytes of length are the Variable
142 * Length Commands (opcode 0x7f) and the XCDB wrapped commands (opcode 0x7e).
143 * Both have an inbuilt length field which can be cross checked with clen.
144 * No NVMe commands (64 bytes long plus some extra added by some OSes) have
145 * opcodes 0x7e or 0x7f yet. ATA is register based but SATA has FIS
146 * structures that are sent across the wire. The FIS register structure is
147 * used to move a command from a SATA host to device, but the ATA 'command'
148 * is not the first byte. So it is harder to say what will happen if a
149 * FIS structure is presented as a SCSI command, hopefully there is a low
150 * probability this function will yield true in that case. */
152 is_scsi_cdb(const uint8_t * cdbp
, int clen
)
161 top3bits
= opcode
>> 5;
162 if (0x3 == top3bits
) { /* Opcodes 0x60 to 0x7f */
163 if ((clen
< 12) || (clen
% 4))
164 return false; /* must be modulo 4 and 12 or more bytes */
166 case 0x7e: /* Extended cdb (XCDB) */
167 ilen
= 4 + sg_get_unaligned_be16(cdbp
+ 2);
168 return (ilen
== clen
);
169 case 0x7f: /* Variable Length cdb */
171 sa
= sg_get_unaligned_be16(cdbp
+ 8);
172 /* service action (sa) 0x0 is reserved */
173 return ((ilen
== clen
) && sa
);
177 } else if (clen
<= 16) {
180 if (top3bits
> 0x5) /* vendor */
182 return (0x0 == top3bits
); /* 6 byte cdb */
184 if (top3bits
> 0x5) /* vendor */
186 return ((0x1 == top3bits
) || (0x2 == top3bits
)); /* 10 byte cdb */
188 if (top3bits
> 0x5) /* vendor */
190 return (0x4 == top3bits
); /* 16 byte cdb */
192 if (top3bits
> 0x5) /* vendor */
194 return (0x5 == top3bits
); /* 12 byte cdb */
199 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
204 struct scsi_opcode_name
{
209 static struct scsi_opcode_name opcode_name_arr
[] = {
210 /* in ascending opcode order */
211 {TEST_UNIT_READY
, "test unit ready"}, /* 0x00 */
212 {REQUEST_SENSE
, "request sense"}, /* 0x03 */
213 {INQUIRY
, "inquiry"}, /* 0x12 */
214 {MODE_SELECT
, "mode select(6)"}, /* 0x15 */
215 {MODE_SENSE
, "mode sense(6)"}, /* 0x1a */
216 {START_STOP_UNIT
, "start stop unit"}, /* 0x1b */
217 {RECEIVE_DIAGNOSTIC
, "receive diagnostic"}, /* 0x1c */
218 {SEND_DIAGNOSTIC
, "send diagnostic"}, /* 0x1d */
219 {READ_CAPACITY_10
, "read capacity(10)"}, /* 0x25 */
220 {READ_DEFECT_10
, "read defect list(10)"}, /* 0x37 */
221 {LOG_SELECT
, "log select"}, /* 0x4c */
222 {LOG_SENSE
, "log sense"}, /* 0x4d */
223 {MODE_SELECT_10
, "mode select(10)"}, /* 0x55 */
224 {MODE_SENSE_10
, "mode sense(10)"}, /* 0x5a */
225 {SAT_ATA_PASSTHROUGH_16
, "ata pass-through(16)"}, /* 0x85 */
226 {READ_CAPACITY_16
, "read capacity(16)"}, /* 0x9e,0x10 */
227 {REPORT_LUNS
, "report luns"}, /* 0xa0 */
228 {SAT_ATA_PASSTHROUGH_12
, "ata pass-through(12)"}, /* 0xa1 */
229 {READ_DEFECT_12
, "read defect list(12)"}, /* 0xb7 */
232 static const char * vendor_specific
= "<vendor specific>";
234 /* Need to expand to take service action into account. For commands
235 * of interest the service action is in the 2nd command byte */
237 scsi_get_opcode_name(uint8_t opcode
)
239 int len
= sizeof(opcode_name_arr
) / sizeof(opcode_name_arr
[0]);
242 return vendor_specific
;
243 for (int k
= 0; k
< len
; ++k
) {
244 struct scsi_opcode_name
* onp
= &opcode_name_arr
[k
];
245 if (opcode
== onp
->opcode
)
247 else if (opcode
< onp
->opcode
)
254 scsi_do_sense_disect(const struct scsi_cmnd_io
* io_buf
,
255 struct scsi_sense_disect
* out
)
257 memset(out
, 0, sizeof(struct scsi_sense_disect
));
258 if (SCSI_STATUS_CHECK_CONDITION
== io_buf
->scsi_status
) {
259 int resp_code
= (io_buf
->sensep
[0] & 0x7f);
260 out
->resp_code
= resp_code
;
261 if (resp_code
>= 0x72) {
262 out
->sense_key
= (io_buf
->sensep
[1] & 0xf);
263 out
->asc
= io_buf
->sensep
[2];
264 out
->ascq
= io_buf
->sensep
[3];
265 } else if (resp_code
>= 0x70) {
266 out
->sense_key
= (io_buf
->sensep
[2] & 0xf);
267 if (io_buf
->resp_sense_len
> 13) {
268 out
->asc
= io_buf
->sensep
[12];
269 out
->ascq
= io_buf
->sensep
[13];
276 scsiSimpleSenseFilter(const struct scsi_sense_disect
* sinfo
)
278 switch (sinfo
->sense_key
) {
279 case SCSI_SK_NO_SENSE
:
280 case SCSI_SK_RECOVERED_ERR
:
281 return SIMPLE_NO_ERROR
;
282 case SCSI_SK_NOT_READY
:
283 if (SCSI_ASC_NO_MEDIUM
== sinfo
->asc
)
284 return SIMPLE_ERR_NO_MEDIUM
;
285 else if (SCSI_ASC_NOT_READY
== sinfo
->asc
) {
286 if (0x1 == sinfo
->ascq
)
287 return SIMPLE_ERR_BECOMING_READY
;
289 return SIMPLE_ERR_NOT_READY
;
291 return SIMPLE_ERR_NOT_READY
;
292 case SCSI_SK_MEDIUM_ERROR
:
293 case SCSI_SK_HARDWARE_ERROR
:
294 return SIMPLE_ERR_MEDIUM_HARDWARE
;
295 case SCSI_SK_ILLEGAL_REQUEST
:
296 if (SCSI_ASC_UNKNOWN_OPCODE
== sinfo
->asc
)
297 return SIMPLE_ERR_BAD_OPCODE
;
298 else if (SCSI_ASC_INVALID_FIELD
== sinfo
->asc
)
299 return SIMPLE_ERR_BAD_FIELD
;
300 else if (SCSI_ASC_UNKNOWN_PARAM
== sinfo
->asc
)
301 return SIMPLE_ERR_BAD_PARAM
;
303 return SIMPLE_ERR_BAD_PARAM
; /* all other illegal request */
304 case SCSI_SK_UNIT_ATTENTION
:
305 return SIMPLE_ERR_TRY_AGAIN
;
306 case SCSI_SK_ABORTED_COMMAND
:
307 return SIMPLE_ERR_ABORTED_COMMAND
;
309 return SIMPLE_ERR_UNKNOWN
;
314 scsiErrString(int scsiErr
)
317 return strerror(-scsiErr
);
319 case SIMPLE_NO_ERROR
:
321 case SIMPLE_ERR_NOT_READY
:
322 return "device not ready";
323 case SIMPLE_ERR_BAD_OPCODE
:
324 return "unsupported scsi opcode";
325 case SIMPLE_ERR_BAD_FIELD
:
326 return "unsupported field in scsi command";
327 case SIMPLE_ERR_BAD_PARAM
:
328 return "badly formed scsi parameters";
329 case SIMPLE_ERR_BAD_RESP
:
330 return "scsi response fails sanity test";
331 case SIMPLE_ERR_NO_MEDIUM
:
332 return "no medium present";
333 case SIMPLE_ERR_BECOMING_READY
:
334 return "device will be ready soon";
335 case SIMPLE_ERR_TRY_AGAIN
:
336 return "unit attention reported, try again";
337 case SIMPLE_ERR_MEDIUM_HARDWARE
:
338 return "medium or hardware error (serious)";
339 case SIMPLE_ERR_UNKNOWN
:
340 return "unknown error (unexpected sense key)";
341 case SIMPLE_ERR_ABORTED_COMMAND
:
342 return "aborted command";
344 return "unknown error";
348 /* Iterates to next designation descriptor in the device identification
349 * VPD page. The 'initial_desig_desc' should point to start of first
350 * descriptor with 'page_len' being the number of valid bytes in that
351 * and following descriptors. To start, 'off' should point to a negative
352 * value, thereafter it should point to the value yielded by the previous
353 * call. If 0 returned then 'initial_desig_desc + *off' should be a valid
354 * descriptor; returns -1 if normal end condition and -2 for an abnormal
355 * termination. Matches association, designator_type and/or code_set when
356 * any of those values are greater than or equal to zero. */
358 scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc
, int page_len
,
359 int * off
, int m_assoc
, int m_desig_type
, int m_code_set
)
361 const unsigned char * ucp
;
364 for (k
= *off
, ucp
= initial_desig_desc
; (k
+ 3) < page_len
; ) {
365 k
= (k
< 0) ? 0 : (k
+ ucp
[k
+ 3] + 4);
366 if ((k
+ 4) > page_len
)
368 int c_set
= (ucp
[k
] & 0xf);
369 if ((m_code_set
>= 0) && (m_code_set
!= c_set
))
371 int assoc
= ((ucp
[k
+ 1] >> 4) & 0x3);
372 if ((m_assoc
>= 0) && (m_assoc
!= assoc
))
374 int desig_type
= (ucp
[k
+ 1] & 0xf);
375 if ((m_desig_type
>= 0) && (m_desig_type
!= desig_type
))
380 return (k
== page_len
) ? -1 : -2;
383 /* Decode VPD page 0x83 logical unit designator into a string. If both
384 * numeric address and SCSI name string present, prefer the former.
385 * Returns 0 on success, -1 on error with error string in s. */
387 scsi_decode_lu_dev_id(const unsigned char * b
, int blen
, char * s
, int slen
,
400 int have_scsi_ns
= 0;
403 while ((u
= scsi_vpd_dev_id_iter(b
, blen
, &off
, -1, -1, -1)) == 0) {
404 const unsigned char * ucp
= b
+ off
;
406 if ((off
+ i_len
+ 4) > blen
) {
407 snprintf(s
+si
, slen
-si
, "error: designator length");
410 int assoc
= ((ucp
[1] >> 4) & 0x3);
411 if (transport
&& assoc
&& (ucp
[1] & 0x80) && (*transport
< 0))
412 *transport
= (ucp
[0] >> 4) & 0xf;
415 const unsigned char * ip
= ucp
+ 4;
416 int c_set
= (ucp
[0] & 0xf);
417 int desig_type
= (ucp
[1] & 0xf);
420 switch (desig_type
) {
421 case 0: /* vendor specific */
422 case 1: /* T10 vendor identification */
424 case 2: /* EUI-64 based */
425 if ((8 != i_len
) && (12 != i_len
) && (16 != i_len
)) {
426 snprintf(s
+si
, slen
-si
, "error: EUI-64 length");
431 si
+= snprintf(s
+si
, slen
-si
, "0x");
432 for (int m
= 0; m
< i_len
; ++m
)
433 si
+= snprintf(s
+si
, slen
-si
, "%02x", (unsigned int)ip
[m
]);
437 snprintf(s
+si
, slen
-si
, "error: NAA bad code_set");
440 naa
= (ip
[0] >> 4) & 0xff;
441 if ((naa
< 2) || (naa
> 6) || (4 == naa
)) {
442 snprintf(s
+si
, slen
-si
, "error: unexpected NAA");
447 if (2 == naa
) { /* NAA IEEE Extended */
449 snprintf(s
+si
, slen
-si
, "error: NAA 2 length");
452 si
+= snprintf(s
+si
, slen
-si
, "0x");
453 for (int m
= 0; m
< 8; ++m
)
454 si
+= snprintf(s
+si
, slen
-si
, "%02x", (unsigned int)ip
[m
]);
455 } else if ((3 == naa
) || (5 == naa
)) {
456 /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
458 snprintf(s
+si
, slen
-si
, "error: NAA 3 or 5 length");
461 si
+= snprintf(s
+si
, slen
-si
, "0x");
462 for (int m
= 0; m
< 8; ++m
)
463 si
+= snprintf(s
+si
, slen
-si
, "%02x", (unsigned int)ip
[m
]);
464 } else if (6 == naa
) { /* NAA IEEE Registered extended */
466 snprintf(s
+si
, slen
-si
, "error: NAA 6 length");
469 si
+= snprintf(s
+si
, slen
-si
, "0x");
470 for (int m
= 0; m
< 16; ++m
)
471 si
+= snprintf(s
+si
, slen
-si
, "%02x", (unsigned int)ip
[m
]);
474 case 4: /* Relative target port */
475 case 5: /* (primary) Target port group */
476 case 6: /* Logical unit group */
477 case 7: /* MD5 logical unit identifier */
479 case 8: /* SCSI name string */
481 snprintf(s
+si
, slen
-si
, "error: SCSI name string");
484 /* does %s print out UTF-8 ok?? */
486 si
+= snprintf(s
+si
, slen
-si
, "%s", (const char *)ip
);
490 default: /* reserved */
495 snprintf(s
+si
, slen
-si
, "error: bad structure");
501 /* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if
502 * command not supported, 3 if field (within command) not supported or
503 * returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a).
504 * N.B. Sets PC==1 to fetch "current cumulative" log pages.
505 * If known_resp_len > 0 then a single fetch is done for this response
506 * length. If known_resp_len == 0 then twin fetches are performed, the
507 * first to deduce the response length, then send the same command again
508 * requesting the deduced response length. This protects certain fragile
509 * HBAs. The twin fetch technique should not be used with the TapeAlert
510 * log page since it clears its state flags after each fetch. If
511 * known_resp_len < 0 then does single fetch for BufLen bytes. */
513 scsiLogSense(scsi_device
* device
, int pagenum
, int subpagenum
, uint8_t *pBuf
,
514 int bufLen
, int known_resp_len
)
517 struct scsi_cmnd_io io_hdr
;
518 struct scsi_sense_disect sinfo
;
522 if (known_resp_len
> bufLen
)
524 if (known_resp_len
> 0)
525 pageLen
= known_resp_len
;
526 else if (known_resp_len
< 0)
528 else { /* 0 == known_resp_len */
529 /* Starting twin fetch strategy: first fetch to find respone length */
531 if (pageLen
> bufLen
)
534 memset(pBuf
, 0, pageLen
);
536 memset(&io_hdr
, 0, sizeof(io_hdr
));
537 memset(cdb
, 0, sizeof(cdb
));
538 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
539 io_hdr
.dxfer_len
= pageLen
;
540 io_hdr
.dxferp
= pBuf
;
542 cdb
[2] = 0x40 | (pagenum
& 0x3f); /* Page control (PC)==1 */
543 cdb
[3] = subpagenum
; /* 0 for no sub-page */
544 sg_put_unaligned_be16(pageLen
, cdb
+ 7);
546 io_hdr
.cmnd_len
= sizeof(cdb
);
547 io_hdr
.sensep
= sense
;
548 io_hdr
.max_sense_len
= sizeof(sense
);
549 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
551 if (!device
->scsi_pass_through(&io_hdr
))
552 return -device
->get_errno();
553 scsi_do_sense_disect(&io_hdr
, &sinfo
);
555 if ((res
= scsiSimpleSenseFilter(&sinfo
)))
557 /* sanity check on response */
558 if ((SUPPORTED_LPAGES
!= pagenum
) && ((pBuf
[0] & 0x3f) != pagenum
))
559 return SIMPLE_ERR_BAD_RESP
;
560 uint16_t u
= sg_get_unaligned_be16(pBuf
+ 2);
562 return SIMPLE_ERR_BAD_RESP
;
564 if (4 == pageLen
) /* why define a lpage with no payload? */
565 pageLen
= 252; /* some IBM tape drives don't like double fetch */
566 /* some SCSI HBA don't like "odd" length transfers */
569 if (pageLen
> bufLen
)
573 memset(&io_hdr
, 0, sizeof(io_hdr
));
574 memset(cdb
, 0, sizeof(cdb
));
575 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
576 io_hdr
.dxfer_len
= pageLen
;
577 io_hdr
.dxferp
= pBuf
;
579 cdb
[2] = 0x40 | (pagenum
& 0x3f); /* Page control (PC)==1 */
581 sg_put_unaligned_be16(pageLen
, cdb
+ 7);
583 io_hdr
.cmnd_len
= sizeof(cdb
);
584 io_hdr
.sensep
= sense
;
585 io_hdr
.max_sense_len
= sizeof(sense
);
586 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
588 if (!device
->scsi_pass_through(&io_hdr
))
589 return -device
->get_errno();
590 scsi_do_sense_disect(&io_hdr
, &sinfo
);
591 int status
= scsiSimpleSenseFilter(&sinfo
);
594 /* sanity check on response */
595 if ((SUPPORTED_LPAGES
!= pagenum
) && ((pBuf
[0] & 0x3f) != pagenum
))
596 return SIMPLE_ERR_BAD_RESP
;
597 if (0 == sg_get_unaligned_be16(pBuf
+ 2))
598 return SIMPLE_ERR_BAD_RESP
;
602 /* Sends a LOG SELECT command. Can be used to set log page values
603 * or reset one log page (or all of them) to its defaults (typically zero).
604 * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if
605 * field in command not supported, * 4 if bad parameter to command or
606 * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */
608 scsiLogSelect(scsi_device
* device
, int pcr
, int sp
, int pc
, int pagenum
,
609 int subpagenum
, uint8_t *pBuf
, int bufLen
)
611 struct scsi_cmnd_io io_hdr
;
612 struct scsi_sense_disect sinfo
;
616 memset(&io_hdr
, 0, sizeof(io_hdr
));
617 memset(cdb
, 0, sizeof(cdb
));
618 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
619 io_hdr
.dxfer_len
= bufLen
;
620 io_hdr
.dxferp
= pBuf
;
622 cdb
[1] = (pcr
? 2 : 0) | (sp
? 1 : 0);
623 cdb
[2] = ((pc
<< 6) & 0xc0) | (pagenum
& 0x3f);
624 cdb
[3] = (subpagenum
& 0xff);
625 sg_put_unaligned_be16(bufLen
, cdb
+ 7);
627 io_hdr
.cmnd_len
= sizeof(cdb
);
628 io_hdr
.sensep
= sense
;
629 io_hdr
.max_sense_len
= sizeof(sense
);
630 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
632 if (!device
->scsi_pass_through(&io_hdr
))
633 return -device
->get_errno();
634 scsi_do_sense_disect(&io_hdr
, &sinfo
);
635 return scsiSimpleSenseFilter(&sinfo
);
638 /* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY,
639 * 2 if command not supported (then MODE SENSE(10) should be supported),
640 * 3 if field in command not supported or returns negated errno.
641 * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
643 scsiModeSense(scsi_device
* device
, int pagenum
, int subpagenum
, int pc
,
644 uint8_t *pBuf
, int bufLen
)
646 struct scsi_cmnd_io io_hdr
;
647 struct scsi_sense_disect sinfo
;
651 if ((bufLen
< 0) || (bufLen
> 255))
653 memset(&io_hdr
, 0, sizeof(io_hdr
));
654 memset(cdb
, 0, sizeof(cdb
));
655 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
656 io_hdr
.dxfer_len
= bufLen
;
657 io_hdr
.dxferp
= pBuf
;
659 cdb
[2] = (pc
<< 6) | (pagenum
& 0x3f);
663 io_hdr
.cmnd_len
= sizeof(cdb
);
664 io_hdr
.sensep
= sense
;
665 io_hdr
.max_sense_len
= sizeof(sense
);
666 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
668 if (!device
->scsi_pass_through(&io_hdr
))
669 return -device
->get_errno();
670 scsi_do_sense_disect(&io_hdr
, &sinfo
);
671 int status
= scsiSimpleSenseFilter(&sinfo
);
672 if (SIMPLE_ERR_TRY_AGAIN
== status
) {
673 if (!device
->scsi_pass_through(&io_hdr
))
674 return -device
->get_errno();
675 scsi_do_sense_disect(&io_hdr
, &sinfo
);
676 status
= scsiSimpleSenseFilter(&sinfo
);
678 if ((0 == status
) && (ALL_MODE_PAGES
!= pagenum
)) {
681 offset
= scsiModePageOffset(pBuf
, bufLen
, 0);
683 return SIMPLE_ERR_BAD_RESP
;
684 else if (pagenum
!= (pBuf
[offset
] & 0x3f))
685 return SIMPLE_ERR_BAD_RESP
;
690 /* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response
691 * from a corresponding 6 byte MODE SENSE command. Such a response should
692 * have a 4 byte header followed by 0 or more 8 byte block descriptors
693 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY,
694 * 2 if command not supported (then MODE SELECT(10) may be supported),
695 * 3 if field in command not supported, 4 if bad parameter to command
696 * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */
698 scsiModeSelect(scsi_device
* device
, int sp
, uint8_t *pBuf
, int bufLen
)
700 struct scsi_cmnd_io io_hdr
;
701 struct scsi_sense_disect sinfo
;
704 int pg_offset
, pg_len
, hdr_plus_1_pg
;
706 pg_offset
= 4 + pBuf
[3];
707 if (pg_offset
+ 2 >= bufLen
)
709 pg_len
= pBuf
[pg_offset
+ 1] + 2;
710 hdr_plus_1_pg
= pg_offset
+ pg_len
;
711 if (hdr_plus_1_pg
> bufLen
)
713 pBuf
[0] = 0; /* Length of returned mode sense data reserved for SELECT */
714 pBuf
[pg_offset
] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
715 memset(&io_hdr
, 0, sizeof(io_hdr
));
716 memset(cdb
, 0, sizeof(cdb
));
717 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
718 io_hdr
.dxfer_len
= hdr_plus_1_pg
;
719 io_hdr
.dxferp
= pBuf
;
720 cdb
[0] = MODE_SELECT
;
721 cdb
[1] = 0x10 | (sp
& 1); /* set PF (page format) bit always */
722 cdb
[4] = hdr_plus_1_pg
; /* make sure only one page sent */
724 io_hdr
.cmnd_len
= sizeof(cdb
);
725 io_hdr
.sensep
= sense
;
726 io_hdr
.max_sense_len
= sizeof(sense
);
727 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
729 if (!device
->scsi_pass_through(&io_hdr
))
730 return -device
->get_errno();
731 scsi_do_sense_disect(&io_hdr
, &sinfo
);
732 return scsiSimpleSenseFilter(&sinfo
);
735 /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
736 * not supported (then MODE SENSE(6) might be supported), 3 if field in
737 * command not supported or returns negated errno.
738 * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
740 scsiModeSense10(scsi_device
* device
, int pagenum
, int subpagenum
, int pc
,
741 uint8_t *pBuf
, int bufLen
)
743 struct scsi_cmnd_io io_hdr
;
744 struct scsi_sense_disect sinfo
;
748 memset(&io_hdr
, 0, sizeof(io_hdr
));
749 memset(cdb
, 0, sizeof(cdb
));
750 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
751 io_hdr
.dxfer_len
= bufLen
;
752 io_hdr
.dxferp
= pBuf
;
753 cdb
[0] = MODE_SENSE_10
;
754 cdb
[2] = (pc
<< 6) | (pagenum
& 0x3f);
756 sg_put_unaligned_be16(bufLen
, cdb
+ 7);
758 io_hdr
.cmnd_len
= sizeof(cdb
);
759 io_hdr
.sensep
= sense
;
760 io_hdr
.max_sense_len
= sizeof(sense
);
761 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
763 if (!device
->scsi_pass_through(&io_hdr
))
764 return -device
->get_errno();
765 scsi_do_sense_disect(&io_hdr
, &sinfo
);
766 int status
= scsiSimpleSenseFilter(&sinfo
);
767 if (SIMPLE_ERR_TRY_AGAIN
== status
) {
768 if (!device
->scsi_pass_through(&io_hdr
))
769 return -device
->get_errno();
770 scsi_do_sense_disect(&io_hdr
, &sinfo
);
771 status
= scsiSimpleSenseFilter(&sinfo
);
773 if ((0 == status
) && (ALL_MODE_PAGES
!= pagenum
)) {
776 offset
= scsiModePageOffset(pBuf
, bufLen
, 1);
778 return SIMPLE_ERR_BAD_RESP
;
779 else if (pagenum
!= (pBuf
[offset
] & 0x3f))
780 return SIMPLE_ERR_BAD_RESP
;
785 /* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response
786 * from a corresponding 10 byte MODE SENSE command. Such a response should
787 * have a 8 byte header followed by 0 or more 8 byte block descriptors
788 * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
789 * command not supported (then MODE SELECT(6) may be supported), 3 if field
790 * in command not supported, 4 if bad parameter to command or returns
791 * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */
793 scsiModeSelect10(scsi_device
* device
, int sp
, uint8_t *pBuf
, int bufLen
)
795 struct scsi_cmnd_io io_hdr
;
796 struct scsi_sense_disect sinfo
;
799 int pg_offset
, pg_len
, hdr_plus_1_pg
;
801 pg_offset
= 8 + sg_get_unaligned_be16(pBuf
+ 6);
802 if (pg_offset
+ 2 >= bufLen
)
804 pg_len
= pBuf
[pg_offset
+ 1] + 2;
805 hdr_plus_1_pg
= pg_offset
+ pg_len
;
806 if (hdr_plus_1_pg
> bufLen
)
809 pBuf
[1] = 0; /* Length of returned mode sense data reserved for SELECT */
810 pBuf
[pg_offset
] &= 0x7f; /* Mask out PS bit from byte 0 of page data */
811 memset(&io_hdr
, 0, sizeof(io_hdr
));
812 memset(cdb
, 0, sizeof(cdb
));
813 io_hdr
.dxfer_dir
= DXFER_TO_DEVICE
;
814 io_hdr
.dxfer_len
= hdr_plus_1_pg
;
815 io_hdr
.dxferp
= pBuf
;
816 cdb
[0] = MODE_SELECT_10
;
817 cdb
[1] = 0x10 | (sp
& 1); /* set PF (page format) bit always */
818 /* make sure only one page sent */
819 sg_put_unaligned_be16(hdr_plus_1_pg
, cdb
+ 7);
821 io_hdr
.cmnd_len
= sizeof(cdb
);
822 io_hdr
.sensep
= sense
;
823 io_hdr
.max_sense_len
= sizeof(sense
);
824 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
826 if (!device
->scsi_pass_through(&io_hdr
))
827 return -device
->get_errno();
828 scsi_do_sense_disect(&io_hdr
, &sinfo
);
829 return scsiSimpleSenseFilter(&sinfo
);
832 /* Standard INQUIRY returns 0 for ok, anything else is a major problem.
833 * bufLen should be 36 for unsafe devices (like USB mass storage stuff)
834 * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */
836 scsiStdInquiry(scsi_device
* device
, uint8_t *pBuf
, int bufLen
)
838 struct scsi_sense_disect sinfo
;
839 struct scsi_cmnd_io io_hdr
;
843 if ((bufLen
< 0) || (bufLen
> 1023))
845 memset(&io_hdr
, 0, sizeof(io_hdr
));
846 memset(cdb
, 0, sizeof(cdb
));
847 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
848 io_hdr
.dxfer_len
= bufLen
;
849 io_hdr
.dxferp
= pBuf
;
851 sg_put_unaligned_be16(bufLen
, cdb
+ 3);
853 io_hdr
.cmnd_len
= sizeof(cdb
);
854 io_hdr
.sensep
= sense
;
855 io_hdr
.max_sense_len
= sizeof(sense
);
856 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
858 if (!device
->scsi_pass_through(&io_hdr
))
859 return -device
->get_errno();
860 scsi_do_sense_disect(&io_hdr
, &sinfo
);
861 return scsiSimpleSenseFilter(&sinfo
);
864 /* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY
865 * (unlikely), 2 if command not supported, 3 if field in command not
866 * supported, 5 if response indicates that EVPD bit ignored or returns
867 * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */
869 scsiInquiryVpd(scsi_device
* device
, int vpd_page
, uint8_t *pBuf
, int bufLen
)
871 struct scsi_cmnd_io io_hdr
;
872 struct scsi_sense_disect sinfo
;
877 /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */
878 if ((SCSI_VPD_SUPPORTED_VPD_PAGES
!= vpd_page
) &&
879 supported_vpd_pages_p
&&
880 (! supported_vpd_pages_p
->is_supported(vpd_page
)))
883 if ((bufLen
< 0) || (bufLen
> 1023))
886 memset(&io_hdr
, 0, sizeof(io_hdr
));
887 memset(cdb
, 0, sizeof(cdb
));
890 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
891 io_hdr
.dxfer_len
= bufLen
;
892 io_hdr
.dxferp
= pBuf
;
894 cdb
[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
896 sg_put_unaligned_be16(bufLen
, cdb
+ 3);
898 io_hdr
.cmnd_len
= sizeof(cdb
);
899 io_hdr
.sensep
= sense
;
900 io_hdr
.max_sense_len
= sizeof(sense
);
901 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
903 if (!device
->scsi_pass_through(&io_hdr
))
904 return -device
->get_errno();
905 scsi_do_sense_disect(&io_hdr
, &sinfo
);
906 if ((SCSI_STATUS_CHECK_CONDITION
== io_hdr
.scsi_status
) &&
907 (SCSI_SK_ILLEGAL_REQUEST
== sinfo
.sense_key
) &&
908 (SCSI_ASC_INVALID_FIELD
== sinfo
.asc
) &&
910 bufLen
&= 0xff; /* make sure cdb[3] is 0 next time around */
914 if ((res
= scsiSimpleSenseFilter(&sinfo
)))
916 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
918 if (vpd_page
== pBuf
[1]) {
919 if ((0x80 == vpd_page
) && (bufLen
> 2) && (0x0 != pBuf
[2]))
920 return SIMPLE_ERR_BAD_RESP
;
922 return SIMPLE_ERR_BAD_RESP
;
927 /* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
928 * SPC-3 section 6.27 (rev 22a) */
930 scsiRequestSense(scsi_device
* device
, struct scsi_sense_disect
* sense_info
)
932 struct scsi_cmnd_io io_hdr
;
936 int sz_buff
= sizeof(buff
);
938 memset(&io_hdr
, 0, sizeof(io_hdr
));
939 memset(cdb
, 0, sizeof(cdb
));
940 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
941 io_hdr
.dxfer_len
= sz_buff
;
942 io_hdr
.dxferp
= buff
;
943 cdb
[0] = REQUEST_SENSE
;
946 io_hdr
.cmnd_len
= sizeof(cdb
);
947 io_hdr
.sensep
= sense
;
948 io_hdr
.max_sense_len
= sizeof(sense
);
949 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
951 if (!device
->scsi_pass_through(&io_hdr
))
952 return -device
->get_errno();
954 uint8_t resp_code
= buff
[0] & 0x7f;
955 sense_info
->resp_code
= resp_code
;
956 sense_info
->sense_key
= buff
[2] & 0xf;
958 sense_info
->ascq
= 0;
959 if ((0x70 == resp_code
) || (0x71 == resp_code
)) {
960 int len
= buff
[7] + 8;
962 sense_info
->asc
= buff
[12];
963 sense_info
->ascq
= buff
[13];
966 // fill progress indicator, if available
967 sense_info
->progress
= -1;
969 const unsigned char * ucp
;
973 sk
= (buff
[2] & 0xf);
974 if (! ((SCSI_SK_NO_SENSE
== sk
) || (SCSI_SK_NOT_READY
== sk
))) {
977 if (buff
[15] & 0x80) { /* SKSV bit set */
978 sense_info
->progress
= sg_get_unaligned_be16(buff
+ 16);
985 /* sense key specific progress (0x2) or progress descriptor (0xa) */
986 sk
= (buff
[1] & 0xf);
987 sk_pr
= (SCSI_SK_NO_SENSE
== sk
) || (SCSI_SK_NOT_READY
== sk
);
988 if (sk_pr
&& ((ucp
= sg_scsi_sense_desc_find(buff
, sz_buff
, 2))) &&
989 (0x6 == ucp
[1]) && (0x80 & ucp
[4])) {
990 sense_info
->progress
= sg_get_unaligned_be16(ucp
+ 5);
992 } else if (((ucp
= sg_scsi_sense_desc_find(buff
, sz_buff
, 0xa))) &&
994 sense_info
->progress
= sg_get_unaligned_be16(ucp
+ 6);
1005 /* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command
1006 * not supported, 3 if field in command not supported or returns negated
1007 * errno. SPC-3 section 6.28 (rev 22a) */
1009 scsiSendDiagnostic(scsi_device
* device
, int functioncode
, uint8_t *pBuf
,
1012 struct scsi_cmnd_io io_hdr
;
1013 struct scsi_sense_disect sinfo
;
1017 memset(&io_hdr
, 0, sizeof(io_hdr
));
1018 memset(cdb
, 0, sizeof(cdb
));
1019 io_hdr
.dxfer_dir
= bufLen
? DXFER_TO_DEVICE
: DXFER_NONE
;
1020 io_hdr
.dxfer_len
= bufLen
;
1021 io_hdr
.dxferp
= pBuf
;
1022 cdb
[0] = SEND_DIAGNOSTIC
;
1023 if (SCSI_DIAG_DEF_SELF_TEST
== functioncode
)
1024 cdb
[1] = 0x4; /* SelfTest bit */
1025 else if (SCSI_DIAG_NO_SELF_TEST
!= functioncode
)
1026 cdb
[1] = (functioncode
& 0x7) << 5; /* SelfTest _code_ */
1027 else /* SCSI_DIAG_NO_SELF_TEST == functioncode */
1028 cdb
[1] = 0x10; /* PF bit */
1029 sg_put_unaligned_be16(bufLen
, cdb
+ 3);
1031 io_hdr
.cmnd_len
= sizeof(cdb
);
1032 io_hdr
.sensep
= sense
;
1033 io_hdr
.max_sense_len
= sizeof(sense
);
1034 /* worst case is an extended foreground self test on a big disk */
1035 io_hdr
.timeout
= SCSI_TIMEOUT_SELF_TEST
;
1037 if (!device
->scsi_pass_through(&io_hdr
))
1038 return -device
->get_errno();
1039 scsi_do_sense_disect(&io_hdr
, &sinfo
);
1040 return scsiSimpleSenseFilter(&sinfo
);
1043 /* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
1045 _testunitready(scsi_device
* device
, struct scsi_sense_disect
* sinfo
)
1047 struct scsi_cmnd_io io_hdr
;
1051 memset(&io_hdr
, 0, sizeof(io_hdr
));
1052 memset(cdb
, 0, sizeof(cdb
));
1053 io_hdr
.dxfer_dir
= DXFER_NONE
;
1054 io_hdr
.dxfer_len
= 0;
1055 io_hdr
.dxferp
= NULL
;
1056 cdb
[0] = TEST_UNIT_READY
;
1058 io_hdr
.cmnd_len
= sizeof(cdb
);
1059 io_hdr
.sensep
= sense
;
1060 io_hdr
.max_sense_len
= sizeof(sense
);
1061 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
1063 if (!device
->scsi_pass_through(&io_hdr
))
1064 return -device
->get_errno();
1065 scsi_do_sense_disect(&io_hdr
, sinfo
);
1069 /* Returns 0 for device responds and media ready, 1 for device responds and
1070 media not ready, or returns a negated errno value */
1072 scsiTestUnitReady(scsi_device
* device
)
1074 struct scsi_sense_disect sinfo
;
1077 status
= _testunitready(device
, &sinfo
);
1080 status
= scsiSimpleSenseFilter(&sinfo
);
1081 if (SIMPLE_ERR_TRY_AGAIN
== status
) {
1082 /* power on reset, media changed, ok ... try again */
1083 status
= _testunitready(device
, &sinfo
);
1086 status
= scsiSimpleSenseFilter(&sinfo
);
1091 /* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1092 * command not supported, 3 if field in command not supported, 101 if
1093 * defect list not found (e.g. SSD may not have defect list) or returns
1094 * negated errno. SBC-2 section 5.12 (rev 16) */
1096 scsiReadDefect10(scsi_device
* device
, int req_plist
, int req_glist
,
1097 int dl_format
, uint8_t *pBuf
, int bufLen
)
1099 struct scsi_cmnd_io io_hdr
;
1100 struct scsi_sense_disect sinfo
;
1104 memset(&io_hdr
, 0, sizeof(io_hdr
));
1105 memset(cdb
, 0, sizeof(cdb
));
1106 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1107 io_hdr
.dxfer_len
= bufLen
;
1108 io_hdr
.dxferp
= pBuf
;
1109 cdb
[0] = READ_DEFECT_10
;
1110 cdb
[2] = (unsigned char)(((req_plist
<< 4) & 0x10) |
1111 ((req_glist
<< 3) & 0x8) | (dl_format
& 0x7));
1112 sg_put_unaligned_be16(bufLen
, cdb
+ 7);
1114 io_hdr
.cmnd_len
= sizeof(cdb
);
1115 io_hdr
.sensep
= sense
;
1116 io_hdr
.max_sense_len
= sizeof(sense
);
1117 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
1119 if (!device
->scsi_pass_through(&io_hdr
))
1120 return -device
->get_errno();
1121 scsi_do_sense_disect(&io_hdr
, &sinfo
);
1122 /* Look for "(Primary|Grown) defect list not found" */
1123 if ((sinfo
.resp_code
>= 0x70) && (0x1c == sinfo
.asc
))
1125 return scsiSimpleSenseFilter(&sinfo
);
1128 /* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if
1129 * command not supported, 3 if field in command not supported, 101 if
1130 * defect list not found (e.g. SSD may not have defect list) or returns
1131 * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */
1133 scsiReadDefect12(scsi_device
* device
, int req_plist
, int req_glist
,
1134 int dl_format
, int addrDescIndex
, uint8_t *pBuf
, int bufLen
)
1136 struct scsi_cmnd_io io_hdr
;
1137 struct scsi_sense_disect sinfo
;
1141 memset(&io_hdr
, 0, sizeof(io_hdr
));
1142 memset(cdb
, 0, sizeof(cdb
));
1143 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1144 io_hdr
.dxfer_len
= bufLen
;
1145 io_hdr
.dxferp
= pBuf
;
1146 cdb
[0] = READ_DEFECT_12
;
1147 cdb
[1] = (unsigned char)(((req_plist
<< 4) & 0x10) |
1148 ((req_glist
<< 3) & 0x8) | (dl_format
& 0x7));
1149 sg_put_unaligned_be32(addrDescIndex
, cdb
+ 2);
1150 sg_put_unaligned_be32(bufLen
, cdb
+ 6);
1152 io_hdr
.cmnd_len
= sizeof(cdb
);
1153 io_hdr
.sensep
= sense
;
1154 io_hdr
.max_sense_len
= sizeof(sense
);
1155 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
1157 if (!device
->scsi_pass_through(&io_hdr
))
1158 return -device
->get_errno();
1159 scsi_do_sense_disect(&io_hdr
, &sinfo
);
1160 /* Look for "(Primary|Grown) defect list not found" */
1161 if ((sinfo
.resp_code
>= 0x70) && (0x1c == sinfo
.asc
))
1163 return scsiSimpleSenseFilter(&sinfo
);
1166 /* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if
1167 * command not supported, 3 if field in command not supported or returns
1168 * negated errno. SBC-3 section 5.15 (rev 26) */
1170 scsiReadCapacity10(scsi_device
* device
, unsigned int * last_lbap
,
1171 unsigned int * lb_sizep
)
1174 struct scsi_cmnd_io io_hdr
;
1175 struct scsi_sense_disect sinfo
;
1180 memset(&io_hdr
, 0, sizeof(io_hdr
));
1181 memset(cdb
, 0, sizeof(cdb
));
1182 memset(resp
, 0, sizeof(resp
));
1183 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1184 io_hdr
.dxfer_len
= sizeof(resp
);
1185 io_hdr
.dxferp
= resp
;
1186 cdb
[0] = READ_CAPACITY_10
;
1188 io_hdr
.cmnd_len
= sizeof(cdb
);
1189 io_hdr
.sensep
= sense
;
1190 io_hdr
.max_sense_len
= sizeof(sense
);
1191 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
1193 if (!device
->scsi_pass_through(&io_hdr
))
1194 return -device
->get_errno();
1195 scsi_do_sense_disect(&io_hdr
, &sinfo
);
1196 res
= scsiSimpleSenseFilter(&sinfo
);
1200 *last_lbap
= sg_get_unaligned_be32(resp
+ 0);
1202 *lb_sizep
= sg_get_unaligned_be32(resp
+ 4);
1206 /* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0
1207 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command
1208 * not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */
1210 scsiReadCapacity16(scsi_device
* device
, uint8_t *pBuf
, int bufLen
)
1212 struct scsi_cmnd_io io_hdr
;
1213 struct scsi_sense_disect sinfo
;
1217 memset(&io_hdr
, 0, sizeof(io_hdr
));
1218 memset(cdb
, 0, sizeof(cdb
));
1219 io_hdr
.dxfer_dir
= DXFER_FROM_DEVICE
;
1220 io_hdr
.dxfer_len
= bufLen
;
1221 io_hdr
.dxferp
= pBuf
;
1222 cdb
[0] = READ_CAPACITY_16
;
1223 cdb
[1] = SAI_READ_CAPACITY_16
;
1224 sg_put_unaligned_be32(bufLen
, cdb
+ 10);
1226 io_hdr
.cmnd_len
= sizeof(cdb
);
1227 io_hdr
.sensep
= sense
;
1228 io_hdr
.max_sense_len
= sizeof(sense
);
1229 io_hdr
.timeout
= SCSI_TIMEOUT_DEFAULT
;
1231 if (!device
->scsi_pass_through(&io_hdr
))
1232 return -device
->get_errno();
1233 scsi_do_sense_disect(&io_hdr
, &sinfo
);
1234 return scsiSimpleSenseFilter(&sinfo
);
1237 /* Return number of bytes of storage in 'device' or 0 if error. If
1238 * successful and lb_sizep is not NULL then the logical block size in bytes
1239 * is written to the location pointed to by lb_sizep. If the 'Logical Blocks
1240 * per Physical Block Exponent' pointer (lb_per_pb_expp,) is non-null then
1241 * the value is written. If 'Protection information Intervals Exponent'*/
1243 scsiGetSize(scsi_device
* device
, bool avoid_rcap16
,
1244 struct scsi_readcap_resp
* srrp
)
1246 bool try_16
= false;
1247 bool try_12
= false;
1248 unsigned int last_lba
= 0, lb_size
= 0;
1250 uint64_t ret_val
= 0;
1251 uint8_t rc16resp
[32];
1254 res
= scsiReadCapacity10(device
, &last_lba
, &lb_size
);
1257 pout("%s: READ CAPACITY(10) failed, res=%d\n", __func__
, res
);
1259 } else { /* rcap10 succeeded */
1260 if (0xffffffff == last_lba
) {
1261 /* so number of blocks needs > 32 bits to represent */
1263 device
->set_rcap16_first();
1265 ret_val
= last_lba
+ 1;
1267 memset(srrp
, 0, sizeof(*srrp
));
1268 srrp
->num_lblocks
= ret_val
;
1269 srrp
->lb_size
= lb_size
;
1274 if (try_16
|| (! avoid_rcap16
)) {
1275 res
= scsiReadCapacity16(device
, rc16resp
, sizeof(rc16resp
));
1278 pout("%s: READ CAPACITY(16) failed, res=%d\n", __func__
, res
);
1279 if (try_16
) /* so already tried rcap10 */
1282 } else { /* rcap16 succeeded */
1286 ret_val
= sg_get_unaligned_be64(rc16resp
+ 0) + 1;
1287 lb_size
= sg_get_unaligned_be32(rc16resp
+ 8);
1288 if (srrp
) { /* writes to all fields */
1289 srrp
->num_lblocks
= ret_val
;
1290 srrp
->lb_size
= lb_size
;
1291 prot_en
= !!(0x1 & rc16resp
[12]);
1292 p_type
= ((rc16resp
[12] >> 1) & 0x7);
1293 srrp
->prot_type
= prot_en
? (1 + p_type
) : 0;
1294 srrp
->p_i_exp
= ((rc16resp
[13] >> 4) & 0xf);
1295 srrp
->lb_p_pb_exp
= (rc16resp
[13] & 0xf);
1296 srrp
->lbpme
= !!(0x80 & rc16resp
[14]);
1297 srrp
->lbprz
= !!(0x40 & rc16resp
[14]);
1298 srrp
->l_a_lba
= sg_get_unaligned_be16(rc16resp
+ 14) & 0x3fff;
1302 if (try_12
) { /* case where only rcap16 has been tried and failed */
1303 res
= scsiReadCapacity10(device
, &last_lba
, &lb_size
);
1306 pout("%s: 2nd READ CAPACITY(10) failed, res=%d\n", __func__
,
1309 } else { /* rcap10 succeeded */
1310 ret_val
= (uint64_t)last_lba
+ 1;
1312 memset(srrp
, 0, sizeof(*srrp
));
1313 srrp
->num_lblocks
= ret_val
;
1314 srrp
->lb_size
= lb_size
;
1318 return (ret_val
* lb_size
);
1321 /* Offset into mode sense (6 or 10 byte) response that actual mode page
1322 * starts at (relative to resp[0]). Returns -1 if problem */
1324 scsiModePageOffset(const uint8_t * resp
, int len
, int modese_len
)
1329 int resp_len
, bd_len
;
1330 if (10 == modese_len
) {
1331 resp_len
= sg_get_unaligned_be16(resp
+ 0) + 2;
1332 bd_len
= sg_get_unaligned_be16(resp
+ 6);
1333 offset
= bd_len
+ 8;
1335 resp_len
= resp
[0] + 1;
1337 offset
= bd_len
+ 4;
1339 if ((offset
+ 2) > len
) {
1340 pout("scsiModePageOffset: raw_curr too small, offset=%d "
1341 "resp_len=%d bd_len=%d\n", offset
, resp_len
, bd_len
);
1343 } else if ((offset
+ 2) > resp_len
) {
1344 if ((resp_len
> 2) || scsi_debugmode
)
1345 pout("scsiModePageOffset: response length too short, "
1346 "resp_len=%d offset=%d bd_len=%d\n", resp_len
,
1354 /* IEC mode page byte 2 bit masks */
1355 #define DEXCPT_ENABLE 0x08
1356 #define EWASC_ENABLE 0x10
1357 #define DEXCPT_DISABLE 0xf7
1358 #define EWASC_DISABLE 0xef
1359 #define TEST_DISABLE 0xfb
1361 /* Fetches the Informational Exceptions Control mode page. First tries
1362 * the 6 byte MODE SENSE command and if that fails with an illegal opcode
1363 * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive
1364 * number if a known error (see SIMPLE_ERR_ ...) or a negative errno
1367 scsiFetchIECmpage(scsi_device
* device
, struct scsi_iec_mode_page
*iecp
,
1372 memset(iecp
, 0, sizeof(*iecp
));
1373 iecp
->modese_len
= modese_len
;
1374 iecp
->requestedCurrent
= 1;
1375 if (iecp
->modese_len
<= 6) {
1376 if ((err
= scsiModeSense(device
, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
,
1377 0, MPAGE_CONTROL_CURRENT
,
1378 iecp
->raw_curr
, sizeof(iecp
->raw_curr
)))) {
1379 if (SIMPLE_ERR_BAD_OPCODE
== err
)
1380 iecp
->modese_len
= 10;
1382 iecp
->modese_len
= 0;
1385 } else if (0 == iecp
->modese_len
)
1386 iecp
->modese_len
= 6;
1388 if (10 == iecp
->modese_len
) {
1389 err
= scsiModeSense10(device
, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
,
1390 0, MPAGE_CONTROL_CURRENT
,
1391 iecp
->raw_curr
, sizeof(iecp
->raw_curr
));
1393 iecp
->modese_len
= 0;
1397 iecp
->gotCurrent
= 1;
1398 iecp
->requestedChangeable
= 1;
1399 if (10 == iecp
->modese_len
)
1400 err
= scsiModeSense10(device
, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
,
1401 0, MPAGE_CONTROL_CHANGEABLE
,
1402 iecp
->raw_chg
, sizeof(iecp
->raw_chg
));
1403 else if (6 == iecp
->modese_len
)
1404 err
= scsiModeSense(device
, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE
,
1405 0, MPAGE_CONTROL_CHANGEABLE
,
1406 iecp
->raw_chg
, sizeof(iecp
->raw_chg
));
1409 iecp
->gotChangeable
= 1;
1414 scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page
*iecp
)
1416 if (iecp
&& iecp
->gotCurrent
) {
1417 int offset
= scsiModePageOffset(iecp
->raw_curr
, sizeof(iecp
->raw_curr
),
1420 return (iecp
->raw_curr
[offset
+ 2] & DEXCPT_ENABLE
) ? 0 : 1;
1428 scsi_IsWarningEnabled(const struct scsi_iec_mode_page
*iecp
)
1430 if (iecp
&& iecp
->gotCurrent
) {
1431 int offset
= scsiModePageOffset(iecp
->raw_curr
, sizeof(iecp
->raw_curr
),
1434 return (iecp
->raw_curr
[offset
+ 2] & EWASC_ENABLE
) ? 1 : 0;
1441 /* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */
1442 #define SCSI_IEC_MP_BYTE2_ENABLED 0x10
1443 #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
1444 /* exception/warning via an unrequested REQUEST SENSE command */
1445 #define SCSI_IEC_MP_MRIE 6
1446 #define SCSI_IEC_MP_INTERVAL_T 0
1447 #define SCSI_IEC_MP_REPORT_COUNT 1
1449 /* Try to set (or clear) both Exception Control and Warning in the IE
1450 * mode page subject to the "changeable" mask. The object pointed to
1451 * by iecp is (possibly) inaccurate after this call, therefore
1452 * scsiFetchIECmpage() should be called again if the IEC mode page
1453 * is to be re-examined.
1454 * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...'
1455 * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */
1457 scsiSetExceptionControlAndWarning(scsi_device
* device
, int enabled
,
1458 const struct scsi_iec_mode_page
*iecp
)
1460 int offset
, resp_len
;
1462 uint8_t rout
[SCSI_IECMP_RAW_LEN
];
1464 if ((! iecp
) || (! iecp
->gotCurrent
))
1466 offset
= scsiModePageOffset(iecp
->raw_curr
, sizeof(iecp
->raw_curr
),
1470 memcpy(rout
, iecp
->raw_curr
, SCSI_IECMP_RAW_LEN
);
1471 /* mask out DPOFUA device specific (disk) parameter bit */
1472 if (10 == iecp
->modese_len
) {
1473 resp_len
= sg_get_unaligned_be16(rout
+ 0) + 2;
1476 resp_len
= rout
[0] + 1;
1479 int sp
= !! (rout
[offset
] & 0x80); /* PS bit becomes 'SELECT's SP bit */
1481 rout
[offset
+ 2] = SCSI_IEC_MP_BYTE2_ENABLED
;
1482 if (scsi_debugmode
> 2)
1483 rout
[offset
+ 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK
;
1484 rout
[offset
+ 3] = SCSI_IEC_MP_MRIE
;
1485 sg_put_unaligned_be32(SCSI_IEC_MP_INTERVAL_T
, rout
+ offset
+ 4);
1486 sg_put_unaligned_be32(SCSI_IEC_MP_REPORT_COUNT
, rout
+ offset
+ 8);
1487 if (iecp
->gotChangeable
) {
1488 uint8_t chg2
= iecp
->raw_chg
[offset
+ 2];
1490 rout
[offset
+ 2] = chg2
? (rout
[offset
+ 2] & chg2
) :
1491 iecp
->raw_curr
[offset
+ 2];
1492 for (int k
= 3; k
< 12; ++k
) {
1493 if (0 == iecp
->raw_chg
[offset
+ k
])
1494 rout
[offset
+ k
] = iecp
->raw_curr
[offset
+ k
];
1497 if (0 == memcmp(&rout
[offset
+ 2], &iecp
->raw_chg
[offset
+ 2], 10)) {
1498 if (scsi_debugmode
> 0)
1499 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1502 } else { /* disabling Exception Control and (temperature) Warnings */
1503 int eCEnabled
= (rout
[offset
+ 2] & DEXCPT_ENABLE
) ? 0 : 1;
1504 int wEnabled
= (rout
[offset
+ 2] & EWASC_ENABLE
) ? 1 : 0;
1505 if ((! eCEnabled
) && (! wEnabled
)) {
1506 if (scsi_debugmode
> 0)
1507 pout("scsiSetExceptionControlAndWarning: already disabled\n");
1508 return 0; /* nothing to do, leave other setting alone */
1511 rout
[offset
+ 2] &= EWASC_DISABLE
;
1513 if (iecp
->gotChangeable
&&
1514 (iecp
->raw_chg
[offset
+ 2] & DEXCPT_ENABLE
))
1515 rout
[offset
+ 2] |= DEXCPT_ENABLE
;
1516 rout
[offset
+ 2] &= TEST_DISABLE
; /* clear TEST bit for spec */
1519 if (10 == iecp
->modese_len
)
1520 err
= scsiModeSelect10(device
, sp
, rout
, resp_len
);
1521 else if (6 == iecp
->modese_len
)
1522 err
= scsiModeSelect(device
, sp
, rout
, resp_len
);
1527 scsiGetTemp(scsi_device
* device
, uint8_t *currenttemp
, uint8_t *triptemp
)
1532 memset(tBuf
, 0, sizeof(tBuf
));
1533 if ((err
= scsiLogSense(device
, TEMPERATURE_LPAGE
, 0, tBuf
,
1534 sizeof(tBuf
), 0))) {
1537 pout("%s for temperature failed [%s]\n", logSenStr
,
1538 scsiErrString(err
));
1541 *currenttemp
= tBuf
[9];
1542 *triptemp
= tBuf
[15];
1546 /* Read informational exception log page or Request Sense response.
1547 * Fetching asc/ascq code potentially flagging an exception or warning.
1548 * Returns 0 if ok, else error number. A current temperature of 255
1549 * (Celsius) implies that the temperature not available. */
1551 scsiCheckIE(scsi_device
* device
, int hasIELogPage
, int hasTempLogPage
,
1552 uint8_t *asc
, uint8_t *ascq
, uint8_t *currenttemp
,
1556 struct scsi_sense_disect sense_info
;
1558 uint8_t currTemp
, trTemp
;
1564 memset(tBuf
,0,sizeof(tBuf
)); // need to clear stack space of junk
1565 memset(&sense_info
, 0, sizeof(sense_info
));
1567 if ((err
= scsiLogSense(device
, IE_LPAGE
, 0, tBuf
,
1568 sizeof(tBuf
), 0))) {
1569 pout("%s failed, IE page [%s]\n", logSenStr
, scsiErrString(err
));
1572 // pull out page size from response, don't forget to add 4
1573 unsigned short pagesize
= sg_get_unaligned_be16(tBuf
+ 2) + 4;
1574 if ((pagesize
< 4) || tBuf
[4] || tBuf
[5]) {
1575 pout("%s failed, IE page, bad parameter code or length\n",
1577 return SIMPLE_ERR_BAD_PARAM
;
1580 sense_info
.asc
= tBuf
[8];
1581 sense_info
.ascq
= tBuf
[9];
1582 if (! hasTempLogPage
) {
1584 *currenttemp
= tBuf
[10];
1585 if (tBuf
[7] > 3) /* IBM extension in SMART (IE) lpage */
1586 *triptemp
= tBuf
[11];
1590 if (0 == sense_info
.asc
) {
1591 /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
1592 if ((err
= scsiRequestSense(device
, &sense_info
))) {
1593 pout("Request Sense failed, [%s]\n", scsiErrString(err
));
1597 *asc
= sense_info
.asc
;
1598 *ascq
= sense_info
.ascq
;
1599 if (hasTempLogPage
) {
1600 if (0 == scsiGetTemp(device
, &currTemp
, &trTemp
)) {
1601 *currenttemp
= currTemp
;
1608 // The first character (W, C, I) tells the severity
1609 static const char * TapeAlertsMessageTable
[]= {
1612 "W: The tape drive is having problems reading data. No data has been "
1614 " but there has been a reduction in the performance of the tape.",
1616 "W: The tape drive is having problems writing data. No data has been "
1618 " but there has been a reduction in the capacity of the tape.",
1620 "W: The operation has stopped because an error has occurred while "
1622 " or writing data that the drive cannot correct.",
1624 "C: Your data is at risk:\n"
1625 " 1. Copy any data you require from this tape. \n"
1626 " 2. Do not use this tape again.\n"
1627 " 3. Restart the operation with a different tape.",
1629 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
1630 " supplier helpline.",
1632 "C: The tape is from a faulty batch or the tape drive is faulty:\n"
1633 " 1. Use a good tape to test the drive.\n"
1634 " 2. If problem persists, call the tape drive supplier helpline.",
1636 "W: The tape cartridge has reached the end of its calculated useful "
1638 " 1. Copy data you need to another tape.\n"
1639 " 2. Discard the old tape.",
1641 "W: The tape cartridge is not data-grade. Any data you back up to the "
1643 " is at risk. Replace the cartridge with a data-grade tape.",
1645 "C: You are trying to write to a write-protected cartridge. Remove the\n"
1646 " write-protection or use another tape.",
1648 "I: You cannot eject the cartridge because the tape drive is in use. "
1650 " until the operation is complete before ejecting the cartridge.",
1652 "I: The tape in the drive is a cleaning cartridge.",
1654 "I: You have tried to load a cartridge of a type which is not supported\n"
1657 "C: The operation has failed because the tape in the drive has "
1659 " a mechanical failure:\n"
1660 " 1. Discard the old tape.\n"
1661 " 2. Restart the operation with a different tape.",
1663 "C: The operation has failed because the tape in the drive has "
1665 " a mechanical failure:\n"
1666 " 1. Do not attempt to extract the tape cartridge\n"
1667 " 2. Call the tape drive supplier helpline.",
1669 "W: The memory in the tape cartridge has failed, which reduces\n"
1670 " performance. Do not use the cartridge for further write "
1673 "C: The operation has failed because the tape cartridge was manually\n"
1674 " de-mounted while the tape drive was actively writing or reading.",
1676 "W: You have loaded a cartridge of a type that is read-only in this "
1678 " The cartridge will appear as write-protected.",
1680 "W: The tape directory on the tape cartridge has been corrupted. File\n"
1681 " search performance will be degraded. The tape directory can be "
1683 " by reading all the data on the cartridge.",
1685 "I: The tape cartridge is nearing the end of its calculated life. It is\n"
1686 " recommended that you:\n"
1687 " 1. Use another tape cartridge for your next backup.\n"
1688 " 2. Store this tape in a safe place in case you need to restore "
1691 "C: The tape drive needs cleaning:\n"
1692 " 1. If the operation has stopped, eject the tape and clean the "
1694 " 2. If the operation has not stopped, wait for it to finish and "
1696 " clean the drive.\n"
1697 " Check the tape drive users manual for device specific cleaning "
1700 "W: The tape drive is due for routine cleaning:\n"
1701 " 1. Wait for the current operation to finish.\n"
1702 " 2. The use a cleaning cartridge.\n"
1703 " Check the tape drive users manual for device specific cleaning "
1706 "C: The last cleaning cartridge used in the tape drive has worn out:\n"
1707 " 1. Discard the worn out cleaning cartridge.\n"
1708 " 2. Wait for the current operation to finish.\n"
1709 " 3. Then use a new cleaning cartridge.",
1711 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
1713 " 1. Do not use this cleaning cartridge in this drive.\n"
1714 " 2. Wait for the current operation to finish.\n"
1715 " 3. Then use a new cleaning cartridge.",
1717 "W: The tape drive has requested a retention operation",
1719 "W: A redundant interface port on the tape drive has failed",
1721 "W: A tape drive cooling fan has failed",
1723 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
1724 " Check the enclosure users manual for instructions on replacing "
1726 " failed power supply.",
1728 "W: The tape drive power consumption is outside the specified range.",
1730 "W: Preventive maintenance of the tape drive is required. Check the tape\n"
1731 " drive users manual for device specific preventive maintenance\n"
1732 " tasks or call the tape drive supplier helpline.",
1734 "C: The tape drive has a hardware fault:\n"
1735 " 1. Eject the tape or magazine.\n"
1736 " 2. Reset the drive.\n"
1737 " 3. Restart the operation.",
1739 "C: The tape drive has a hardware fault:\n"
1740 " 1. Turn the tape drive off and then on again.\n"
1741 " 2. Restart the operation.\n"
1742 " 3. If the problem persists, call the tape drive supplier helpline.",
1744 "W: The tape drive has a problem with the application client interface:\n"
1745 " 1. Check the cables and cable connections.\n"
1746 " 2. Restart the operation.",
1748 "C: The operation has failed:\n"
1749 " 1. Eject the tape or magazine.\n"
1750 " 2. Insert the tape or magazine again.\n"
1751 " 3. Restart the operation.",
1753 "W: The firmware download has failed because you have tried to use the\n"
1754 " incorrect firmware for this tape drive. Obtain the correct\n"
1755 " firmware and try again.",
1757 "W: Environmental conditions inside the tape drive are outside the\n"
1758 " specified humidity range.",
1760 "W: Environmental conditions inside the tape drive are outside the\n"
1761 " specified temperature range.",
1763 "W: The voltage supply to the tape drive is outside the specified range.",
1765 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
1766 " drive supplier helpline.",
1768 "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
1769 " verify and diagnose the problem. Check the tape drive users manual "
1771 " device specific instructions on running extended diagnostic tests.",
1773 "C: The changer mechanism is having difficulty communicating with the "
1776 " 1. Turn the autoloader off then on.\n"
1777 " 2. Restart the operation.\n"
1778 " 3. If problem persists, call the tape drive supplier helpline.",
1780 "C: A tape has been left in the autoloader by a previous hardware fault:\n"
1781 " 1. Insert an empty magazine to clear the fault.\n"
1782 " 2. If the fault does not clear, turn the autoloader off and then\n"
1784 " 3. If the problem persists, call the tape drive supplier helpline.",
1786 "W: There is a problem with the autoloader mechanism.",
1788 "C: The operation has failed because the autoloader door is open:\n"
1789 " 1. Clear any obstructions from the autoloader door.\n"
1790 " 2. Eject the magazine and then insert it again.\n"
1791 " 3. If the fault does not clear, turn the autoloader off and then\n"
1793 " 4. If the problem persists, call the tape drive supplier helpline.",
1795 "C: The autoloader has a hardware fault:\n"
1796 " 1. Turn the autoloader off and then on again.\n"
1797 " 2. Restart the operation.\n"
1798 " 3. If the problem persists, call the tape drive supplier helpline.\n"
1799 " Check the autoloader users manual for device specific instructions\n"
1800 " on turning the device power on and off.",
1802 "C: The autoloader cannot operate without the magazine,\n"
1803 " 1. Insert the magazine into the autoloader.\n"
1804 " 2. Restart the operation.",
1806 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
1807 " tape drive supplier helpline.",
1815 "W: Media statistics have been lost at some time in the past",
1817 "W: The tape directory on the tape cartridge just unloaded has been\n"
1818 " corrupted. File search performance will be degraded. The tape\n"
1819 " directory can be rebuilt by reading all the data.",
1821 "C: The tape just unloaded could not write its system area successfully:\n"
1822 " 1. Copy data to another tape cartridge.\n"
1823 " 2. Discard the old cartridge.",
1825 "C: The tape system are could not be read successfully at load time:\n"
1826 " 1. Copy data to another tape cartridge.\n",
1828 "C: The start or data could not be found on the tape:\n"
1829 " 1. Check you are using the correct format tape.\n"
1830 " 2. Discard the tape or return the tape to your supplier",
1832 "C: The operation has failed because the media cannot be loaded\n"
1834 " 1. Remove the cartridge, inspect it as specified in the product\n"
1835 " manual, and retry the operation.\n"
1836 " 2. If the problem persists, call the tape drive supplier help "
1839 "C: The operation has failed because the medium cannot be unloaded:\n"
1840 " 1. Do not attempt to extract the tape cartridge.\n"
1841 " 2. Call the tape driver supplier help line.",
1843 "C: The tape drive has a problem with the automation interface:\n"
1844 " 1. Check the power to the automation system.\n"
1845 " 2. Check the cables and cable connections.\n"
1846 " 3. Call the supplier help line if problem persists.",
1848 "W: The tape drive has reset itself due to a detected firmware\n"
1849 " fault. If problem persists, call the supplier help line.",
1853 scsiTapeAlertsTapeDevice(unsigned short code
)
1855 const int num
= sizeof(TapeAlertsMessageTable
) /
1856 sizeof(TapeAlertsMessageTable
[0]);
1858 return (code
< num
) ? TapeAlertsMessageTable
[code
] : "Unknown Alert";
1861 // The first character (W, C, I) tells the severity
1862 static const char * ChangerTapeAlertsMessageTable
[]= {
1865 "C: The library mechanism is having difficulty communicating with the\n"
1867 " 1. Turn the library off then on.\n"
1868 " 2. Restart the operation.\n"
1869 " 3. If the problem persists, call the library supplier help line.",
1871 "W: There is a problem with the library mechanism. If problem persists,\n"
1872 " call the library supplier help line.",
1874 "C: The library has a hardware fault:\n"
1875 " 1. Reset the library.\n"
1876 " 2. Restart the operation.\n"
1877 " Check the library users manual for device specific instructions on "
1881 "C: The library has a hardware fault:\n"
1882 " 1. Turn the library off then on again.\n"
1883 " 2. Restart the operation.\n"
1884 " 3. If the problem persists, call the library supplier help line.\n"
1885 " Check the library users manual for device specific instructions on "
1887 " device power on and off.",
1889 "W: The library mechanism may have a hardware fault.\n"
1890 " Run extended diagnostics to verify and diagnose the problem. "
1891 "Check the library\n"
1892 " users manual for device specific instructions on running extended "
1896 "C: The library has a problem with the host interface:\n"
1897 " 1. Check the cables and connections.\n"
1898 " 2. Restart the operation.",
1900 "W: A hardware failure of the library is predicted. Call the library\n"
1901 " supplier help line.",
1903 "W: Preventive maintenance of the library is required.\n"
1904 " Check the library users manual for device specific preventative "
1906 " tasks, or call your library supplier help line.",
1908 "C: General environmental conditions inside the library are outside the\n"
1909 " specified humidity range.",
1911 "C: General environmental conditions inside the library are outside the\n"
1912 " specified temperature range.",
1914 "C: The voltage supply to the library is outside the specified range.\n"
1915 " There is a potential problem with the power supply or failure of\n"
1916 " a redundant power supply.",
1918 "C: A cartridge has been left inside the library by a previous hardware\n"
1920 " 1. Insert an empty magazine to clear the fault.\n"
1921 " 2. If the fault does not clear, turn the library off and then on "
1923 " 3. If the problem persists, call the library supplier help line.",
1925 "W: There is a potential problem with the drive ejecting cartridges or\n"
1926 " with the library mechanism picking a cartridge from a slot.\n"
1927 " 1. No action needs to be taken at this time.\n"
1928 " 2. If the problem persists, call the library supplier help line.",
1930 "W: There is a potential problem with the library mechanism placing a\n"
1931 " cartridge into a slot.\n"
1932 " 1. No action needs to be taken at this time.\n"
1933 " 2. If the problem persists, call the library supplier help line.",
1935 "W: There is a potential problem with the drive or the library mechanism\n"
1936 " loading cartridges, or an incompatible cartridge.",
1938 "C: The library has failed because the door is open:\n"
1939 " 1. Clear any obstructions from the library door.\n"
1940 " 2. Close the library door.\n"
1941 " 3. If the problem persists, call the library supplier help line.",
1943 "C: There is a mechanical problem with the library media import/export\n"
1946 "C: The library cannot operate without the magazine.\n"
1947 " 1. Insert the magazine into the library.\n"
1948 " 2. Restart the operation.",
1950 "W: Library security has been compromised.",
1952 "I: The library security mode has been changed.\n"
1953 " The library has either been put into secure mode, or the library "
1955 " the secure mode.\n"
1956 " This is for information purposes only. No action is required.",
1958 "I: The library has been manually turned offline and is unavailable for "
1961 "I: A drive inside the library has been taken offline.\n"
1962 " This is for information purposes only. No action is required.",
1964 "W: There is a potential problem with the bar code label or the scanner\n"
1965 " hardware in the library mechanism.\n"
1966 " 1. No action needs to be taken at this time.\n"
1967 " 2. If the problem persists, call the library supplier help line.",
1969 "C: The library has detected an inconsistency in its inventory.\n"
1970 " 1. Redo the library inventory to correct inconsistency.\n"
1971 " 2. Restart the operation.\n"
1972 " Check the applications users manual or the hardware users manual "
1974 " specific instructions on redoing the library inventory.",
1976 "W: A library operation has been attempted that is invalid at this time.",
1978 "W: A redundant interface port on the library has failed.",
1980 "W: A library cooling fan has failed.",
1982 "W: A redundant power supply has failed inside the library. Check the\n"
1983 " library users manual for instructions on replacing the failed "
1986 "W: The library power consumption is outside the specified range.",
1988 "C: A failure has occurred in the cartridge pass-through mechanism "
1990 " two library modules.",
1992 "C: A cartridge has been left in the pass-through mechanism from a\n"
1993 " previous hardware fault. Check the library users guide for "
1995 " clearing this fault.",
1997 "I: The library was unable to read the bar code on a cartridge.",
2001 scsiTapeAlertsChangerDevice(unsigned short code
)
2003 const int num
= sizeof(ChangerTapeAlertsMessageTable
) /
2004 sizeof(ChangerTapeAlertsMessageTable
[0]);
2006 return (code
< num
) ? ChangerTapeAlertsMessageTable
[code
] :
2011 /* this is a subset of the SCSI additional sense code strings indexed
2012 * by "ascq" for the case when asc==SCSI_ASC_IMPENDING_FAILURE (0x5d)
2014 static const char * strs_for_asc_5d
[] = {
2015 /* 0x00 */ "FAILURE PREDICTION THRESHOLD EXCEEDED",
2016 "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED",
2017 "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED",
2018 "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED",
2031 /* 0x10 */ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2032 "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2033 "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2034 "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2035 "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2036 "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2037 "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2038 "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
2039 "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED",
2040 "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2041 "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2042 "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2043 "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2047 /* 0x20 */ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2048 "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2049 "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2050 "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2051 "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2052 "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2053 "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2054 "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS",
2055 "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED",
2056 "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2057 "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE",
2058 "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT",
2059 "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2063 /* 0x30 */ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2064 "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2065 "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2066 "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2067 "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2068 "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2069 "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2070 "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS",
2071 "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED",
2072 "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2073 "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE",
2074 "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT",
2075 "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2079 /* 0x40 */ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2080 "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2081 "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2082 "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2083 "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2084 "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2085 "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2086 "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS",
2087 "SERVO IMPENDING FAILURE CONTROLLER DETECTED",
2088 "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2089 "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE",
2090 "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT",
2091 "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2095 /* 0x50 */ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2096 "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2097 "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2098 "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2099 "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2100 "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2101 "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2102 "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS",
2103 "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED",
2104 "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2105 "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2106 "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2107 "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2111 /* 0x60 */ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2112 "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2113 "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2114 "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2115 "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2116 "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2117 "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2118 "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
2119 "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED",
2120 "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2121 "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2122 "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2123 /* 0x6c */ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"};
2126 /* this is a subset of the SCSI additional sense code strings indexed
2127 * * by "ascq" for the case when asc==SCSI_ASC_WARNING (0xb)
2129 static const char * strs_for_asc_b
[] = {
2130 /* 0x00 */ "WARNING",
2131 "WARNING - SPECIFIED TEMPERATURE EXCEEDED",
2132 "WARNING - ENCLOSURE DEGRADED"};
2134 static char spare_buff
[128];
2137 scsiGetIEString(uint8_t asc
, uint8_t ascq
)
2141 if (SCSI_ASC_IMPENDING_FAILURE
== asc
) {
2143 return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
2145 (sizeof(strs_for_asc_5d
) / sizeof(strs_for_asc_5d
[0]))) {
2146 rp
= strs_for_asc_5d
[ascq
];
2150 snprintf(spare_buff
, sizeof(spare_buff
),
2151 "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq
);
2153 } else if (SCSI_ASC_WARNING
== asc
) {
2154 if (ascq
< (sizeof(strs_for_asc_b
) / sizeof(strs_for_asc_b
[0]))) {
2155 rp
= strs_for_asc_b
[ascq
];
2159 snprintf(spare_buff
, sizeof(spare_buff
), "WARNING: ascq=0x%x", ascq
);
2162 return NULL
; /* not a IE additional sense code */
2167 scsiSmartDefaultSelfTest(scsi_device
* device
)
2171 res
= scsiSendDiagnostic(device
, SCSI_DIAG_DEF_SELF_TEST
, NULL
, 0);
2173 pout("Default self test failed [%s]\n", scsiErrString(res
));
2178 scsiSmartShortSelfTest(scsi_device
* device
)
2182 res
= scsiSendDiagnostic(device
, SCSI_DIAG_BG_SHORT_SELF_TEST
, NULL
, 0);
2184 pout("Short offline self test failed [%s]\n", scsiErrString(res
));
2189 scsiSmartExtendSelfTest(scsi_device
* device
)
2193 res
= scsiSendDiagnostic(device
, SCSI_DIAG_BG_EXTENDED_SELF_TEST
, NULL
, 0);
2195 pout("Long (extended) offline self test failed [%s]\n",
2196 scsiErrString(res
));
2201 scsiSmartShortCapSelfTest(scsi_device
* device
)
2205 res
= scsiSendDiagnostic(device
, SCSI_DIAG_FG_SHORT_SELF_TEST
, NULL
, 0);
2207 pout("Short foreground self test failed [%s]\n", scsiErrString(res
));
2212 scsiSmartExtendCapSelfTest(scsi_device
* device
)
2216 res
= scsiSendDiagnostic(device
, SCSI_DIAG_FG_EXTENDED_SELF_TEST
, NULL
, 0);
2218 pout("Long (extended) foreground self test failed [%s]\n",
2219 scsiErrString(res
));
2224 scsiSmartSelfTestAbort(scsi_device
* device
)
2228 res
= scsiSendDiagnostic(device
, SCSI_DIAG_ABORT_SELF_TEST
, NULL
, 0);
2230 pout("Abort self test failed [%s]\n", scsiErrString(res
));
2234 /* Returns 0 and the expected duration of an extended self test (in seconds)
2235 if successful; any other return value indicates a failure. */
2237 scsiFetchExtendedSelfTestTime(scsi_device
* device
, int * durationSec
,
2243 memset(buff
, 0, sizeof(buff
));
2244 if (modese_len
<= 6) {
2245 if ((err
= scsiModeSense(device
, CONTROL_MODE_PAGE
, 0,
2246 MPAGE_CONTROL_CURRENT
,
2247 buff
, sizeof(buff
)))) {
2248 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2252 } else if (0 == modese_len
)
2255 if (10 == modese_len
) {
2256 err
= scsiModeSense10(device
, CONTROL_MODE_PAGE
, 0,
2257 MPAGE_CONTROL_CURRENT
,
2258 buff
, sizeof(buff
));
2262 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2265 if (buff
[offset
+ 1] >= 0xa) {
2266 int res
= sg_get_unaligned_be16(buff
+ offset
+ 10);
2275 scsiDecodeErrCounterPage(unsigned char * resp
, struct scsiErrorCounter
*ecp
)
2277 memset(ecp
, 0, sizeof(*ecp
));
2278 int num
= sg_get_unaligned_be16(resp
+ 2);
2279 unsigned char * ucp
= &resp
[0] + 4;
2281 int pc
= sg_get_unaligned_be16(ucp
+ 0);
2282 int pl
= ucp
[3] + 4;
2293 ullp
= &ecp
->counter
[pc
];
2296 ecp
->gotExtraPC
= 1;
2297 ullp
= &ecp
->counter
[7];
2301 unsigned char * xp
= ucp
+ 4;
2302 if (k
> (int)sizeof(*ullp
)) {
2303 xp
+= (k
- sizeof(*ullp
));
2306 *ullp
= sg_get_unaligned_be(k
, xp
);
2313 scsiDecodeNonMediumErrPage(unsigned char *resp
,
2314 struct scsiNonMediumError
*nmep
)
2316 memset(nmep
, 0, sizeof(*nmep
));
2317 int num
= sg_get_unaligned_be16(resp
+ 2);
2318 unsigned char * ucp
= &resp
[0] + 4;
2319 int szof
= sizeof(nmep
->counterPC0
);
2321 int pc
= sg_get_unaligned_be16(ucp
+ 0);
2322 int pl
= ucp
[3] + 4;
2334 nmep
->counterPC0
= sg_get_unaligned_be(k
, xp
+ 0);
2344 nmep
->counterTFE_H
= sg_get_unaligned_be(k
, xp
+ 0);
2354 nmep
->counterPE_H
= sg_get_unaligned_be(k
, xp
+ 0);
2357 nmep
->gotExtraPC
= 1;
2365 /* Counts number of failed self-tests. Also encodes the poweron_hour
2366 of the most recent failed self-test. Return value is negative if
2367 this function has a problem (typically -1), otherwise the bottom 8
2368 bits are the number of failed self tests and the 16 bits above that
2369 are the poweron hour of the most recent failure. Note: aborted self
2370 tests (typically by the user) and self tests in progress are not
2371 considered failures. See Working Draft SCSI Primary Commands - 3
2372 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
2374 scsiCountFailedSelfTests(scsi_device
* fd
, int noisy
)
2376 int num
, k
, err
, fails
, fail_hour
;
2378 unsigned char resp
[LOG_RESP_SELF_TEST_LEN
];
2380 if ((err
= scsiLogSense(fd
, SELFTEST_RESULTS_LPAGE
, 0, resp
,
2381 LOG_RESP_SELF_TEST_LEN
, 0))) {
2383 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err
));
2386 if ((resp
[0] & 0x3f) != SELFTEST_RESULTS_LPAGE
) {
2388 pout("Self-test %s Failed, page mismatch\n", logSenStr
);
2391 // compute page length
2392 num
= sg_get_unaligned_be16(resp
+ 2);
2393 // Log sense page length 0x190 bytes
2396 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr
,
2402 // loop through the twenty possible entries
2403 for (k
= 0, ucp
= resp
+ 4; k
< 20; ++k
, ucp
+= 20 ) {
2405 // timestamp in power-on hours (or zero if test in progress)
2406 int n
= sg_get_unaligned_be16(ucp
+ 6);
2408 // The spec says "all 20 bytes will be zero if no test" but
2409 // DG has found otherwise. So this is a heuristic.
2410 if ((0 == n
) && (0 == ucp
[4]))
2412 int res
= ucp
[4] & 0xf;
2413 if ((res
> 2) && (res
< 8)) {
2416 fail_hour
= sg_get_unaligned_be16(ucp
+ 6);
2419 return (fail_hour
<< 8) + fails
;
2422 /* Returns 0 if able to read self test log page; then outputs 1 into
2423 *inProgress if self test still in progress, else outputs 0. */
2425 scsiSelfTestInProgress(scsi_device
* fd
, int * inProgress
)
2429 unsigned char resp
[LOG_RESP_SELF_TEST_LEN
];
2431 if (scsiLogSense(fd
, SELFTEST_RESULTS_LPAGE
, 0, resp
,
2432 LOG_RESP_SELF_TEST_LEN
, 0))
2434 if (resp
[0] != SELFTEST_RESULTS_LPAGE
)
2436 // compute page length
2437 num
= sg_get_unaligned_be16(resp
+ 2);
2438 // Log sense page length 0x190 bytes
2444 *inProgress
= (0xf == (ucp
[4] & 0xf)) ? 1 : 0;
2448 /* Returns a negative value if failed to fetch Control mode page or it was
2449 malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2450 bit is set. Examines default mode page when current==0 else examines
2451 current mode page. */
2453 scsiFetchControlGLTSD(scsi_device
* device
, int modese_len
, int current
)
2457 int pc
= current
? MPAGE_CONTROL_CURRENT
: MPAGE_CONTROL_DEFAULT
;
2459 memset(buff
, 0, sizeof(buff
));
2460 if (modese_len
<= 6) {
2461 if ((err
= scsiModeSense(device
, CONTROL_MODE_PAGE
, 0, pc
,
2462 buff
, sizeof(buff
)))) {
2463 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2467 } else if (0 == modese_len
)
2470 if (10 == modese_len
) {
2471 err
= scsiModeSense10(device
, CONTROL_MODE_PAGE
, 0, pc
,
2472 buff
, sizeof(buff
));
2476 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2477 if ((offset
>= 0) && (buff
[offset
+ 1] >= 0xa))
2478 return (buff
[offset
+ 2] & 2) ? 1 : 0;
2482 /* Returns a negative value on error, 0 if unknown and 1 if SSD,
2483 * otherwise the positive returned value is the speed in rpm. First checks
2484 * the Block Device Characteristics VPD page and if that fails it tries the
2485 * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page. */
2488 scsiGetRPM(scsi_device
* device
, int modese_len
, int * form_factorp
,
2493 int pc
= MPAGE_CONTROL_DEFAULT
;
2495 memset(buff
, 0, sizeof(buff
));
2496 if ((0 == scsiInquiryVpd(device
, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS
,
2497 buff
, sizeof(buff
))) &&
2498 ((sg_get_unaligned_be16(buff
+ 2)) > 2)) {
2499 int speed
= sg_get_unaligned_be16(buff
+ 4);
2501 *form_factorp
= buff
[7] & 0xf;
2503 *haw_zbcp
= !!(0x10 & buff
[8]);
2510 if (modese_len
<= 6) {
2511 if ((err
= scsiModeSense(device
, RIGID_DISK_DRIVE_GEOMETRY_PAGE
, 0, pc
,
2512 buff
, sizeof(buff
)))) {
2513 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2517 } else if (0 == modese_len
)
2520 if (10 == modese_len
) {
2521 err
= scsiModeSense10(device
, RIGID_DISK_DRIVE_GEOMETRY_PAGE
, 0, pc
,
2522 buff
, sizeof(buff
));
2526 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2527 return sg_get_unaligned_be16(buff
+ offset
+ 20);
2530 /* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2531 0 - clear bit, 1 - set bit */
2534 scsiGetSetCache(scsi_device
* device
, int modese_len
, short int * wcep
,
2537 int err
, offset
, resp_len
, sp
;
2538 uint8_t buff
[64], ch_buff
[64];
2539 short set_wce
= *wcep
;
2540 short set_rcd
= *rcdp
;
2542 memset(buff
, 0, sizeof(buff
));
2543 if (modese_len
<= 6) {
2544 err
= scsiModeSense(device
, CACHING_PAGE
, 0, MPAGE_CONTROL_CURRENT
,
2545 buff
, sizeof(buff
));
2547 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2550 device
->set_err(EINVAL
, "SCSI MODE SENSE failed");
2553 } else if (0 == modese_len
)
2557 if (10 == modese_len
) {
2558 err
= scsiModeSense10(device
, CACHING_PAGE
, 0, MPAGE_CONTROL_CURRENT
,
2559 buff
, sizeof(buff
));
2561 device
->set_err(EINVAL
, "SCSI MODE SENSE failed");
2565 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2566 if ((offset
< 0) || (buff
[offset
+ 1] < 0xa)) {
2567 device
->set_err(EINVAL
, "Bad response");
2568 return SIMPLE_ERR_BAD_RESP
;
2571 *wcep
= ((buff
[offset
+ 2] & 0x04) != 0);
2572 *rcdp
= ((buff
[offset
+ 2] & 0x01) != 0);
2574 if((*wcep
== set_wce
|| set_wce
== -1)
2575 && ((*rcdp
== set_rcd
) || set_rcd
== -1))
2576 return 0; // no changes needed or nothing to set
2578 if (modese_len
== 6)
2579 err
= scsiModeSense(device
, CACHING_PAGE
, 0,
2580 MPAGE_CONTROL_CHANGEABLE
,
2581 ch_buff
, sizeof(ch_buff
));
2583 err
= scsiModeSense10(device
, CACHING_PAGE
, 0,
2584 MPAGE_CONTROL_CHANGEABLE
,
2585 ch_buff
, sizeof(ch_buff
));
2587 device
->set_err(EINVAL
, "WCE/RCD bits not changeable");
2592 if(set_wce
>= 0 && *wcep
!= set_wce
) {
2593 if (0 == (ch_buff
[offset
+ 2] & 0x04)) {
2594 device
->set_err(EINVAL
, "WCE bit not changeable");
2598 buff
[offset
+ 2] |= 0x04; // set bit
2600 buff
[offset
+ 2] &= 0xfb; // clear bit
2603 if(set_rcd
>= 0 && *rcdp
!= set_rcd
) {
2604 if (0 == (ch_buff
[offset
+ 2] & 0x01)) {
2605 device
->set_err(EINVAL
, "RCD bit not changeable");
2609 buff
[offset
+ 2] |= 0x01; // set bit
2611 buff
[offset
+ 2] &= 0xfe; // clear bit
2614 /* mask out DPOFUA device specific (disk) parameter bit */
2615 if (10 == modese_len
) {
2616 resp_len
= sg_get_unaligned_be16(buff
+ 0) + 2;
2619 resp_len
= buff
[0] + 1;
2622 sp
= 0; /* Do not change saved values */
2623 if (10 == modese_len
)
2624 err
= scsiModeSelect10(device
, sp
, buff
, resp_len
);
2625 else if (6 == modese_len
)
2626 err
= scsiModeSelect(device
, sp
, buff
, resp_len
);
2628 device
->set_err(EINVAL
, "MODE SELECT command failed");
2633 /* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
2634 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
2635 successful, negative if low level error, > 0 if higher level error (e.g.
2636 SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
2638 scsiSetControlGLTSD(scsi_device
* device
, int enabled
, int modese_len
)
2640 int err
, offset
, resp_len
, sp
;
2642 uint8_t ch_buff
[64];
2644 memset(buff
, 0, sizeof(buff
));
2645 if (modese_len
<= 6) {
2646 if ((err
= scsiModeSense(device
, CONTROL_MODE_PAGE
, 0,
2647 MPAGE_CONTROL_CURRENT
,
2648 buff
, sizeof(buff
)))) {
2649 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2653 } else if (0 == modese_len
)
2656 if (10 == modese_len
) {
2657 err
= scsiModeSense10(device
, CONTROL_MODE_PAGE
, 0,
2658 MPAGE_CONTROL_CURRENT
,
2659 buff
, sizeof(buff
));
2663 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2664 if ((offset
< 0) || (buff
[offset
+ 1] < 0xa))
2665 return SIMPLE_ERR_BAD_RESP
;
2669 if (enabled
== (buff
[offset
+ 2] & 2))
2670 return 0; /* GLTSD already in wanted state so nothing to do */
2672 if (modese_len
== 6)
2673 err
= scsiModeSense(device
, CONTROL_MODE_PAGE
, 0,
2674 MPAGE_CONTROL_CHANGEABLE
,
2675 ch_buff
, sizeof(ch_buff
));
2677 err
= scsiModeSense10(device
, CONTROL_MODE_PAGE
, 0,
2678 MPAGE_CONTROL_CHANGEABLE
,
2679 ch_buff
, sizeof(ch_buff
));
2682 if (0 == (ch_buff
[offset
+ 2] & 2))
2683 return SIMPLE_ERR_BAD_PARAM
; /* GLTSD bit not changeable */
2685 /* mask out DPOFUA device specific (disk) parameter bit */
2686 if (10 == modese_len
) {
2687 resp_len
= sg_get_unaligned_be16(buff
+ 0) + 2;
2690 resp_len
= buff
[0] + 1;
2693 sp
= (buff
[offset
] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
2695 buff
[offset
+ 2] |= 0x2; /* set GLTSD bit */
2697 buff
[offset
+ 2] &= 0xfd; /* clear GLTSD bit */
2698 if (10 == modese_len
)
2699 err
= scsiModeSelect10(device
, sp
, buff
, resp_len
);
2700 else if (6 == modese_len
)
2701 err
= scsiModeSelect(device
, sp
, buff
, resp_len
);
2705 /* Returns a negative value if failed to fetch Protocol specific port mode
2706 page or it was malformed. Returns transport protocol identifier when
2709 scsiFetchTransportProtocol(scsi_device
* device
, int modese_len
)
2714 memset(buff
, 0, sizeof(buff
));
2715 if (modese_len
<= 6) {
2716 if ((err
= scsiModeSense(device
, PROTOCOL_SPECIFIC_PORT_PAGE
, 0,
2717 MPAGE_CONTROL_CURRENT
,
2718 buff
, sizeof(buff
)))) {
2719 if (SIMPLE_ERR_BAD_OPCODE
== err
)
2723 } else if (0 == modese_len
)
2726 if (10 == modese_len
) {
2727 err
= scsiModeSense10(device
, PROTOCOL_SPECIFIC_PORT_PAGE
, 0,
2728 MPAGE_CONTROL_CURRENT
,
2729 buff
, sizeof(buff
));
2733 offset
= scsiModePageOffset(buff
, sizeof(buff
), modese_len
);
2734 if ((offset
>= 0) && (buff
[offset
+ 1] > 1)) {
2735 if ((0 == (buff
[offset
] & 0x40)) && /* SPF==0 */
2736 (PROTOCOL_SPECIFIC_PORT_PAGE
== (buff
[offset
] & 0x3f)))
2737 return (buff
[offset
+ 2] & 0xf);
2742 const unsigned char *
2743 sg_scsi_sense_desc_find(const unsigned char * sensep
, int sense_len
,
2747 const unsigned char * descp
;
2749 if ((sense_len
< 8) || (0 == (add_sen_len
= sensep
[7])))
2751 if ((sensep
[0] < 0x72) || (sensep
[0] > 0x73))
2753 add_sen_len
= (add_sen_len
< (sense_len
- 8)) ?
2754 add_sen_len
: (sense_len
- 8);
2756 for (int desc_len
= 0, k
= 0; k
< add_sen_len
; k
+= desc_len
) {
2758 int add_len
= (k
< (add_sen_len
- 1)) ? descp
[1]: -1;
2759 desc_len
= add_len
+ 2;
2760 if (descp
[0] == desc_type
)
2762 if (add_len
< 0) /* short descriptor ?? */
2768 // Convenience function for formatting strings from SCSI identify
2770 scsi_format_id_string(char * out
, const uint8_t * in
, int n
)
2773 n
= n
> 64 ? 64 : n
;
2774 strncpy(tmp
, (const char *)in
, n
);
2777 // Find the first non-space character (maybe none).
2780 for (i
= 0; tmp
[i
]; i
++)
2781 if (!isspace((int)tmp
[i
])) {
2787 // There are only space characters.
2792 // Find the last non-space character.
2793 for (i
= strlen(tmp
)-1; i
>= first
&& isspace((int)tmp
[i
]); i
--);
2796 strncpy(out
, tmp
+first
, last
-first
+1);
2797 out
[last
-first
+1] = '\0';