]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - scsicmds.cpp
import smartmontools 7.0
[mirror_smartmontools-debian.git] / scsicmds.cpp
1 /*
2 * scsicmds.cpp
3 *
4 * Home page of code is: http://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 "atacmds.h" // FIXME: for smart_command_set only
36 #include "dev_interface.h"
37 #include "utility.h"
38 #include "sg_unaligned.h"
39
40 const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 4842 2018-12-02 16:07:26Z chrfranke $"
41 SCSICMDS_H_CVSID;
42
43 static const char * logSenStr = "Log Sense";
44
45 // Print SCSI debug messages?
46 unsigned char scsi_debugmode = 0;
47
48 supported_vpd_pages * supported_vpd_pages_p = NULL;
49
50
51 supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0)
52 {
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,
56 b, sizeof(b)))) {
57 num_valid = sg_get_unaligned_be16(b + 2);
58 int n = sizeof(pages);
59 if (num_valid > n)
60 num_valid = n;
61 memcpy(pages, b + 4, num_valid);
62 }
63 }
64
65 bool
66 supported_vpd_pages::is_supported(int vpd_page_num) const
67 {
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])
72 return true;
73 }
74 return false;
75 }
76
77 /* output binary in ASCII hex and optionally ASCII. Uses pout() for output. */
78 void
79 dStrHex(const uint8_t * up, int len, int no_ascii)
80 {
81 const uint8_t * p = up;
82 char buff[82];
83 int a = 0;
84 const int bpstart = 5;
85 const int cpstart = 60;
86 int cpos = cpstart;
87 int bpos = bpstart;
88 int i, k;
89
90 if (len <= 0) return;
91 memset(buff,' ',80);
92 buff[80]='\0';
93 k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
94 buff[k + 1] = ' ';
95 if (bpos >= ((bpstart + (9 * 3))))
96 bpos++;
97
98 for(i = 0; i < len; i++)
99 {
100 uint8_t c = *p++;
101 bpos += 3;
102 if (bpos == (bpstart + (9 * 3)))
103 bpos++;
104 snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (unsigned int)c);
105 buff[bpos + 2] = ' ';
106 if (no_ascii)
107 buff[cpos++] = ' ';
108 else {
109 if ((c < ' ') || (c >= 0x7f))
110 c='.';
111 buff[cpos++] = c;
112 }
113 if (cpos > (cpstart+15))
114 {
115 while (cpos > 0 && buff[cpos-1] == ' ')
116 cpos--;
117 buff[cpos] = 0;
118 pout("%s\n", buff);
119 bpos = bpstart;
120 cpos = cpstart;
121 a += 16;
122 memset(buff,' ',80);
123 k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
124 buff[k + 1] = ' ';
125 }
126 }
127 if (cpos > cpstart)
128 {
129 while (cpos > 0 && buff[cpos-1] == ' ')
130 cpos--;
131 buff[cpos] = 0;
132 pout("%s\n", buff);
133 }
134 }
135
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. */
151 bool
152 is_scsi_cdb(const uint8_t * cdbp, int clen)
153 {
154 int ilen, sa;
155 uint8_t opcode;
156 uint8_t top3bits;
157
158 if (clen < 6)
159 return false;
160 opcode = cdbp[0];
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 */
165 switch (opcode) {
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 */
170 ilen = 8 + cdbp[7];
171 sa = sg_get_unaligned_be16(cdbp + 8);
172 /* service action (sa) 0x0 is reserved */
173 return ((ilen == clen) && sa);
174 default:
175 return false;
176 }
177 } else if (clen <= 16) {
178 switch (clen) {
179 case 6:
180 if (top3bits > 0x5) /* vendor */
181 return true;
182 return (0x0 == top3bits); /* 6 byte cdb */
183 case 10:
184 if (top3bits > 0x5) /* vendor */
185 return true;
186 return ((0x1 == top3bits) || (0x2 == top3bits)); /* 10 byte cdb */
187 case 16:
188 if (top3bits > 0x5) /* vendor */
189 return true;
190 return (0x4 == top3bits); /* 16 byte cdb */
191 case 12:
192 if (top3bits > 0x5) /* vendor */
193 return true;
194 return (0x5 == top3bits); /* 12 byte cdb */
195 default:
196 return false;
197 }
198 }
199 /* NVMe probably falls out here, clen > 16 and (opcode < 0x60 or
200 * opcode > 0x7f). */
201 return false;
202 }
203
204 struct scsi_opcode_name {
205 uint8_t opcode;
206 const char * name;
207 };
208
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 */
230 };
231
232 static const char * vendor_specific = "<vendor specific>";
233
234 /* Need to expand to take service action into account. For commands
235 * of interest the service action is in the 2nd command byte */
236 const char *
237 scsi_get_opcode_name(uint8_t opcode)
238 {
239 int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]);
240
241 if (opcode >= 0xc0)
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)
246 return onp->name;
247 else if (opcode < onp->opcode)
248 return NULL;
249 }
250 return NULL;
251 }
252
253 void
254 scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
255 struct scsi_sense_disect * out)
256 {
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];
270 }
271 }
272 }
273 }
274
275 int
276 scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo)
277 {
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;
288 else
289 return SIMPLE_ERR_NOT_READY;
290 } else
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;
302 else
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;
308 default:
309 return SIMPLE_ERR_UNKNOWN;
310 }
311 }
312
313 const char *
314 scsiErrString(int scsiErr)
315 {
316 if (scsiErr < 0)
317 return strerror(-scsiErr);
318 switch (scsiErr) {
319 case SIMPLE_NO_ERROR:
320 return "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";
343 default:
344 return "unknown error";
345 }
346 }
347
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. */
357 int
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)
360 {
361 const unsigned char * ucp;
362 int k;
363
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)
367 break;
368 int c_set = (ucp[k] & 0xf);
369 if ((m_code_set >= 0) && (m_code_set != c_set))
370 continue;
371 int assoc = ((ucp[k + 1] >> 4) & 0x3);
372 if ((m_assoc >= 0) && (m_assoc != assoc))
373 continue;
374 int desig_type = (ucp[k + 1] & 0xf);
375 if ((m_desig_type >= 0) && (m_desig_type != desig_type))
376 continue;
377 *off = k;
378 return 0;
379 }
380 return (k == page_len) ? -1 : -2;
381 }
382
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. */
386 int
387 scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
388 int * transport)
389 {
390 if (transport)
391 *transport = -1;
392 if (slen < 32) {
393 if (slen > 0)
394 s[0] = '\0';
395 return -1;
396 }
397
398 s[0] = '\0';
399 int si = 0;
400 int have_scsi_ns = 0;
401 int off = -1;
402 int u;
403 while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) {
404 const unsigned char * ucp = b + off;
405 int i_len = ucp[3];
406 if ((off + i_len + 4) > blen) {
407 snprintf(s+si, slen-si, "error: designator length");
408 return -1;
409 }
410 int assoc = ((ucp[1] >> 4) & 0x3);
411 if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
412 *transport = (ucp[0] >> 4) & 0xf;
413 if (0 != assoc)
414 continue;
415 const unsigned char * ip = ucp + 4;
416 int c_set = (ucp[0] & 0xf);
417 int desig_type = (ucp[1] & 0xf);
418
419 int naa;
420 switch (desig_type) {
421 case 0: /* vendor specific */
422 case 1: /* T10 vendor identification */
423 break;
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");
427 return -1;
428 }
429 if (have_scsi_ns)
430 si = 0;
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]);
434 break;
435 case 3: /* NAA */
436 if (1 != c_set) {
437 snprintf(s+si, slen-si, "error: NAA bad code_set");
438 return -1;
439 }
440 naa = (ip[0] >> 4) & 0xff;
441 if ((naa < 2) || (naa > 6) || (4 == naa)) {
442 snprintf(s+si, slen-si, "error: unexpected NAA");
443 return -1;
444 }
445 if (have_scsi_ns)
446 si = 0;
447 if (2 == naa) { /* NAA IEEE Extended */
448 if (8 != i_len) {
449 snprintf(s+si, slen-si, "error: NAA 2 length");
450 return -1;
451 }
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 */
457 if (8 != i_len) {
458 snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
459 return -1;
460 }
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 */
465 if (16 != i_len) {
466 snprintf(s+si, slen-si, "error: NAA 6 length");
467 return -1;
468 }
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]);
472 }
473 break;
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 */
478 break;
479 case 8: /* SCSI name string */
480 if (3 != c_set) {
481 snprintf(s+si, slen-si, "error: SCSI name string");
482 return -1;
483 }
484 /* does %s print out UTF-8 ok?? */
485 if (si == 0) {
486 si += snprintf(s+si, slen-si, "%s", (const char *)ip);
487 ++have_scsi_ns;
488 }
489 break;
490 default: /* reserved */
491 break;
492 }
493 }
494 if (-2 == u) {
495 snprintf(s+si, slen-si, "error: bad structure");
496 return -1;
497 }
498 return 0;
499 }
500
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. */
512 int
513 scsiLogSense(scsi_device * device, int pagenum, int subpagenum, uint8_t *pBuf,
514 int bufLen, int known_resp_len)
515 {
516 int pageLen;
517 struct scsi_cmnd_io io_hdr;
518 struct scsi_sense_disect sinfo;
519 uint8_t cdb[10];
520 uint8_t sense[32];
521
522 if (known_resp_len > bufLen)
523 return -EIO;
524 if (known_resp_len > 0)
525 pageLen = known_resp_len;
526 else if (known_resp_len < 0)
527 pageLen = bufLen;
528 else { /* 0 == known_resp_len */
529 /* Starting twin fetch strategy: first fetch to find respone length */
530 pageLen = 4;
531 if (pageLen > bufLen)
532 return -EIO;
533 else
534 memset(pBuf, 0, pageLen);
535
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;
541 cdb[0] = LOG_SENSE;
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);
545 io_hdr.cmnd = cdb;
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;
550
551 if (!device->scsi_pass_through(&io_hdr))
552 return -device->get_errno();
553 scsi_do_sense_disect(&io_hdr, &sinfo);
554 int res;
555 if ((res = scsiSimpleSenseFilter(&sinfo)))
556 return res;
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);
561 if (0 == u)
562 return SIMPLE_ERR_BAD_RESP;
563 pageLen = u + 4;
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 */
567 if (pageLen % 2)
568 pageLen += 1;
569 if (pageLen > bufLen)
570 pageLen = bufLen;
571 }
572 memset(pBuf, 0, 4);
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;
578 cdb[0] = LOG_SENSE;
579 cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */
580 cdb[3] = subpagenum;
581 sg_put_unaligned_be16(pageLen, cdb + 7);
582 io_hdr.cmnd = cdb;
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;
587
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);
592 if (0 != status)
593 return status;
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;
599 return 0;
600 }
601
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) */
607 int
608 scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
609 int subpagenum, uint8_t *pBuf, int bufLen)
610 {
611 struct scsi_cmnd_io io_hdr;
612 struct scsi_sense_disect sinfo;
613 uint8_t cdb[10];
614 uint8_t sense[32];
615
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;
621 cdb[0] = LOG_SELECT;
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);
626 io_hdr.cmnd = cdb;
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;
631
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);
636 }
637
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] */
642 int
643 scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
644 uint8_t *pBuf, int bufLen)
645 {
646 struct scsi_cmnd_io io_hdr;
647 struct scsi_sense_disect sinfo;
648 uint8_t cdb[6];
649 uint8_t sense[32];
650
651 if ((bufLen < 0) || (bufLen > 255))
652 return -EINVAL;
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;
658 cdb[0] = MODE_SENSE;
659 cdb[2] = (pc << 6) | (pagenum & 0x3f);
660 cdb[3] = subpagenum;
661 cdb[4] = bufLen;
662 io_hdr.cmnd = cdb;
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;
667
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);
677 }
678 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
679 int offset;
680
681 offset = scsiModePageOffset(pBuf, bufLen, 0);
682 if (offset < 0)
683 return SIMPLE_ERR_BAD_RESP;
684 else if (pagenum != (pBuf[offset] & 0x3f))
685 return SIMPLE_ERR_BAD_RESP;
686 }
687 return status;
688 }
689
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) */
697 int
698 scsiModeSelect(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
699 {
700 struct scsi_cmnd_io io_hdr;
701 struct scsi_sense_disect sinfo;
702 uint8_t cdb[6];
703 uint8_t sense[32];
704 int pg_offset, pg_len, hdr_plus_1_pg;
705
706 pg_offset = 4 + pBuf[3];
707 if (pg_offset + 2 >= bufLen)
708 return -EINVAL;
709 pg_len = pBuf[pg_offset + 1] + 2;
710 hdr_plus_1_pg = pg_offset + pg_len;
711 if (hdr_plus_1_pg > bufLen)
712 return -EINVAL;
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 */
723 io_hdr.cmnd = cdb;
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;
728
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);
733 }
734
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] */
739 int
740 scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
741 uint8_t *pBuf, int bufLen)
742 {
743 struct scsi_cmnd_io io_hdr;
744 struct scsi_sense_disect sinfo;
745 uint8_t cdb[10];
746 uint8_t sense[32];
747
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);
755 cdb[3] = subpagenum;
756 sg_put_unaligned_be16(bufLen, cdb + 7);
757 io_hdr.cmnd = cdb;
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;
762
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);
772 }
773 if ((0 == status) && (ALL_MODE_PAGES != pagenum)) {
774 int offset;
775
776 offset = scsiModePageOffset(pBuf, bufLen, 1);
777 if (offset < 0)
778 return SIMPLE_ERR_BAD_RESP;
779 else if (pagenum != (pBuf[offset] & 0x3f))
780 return SIMPLE_ERR_BAD_RESP;
781 }
782 return status;
783 }
784
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) */
792 int
793 scsiModeSelect10(scsi_device * device, int sp, uint8_t *pBuf, int bufLen)
794 {
795 struct scsi_cmnd_io io_hdr;
796 struct scsi_sense_disect sinfo;
797 uint8_t cdb[10];
798 uint8_t sense[32];
799 int pg_offset, pg_len, hdr_plus_1_pg;
800
801 pg_offset = 8 + sg_get_unaligned_be16(pBuf + 6);
802 if (pg_offset + 2 >= bufLen)
803 return -EINVAL;
804 pg_len = pBuf[pg_offset + 1] + 2;
805 hdr_plus_1_pg = pg_offset + pg_len;
806 if (hdr_plus_1_pg > bufLen)
807 return -EINVAL;
808 pBuf[0] = 0;
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);
820 io_hdr.cmnd = cdb;
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;
825
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);
830 }
831
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) */
835 int
836 scsiStdInquiry(scsi_device * device, uint8_t *pBuf, int bufLen)
837 {
838 struct scsi_sense_disect sinfo;
839 struct scsi_cmnd_io io_hdr;
840 uint8_t cdb[6];
841 uint8_t sense[32];
842
843 if ((bufLen < 0) || (bufLen > 1023))
844 return -EINVAL;
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;
850 cdb[0] = INQUIRY;
851 sg_put_unaligned_be16(bufLen, cdb + 3);
852 io_hdr.cmnd = cdb;
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;
857
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);
862 }
863
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) */
868 int
869 scsiInquiryVpd(scsi_device * device, int vpd_page, uint8_t *pBuf, int bufLen)
870 {
871 struct scsi_cmnd_io io_hdr;
872 struct scsi_sense_disect sinfo;
873 uint8_t cdb[6];
874 uint8_t sense[32];
875 int res;
876
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)))
881 return 3;
882
883 if ((bufLen < 0) || (bufLen > 1023))
884 return -EINVAL;
885 try_again:
886 memset(&io_hdr, 0, sizeof(io_hdr));
887 memset(cdb, 0, sizeof(cdb));
888 if (bufLen > 1)
889 pBuf[1] = 0x0;
890 io_hdr.dxfer_dir = DXFER_FROM_DEVICE;
891 io_hdr.dxfer_len = bufLen;
892 io_hdr.dxferp = pBuf;
893 cdb[0] = INQUIRY;
894 cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */
895 cdb[2] = vpd_page;
896 sg_put_unaligned_be16(bufLen, cdb + 3);
897 io_hdr.cmnd = cdb;
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;
902
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) &&
909 (cdb[3] > 0)) {
910 bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */
911 goto try_again;
912 }
913
914 if ((res = scsiSimpleSenseFilter(&sinfo)))
915 return res;
916 /* Guard against devices that ignore EVPD bit and do standard INQUIRY */
917 if (bufLen > 1) {
918 if (vpd_page == pBuf[1]) {
919 if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2]))
920 return SIMPLE_ERR_BAD_RESP;
921 } else
922 return SIMPLE_ERR_BAD_RESP;
923 }
924 return 0;
925 }
926
927 /* REQUEST SENSE command. Returns 0 if ok, anything else major problem.
928 * SPC-3 section 6.27 (rev 22a) */
929 int
930 scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
931 {
932 struct scsi_cmnd_io io_hdr;
933 uint8_t cdb[6];
934 uint8_t sense[32];
935 uint8_t buff[18];
936 int sz_buff = sizeof(buff);
937
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;
944 cdb[4] = sz_buff;
945 io_hdr.cmnd = cdb;
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;
950
951 if (!device->scsi_pass_through(&io_hdr))
952 return -device->get_errno();
953 if (sense_info) {
954 uint8_t resp_code = buff[0] & 0x7f;
955 sense_info->resp_code = resp_code;
956 sense_info->sense_key = buff[2] & 0xf;
957 sense_info->asc = 0;
958 sense_info->ascq = 0;
959 if ((0x70 == resp_code) || (0x71 == resp_code)) {
960 int len = buff[7] + 8;
961 if (len > 13) {
962 sense_info->asc = buff[12];
963 sense_info->ascq = buff[13];
964 }
965 }
966 // fill progress indicator, if available
967 sense_info->progress = -1;
968 switch (resp_code) {
969 const unsigned char * ucp;
970 int sk, sk_pr;
971 case 0x70:
972 case 0x71:
973 sk = (buff[2] & 0xf);
974 if (! ((SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk))) {
975 break;
976 }
977 if (buff[15] & 0x80) { /* SKSV bit set */
978 sense_info->progress = sg_get_unaligned_be16(buff + 16);
979 break;
980 } else {
981 break;
982 }
983 case 0x72:
984 case 0x73:
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);
991 break;
992 } else if (((ucp = sg_scsi_sense_desc_find(buff, sz_buff, 0xa))) &&
993 ((0x6 == ucp[1]))) {
994 sense_info->progress = sg_get_unaligned_be16(ucp + 6);
995 break;
996 } else
997 break;
998 default:
999 return 0;
1000 }
1001 }
1002 return 0;
1003 }
1004
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) */
1008 int
1009 scsiSendDiagnostic(scsi_device * device, int functioncode, uint8_t *pBuf,
1010 int bufLen)
1011 {
1012 struct scsi_cmnd_io io_hdr;
1013 struct scsi_sense_disect sinfo;
1014 uint8_t cdb[6];
1015 uint8_t sense[32];
1016
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);
1030 io_hdr.cmnd = cdb;
1031 io_hdr.cmnd_len = sizeof(cdb);
1032 io_hdr.sensep = sense;
1033 io_hdr.max_sense_len = sizeof(sense);
1034 /* worst case is an extended foreground self test on a big disk */
1035 io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST;
1036
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);
1041 }
1042
1043 /* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */
1044 static int
1045 _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
1046 {
1047 struct scsi_cmnd_io io_hdr;
1048 uint8_t cdb[6];
1049 uint8_t sense[32];
1050
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;
1057 io_hdr.cmnd = cdb;
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;
1062
1063 if (!device->scsi_pass_through(&io_hdr))
1064 return -device->get_errno();
1065 scsi_do_sense_disect(&io_hdr, sinfo);
1066 return 0;
1067 }
1068
1069 /* Returns 0 for device responds and media ready, 1 for device responds and
1070 media not ready, or returns a negated errno value */
1071 int
1072 scsiTestUnitReady(scsi_device * device)
1073 {
1074 struct scsi_sense_disect sinfo;
1075 int status;
1076
1077 status = _testunitready(device, &sinfo);
1078 if (0 != status)
1079 return status;
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);
1084 if (0 != status)
1085 return status;
1086 status = scsiSimpleSenseFilter(&sinfo);
1087 }
1088 return status;
1089 }
1090
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) */
1095 int
1096 scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
1097 int dl_format, uint8_t *pBuf, int bufLen)
1098 {
1099 struct scsi_cmnd_io io_hdr;
1100 struct scsi_sense_disect sinfo;
1101 uint8_t cdb[10];
1102 uint8_t sense[32];
1103
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);
1113 io_hdr.cmnd = cdb;
1114 io_hdr.cmnd_len = sizeof(cdb);
1115 io_hdr.sensep = sense;
1116 io_hdr.max_sense_len = sizeof(sense);
1117 io_hdr.timeout = SCSI_TIMEOUT_DEFAULT;
1118
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))
1124 return 101;
1125 return scsiSimpleSenseFilter(&sinfo);
1126 }
1127
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) */
1132 int
1133 scsiReadDefect12(scsi_device * device, int req_plist, int req_glist,
1134 int dl_format, int addrDescIndex, uint8_t *pBuf, int bufLen)
1135 {
1136 struct scsi_cmnd_io io_hdr;
1137 struct scsi_sense_disect sinfo;
1138 uint8_t cdb[12];
1139 uint8_t sense[32];
1140
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);
1151 io_hdr.cmnd = cdb;
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;
1156
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))
1162 return 101;
1163 return scsiSimpleSenseFilter(&sinfo);
1164 }
1165
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) */
1169 int
1170 scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
1171 unsigned int * lb_sizep)
1172 {
1173 int res;
1174 struct scsi_cmnd_io io_hdr;
1175 struct scsi_sense_disect sinfo;
1176 uint8_t cdb[10];
1177 uint8_t sense[32];
1178 uint8_t resp[8];
1179
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;
1187 io_hdr.cmnd = cdb;
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;
1192
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);
1197 if (res)
1198 return res;
1199 if (last_lbap)
1200 *last_lbap = sg_get_unaligned_be32(resp + 0);
1201 if (lb_sizep)
1202 *lb_sizep = sg_get_unaligned_be32(resp + 4);
1203 return 0;
1204 }
1205
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) */
1209 int
1210 scsiReadCapacity16(scsi_device * device, uint8_t *pBuf, int bufLen)
1211 {
1212 struct scsi_cmnd_io io_hdr;
1213 struct scsi_sense_disect sinfo;
1214 uint8_t cdb[16];
1215 uint8_t sense[32];
1216
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);
1225 io_hdr.cmnd = cdb;
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;
1230
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);
1235 }
1236
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'*/
1242 uint64_t
1243 scsiGetSize(scsi_device * device, bool avoid_rcap16,
1244 struct scsi_readcap_resp * srrp)
1245 {
1246 bool try_16 = false;
1247 bool try_12 = false;
1248 unsigned int last_lba = 0, lb_size = 0;
1249 int res;
1250 uint64_t ret_val = 0;
1251 uint8_t rc16resp[32];
1252
1253 if (avoid_rcap16) {
1254 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1255 if (res) {
1256 if (scsi_debugmode)
1257 pout("%s: READ CAPACITY(10) failed, res=%d\n", __func__, res);
1258 try_16 = true;
1259 } else { /* rcap10 succeeded */
1260 if (0xffffffff == last_lba) {
1261 /* so number of blocks needs > 32 bits to represent */
1262 try_16 = true;
1263 device->set_rcap16_first();
1264 } else {
1265 ret_val = last_lba + 1;
1266 if (srrp) {
1267 memset(srrp, 0, sizeof(*srrp));
1268 srrp->num_lblocks = ret_val;
1269 srrp->lb_size = lb_size;
1270 }
1271 }
1272 }
1273 }
1274 if (try_16 || (! avoid_rcap16)) {
1275 res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
1276 if (res) {
1277 if (scsi_debugmode)
1278 pout("%s: READ CAPACITY(16) failed, res=%d\n", __func__, res);
1279 if (try_16) /* so already tried rcap10 */
1280 return 0;
1281 try_12 = true;
1282 } else { /* rcap16 succeeded */
1283 bool prot_en;
1284 uint8_t p_type;
1285
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;
1299 }
1300 }
1301 }
1302 if (try_12) { /* case where only rcap16 has been tried and failed */
1303 res = scsiReadCapacity10(device, &last_lba, &lb_size);
1304 if (res) {
1305 if (scsi_debugmode)
1306 pout("%s: 2nd READ CAPACITY(10) failed, res=%d\n", __func__,
1307 res);
1308 return 0;
1309 } else { /* rcap10 succeeded */
1310 ret_val = (uint64_t)last_lba + 1;
1311 if (srrp) {
1312 memset(srrp, 0, sizeof(*srrp));
1313 srrp->num_lblocks = ret_val;
1314 srrp->lb_size = lb_size;
1315 }
1316 }
1317 }
1318 return (ret_val * lb_size);
1319 }
1320
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 */
1323 int
1324 scsiModePageOffset(const uint8_t * resp, int len, int modese_len)
1325 {
1326 int offset = -1;
1327
1328 if (resp) {
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;
1334 } else {
1335 resp_len = resp[0] + 1;
1336 bd_len = resp[3];
1337 offset = bd_len + 4;
1338 }
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);
1342 offset = -1;
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,
1347 offset, bd_len);
1348 offset = -1;
1349 }
1350 }
1351 return offset;
1352 }
1353
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
1360
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
1365 * value. */
1366 int
1367 scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
1368 int modese_len)
1369 {
1370 int err = 0;
1371
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;
1381 else {
1382 iecp->modese_len = 0;
1383 return err;
1384 }
1385 } else if (0 == iecp->modese_len)
1386 iecp->modese_len = 6;
1387 }
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));
1392 if (err) {
1393 iecp->modese_len = 0;
1394 return err;
1395 }
1396 }
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));
1407 if (err)
1408 return err;
1409 iecp->gotChangeable = 1;
1410 return 0;
1411 }
1412
1413 int
1414 scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
1415 {
1416 if (iecp && iecp->gotCurrent) {
1417 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1418 iecp->modese_len);
1419 if (offset >= 0)
1420 return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1421 else
1422 return 0;
1423 } else
1424 return 0;
1425 }
1426
1427 int
1428 scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
1429 {
1430 if (iecp && iecp->gotCurrent) {
1431 int offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1432 iecp->modese_len);
1433 if (offset >= 0)
1434 return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1435 else
1436 return 0;
1437 } else
1438 return 0;
1439 }
1440
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
1448
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). */
1456 int
1457 scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
1458 const struct scsi_iec_mode_page *iecp)
1459 {
1460 int offset, resp_len;
1461 int err = 0;
1462 uint8_t rout[SCSI_IECMP_RAW_LEN];
1463
1464 if ((! iecp) || (! iecp->gotCurrent))
1465 return -EINVAL;
1466 offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr),
1467 iecp->modese_len);
1468 if (offset < 0)
1469 return -EINVAL;
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;
1474 rout[3] &= 0xef;
1475 } else {
1476 resp_len = rout[0] + 1;
1477 rout[2] &= 0xef;
1478 }
1479 int sp = !! (rout[offset] & 0x80); /* PS bit becomes 'SELECT's SP bit */
1480 if (enabled) {
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];
1489
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];
1495 }
1496 }
1497 if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
1498 if (scsi_debugmode > 0)
1499 pout("scsiSetExceptionControlAndWarning: already enabled\n");
1500 return 0;
1501 }
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 */
1509 }
1510 if (wEnabled)
1511 rout[offset + 2] &= EWASC_DISABLE;
1512 if (eCEnabled) {
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 */
1517 }
1518 }
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);
1523 return err;
1524 }
1525
1526 int
1527 scsiGetTemp(scsi_device * device, uint8_t *currenttemp, uint8_t *triptemp)
1528 {
1529 uint8_t tBuf[252];
1530 int err;
1531
1532 memset(tBuf, 0, sizeof(tBuf));
1533 if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
1534 sizeof(tBuf), 0))) {
1535 *currenttemp = 0;
1536 *triptemp = 0;
1537 pout("%s for temperature failed [%s]\n", logSenStr,
1538 scsiErrString(err));
1539 return err;
1540 }
1541 *currenttemp = tBuf[9];
1542 *triptemp = tBuf[15];
1543 return 0;
1544 }
1545
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. */
1550 int
1551 scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
1552 uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp,
1553 uint8_t *triptemp)
1554 {
1555 uint8_t tBuf[252];
1556 struct scsi_sense_disect sense_info;
1557 int err;
1558 uint8_t currTemp, trTemp;
1559
1560 *asc = 0;
1561 *ascq = 0;
1562 *currenttemp = 0;
1563 *triptemp = 0;
1564 memset(tBuf,0,sizeof(tBuf)); // need to clear stack space of junk
1565 memset(&sense_info, 0, sizeof(sense_info));
1566 if (hasIELogPage) {
1567 if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
1568 sizeof(tBuf), 0))) {
1569 pout("%s failed, IE page [%s]\n", logSenStr, scsiErrString(err));
1570 return err;
1571 }
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",
1576 logSenStr);
1577 return SIMPLE_ERR_BAD_PARAM;
1578 }
1579 if (tBuf[7] > 1) {
1580 sense_info.asc = tBuf[8];
1581 sense_info.ascq = tBuf[9];
1582 if (! hasTempLogPage) {
1583 if (tBuf[7] > 2)
1584 *currenttemp = tBuf[10];
1585 if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
1586 *triptemp = tBuf[11];
1587 }
1588 }
1589 }
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));
1594 return err;
1595 }
1596 }
1597 *asc = sense_info.asc;
1598 *ascq = sense_info.ascq;
1599 if (hasTempLogPage) {
1600 if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
1601 *currenttemp = currTemp;
1602 *triptemp = trTemp;
1603 }
1604 }
1605 return 0;
1606 }
1607
1608 // The first character (W, C, I) tells the severity
1609 static const char * TapeAlertsMessageTable[]= {
1610 " ",
1611 /* 0x01 */
1612 "W: The tape drive is having problems reading data. No data has been "
1613 "lost,\n"
1614 " but there has been a reduction in the performance of the tape.",
1615 /* 0x02 */
1616 "W: The tape drive is having problems writing data. No data has been "
1617 "lost,\n"
1618 " but there has been a reduction in the capacity of the tape.",
1619 /* 0x03 */
1620 "W: The operation has stopped because an error has occurred while "
1621 "reading\n"
1622 " or writing data that the drive cannot correct.",
1623 /* 0x04 */
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.",
1628 /* 0x05 */
1629 "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
1630 " supplier helpline.",
1631 /* 0x06 */
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.",
1635 /* 0x07 */
1636 "W: The tape cartridge has reached the end of its calculated useful "
1637 "life:\n"
1638 " 1. Copy data you need to another tape.\n"
1639 " 2. Discard the old tape.",
1640 /* 0x08 */
1641 "W: The tape cartridge is not data-grade. Any data you back up to the "
1642 "tape\n"
1643 " is at risk. Replace the cartridge with a data-grade tape.",
1644 /* 0x09 */
1645 "C: You are trying to write to a write-protected cartridge. Remove the\n"
1646 " write-protection or use another tape.",
1647 /* 0x0a */
1648 "I: You cannot eject the cartridge because the tape drive is in use. "
1649 "Wait\n"
1650 " until the operation is complete before ejecting the cartridge.",
1651 /* 0x0b */
1652 "I: The tape in the drive is a cleaning cartridge.",
1653 /* 0x0c */
1654 "I: You have tried to load a cartridge of a type which is not supported\n"
1655 " by this drive.",
1656 /* 0x0d */
1657 "C: The operation has failed because the tape in the drive has "
1658 "experienced\n"
1659 " a mechanical failure:\n"
1660 " 1. Discard the old tape.\n"
1661 " 2. Restart the operation with a different tape.",
1662 /* 0x0e */
1663 "C: The operation has failed because the tape in the drive has "
1664 "experienced\n"
1665 " a mechanical failure:\n"
1666 " 1. Do not attempt to extract the tape cartridge\n"
1667 " 2. Call the tape drive supplier helpline.",
1668 /* 0x0f */
1669 "W: The memory in the tape cartridge has failed, which reduces\n"
1670 " performance. Do not use the cartridge for further write "
1671 "operations.",
1672 /* 0x10 */
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.",
1675 /* 0x11 */
1676 "W: You have loaded a cartridge of a type that is read-only in this "
1677 "drive.\n"
1678 " The cartridge will appear as write-protected.",
1679 /* 0x12 */
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 "
1682 "rebuilt\n"
1683 " by reading all the data on the cartridge.",
1684 /* 0x13 */
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 "
1689 " data from it.",
1690 /* 0x14 */
1691 "C: The tape drive needs cleaning:\n"
1692 " 1. If the operation has stopped, eject the tape and clean the "
1693 "drive.\n"
1694 " 2. If the operation has not stopped, wait for it to finish and "
1695 "then\n"
1696 " clean the drive.\n"
1697 " Check the tape drive users manual for device specific cleaning "
1698 "instructions.",
1699 /* 0x15 */
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 "
1704 "instructions.",
1705 /* 0x16 */
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.",
1710 /* 0x17 */
1711 "C: The last cleaning cartridge used in the tape drive was an invalid\n"
1712 " type:\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.",
1716 /* 0x18 */
1717 "W: The tape drive has requested a retention operation",
1718 /* 0x19 */
1719 "W: A redundant interface port on the tape drive has failed",
1720 /* 0x1a */
1721 "W: A tape drive cooling fan has failed",
1722 /* 0x1b */
1723 "W: A redundant power supply has failed inside the tape drive enclosure.\n"
1724 " Check the enclosure users manual for instructions on replacing "
1725 "the\n"
1726 " failed power supply.",
1727 /* 0x1c */
1728 "W: The tape drive power consumption is outside the specified range.",
1729 /* 0x1d */
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.",
1733 /* 0x1e */
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.",
1738 /* 0x1f */
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.",
1743 /* 0x20 */
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.",
1747 /* 0x21 */
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.",
1752 /* 0x22 */
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.",
1756 /* 0x23 */
1757 "W: Environmental conditions inside the tape drive are outside the\n"
1758 " specified humidity range.",
1759 /* 0x24 */
1760 "W: Environmental conditions inside the tape drive are outside the\n"
1761 " specified temperature range.",
1762 /* 0x25 */
1763 "W: The voltage supply to the tape drive is outside the specified range.",
1764 /* 0x26 */
1765 "C: A hardware failure of the tape drive is predicted. Call the tape\n"
1766 " drive supplier helpline.",
1767 /* 0x27 */
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 "
1770 "for\n"
1771 " device specific instructions on running extended diagnostic tests.",
1772 /* 0x28 */
1773 "C: The changer mechanism is having difficulty communicating with the "
1774 "tape\n"
1775 " drive:\n"
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.",
1779 /* 0x29 */
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"
1783 " on again.\n"
1784 " 3. If the problem persists, call the tape drive supplier helpline.",
1785 /* 0x2a */
1786 "W: There is a problem with the autoloader mechanism.",
1787 /* 0x2b */
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"
1792 " on again.\n"
1793 " 4. If the problem persists, call the tape drive supplier helpline.",
1794 /* 0x2c */
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.",
1801 /* 0x2d */
1802 "C: The autoloader cannot operate without the magazine,\n"
1803 " 1. Insert the magazine into the autoloader.\n"
1804 " 2. Restart the operation.",
1805 /* 0x2e */
1806 "W: A hardware failure of the changer mechanism is predicted. Call the\n"
1807 " tape drive supplier helpline.",
1808 /* 0x2f */
1809 "I: Reserved.",
1810 /* 0x30 */
1811 "I: Reserved.",
1812 /* 0x31 */
1813 "I: Reserved.",
1814 /* 0x32 */
1815 "W: Media statistics have been lost at some time in the past",
1816 /* 0x33 */
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.",
1820 /* 0x34 */
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.",
1824 /* 0x35 */
1825 "C: The tape system are could not be read successfully at load time:\n"
1826 " 1. Copy data to another tape cartridge.\n",
1827 /* 0x36 */
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",
1831 /* 0x37 */
1832 "C: The operation has failed because the media cannot be loaded\n"
1833 " and threaded.\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 "
1837 "line.",
1838 /* 0x38 */
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.",
1842 /* 0x39 */
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.",
1847 /* 0x3a */
1848 "W: The tape drive has reset itself due to a detected firmware\n"
1849 " fault. If problem persists, call the supplier help line.",
1850 };
1851
1852 const char *
1853 scsiTapeAlertsTapeDevice(unsigned short code)
1854 {
1855 const int num = sizeof(TapeAlertsMessageTable) /
1856 sizeof(TapeAlertsMessageTable[0]);
1857
1858 return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
1859 }
1860
1861 // The first character (W, C, I) tells the severity
1862 static const char * ChangerTapeAlertsMessageTable[]= {
1863 " ",
1864 /* 0x01 */
1865 "C: The library mechanism is having difficulty communicating with the\n"
1866 " drive:\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.",
1870 /* 0x02 */
1871 "W: There is a problem with the library mechanism. If problem persists,\n"
1872 " call the library supplier help line.",
1873 /* 0x03 */
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 "
1878 "resetting\n"
1879 " the device.",
1880 /* 0x04 */
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 "
1886 "turning the\n"
1887 " device power on and off.",
1888 /* 0x05 */
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 "
1893 "diagnostic\n"
1894 " tests.",
1895 /* 0x06 */
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.",
1899 /* 0x07 */
1900 "W: A hardware failure of the library is predicted. Call the library\n"
1901 " supplier help line.",
1902 /* 0x08 */
1903 "W: Preventive maintenance of the library is required.\n"
1904 " Check the library users manual for device specific preventative "
1905 "maintenance\n"
1906 " tasks, or call your library supplier help line.",
1907 /* 0x09 */
1908 "C: General environmental conditions inside the library are outside the\n"
1909 " specified humidity range.",
1910 /* 0x0a */
1911 "C: General environmental conditions inside the library are outside the\n"
1912 " specified temperature range.",
1913 /* 0x0b */
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.",
1917 /* 0x0c */
1918 "C: A cartridge has been left inside the library by a previous hardware\n"
1919 " fault:\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 "
1922 "again.\n"
1923 " 3. If the problem persists, call the library supplier help line.",
1924 /* 0x0d */
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.",
1929 /* 0x0e */
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.",
1934 /* 0x0f */
1935 "W: There is a potential problem with the drive or the library mechanism\n"
1936 " loading cartridges, or an incompatible cartridge.",
1937 /* 0x10 */
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.",
1942 /* 0x11 */
1943 "C: There is a mechanical problem with the library media import/export\n"
1944 " mailslot.",
1945 /* 0x12 */
1946 "C: The library cannot operate without the magazine.\n"
1947 " 1. Insert the magazine into the library.\n"
1948 " 2. Restart the operation.",
1949 /* 0x13 */
1950 "W: Library security has been compromised.",
1951 /* 0x14 */
1952 "I: The library security mode has been changed.\n"
1953 " The library has either been put into secure mode, or the library "
1954 "has exited\n"
1955 " the secure mode.\n"
1956 " This is for information purposes only. No action is required.",
1957 /* 0x15 */
1958 "I: The library has been manually turned offline and is unavailable for "
1959 "use.",
1960 /* 0x16 */
1961 "I: A drive inside the library has been taken offline.\n"
1962 " This is for information purposes only. No action is required.",
1963 /* 0x17 */
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.",
1968 /* 0x18 */
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 "
1973 "for\n"
1974 " specific instructions on redoing the library inventory.",
1975 /* 0x19 */
1976 "W: A library operation has been attempted that is invalid at this time.",
1977 /* 0x1a */
1978 "W: A redundant interface port on the library has failed.",
1979 /* 0x1b */
1980 "W: A library cooling fan has failed.",
1981 /* 0x1c */
1982 "W: A redundant power supply has failed inside the library. Check the\n"
1983 " library users manual for instructions on replacing the failed "
1984 "power supply.",
1985 /* 0x1d */
1986 "W: The library power consumption is outside the specified range.",
1987 /* 0x1e */
1988 "C: A failure has occurred in the cartridge pass-through mechanism "
1989 "between\n"
1990 " two library modules.",
1991 /* 0x1f */
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 "
1994 "instructions on\n"
1995 " clearing this fault.",
1996 /* 0x20 */
1997 "I: The library was unable to read the bar code on a cartridge.",
1998 };
1999
2000 const char *
2001 scsiTapeAlertsChangerDevice(unsigned short code)
2002 {
2003 const int num = sizeof(ChangerTapeAlertsMessageTable) /
2004 sizeof(ChangerTapeAlertsMessageTable[0]);
2005
2006 return (code < num) ? ChangerTapeAlertsMessageTable[code] :
2007 "Unknown Alert";
2008 }
2009
2010
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)
2013 */
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",
2019 "",
2020 "",
2021 "",
2022 "",
2023 "",
2024 "",
2025 "",
2026 "",
2027 "",
2028 "",
2029 "",
2030 "",
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",
2044 "",
2045 "",
2046 "",
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",
2060 "",
2061 "",
2062 "",
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",
2076 "",
2077 "",
2078 "",
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",
2092 "",
2093 "",
2094 "",
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",
2108 "",
2109 "",
2110 "",
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"};
2124
2125
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)
2128 * */
2129 static const char * strs_for_asc_b[] = {
2130 /* 0x00 */ "WARNING",
2131 "WARNING - SPECIFIED TEMPERATURE EXCEEDED",
2132 "WARNING - ENCLOSURE DEGRADED"};
2133
2134 static char spare_buff[128];
2135
2136 const char *
2137 scsiGetIEString(uint8_t asc, uint8_t ascq)
2138 {
2139 const char * rp;
2140
2141 if (SCSI_ASC_IMPENDING_FAILURE == asc) {
2142 if (ascq == 0xff)
2143 return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
2144 else if (ascq <
2145 (sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) {
2146 rp = strs_for_asc_5d[ascq];
2147 if (strlen(rp) > 0)
2148 return rp;
2149 }
2150 snprintf(spare_buff, sizeof(spare_buff),
2151 "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq);
2152 return spare_buff;
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];
2156 if (strlen(rp) > 0)
2157 return rp;
2158 }
2159 snprintf(spare_buff, sizeof(spare_buff), "WARNING: ascq=0x%x", ascq);
2160 return spare_buff;
2161 }
2162 return NULL; /* not a IE additional sense code */
2163 }
2164
2165
2166 int
2167 scsiSmartDefaultSelfTest(scsi_device * device)
2168 {
2169 int res;
2170
2171 res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0);
2172 if (res)
2173 pout("Default self test failed [%s]\n", scsiErrString(res));
2174 return res;
2175 }
2176
2177 int
2178 scsiSmartShortSelfTest(scsi_device * device)
2179 {
2180 int res;
2181
2182 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0);
2183 if (res)
2184 pout("Short offline self test failed [%s]\n", scsiErrString(res));
2185 return res;
2186 }
2187
2188 int
2189 scsiSmartExtendSelfTest(scsi_device * device)
2190 {
2191 int res;
2192
2193 res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0);
2194 if (res)
2195 pout("Long (extended) offline self test failed [%s]\n",
2196 scsiErrString(res));
2197 return res;
2198 }
2199
2200 int
2201 scsiSmartShortCapSelfTest(scsi_device * device)
2202 {
2203 int res;
2204
2205 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0);
2206 if (res)
2207 pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2208 return res;
2209 }
2210
2211 int
2212 scsiSmartExtendCapSelfTest(scsi_device * device)
2213 {
2214 int res;
2215
2216 res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0);
2217 if (res)
2218 pout("Long (extended) foreground self test failed [%s]\n",
2219 scsiErrString(res));
2220 return res;
2221 }
2222
2223 int
2224 scsiSmartSelfTestAbort(scsi_device * device)
2225 {
2226 int res;
2227
2228 res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0);
2229 if (res)
2230 pout("Abort self test failed [%s]\n", scsiErrString(res));
2231 return res;
2232 }
2233
2234 /* Returns 0 and the expected duration of an extended self test (in seconds)
2235 if successful; any other return value indicates a failure. */
2236 int
2237 scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2238 int modese_len)
2239 {
2240 int err, offset;
2241 uint8_t buff[64];
2242
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)
2249 modese_len = 10;
2250 else
2251 return err;
2252 } else if (0 == modese_len)
2253 modese_len = 6;
2254 }
2255 if (10 == modese_len) {
2256 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2257 MPAGE_CONTROL_CURRENT,
2258 buff, sizeof(buff));
2259 if (err)
2260 return err;
2261 }
2262 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2263 if (offset < 0)
2264 return -EINVAL;
2265 if (buff[offset + 1] >= 0xa) {
2266 int res = sg_get_unaligned_be16(buff + offset + 10);
2267 *durationSec = res;
2268 return 0;
2269 }
2270 else
2271 return -EINVAL;
2272 }
2273
2274 void
2275 scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
2276 {
2277 memset(ecp, 0, sizeof(*ecp));
2278 int num = sg_get_unaligned_be16(resp + 2);
2279 unsigned char * ucp = &resp[0] + 4;
2280 while (num > 3) {
2281 int pc = sg_get_unaligned_be16(ucp + 0);
2282 int pl = ucp[3] + 4;
2283 uint64_t * ullp;
2284 switch (pc) {
2285 case 0:
2286 case 1:
2287 case 2:
2288 case 3:
2289 case 4:
2290 case 5:
2291 case 6:
2292 ecp->gotPC[pc] = 1;
2293 ullp = &ecp->counter[pc];
2294 break;
2295 default:
2296 ecp->gotExtraPC = 1;
2297 ullp = &ecp->counter[7];
2298 break;
2299 }
2300 int k = pl - 4;
2301 unsigned char * xp = ucp + 4;
2302 if (k > (int)sizeof(*ullp)) {
2303 xp += (k - sizeof(*ullp));
2304 k = sizeof(*ullp);
2305 }
2306 *ullp = sg_get_unaligned_be(k, xp);
2307 num -= pl;
2308 ucp += pl;
2309 }
2310 }
2311
2312 void
2313 scsiDecodeNonMediumErrPage(unsigned char *resp,
2314 struct scsiNonMediumError *nmep)
2315 {
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);
2320 while (num > 3) {
2321 int pc = sg_get_unaligned_be16(ucp + 0);
2322 int pl = ucp[3] + 4;
2323 int k;
2324 unsigned char * xp;
2325 switch (pc) {
2326 case 0:
2327 nmep->gotPC0 = 1;
2328 k = pl - 4;
2329 xp = ucp + 4;
2330 if (k > szof) {
2331 xp += (k - szof);
2332 k = szof;
2333 }
2334 nmep->counterPC0 = sg_get_unaligned_be(k, xp + 0);
2335 break;
2336 case 0x8009:
2337 nmep->gotTFE_H = 1;
2338 k = pl - 4;
2339 xp = ucp + 4;
2340 if (k > szof) {
2341 xp += (k - szof);
2342 k = szof;
2343 }
2344 nmep->counterTFE_H = sg_get_unaligned_be(k, xp + 0);
2345 break;
2346 case 0x8015:
2347 nmep->gotPE_H = 1;
2348 k = pl - 4;
2349 xp = ucp + 4;
2350 if (k > szof) {
2351 xp += (k - szof);
2352 k = szof;
2353 }
2354 nmep->counterPE_H = sg_get_unaligned_be(k, xp + 0);
2355 break;
2356 default:
2357 nmep->gotExtraPC = 1;
2358 break;
2359 }
2360 num -= pl;
2361 ucp += pl;
2362 }
2363 }
2364
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) */
2373 int
2374 scsiCountFailedSelfTests(scsi_device * fd, int noisy)
2375 {
2376 int num, k, err, fails, fail_hour;
2377 uint8_t * ucp;
2378 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2379
2380 if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2381 LOG_RESP_SELF_TEST_LEN, 0))) {
2382 if (noisy)
2383 pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2384 return -1;
2385 }
2386 if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
2387 if (noisy)
2388 pout("Self-test %s Failed, page mismatch\n", logSenStr);
2389 return -1;
2390 }
2391 // compute page length
2392 num = sg_get_unaligned_be16(resp + 2);
2393 // Log sense page length 0x190 bytes
2394 if (num != 0x190) {
2395 if (noisy)
2396 pout("Self-test %s length is 0x%x not 0x190 bytes\n", logSenStr,
2397 num);
2398 return -1;
2399 }
2400 fails = 0;
2401 fail_hour = 0;
2402 // loop through the twenty possible entries
2403 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2404
2405 // timestamp in power-on hours (or zero if test in progress)
2406 int n = sg_get_unaligned_be16(ucp + 6);
2407
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]))
2411 break;
2412 int res = ucp[4] & 0xf;
2413 if ((res > 2) && (res < 8)) {
2414 fails++;
2415 if (1 == fails)
2416 fail_hour = sg_get_unaligned_be16(ucp + 6);
2417 }
2418 }
2419 return (fail_hour << 8) + fails;
2420 }
2421
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. */
2424 int
2425 scsiSelfTestInProgress(scsi_device * fd, int * inProgress)
2426 {
2427 int num;
2428 uint8_t * ucp;
2429 unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2430
2431 if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2432 LOG_RESP_SELF_TEST_LEN, 0))
2433 return -1;
2434 if (resp[0] != SELFTEST_RESULTS_LPAGE)
2435 return -1;
2436 // compute page length
2437 num = sg_get_unaligned_be16(resp + 2);
2438 // Log sense page length 0x190 bytes
2439 if (num != 0x190) {
2440 return -1;
2441 }
2442 ucp = resp + 4;
2443 if (inProgress)
2444 *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2445 return 0;
2446 }
2447
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. */
2452 int
2453 scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current)
2454 {
2455 int err, offset;
2456 uint8_t buff[64];
2457 int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2458
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)
2464 modese_len = 10;
2465 else
2466 return -EINVAL;
2467 } else if (0 == modese_len)
2468 modese_len = 6;
2469 }
2470 if (10 == modese_len) {
2471 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
2472 buff, sizeof(buff));
2473 if (err)
2474 return -EINVAL;
2475 }
2476 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2477 if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2478 return (buff[offset + 2] & 2) ? 1 : 0;
2479 return -EINVAL;
2480 }
2481
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. */
2486
2487 int
2488 scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp,
2489 int * haw_zbcp)
2490 {
2491 int err, offset;
2492 uint8_t buff[64];
2493 int pc = MPAGE_CONTROL_DEFAULT;
2494
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);
2500 if (form_factorp)
2501 *form_factorp = buff[7] & 0xf;
2502 if (haw_zbcp)
2503 *haw_zbcp = !!(0x10 & buff[8]);
2504 return speed;
2505 }
2506 if (form_factorp)
2507 *form_factorp = 0;
2508 if (haw_zbcp)
2509 *haw_zbcp = 0;
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)
2514 modese_len = 10;
2515 else
2516 return -EINVAL;
2517 } else if (0 == modese_len)
2518 modese_len = 6;
2519 }
2520 if (10 == modese_len) {
2521 err = scsiModeSense10(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2522 buff, sizeof(buff));
2523 if (err)
2524 return -EINVAL;
2525 }
2526 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2527 return sg_get_unaligned_be16(buff + offset + 20);
2528 }
2529
2530 /* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2531 0 - clear bit, 1 - set bit */
2532
2533 int
2534 scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2535 short int * rcdp)
2536 {
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;
2541
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));
2546 if (err) {
2547 if (SIMPLE_ERR_BAD_OPCODE == err)
2548 modese_len = 10;
2549 else {
2550 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2551 return -EINVAL;
2552 }
2553 } else if (0 == modese_len)
2554 modese_len = 6;
2555 }
2556
2557 if (10 == modese_len) {
2558 err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT,
2559 buff, sizeof(buff));
2560 if (err) {
2561 device->set_err(EINVAL, "SCSI MODE SENSE failed");
2562 return -EINVAL;
2563 }
2564 }
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;
2569 }
2570
2571 *wcep = ((buff[offset + 2] & 0x04) != 0);
2572 *rcdp = ((buff[offset + 2] & 0x01) != 0);
2573
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
2577
2578 if (modese_len == 6)
2579 err = scsiModeSense(device, CACHING_PAGE, 0,
2580 MPAGE_CONTROL_CHANGEABLE,
2581 ch_buff, sizeof(ch_buff));
2582 else
2583 err = scsiModeSense10(device, CACHING_PAGE, 0,
2584 MPAGE_CONTROL_CHANGEABLE,
2585 ch_buff, sizeof(ch_buff));
2586 if (err) {
2587 device->set_err(EINVAL, "WCE/RCD bits not changeable");
2588 return err;
2589 }
2590
2591 // set WCE bit
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");
2595 return 1;
2596 }
2597 if(set_wce)
2598 buff[offset + 2] |= 0x04; // set bit
2599 else
2600 buff[offset + 2] &= 0xfb; // clear bit
2601 }
2602 // set RCD 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");
2606 return 1;
2607 }
2608 if(set_rcd)
2609 buff[offset + 2] |= 0x01; // set bit
2610 else
2611 buff[offset + 2] &= 0xfe; // clear bit
2612 }
2613
2614 /* mask out DPOFUA device specific (disk) parameter bit */
2615 if (10 == modese_len) {
2616 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2617 buff[3] &= 0xef;
2618 } else {
2619 resp_len = buff[0] + 1;
2620 buff[2] &= 0xef;
2621 }
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);
2627 if(err)
2628 device->set_err(EINVAL, "MODE SELECT command failed");
2629 return err;
2630 }
2631
2632
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). */
2637 int
2638 scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
2639 {
2640 int err, offset, resp_len, sp;
2641 uint8_t buff[64];
2642 uint8_t ch_buff[64];
2643
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)
2650 modese_len = 10;
2651 else
2652 return err;
2653 } else if (0 == modese_len)
2654 modese_len = 6;
2655 }
2656 if (10 == modese_len) {
2657 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2658 MPAGE_CONTROL_CURRENT,
2659 buff, sizeof(buff));
2660 if (err)
2661 return err;
2662 }
2663 offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2664 if ((offset < 0) || (buff[offset + 1] < 0xa))
2665 return SIMPLE_ERR_BAD_RESP;
2666
2667 if (enabled)
2668 enabled = 2;
2669 if (enabled == (buff[offset + 2] & 2))
2670 return 0; /* GLTSD already in wanted state so nothing to do */
2671
2672 if (modese_len == 6)
2673 err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2674 MPAGE_CONTROL_CHANGEABLE,
2675 ch_buff, sizeof(ch_buff));
2676 else
2677 err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2678 MPAGE_CONTROL_CHANGEABLE,
2679 ch_buff, sizeof(ch_buff));
2680 if (err)
2681 return err;
2682 if (0 == (ch_buff[offset + 2] & 2))
2683 return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not changeable */
2684
2685 /* mask out DPOFUA device specific (disk) parameter bit */
2686 if (10 == modese_len) {
2687 resp_len = sg_get_unaligned_be16(buff + 0) + 2;
2688 buff[3] &= 0xef;
2689 } else {
2690 resp_len = buff[0] + 1;
2691 buff[2] &= 0xef;
2692 }
2693 sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
2694 if (enabled)
2695 buff[offset + 2] |= 0x2; /* set GLTSD bit */
2696 else
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);
2702 return err;
2703 }
2704
2705 /* Returns a negative value if failed to fetch Protocol specific port mode
2706 page or it was malformed. Returns transport protocol identifier when
2707 value >= 0 . */
2708 int
2709 scsiFetchTransportProtocol(scsi_device * device, int modese_len)
2710 {
2711 int err, offset;
2712 uint8_t buff[64];
2713
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)
2720 modese_len = 10;
2721 else
2722 return -EINVAL;
2723 } else if (0 == modese_len)
2724 modese_len = 6;
2725 }
2726 if (10 == modese_len) {
2727 err = scsiModeSense10(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
2728 MPAGE_CONTROL_CURRENT,
2729 buff, sizeof(buff));
2730 if (err)
2731 return -EINVAL;
2732 }
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);
2738 }
2739 return -EINVAL;
2740 }
2741
2742 const unsigned char *
2743 sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
2744 int desc_type)
2745 {
2746 int add_sen_len;
2747 const unsigned char * descp;
2748
2749 if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
2750 return NULL;
2751 if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
2752 return NULL;
2753 add_sen_len = (add_sen_len < (sense_len - 8)) ?
2754 add_sen_len : (sense_len - 8);
2755 descp = &sensep[8];
2756 for (int desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
2757 descp += 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)
2761 return descp;
2762 if (add_len < 0) /* short descriptor ?? */
2763 break;
2764 }
2765 return NULL;
2766 }
2767
2768 // Convenience function for formatting strings from SCSI identify
2769 void
2770 scsi_format_id_string(char * out, const uint8_t * in, int n)
2771 {
2772 char tmp[65];
2773 n = n > 64 ? 64 : n;
2774 strncpy(tmp, (const char *)in, n);
2775 tmp[n] = '\0';
2776
2777 // Find the first non-space character (maybe none).
2778 int first = -1;
2779 int i;
2780 for (i = 0; tmp[i]; i++)
2781 if (!isspace((int)tmp[i])) {
2782 first = i;
2783 break;
2784 }
2785
2786 if (first == -1) {
2787 // There are only space characters.
2788 out[0] = '\0';
2789 return;
2790 }
2791
2792 // Find the last non-space character.
2793 for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
2794 int last = i;
2795
2796 strncpy(out, tmp+first, last-first+1);
2797 out[last-first+1] = '\0';
2798 }