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