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