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