Annotation of embedaddon/smartmontools/scsicmds.cpp, revision 1.1.1.3
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:
1.1.1.2 misho 10: * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
1.1 misho 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
1.1.1.2 misho 18: * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
1.1 misho 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>
1.1.1.3 ! misho 43: #include <ctype.h>
1.1 misho 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:
1.1.1.3 ! misho 52: const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 3820 2013-06-17 08:45:10Z samm2 $"
1.1 misho 53: SCSICMDS_H_CVSID;
54:
55: // Print SCSI debug messages?
56: unsigned char scsi_debugmode = 0;
57:
1.1.1.2 misho 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[0x1fc]; /* size chosen for old INQUIRY command */
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:
1.1 misho 89: /* output binary in hex and optionally ascii */
1.1.1.2 misho 90: void
91: dStrHex(const char* str, int len, int no_ascii)
1.1 misho 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;
1.1.1.2 misho 102:
1.1 misho 103: if (len <= 0) return;
104: memset(buff,' ',80);
105: buff[80]='\0';
1.1.1.2 misho 106: k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
1.1 misho 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++;
1.1.1.2 misho 117: snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (int)(unsigned char)c);
1.1 misho 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);
1.1.1.2 misho 133: k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
1.1 misho 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 */
1.1.1.2 misho 168: {READ_DEFECT_12, "read defect list(12)"}, /* 0xb7 */
1.1 misho 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 */
1.1.1.2 misho 175: const char *
176: scsi_get_opcode_name(UINT8 opcode)
1.1 misho 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:
1.1.1.2 misho 194: void
195: scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
196: struct scsi_sense_disect * out)
1.1 misho 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);
1.1.1.2 misho 203: out->resp_code = resp_code;
1.1 misho 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:
1.1.1.2 misho 218: int
219: scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo)
1.1 misho 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:
1.1.1.2 misho 226: if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
1.1 misho 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;
1.1.1.2 misho 241: else if (SCSI_ASC_INVALID_FIELD == sinfo->asc)
1.1 misho 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:
1.1.1.2 misho 256: const char *
257: scsiErrString(int scsiErr)
1.1 misho 258: {
259: if (scsiErr < 0)
260: return strerror(-scsiErr);
261: switch (scsiErr) {
1.1.1.2 misho 262: case SIMPLE_NO_ERROR:
1.1 misho 263: return "no error";
1.1.1.2 misho 264: case SIMPLE_ERR_NOT_READY:
1.1 misho 265: return "device not ready";
1.1.1.2 misho 266: case SIMPLE_ERR_BAD_OPCODE:
1.1 misho 267: return "unsupported scsi opcode";
1.1.1.2 misho 268: case SIMPLE_ERR_BAD_FIELD:
1.1 misho 269: return "unsupported field in scsi command";
1.1.1.2 misho 270: case SIMPLE_ERR_BAD_PARAM:
1.1 misho 271: return "badly formed scsi parameters";
1.1.1.2 misho 272: case SIMPLE_ERR_BAD_RESP:
1.1 misho 273: return "scsi response fails sanity test";
1.1.1.2 misho 274: case SIMPLE_ERR_NO_MEDIUM:
1.1 misho 275: return "no medium present";
1.1.1.2 misho 276: case SIMPLE_ERR_BECOMING_READY:
1.1 misho 277: return "device will be ready soon";
1.1.1.2 misho 278: case SIMPLE_ERR_TRY_AGAIN:
1.1 misho 279: return "unit attention reported, try again";
1.1.1.2 misho 280: case SIMPLE_ERR_MEDIUM_HARDWARE:
1.1 misho 281: return "medium or hardware error (serious)";
1.1.1.2 misho 282: case SIMPLE_ERR_UNKNOWN:
1.1 misho 283: return "unknown error (unexpected sense key)";
1.1.1.2 misho 284: case SIMPLE_ERR_ABORTED_COMMAND:
1.1 misho 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. */
1.1.1.2 misho 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)
1.1 misho 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. */
1.1.1.2 misho 329: int
330: scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
331: int * transport)
1.1 misho 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;
1.1.1.2 misho 336: int si = 0;
1.1 misho 337:
338: if (transport)
1.1.1.2 misho 339: *transport = -1;
1.1 misho 340: if (slen < 32) {
1.1.1.2 misho 341: if (slen > 0)
342: s[0] = '\0';
343: return -1;
1.1 misho 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) {
1.1.1.2 misho 352: snprintf(s+si, slen-si, "error: designator length");
353: return -1;
1.1 misho 354: }
355: assoc = ((ucp[1] >> 4) & 0x3);
1.1.1.2 misho 356: if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
357: *transport = (ucp[0] >> 4) & 0xf;
358: if (0 != assoc)
359: continue;
1.1 misho 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)) {
1.1.1.2 misho 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");
1.1 misho 376: for (m = 0; m < i_len; ++m)
1.1.1.2 misho 377: si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
1.1 misho 378: break;
379: case 3: /* NAA */
380: if (1 != c_set) {
1.1.1.2 misho 381: snprintf(s+si, slen-si, "error: NAA bad code_set");
382: return -1;
383: }
1.1 misho 384: naa = (ip[0] >> 4) & 0xff;
385: if ((naa < 2) || (naa > 6) || (4 == naa)) {
1.1.1.2 misho 386: snprintf(s+si, slen-si, "error: unexpected NAA");
387: return -1;
1.1 misho 388: }
1.1.1.2 misho 389: if (have_scsi_ns)
390: si = 0;
1.1 misho 391: if (2 == naa) { /* NAA IEEE Extended */
392: if (8 != i_len) {
1.1.1.2 misho 393: snprintf(s+si, slen-si, "error: NAA 2 length");
394: return -1;
1.1 misho 395: }
1.1.1.2 misho 396: si += snprintf(s+si, slen-si, "0x");
1.1 misho 397: for (m = 0; m < 8; ++m)
1.1.1.2 misho 398: si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
1.1 misho 399: } else if ((3 == naa ) || (5 == naa)) {
400: /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
401: if (8 != i_len) {
1.1.1.2 misho 402: snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
403: return -1;
1.1 misho 404: }
1.1.1.2 misho 405: si += snprintf(s+si, slen-si, "0x");
1.1 misho 406: for (m = 0; m < 8; ++m)
1.1.1.2 misho 407: si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
1.1 misho 408: } else if (6 == naa) { /* NAA IEEE Registered extended */
409: if (16 != i_len) {
1.1.1.2 misho 410: snprintf(s+si, slen-si, "error: NAA 6 length");
411: return -1;
1.1 misho 412: }
1.1.1.2 misho 413: si += snprintf(s+si, slen-si, "0x");
1.1 misho 414: for (m = 0; m < 16; ++m)
1.1.1.2 misho 415: si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
1.1 misho 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) {
1.1.1.2 misho 425: snprintf(s+si, slen-si, "error: SCSI name string");
426: return -1;
1.1 misho 427: }
428: /* does %s print out UTF-8 ok?? */
1.1.1.2 misho 429: if (si == 0) {
430: si += snprintf(s+si, slen-si, "%s", (const char *)ip);
431: ++have_scsi_ns;
432: }
1.1 misho 433: break;
434: default: /* reserved */
435: break;
436: }
437: }
438: if (-2 == u) {
1.1.1.2 misho 439: snprintf(s+si, slen-si, "error: bad structure");
440: return -1;
1.1 misho 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
1.1.1.2 misho 452: requesting the deduced response length. This protects certain fragile
1.1 misho 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. */
1.1.1.2 misho 455: int
456: scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
457: int bufLen, int known_resp_len)
1.1 misho 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)
1.1.1.2 misho 509: pageLen += 1;
1.1 misho 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) */
1.1.1.2 misho 548: int
549: scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
550: int subpagenum, UINT8 *pBuf, int bufLen)
1.1 misho 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),
1.1.1.2 misho 582: * 3 if field in command not supported or returns negated errno.
1.1 misho 583: * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
1.1.1.2 misho 584: int
585: scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
586: UINT8 *pBuf, int bufLen)
1.1 misho 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,
1.1.1.2 misho 637: * 2 if command not supported (then MODE SELECT(10) may be supported),
1.1 misho 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) */
1.1.1.2 misho 640: int
641: scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
1.1 misho 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:
1.1.1.2 misho 678: /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
1.1 misho 679: * not supported (then MODE SENSE(6) might be supported), 3 if field in
1.1.1.2 misho 680: * command not supported or returns negated errno.
1.1 misho 681: * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
1.1.1.2 misho 682: int
683: scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
684: UINT8 *pBuf, int bufLen)
1.1 misho 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
1.1.1.2 misho 733: * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
1.1 misho 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) */
1.1.1.2 misho 737: int
738: scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
1.1 misho 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;
1.1.1.2 misho 753: pBuf[0] = 0;
1.1 misho 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) */
1.1.1.2 misho 779: int
780: scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen)
1.1 misho 781: {
782: struct scsi_sense_disect sinfo;
783: struct scsi_cmnd_io io_hdr;
784: UINT8 cdb[6];
785: UINT8 sense[32];
786:
1.1.1.2 misho 787: if ((bufLen < 0) || (bufLen > 1023))
1.1 misho 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;
1.1.1.2 misho 795: cdb[3] = (bufLen >> 8) & 0xff;
796: cdb[4] = (bufLen & 0xff);
1.1 misho 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
1.1.1.2 misho 810: * (unlikely), 2 if command not supported, 3 if field in command not
1.1 misho 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) */
1.1.1.2 misho 813: int
814: scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen)
1.1 misho 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:
1.1.1.2 misho 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))
1.1 misho 829: return -EINVAL;
1.1.1.2 misho 830: try_again:
1.1 misho 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;
1.1.1.2 misho 841: cdb[3] = (bufLen >> 8) & 0xff;
842: cdb[4] = (bufLen & 0xff);
1.1 misho 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);
1.1.1.2 misho 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:
1.1 misho 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) */
1.1.1.2 misho 875: int
876: scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
1.1 misho 877: {
878: struct scsi_cmnd_io io_hdr;
879: UINT8 cdb[6];
880: UINT8 sense[32];
881: UINT8 buff[18];
882: int len;
1.1.1.2 misho 883: UINT8 resp_code;
1.1 misho 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) {
1.1.1.2 misho 901: resp_code = buff[0] & 0x7f;
902: sense_info->resp_code = resp_code;
1.1 misho 903: sense_info->sense_key = buff[2] & 0xf;
904: sense_info->asc = 0;
905: sense_info->ascq = 0;
1.1.1.2 misho 906: if ((0x70 == resp_code) || (0x71 == resp_code)) {
1.1 misho 907: len = buff[7] + 8;
908: if (len > 13) {
909: sense_info->asc = buff[12];
910: sense_info->ascq = buff[13];
911: }
912: }
1.1.1.2 misho 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: }
1.1 misho 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) */
1.1.1.2 misho 956: int
957: scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf,
958: int bufLen)
1.1 misho 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;
1.1.1.2 misho 985:
1.1 misho 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) */
1.1.1.2 misho 995: int
996: scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf,
1.1 misho 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) */
1.1.1.2 misho 1027: static int
1028: _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
1.1 misho 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 */
1.1.1.2 misho 1054: int
1055: scsiTestUnitReady(scsi_device * device)
1.1 misho 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 */
1.1.1.2 misho 1066: status = _testunitready(device, &sinfo);
1.1 misho 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) */
1.1.1.2 misho 1077: int
1078: scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
1079: int dl_format, UINT8 *pBuf, int bufLen)
1.1 misho 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:
1.1.1.2 misho 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:
1.1 misho 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) */
1.1.1.2 misho 1151: int
1152: scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
1153: unsigned int * lb_sizep)
1.1 misho 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) */
1.1.1.2 misho 1193: int
1194: scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen)
1.1 misho 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. */
1.1.1.2 misho 1227: uint64_t
1228: scsiGetSize(scsi_device * device, unsigned int * lb_sizep,
1229: int * lb_per_pb_expp)
1.1 misho 1230: {
1.1.1.3 ! misho 1231: unsigned int last_lba = 0, lb_size = 0;
1.1 misho 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) {
1.1.1.2 misho 1238: if (scsi_debugmode)
1239: pout("scsiGetSize: READ CAPACITY(10) failed, res=%d\n", res);
1240: return 0;
1.1 misho 1241: }
1242: if (0xffffffff == last_lba) {
1.1.1.2 misho 1243: res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
1.1 misho 1244: if (res) {
1.1.1.2 misho 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)
1.1 misho 1251: ret_val <<= 8;
1252: ret_val |= rc16resp[k + 0];
1253: }
1.1.1.2 misho 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: }
1.1 misho 1261: if (lb_sizep)
1.1.1.2 misho 1262: *lb_sizep = lb_size;
1263: ++ret_val; /* last_lba is origin 0 so need to bump to get number of */
1.1 misho 1264: return ret_val * lb_size;
1265: }
1266:
1.1.1.2 misho 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: }
1.1 misho 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 */
1.1.1.2 misho 1291: int
1292: scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
1.1 misho 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. */
1.1.1.2 misho 1334: int
1335: scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
1336: int modese_len)
1.1 misho 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: }
1.1.1.2 misho 1364: }
1.1 misho 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)
1.1.1.2 misho 1372: err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
1373: 0, MPAGE_CONTROL_CHANGEABLE,
1.1 misho 1374: iecp->raw_chg, sizeof(iecp->raw_chg));
1375: if (err)
1376: return err;
1377: iecp->gotChangeable = 1;
1378: return 0;
1379: }
1380:
1.1.1.2 misho 1381: int
1382: scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
1.1 misho 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:
1.1.1.2 misho 1397: int
1398: scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
1.1 misho 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 */
1.1.1.2 misho 1414: #define SCSI_IEC_MP_BYTE2_ENABLED 0x10
1.1 misho 1415: #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
1416: /* exception/warning via an unrequested REQUEST SENSE command */
1.1.1.2 misho 1417: #define SCSI_IEC_MP_MRIE 6
1.1 misho 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). */
1.1.1.2 misho 1428: int
1429: scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
1430: const struct scsi_iec_mode_page *iecp)
1.1 misho 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: if (10 == iecp->modese_len) {
1445: resp_len = (rout[0] << 8) + rout[1] + 2;
1446: rout[3] &= 0xef; /* for disks mask out DPOFUA bit */
1447: } else {
1448: resp_len = rout[0] + 1;
1449: rout[2] &= 0xef; /* for disks mask out DPOFUA bit */
1450: }
1451: sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
1452: if (enabled) {
1453: rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED;
1454: if (scsi_debugmode > 2)
1455: rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK;
1456: rout[offset + 3] = SCSI_IEC_MP_MRIE;
1457: rout[offset + 4] = (SCSI_IEC_MP_INTERVAL_T >> 24) & 0xff;
1458: rout[offset + 5] = (SCSI_IEC_MP_INTERVAL_T >> 16) & 0xff;
1459: rout[offset + 6] = (SCSI_IEC_MP_INTERVAL_T >> 8) & 0xff;
1460: rout[offset + 7] = SCSI_IEC_MP_INTERVAL_T & 0xff;
1461: rout[offset + 8] = (SCSI_IEC_MP_REPORT_COUNT >> 24) & 0xff;
1462: rout[offset + 9] = (SCSI_IEC_MP_REPORT_COUNT >> 16) & 0xff;
1463: rout[offset + 10] = (SCSI_IEC_MP_REPORT_COUNT >> 8) & 0xff;
1464: rout[offset + 11] = SCSI_IEC_MP_REPORT_COUNT & 0xff;
1465: if (iecp->gotChangeable) {
1466: UINT8 chg2 = iecp->raw_chg[offset + 2];
1467:
1468: rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) :
1469: iecp->raw_curr[offset + 2];
1470: for (k = 3; k < 12; ++k) {
1471: if (0 == iecp->raw_chg[offset + k])
1472: rout[offset + k] = iecp->raw_curr[offset + k];
1473: }
1474: }
1475: if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) {
1476: if (scsi_debugmode > 0)
1477: pout("scsiSetExceptionControlAndWarning: already enabled\n");
1478: return 0;
1479: }
1480: } else { /* disabling Exception Control and (temperature) Warnings */
1481: eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1;
1482: wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0;
1483: if ((! eCEnabled) && (! wEnabled)) {
1484: if (scsi_debugmode > 0)
1485: pout("scsiSetExceptionControlAndWarning: already disabled\n");
1486: return 0; /* nothing to do, leave other setting alone */
1487: }
1.1.1.2 misho 1488: if (wEnabled)
1.1 misho 1489: rout[offset + 2] &= EWASC_DISABLE;
1490: if (eCEnabled) {
1.1.1.2 misho 1491: if (iecp->gotChangeable &&
1.1 misho 1492: (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE))
1493: rout[offset + 2] |= DEXCPT_ENABLE;
1494: rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */
1495: }
1496: }
1497: if (10 == iecp->modese_len)
1498: err = scsiModeSelect10(device, sp, rout, resp_len);
1499: else if (6 == iecp->modese_len)
1500: err = scsiModeSelect(device, sp, rout, resp_len);
1501: return err;
1502: }
1503:
1.1.1.2 misho 1504: int
1505: scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp)
1.1 misho 1506: {
1507: UINT8 tBuf[252];
1508: int err;
1509:
1510: memset(tBuf, 0, sizeof(tBuf));
1511: if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf,
1512: sizeof(tBuf), 0))) {
1513: *currenttemp = 0;
1514: *triptemp = 0;
1515: pout("Log Sense for temperature failed [%s]\n", scsiErrString(err));
1516: return err;
1517: }
1518: *currenttemp = tBuf[9];
1519: *triptemp = tBuf[15];
1520: return 0;
1521: }
1522:
1523: /* Read informational exception log page or Request Sense response.
1524: * Fetching asc/ascq code potentially flagging an exception or warning.
1525: * Returns 0 if ok, else error number. A current temperature of 255
1526: * (Celsius) implies that the temperature not available. */
1.1.1.2 misho 1527: int
1528: scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
1529: UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp)
1.1 misho 1530: {
1531: UINT8 tBuf[252];
1532: struct scsi_sense_disect sense_info;
1533: int err;
1534: int temperatureSet = 0;
1535: unsigned short pagesize;
1536: UINT8 currTemp, trTemp;
1.1.1.2 misho 1537:
1.1 misho 1538: *asc = 0;
1539: *ascq = 0;
1540: *currenttemp = 0;
1541: *triptemp = 0;
1542: memset(tBuf,0,sizeof(tBuf)); // need to clear stack space of junk
1543: memset(&sense_info, 0, sizeof(sense_info));
1544: if (hasIELogPage) {
1545: if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf,
1546: sizeof(tBuf), 0))) {
1547: pout("Log Sense failed, IE page [%s]\n", scsiErrString(err));
1548: return err;
1549: }
1550: // pull out page size from response, don't forget to add 4
1.1.1.2 misho 1551: pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4;
1.1 misho 1552: if ((pagesize < 4) || tBuf[4] || tBuf[5]) {
1553: pout("Log Sense failed, IE page, bad parameter code or length\n");
1554: return SIMPLE_ERR_BAD_PARAM;
1555: }
1556: if (tBuf[7] > 1) {
1.1.1.2 misho 1557: sense_info.asc = tBuf[8];
1.1 misho 1558: sense_info.ascq = tBuf[9];
1559: if (! hasTempLogPage) {
1.1.1.2 misho 1560: if (tBuf[7] > 2)
1.1 misho 1561: *currenttemp = tBuf[10];
1562: if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */
1563: *triptemp = tBuf[11];
1564: }
1.1.1.2 misho 1565: }
1.1 misho 1566: }
1.1.1.2 misho 1567: if (0 == sense_info.asc) {
1.1 misho 1568: /* ties in with MRIE field of 6 in IEC mode page (0x1c) */
1569: if ((err = scsiRequestSense(device, &sense_info))) {
1570: pout("Request Sense failed, [%s]\n", scsiErrString(err));
1571: return err;
1572: }
1573: }
1574: *asc = sense_info.asc;
1575: *ascq = sense_info.ascq;
1576: if ((! temperatureSet) && hasTempLogPage) {
1577: if (0 == scsiGetTemp(device, &currTemp, &trTemp)) {
1578: *currenttemp = currTemp;
1579: *triptemp = trTemp;
1580: }
1581: }
1582: return 0;
1583: }
1584:
1585: // The first character (W, C, I) tells the severity
1.1.1.2 misho 1586: static const char * TapeAlertsMessageTable[]= {
1.1 misho 1587: " ",
1588: /* 0x01 */
1589: "W: The tape drive is having problems reading data. No data has been lost,\n"
1590: " but there has been a reduction in the performance of the tape.",
1591: /* 0x02 */
1592: "W: The tape drive is having problems writing data. No data has been lost,\n"
1593: " but there has been a reduction in the capacity of the tape.",
1594: /* 0x03 */
1595: "W: The operation has stopped because an error has occurred while reading\n"
1596: " or writing data that the drive cannot correct.",
1597: /* 0x04 */
1598: "C: Your data is at risk:\n"
1599: " 1. Copy any data you require from this tape. \n"
1600: " 2. Do not use this tape again.\n"
1601: " 3. Restart the operation with a different tape.",
1602: /* 0x05 */
1603: "C: The tape is damaged or the drive is faulty. Call the tape drive\n"
1604: " supplier helpline.",
1605: /* 0x06 */
1606: "C: The tape is from a faulty batch or the tape drive is faulty:\n"
1607: " 1. Use a good tape to test the drive.\n"
1608: " 2. If problem persists, call the tape drive supplier helpline.",
1609: /* 0x07 */
1610: "W: The tape cartridge has reached the end of its calculated useful life:\n"
1611: " 1. Copy data you need to another tape.\n"
1612: " 2. Discard the old tape.",
1613: /* 0x08 */
1614: "W: The tape cartridge is not data-grade. Any data you back up to the tape\n"
1615: " is at risk. Replace the cartridge with a data-grade tape.",
1616: /* 0x09 */
1617: "C: You are trying to write to a write-protected cartridge. Remove the\n"
1618: " write-protection or use another tape.",
1619: /* 0x0a */
1620: "I: You cannot eject the cartridge because the tape drive is in use. Wait\n"
1621: " until the operation is complete before ejecting the cartridge.",
1622: /* 0x0b */
1623: "I: The tape in the drive is a cleaning cartridge.",
1624: /* 0x0c */
1625: "I: You have tried to load a cartridge of a type which is not supported\n"
1626: " by this drive.",
1627: /* 0x0d */
1628: "C: The operation has failed because the tape in the drive has experienced\n"
1629: " a mechanical failure:\n"
1630: " 1. Discard the old tape.\n"
1631: " 2. Restart the operation with a different tape.",
1632: /* 0x0e */
1633: "C: The operation has failed because the tape in the drive has experienced\n"
1634: " a mechanical failure:\n"
1635: " 1. Do not attempt to extract the tape cartridge\n"
1636: " 2. Call the tape drive supplier helpline.",
1637: /* 0x0f */
1638: "W: The memory in the tape cartridge has failed, which reduces\n"
1639: " performance. Do not use the cartridge for further write operations.",
1640: /* 0x10 */
1641: "C: The operation has failed because the tape cartridge was manually\n"
1642: " de-mounted while the tape drive was actively writing or reading.",
1643: /* 0x11 */
1644: "W: You have loaded a cartridge of a type that is read-only in this drive.\n"
1645: " The cartridge will appear as write-protected.",
1646: /* 0x12 */
1647: "W: The tape directory on the tape cartridge has been corrupted. File\n"
1648: " search performance will be degraded. The tape directory can be rebuilt\n"
1649: " by reading all the data on the cartridge.",
1650: /* 0x13 */
1651: "I: The tape cartridge is nearing the end of its calculated life. It is\n"
1652: " recommended that you:\n"
1653: " 1. Use another tape cartridge for your next backup.\n"
1654: " 2. Store this tape in a safe place in case you need to restore "
1655: " data from it.",
1656: /* 0x14 */
1657: "C: The tape drive needs cleaning:\n"
1658: " 1. If the operation has stopped, eject the tape and clean the drive.\n"
1659: " 2. If the operation has not stopped, wait for it to finish and then\n"
1660: " clean the drive.\n"
1661: " Check the tape drive users manual for device specific cleaning instructions.",
1662: /* 0x15 */
1663: "W: The tape drive is due for routine cleaning:\n"
1664: " 1. Wait for the current operation to finish.\n"
1665: " 2. The use a cleaning cartridge.\n"
1666: " Check the tape drive users manual for device specific cleaning instructions.",
1667: /* 0x16 */
1668: "C: The last cleaning cartridge used in the tape drive has worn out:\n"
1669: " 1. Discard the worn out cleaning cartridge.\n"
1670: " 2. Wait for the current operation to finish.\n"
1671: " 3. Then use a new cleaning cartridge.",
1672: /* 0x17 */
1673: "C: The last cleaning cartridge used in the tape drive was an invalid\n"
1674: " type:\n"
1675: " 1. Do not use this cleaning cartridge in this drive.\n"
1676: " 2. Wait for the current operation to finish.\n"
1677: " 3. Then use a new cleaning cartridge.",
1678: /* 0x18 */
1679: "W: The tape drive has requested a retention operation",
1680: /* 0x19 */
1681: "W: A redundant interface port on the tape drive has failed",
1682: /* 0x1a */
1683: "W: A tape drive cooling fan has failed",
1684: /* 0x1b */
1685: "W: A redundant power supply has failed inside the tape drive enclosure.\n"
1686: " Check the enclosure users manual for instructions on replacing the\n"
1687: " failed power supply.",
1688: /* 0x1c */
1689: "W: The tape drive power consumption is outside the specified range.",
1690: /* 0x1d */
1691: "W: Preventive maintenance of the tape drive is required. Check the tape\n"
1692: " drive users manual for device specific preventive maintenance\n"
1693: " tasks or call the tape drive supplier helpline.",
1694: /* 0x1e */
1695: "C: The tape drive has a hardware fault:\n"
1696: " 1. Eject the tape or magazine.\n"
1697: " 2. Reset the drive.\n"
1698: " 3. Restart the operation.",
1699: /* 0x1f */
1700: "C: The tape drive has a hardware fault:\n"
1701: " 1. Turn the tape drive off and then on again.\n"
1702: " 2. Restart the operation.\n"
1703: " 3. If the problem persists, call the tape drive supplier helpline.",
1704: /* 0x20 */
1705: "W: The tape drive has a problem with the application client interface:\n"
1706: " 1. Check the cables and cable connections.\n"
1707: " 2. Restart the operation.",
1708: /* 0x21 */
1709: "C: The operation has failed:\n"
1710: " 1. Eject the tape or magazine.\n"
1711: " 2. Insert the tape or magazine again.\n"
1712: " 3. Restart the operation.",
1713: /* 0x22 */
1714: "W: The firmware download has failed because you have tried to use the\n"
1715: " incorrect firmware for this tape drive. Obtain the correct\n"
1716: " firmware and try again.",
1717: /* 0x23 */
1718: "W: Environmental conditions inside the tape drive are outside the\n"
1719: " specified humidity range.",
1720: /* 0x24 */
1721: "W: Environmental conditions inside the tape drive are outside the\n"
1722: " specified temperature range.",
1723: /* 0x25 */
1724: "W: The voltage supply to the tape drive is outside the specified range.",
1725: /* 0x26 */
1726: "C: A hardware failure of the tape drive is predicted. Call the tape\n"
1727: " drive supplier helpline.",
1728: /* 0x27 */
1729: "W: The tape drive may have a hardware fault. Run extended diagnostics to\n"
1730: " verify and diagnose the problem. Check the tape drive users manual for\n"
1731: " device specific instructions on running extended diagnostic tests.",
1732: /* 0x28 */
1733: "C: The changer mechanism is having difficulty communicating with the tape\n"
1734: " drive:\n"
1735: " 1. Turn the autoloader off then on.\n"
1736: " 2. Restart the operation.\n"
1737: " 3. If problem persists, call the tape drive supplier helpline.",
1738: /* 0x29 */
1739: "C: A tape has been left in the autoloader by a previous hardware fault:\n"
1740: " 1. Insert an empty magazine to clear the fault.\n"
1741: " 2. If the fault does not clear, turn the autoloader off and then\n"
1742: " on again.\n"
1743: " 3. If the problem persists, call the tape drive supplier helpline.",
1744: /* 0x2a */
1745: "W: There is a problem with the autoloader mechanism.",
1746: /* 0x2b */
1747: "C: The operation has failed because the autoloader door is open:\n"
1748: " 1. Clear any obstructions from the autoloader door.\n"
1749: " 2. Eject the magazine and then insert it again.\n"
1750: " 3. If the fault does not clear, turn the autoloader off and then\n"
1751: " on again.\n"
1752: " 4. If the problem persists, call the tape drive supplier helpline.",
1753: /* 0x2c */
1754: "C: The autoloader has a hardware fault:\n"
1755: " 1. Turn the autoloader off and then on again.\n"
1756: " 2. Restart the operation.\n"
1757: " 3. If the problem persists, call the tape drive supplier helpline.\n"
1758: " Check the autoloader users manual for device specific instructions\n"
1759: " on turning the device power on and off.",
1760: /* 0x2d */
1761: "C: The autoloader cannot operate without the magazine,\n"
1762: " 1. Insert the magazine into the autoloader.\n"
1763: " 2. Restart the operation.",
1764: /* 0x2e */
1765: "W: A hardware failure of the changer mechanism is predicted. Call the\n"
1766: " tape drive supplier helpline.",
1767: /* 0x2f */
1768: "I: Reserved.",
1769: /* 0x30 */
1770: "I: Reserved.",
1771: /* 0x31 */
1772: "I: Reserved.",
1773: /* 0x32 */
1774: "W: Media statistics have been lost at some time in the past",
1775: /* 0x33 */
1776: "W: The tape directory on the tape cartridge just unloaded has been\n"
1777: " corrupted. File search performance will be degraded. The tape\n"
1778: " directory can be rebuilt by reading all the data.",
1779: /* 0x34 */
1780: "C: The tape just unloaded could not write its system area successfully:\n"
1781: " 1. Copy data to another tape cartridge.\n"
1782: " 2. Discard the old cartridge.",
1783: /* 0x35 */
1784: "C: The tape system are could not be read successfully at load time:\n"
1785: " 1. Copy data to another tape cartridge.\n",
1786: /* 0x36 */
1787: "C: The start or data could not be found on the tape:\n"
1788: " 1. Check you are using the correct format tape.\n"
1789: " 2. Discard the tape or return the tape to your supplier",
1790: /* 0x37 */
1791: "C: The operation has failed because the media cannot be loaded\n"
1792: " and threaded.\n"
1793: " 1. Remove the cartridge, inspect it as specified in the product\n"
1794: " manual, and retry the operation.\n"
1795: " 2. If the problem persists, call the tape drive supplier help line.",
1796: /* 0x38 */
1797: "C: The operation has failed because the medium cannot be unloaded:\n"
1798: " 1. Do not attempt to extract the tape cartridge.\n"
1799: " 2. Call the tape driver supplier help line.",
1800: /* 0x39 */
1801: "C: The tape drive has a problem with the automation interface:\n"
1802: " 1. Check the power to the automation system.\n"
1803: " 2. Check the cables and cable connections.\n"
1804: " 3. Call the supplier help line if problem persists.",
1805: /* 0x3a */
1806: "W: The tape drive has reset itself due to a detected firmware\n"
1807: " fault. If problem persists, call the supplier help line.",
1808: };
1809:
1.1.1.2 misho 1810: const char *
1811: scsiTapeAlertsTapeDevice(unsigned short code)
1.1 misho 1812: {
1813: const int num = sizeof(TapeAlertsMessageTable) /
1814: sizeof(TapeAlertsMessageTable[0]);
1815:
1.1.1.2 misho 1816: return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert";
1.1 misho 1817: }
1818:
1819: // The first character (W, C, I) tells the severity
1.1.1.2 misho 1820: static const char * ChangerTapeAlertsMessageTable[]= {
1.1 misho 1821: " ",
1822: /* 0x01 */
1823: "C: The library mechanism is having difficulty communicating with the\n"
1824: " drive:\n"
1825: " 1. Turn the library off then on.\n"
1826: " 2. Restart the operation.\n"
1827: " 3. If the problem persists, call the library supplier help line.",
1828: /* 0x02 */
1829: "W: There is a problem with the library mechanism. If problem persists,\n"
1830: " call the library supplier help line.",
1831: /* 0x03 */
1832: "C: The library has a hardware fault:\n"
1833: " 1. Reset the library.\n"
1834: " 2. Restart the operation.\n"
1835: " Check the library users manual for device specific instructions on resetting\n"
1836: " the device.",
1837: /* 0x04 */
1838: "C: The library has a hardware fault:\n"
1839: " 1. Turn the library off then on again.\n"
1840: " 2. Restart the operation.\n"
1841: " 3. If the problem persists, call the library supplier help line.\n"
1842: " Check the library users manual for device specific instructions on turning the\n"
1843: " device power on and off.",
1844: /* 0x05 */
1845: "W: The library mechanism may have a hardware fault.\n"
1846: " Run extended diagnostics to verify and diagnose the problem. Check the library\n"
1847: " users manual for device specific instructions on running extended diagnostic\n"
1848: " tests.",
1849: /* 0x06 */
1850: "C: The library has a problem with the host interface:\n"
1851: " 1. Check the cables and connections.\n"
1852: " 2. Restart the operation.",
1853: /* 0x07 */
1854: "W: A hardware failure of the library is predicted. Call the library\n"
1855: " supplier help line.",
1856: /* 0x08 */
1857: "W: Preventive maintenance of the library is required.\n"
1858: " Check the library users manual for device specific preventative maintenance\n"
1859: " tasks, or call your library supplier help line.",
1860: /* 0x09 */
1861: "C: General environmental conditions inside the library are outside the\n"
1862: " specified humidity range.",
1863: /* 0x0a */
1864: "C: General environmental conditions inside the library are outside the\n"
1865: " specified temperature range.",
1866: /* 0x0b */
1867: "C: The voltage supply to the library is outside the specified range.\n"
1868: " There is a potential problem with the power supply or failure of\n"
1869: " a redundant power supply.",
1870: /* 0x0c */
1871: "C: A cartridge has been left inside the library by a previous hardware\n"
1872: " fault:\n"
1873: " 1. Insert an empty magazine to clear the fault.\n"
1874: " 2. If the fault does not clear, turn the library off and then on again.\n"
1875: " 3. If the problem persists, call the library supplier help line.",
1876: /* 0x0d */
1877: "W: There is a potential problem with the drive ejecting cartridges or\n"
1878: " with the library mechanism picking a cartridge from a slot.\n"
1879: " 1. No action needs to be taken at this time.\n"
1880: " 2. If the problem persists, call the library supplier help line.",
1881: /* 0x0e */
1882: "W: There is a potential problem with the library mechanism placing a\n"
1883: " cartridge into a slot.\n"
1884: " 1. No action needs to be taken at this time.\n"
1885: " 2. If the problem persists, call the library supplier help line.",
1886: /* 0x0f */
1887: "W: There is a potential problem with the drive or the library mechanism\n"
1888: " loading cartridges, or an incompatible cartridge.",
1889: /* 0x10 */
1890: "C: The library has failed because the door is open:\n"
1891: " 1. Clear any obstructions from the library door.\n"
1892: " 2. Close the library door.\n"
1893: " 3. If the problem persists, call the library supplier help line.",
1894: /* 0x11 */
1895: "C: There is a mechanical problem with the library media import/export\n"
1896: " mailslot.",
1897: /* 0x12 */
1898: "C: The library cannot operate without the magazine.\n"
1899: " 1. Insert the magazine into the library.\n"
1900: " 2. Restart the operation.",
1901: /* 0x13 */
1902: "W: Library security has been compromised.",
1903: /* 0x14 */
1904: "I: The library security mode has been changed.\n"
1905: " The library has either been put into secure mode, or the library has exited\n"
1906: " the secure mode.\n"
1907: " This is for information purposes only. No action is required.",
1908: /* 0x15 */
1909: "I: The library has been manually turned offline and is unavailable for use.",
1910: /* 0x16 */
1911: "I: A drive inside the library has been taken offline.\n"
1912: " This is for information purposes only. No action is required.",
1913: /* 0x17 */
1914: "W: There is a potential problem with the bar code label or the scanner\n"
1915: " hardware in the library mechanism.\n"
1916: " 1. No action needs to be taken at this time.\n"
1917: " 2. If the problem persists, call the library supplier help line.",
1918: /* 0x18 */
1919: "C: The library has detected an inconsistency in its inventory.\n"
1920: " 1. Redo the library inventory to correct inconsistency.\n"
1921: " 2. Restart the operation.\n"
1922: " Check the applications users manual or the hardware users manual for\n"
1923: " specific instructions on redoing the library inventory.",
1924: /* 0x19 */
1925: "W: A library operation has been attempted that is invalid at this time.",
1926: /* 0x1a */
1927: "W: A redundant interface port on the library has failed.",
1928: /* 0x1b */
1929: "W: A library cooling fan has failed.",
1930: /* 0x1c */
1931: "W: A redundant power supply has failed inside the library. Check the\n"
1932: " library users manual for instructions on replacing the failed power supply.",
1933: /* 0x1d */
1934: "W: The library power consumption is outside the specified range.",
1935: /* 0x1e */
1936: "C: A failure has occurred in the cartridge pass-through mechanism between\n"
1937: " two library modules.",
1938: /* 0x1f */
1939: "C: A cartridge has been left in the pass-through mechanism from a\n"
1940: " previous hardware fault. Check the library users guide for instructions on\n"
1941: " clearing this fault.",
1942: /* 0x20 */
1943: "I: The library was unable to read the bar code on a cartridge.",
1944: };
1945:
1.1.1.2 misho 1946: const char *
1947: scsiTapeAlertsChangerDevice(unsigned short code)
1.1 misho 1948: {
1949: const int num = sizeof(ChangerTapeAlertsMessageTable) /
1950: sizeof(ChangerTapeAlertsMessageTable[0]);
1951:
1.1.1.2 misho 1952: return (code < num) ? ChangerTapeAlertsMessageTable[code] : "Unknown Alert";
1.1 misho 1953: }
1954:
1955:
1956: /* this is a subset of the SCSI additional sense code strings indexed
1957: * by "ascq" for the case when asc==SCSI_ASC_IMPENDING_FAILURE (0x5d)
1958: */
1959: static const char * strs_for_asc_5d[] = {
1960: /* 0x00 */ "FAILURE PREDICTION THRESHOLD EXCEEDED",
1961: "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED",
1962: "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED",
1963: "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED",
1964: "",
1965: "",
1966: "",
1967: "",
1968: "",
1969: "",
1970: "",
1971: "",
1972: "",
1973: "",
1974: "",
1975: "",
1976: /* 0x10 */ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1977: "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1978: "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1979: "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1980: "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1981: "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1982: "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1983: "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
1984: "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED",
1985: "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
1986: "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
1987: "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
1988: "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
1989: "",
1990: "",
1991: "",
1992: /* 0x20 */ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
1993: "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
1994: "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
1995: "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
1996: "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
1997: "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH",
1998: "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH",
1999: "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS",
2000: "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED",
2001: "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2002: "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE",
2003: "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT",
2004: "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2005: "",
2006: "",
2007: "",
2008: /* 0x30 */ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2009: "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2010: "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2011: "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2012: "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2013: "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2014: "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2015: "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS",
2016: "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED",
2017: "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2018: "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE",
2019: "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT",
2020: "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2021: "",
2022: "",
2023: "",
2024: /* 0x40 */ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2025: "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2026: "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2027: "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2028: "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2029: "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2030: "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2031: "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS",
2032: "SERVO IMPENDING FAILURE CONTROLLER DETECTED",
2033: "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2034: "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE",
2035: "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT",
2036: "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2037: "",
2038: "",
2039: "",
2040: /* 0x50 */ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2041: "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2042: "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2043: "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2044: "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2045: "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2046: "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2047: "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS",
2048: "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED",
2049: "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2050: "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2051: "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2052: "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT",
2053: "",
2054: "",
2055: "",
2056: /* 0x60 */ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE",
2057: "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH",
2058: "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH",
2059: "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH",
2060: "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS",
2061: "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH",
2062: "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH",
2063: "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS",
2064: "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED",
2065: "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE",
2066: "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE",
2067: "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT",
2068: /* 0x6c */ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"};
2069:
2070:
2071: /* this is a subset of the SCSI additional sense code strings indexed
2072: * * by "ascq" for the case when asc==SCSI_ASC_WARNING (0xb)
2073: * */
2074: static const char * strs_for_asc_b[] = {
2075: /* 0x00 */ "WARNING",
2076: "WARNING - SPECIFIED TEMPERATURE EXCEEDED",
2077: "WARNING - ENCLOSURE DEGRADED"};
2078:
2079: static char spare_buff[128];
2080:
1.1.1.2 misho 2081: const char *
2082: scsiGetIEString(UINT8 asc, UINT8 ascq)
1.1 misho 2083: {
2084: const char * rp;
2085:
2086: if (SCSI_ASC_IMPENDING_FAILURE == asc) {
2087: if (ascq == 0xff)
2088: return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
1.1.1.2 misho 2089: else if (ascq <
1.1 misho 2090: (sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) {
2091: rp = strs_for_asc_5d[ascq];
2092: if (strlen(rp) > 0)
2093: return rp;
2094: }
2095: snprintf(spare_buff, sizeof(spare_buff),
2096: "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq);
2097: return spare_buff;
2098: } else if (SCSI_ASC_WARNING == asc) {
2099: if (ascq < (sizeof(strs_for_asc_b) / sizeof(strs_for_asc_b[0]))) {
2100: rp = strs_for_asc_b[ascq];
2101: if (strlen(rp) > 0)
2102: return rp;
2103: }
2104: snprintf(spare_buff, sizeof(spare_buff), "WARNING: ascq=0x%x", ascq);
2105: return spare_buff;
2106: }
2107: return NULL; /* not a IE additional sense code */
2108: }
2109:
2110:
2111: /* This is not documented in t10.org, page 0x80 is vendor specific */
2112: /* Some IBM disks do an offline read-scan when they get this command. */
1.1.1.2 misho 2113: int
2114: scsiSmartIBMOfflineTest(scsi_device * device)
2115: {
1.1 misho 2116: UINT8 tBuf[256];
2117: int res;
1.1.1.2 misho 2118:
1.1 misho 2119: memset(tBuf, 0, sizeof(tBuf));
2120: /* Build SMART Off-line Immediate Diag Header */
2121: tBuf[0] = 0x80; /* Page Code */
2122: tBuf[1] = 0x00; /* Reserved */
2123: tBuf[2] = 0x00; /* Page Length MSB */
2124: tBuf[3] = 0x04; /* Page Length LSB */
2125: tBuf[4] = 0x03; /* SMART Revision */
2126: tBuf[5] = 0x00; /* Reserved */
2127: tBuf[6] = 0x00; /* Off-line Immediate Time MSB */
2128: tBuf[7] = 0x00; /* Off-line Immediate Time LSB */
2129: res = scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8);
2130: if (res)
2131: pout("IBM offline test failed [%s]\n", scsiErrString(res));
2132: return res;
2133: }
2134:
1.1.1.2 misho 2135: int
2136: scsiSmartDefaultSelfTest(scsi_device * device)
2137: {
1.1 misho 2138: int res;
2139:
2140: res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0);
2141: if (res)
2142: pout("Default self test failed [%s]\n", scsiErrString(res));
2143: return res;
2144: }
2145:
1.1.1.2 misho 2146: int
2147: scsiSmartShortSelfTest(scsi_device * device)
2148: {
1.1 misho 2149: int res;
2150:
2151: res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0);
2152: if (res)
2153: pout("Short offline self test failed [%s]\n", scsiErrString(res));
2154: return res;
2155: }
2156:
1.1.1.2 misho 2157: int
2158: scsiSmartExtendSelfTest(scsi_device * device)
2159: {
1.1 misho 2160: int res;
2161:
2162: res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0);
2163: if (res)
2164: pout("Long (extended) offline self test failed [%s]\n",
2165: scsiErrString(res));
2166: return res;
2167: }
2168:
1.1.1.2 misho 2169: int
2170: scsiSmartShortCapSelfTest(scsi_device * device)
2171: {
1.1 misho 2172: int res;
2173:
2174: res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0);
2175: if (res)
2176: pout("Short foreground self test failed [%s]\n", scsiErrString(res));
2177: return res;
2178: }
2179:
1.1.1.2 misho 2180: int
2181: scsiSmartExtendCapSelfTest(scsi_device * device)
1.1 misho 2182: {
2183: int res;
2184:
2185: res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0);
2186: if (res)
2187: pout("Long (extended) foreground self test failed [%s]\n",
2188: scsiErrString(res));
2189: return res;
2190: }
2191:
1.1.1.2 misho 2192: int
2193: scsiSmartSelfTestAbort(scsi_device * device)
1.1 misho 2194: {
2195: int res;
2196:
2197: res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0);
2198: if (res)
2199: pout("Abort self test failed [%s]\n", scsiErrString(res));
2200: return res;
2201: }
2202:
2203: /* Returns 0 and the expected duration of an extended self test (in seconds)
2204: if successful; any other return value indicates a failure. */
1.1.1.2 misho 2205: int
2206: scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
2207: int modese_len)
1.1 misho 2208: {
2209: int err, offset, res;
2210: UINT8 buff[64];
2211:
2212: memset(buff, 0, sizeof(buff));
2213: if (modese_len <= 6) {
2214: if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2215: MPAGE_CONTROL_CURRENT,
2216: buff, sizeof(buff)))) {
2217: if (SIMPLE_ERR_BAD_OPCODE == err)
2218: modese_len = 10;
2219: else
2220: return err;
2221: } else if (0 == modese_len)
2222: modese_len = 6;
2223: }
2224: if (10 == modese_len) {
2225: err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
1.1.1.2 misho 2226: MPAGE_CONTROL_CURRENT,
1.1 misho 2227: buff, sizeof(buff));
2228: if (err)
2229: return err;
1.1.1.2 misho 2230: }
1.1 misho 2231: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2232: if (offset < 0)
2233: return -EINVAL;
2234: if (buff[offset + 1] >= 0xa) {
2235: res = (buff[offset + 10] << 8) | buff[offset + 11];
2236: *durationSec = res;
2237: return 0;
2238: }
2239: else
2240: return -EINVAL;
2241: }
2242:
1.1.1.2 misho 2243: void
2244: scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
1.1 misho 2245: {
2246: int k, j, num, pl, pc;
2247: unsigned char * ucp;
2248: unsigned char * xp;
2249: uint64_t * ullp;
2250:
2251: memset(ecp, 0, sizeof(*ecp));
2252: num = (resp[2] << 8) | resp[3];
2253: ucp = &resp[0] + 4;
2254: while (num > 3) {
2255: pc = (ucp[0] << 8) | ucp[1];
2256: pl = ucp[3] + 4;
2257: switch (pc) {
1.1.1.2 misho 2258: case 0:
2259: case 1:
2260: case 2:
2261: case 3:
2262: case 4:
2263: case 5:
2264: case 6:
1.1 misho 2265: ecp->gotPC[pc] = 1;
2266: ullp = &ecp->counter[pc];
2267: break;
1.1.1.2 misho 2268: default:
1.1 misho 2269: ecp->gotExtraPC = 1;
2270: ullp = &ecp->counter[7];
2271: break;
2272: }
2273: k = pl - 4;
2274: xp = ucp + 4;
2275: if (k > (int)sizeof(*ullp)) {
2276: xp += (k - sizeof(*ullp));
2277: k = sizeof(*ullp);
2278: }
2279: *ullp = 0;
2280: for (j = 0; j < k; ++j) {
2281: if (j > 0)
2282: *ullp <<= 8;
2283: *ullp |= xp[j];
2284: }
2285: num -= pl;
2286: ucp += pl;
2287: }
2288: }
2289:
1.1.1.2 misho 2290: void
2291: scsiDecodeNonMediumErrPage(unsigned char *resp,
2292: struct scsiNonMediumError *nmep)
1.1 misho 2293: {
2294: int k, j, num, pl, pc, szof;
2295: unsigned char * ucp;
2296: unsigned char * xp;
2297:
2298: memset(nmep, 0, sizeof(*nmep));
2299: num = (resp[2] << 8) | resp[3];
2300: ucp = &resp[0] + 4;
2301: szof = sizeof(nmep->counterPC0);
2302: while (num > 3) {
2303: pc = (ucp[0] << 8) | ucp[1];
2304: pl = ucp[3] + 4;
2305: switch (pc) {
1.1.1.2 misho 2306: case 0:
1.1 misho 2307: nmep->gotPC0 = 1;
2308: k = pl - 4;
2309: xp = ucp + 4;
2310: if (k > szof) {
2311: xp += (k - szof);
2312: k = szof;
2313: }
2314: nmep->counterPC0 = 0;
2315: for (j = 0; j < k; ++j) {
2316: if (j > 0)
2317: nmep->counterPC0 <<= 8;
2318: nmep->counterPC0 |= xp[j];
2319: }
2320: break;
1.1.1.2 misho 2321: case 0x8009:
1.1 misho 2322: nmep->gotTFE_H = 1;
2323: k = pl - 4;
2324: xp = ucp + 4;
2325: if (k > szof) {
2326: xp += (k - szof);
2327: k = szof;
2328: }
2329: nmep->counterTFE_H = 0;
2330: for (j = 0; j < k; ++j) {
2331: if (j > 0)
2332: nmep->counterTFE_H <<= 8;
2333: nmep->counterTFE_H |= xp[j];
2334: }
2335: break;
1.1.1.2 misho 2336: case 0x8015:
1.1 misho 2337: nmep->gotPE_H = 1;
2338: k = pl - 4;
2339: xp = ucp + 4;
2340: if (k > szof) {
2341: xp += (k - szof);
2342: k = szof;
2343: }
2344: nmep->counterPE_H = 0;
2345: for (j = 0; j < k; ++j) {
2346: if (j > 0)
2347: nmep->counterPE_H <<= 8;
2348: nmep->counterPE_H |= xp[j];
2349: }
2350: break;
1.1.1.2 misho 2351: default:
1.1 misho 2352: nmep->gotExtraPC = 1;
2353: break;
2354: }
2355: num -= pl;
2356: ucp += pl;
2357: }
2358: }
2359:
2360: /* Counts number of failed self-tests. Also encodes the poweron_hour
2361: of the most recent failed self-test. Return value is negative if
2362: this function has a problem (typically -1), otherwise the bottom 8
2363: bits are the number of failed self tests and the 16 bits above that
2364: are the poweron hour of the most recent failure. Note: aborted self
1.1.1.2 misho 2365: tests (typically by the user) and self tests in progress are not
2366: considered failures. See Working Draft SCSI Primary Commands - 3
1.1 misho 2367: (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
1.1.1.2 misho 2368: int
2369: scsiCountFailedSelfTests(scsi_device * fd, int noisy)
1.1 misho 2370: {
2371: int num, k, n, err, res, fails, fail_hour;
2372: UINT8 * ucp;
2373: unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2374:
2375: if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2376: LOG_RESP_SELF_TEST_LEN, 0))) {
2377: if (noisy)
2378: pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err));
2379: return -1;
2380: }
2381: if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
2382: if (noisy)
2383: pout("Self-test Log Sense Failed, page mismatch\n");
2384: return -1;
2385: }
2386: // compute page length
2387: num = (resp[2] << 8) + resp[3];
2388: // Log sense page length 0x190 bytes
2389: if (num != 0x190) {
2390: if (noisy)
2391: pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n", num);
2392: return -1;
2393: }
2394: fails = 0;
2395: fail_hour = 0;
2396: // loop through the twenty possible entries
2397: for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) {
2398:
2399: // timestamp in power-on hours (or zero if test in progress)
2400: n = (ucp[6] << 8) | ucp[7];
2401:
2402: // The spec says "all 20 bytes will be zero if no test" but
2403: // DG has found otherwise. So this is a heuristic.
2404: if ((0 == n) && (0 == ucp[4]))
2405: break;
2406: res = ucp[4] & 0xf;
2407: if ((res > 2) && (res < 8)) {
2408: fails++;
1.1.1.2 misho 2409: if (1 == fails)
1.1 misho 2410: fail_hour = (ucp[6] << 8) + ucp[7];
2411: }
2412: }
2413: return (fail_hour << 8) + fails;
2414: }
2415:
2416: /* Returns 0 if able to read self test log page; then outputs 1 into
2417: *inProgress if self test still in progress, else outputs 0. */
1.1.1.2 misho 2418: int
2419: scsiSelfTestInProgress(scsi_device * fd, int * inProgress)
1.1 misho 2420: {
2421: int num;
2422: UINT8 * ucp;
2423: unsigned char resp[LOG_RESP_SELF_TEST_LEN];
2424:
2425: if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp,
2426: LOG_RESP_SELF_TEST_LEN, 0))
2427: return -1;
2428: if (resp[0] != SELFTEST_RESULTS_LPAGE)
2429: return -1;
2430: // compute page length
2431: num = (resp[2] << 8) + resp[3];
2432: // Log sense page length 0x190 bytes
2433: if (num != 0x190) {
2434: return -1;
2435: }
2436: ucp = resp + 4;
2437: if (inProgress)
2438: *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0;
2439: return 0;
2440: }
2441:
2442: /* Returns a negative value if failed to fetch Contol mode page or it was
2443: malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD
2444: bit is set. Examines default mode page when current==0 else examines
2445: current mode page. */
1.1.1.2 misho 2446: int
2447: scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current)
1.1 misho 2448: {
2449: int err, offset;
2450: UINT8 buff[64];
2451: int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT;
2452:
2453: memset(buff, 0, sizeof(buff));
2454: if (modese_len <= 6) {
2455: if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc,
2456: buff, sizeof(buff)))) {
2457: if (SIMPLE_ERR_BAD_OPCODE == err)
2458: modese_len = 10;
2459: else
2460: return -EINVAL;
2461: } else if (0 == modese_len)
2462: modese_len = 6;
2463: }
2464: if (10 == modese_len) {
2465: err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc,
2466: buff, sizeof(buff));
2467: if (err)
2468: return -EINVAL;
1.1.1.2 misho 2469: }
1.1 misho 2470: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2471: if ((offset >= 0) && (buff[offset + 1] >= 0xa))
2472: return (buff[offset + 2] & 2) ? 1 : 0;
2473: return -EINVAL;
2474: }
2475:
1.1.1.2 misho 2476: /* Returns a negative value on error, 0 if unknown and 1 if SSD,
2477: * otherwise the positive returned value is the speed in rpm. First checks
2478: * the Block Device Characteristics VPD page and if that fails it tries the
2479: * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page. */
2480:
2481: int
2482: scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp)
2483: {
2484: int err, offset, speed;
2485: UINT8 buff[64];
2486: int pc = MPAGE_CONTROL_DEFAULT;
2487:
2488: memset(buff, 0, sizeof(buff));
2489: if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS,
2490: buff, sizeof(buff))) &&
2491: (((buff[2] << 8) + buff[3]) > 2)) {
2492: speed = (buff[4] << 8) + buff[5];
2493: if (form_factorp)
2494: *form_factorp = buff[7] & 0xf;
2495: return speed;
2496: }
2497: if (form_factorp)
2498: *form_factorp = 0;
2499: if (modese_len <= 6) {
2500: if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2501: buff, sizeof(buff)))) {
2502: if (SIMPLE_ERR_BAD_OPCODE == err)
2503: modese_len = 10;
2504: else
2505: return -EINVAL;
2506: } else if (0 == modese_len)
2507: modese_len = 6;
2508: }
2509: if (10 == modese_len) {
2510: err = scsiModeSense10(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc,
2511: buff, sizeof(buff));
2512: if (err)
2513: return -EINVAL;
2514: }
2515: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2516: return (buff[offset + 20] << 8) | buff[offset + 21];
2517: }
2518:
2519: /* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value,
2520: 0 - clear bit, 1 - set bit */
2521:
2522: int
2523: scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep,
2524: short int * rcdp)
2525: {
2526: int err, offset, resp_len, sp;
2527: UINT8 buff[64], ch_buff[64];
2528: short set_wce = *wcep;
2529: short set_rcd = *rcdp;
2530:
2531: memset(buff, 0, sizeof(buff));
2532: if (modese_len <= 6) {
2533: if ((err = scsiModeSense(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT,
2534: buff, sizeof(buff)))) {
2535: if (SIMPLE_ERR_BAD_OPCODE == err)
2536: modese_len = 10;
2537: else {
2538: device->set_err(EINVAL, "SCSI MODE SENSE failed");
2539: return -EINVAL;
2540: }
2541: } else if (0 == modese_len)
2542: modese_len = 6;
2543: }
2544:
2545: if (10 == modese_len) {
2546: err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT,
2547: buff, sizeof(buff));
2548: if (err) {
2549: device->set_err(EINVAL, "SCSI MODE SENSE failed");
2550: return -EINVAL;
2551: }
2552: }
2553: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2554: if ((offset < 0) || (buff[offset + 1] < 0xa)) {
2555: device->set_err(EINVAL, "Bad response");
2556: return SIMPLE_ERR_BAD_RESP;
2557: }
2558:
2559: *wcep = ((buff[offset + 2] & 0x04) != 0);
2560: *rcdp = ((buff[offset + 2] & 0x01) != 0);
2561:
2562: if((*wcep == set_wce || set_wce == -1)
2563: && ((*rcdp == set_rcd) || set_rcd == -1))
2564: return 0; // no changes needed or nothing to set
2565:
2566: if (modese_len == 6)
2567: err = scsiModeSense(device, CACHING_PAGE, 0,
2568: MPAGE_CONTROL_CHANGEABLE,
2569: ch_buff, sizeof(ch_buff));
2570: else
2571: err = scsiModeSense10(device, CACHING_PAGE, 0,
2572: MPAGE_CONTROL_CHANGEABLE,
2573: ch_buff, sizeof(ch_buff));
2574: if (err) {
2575: device->set_err(EINVAL, "WCE/RCD bits not changable");
2576: return err;
2577: }
2578:
2579: // set WCE bit
2580: if(set_wce >= 0 && *wcep != set_wce) {
2581: if (0 == (ch_buff[offset + 2] & 0x04)) {
2582: device->set_err(EINVAL, "WCE bit not changable");
2583: return 1;
2584: }
2585: if(set_wce)
2586: buff[offset + 2] |= 0x04; // set bit
2587: else
2588: buff[offset + 2] &= 0xfb; // clear bit
2589: }
2590: // set RCD bit
2591: if(set_rcd >= 0 && *rcdp != set_rcd) {
2592: if (0 == (ch_buff[offset + 2] & 0x01)) {
2593: device->set_err(EINVAL, "RCD bit not changable");
2594: return 1;
2595: }
2596: if(set_rcd)
2597: buff[offset + 2] |= 0x01; // set bit
2598: else
2599: buff[offset + 2] &= 0xfe; // clear bit
2600: }
2601:
2602: if (10 == modese_len) {
2603: resp_len = (buff[0] << 8) + buff[1] + 2;
2604: buff[3] &= 0xef; /* for disks mask out DPOFUA bit */
2605: } else {
2606: resp_len = buff[0] + 1;
2607: buff[2] &= 0xef; /* for disks mask out DPOFUA bit */
2608: }
2609: sp = 0; /* Do not change saved values */
2610: if (10 == modese_len)
2611: err = scsiModeSelect10(device, sp, buff, resp_len);
2612: else if (6 == modese_len)
2613: err = scsiModeSelect(device, sp, buff, resp_len);
2614: if(err)
2615: device->set_err(EINVAL, "MODE SELECT command failed");
2616: return err;
2617: }
2618:
2619:
1.1 misho 2620: /* Attempts to set or clear GLTSD bit in Control mode page. If enabled is
2621: 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if
2622: successful, negative if low level error, > 0 if higher level error (e.g.
2623: SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */
1.1.1.2 misho 2624: int
2625: scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
1.1 misho 2626: {
2627: int err, offset, resp_len, sp;
2628: UINT8 buff[64];
2629: UINT8 ch_buff[64];
2630:
2631: memset(buff, 0, sizeof(buff));
2632: if (modese_len <= 6) {
2633: if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2634: MPAGE_CONTROL_CURRENT,
2635: buff, sizeof(buff)))) {
2636: if (SIMPLE_ERR_BAD_OPCODE == err)
2637: modese_len = 10;
2638: else
2639: return err;
2640: } else if (0 == modese_len)
2641: modese_len = 6;
2642: }
2643: if (10 == modese_len) {
2644: err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2645: MPAGE_CONTROL_CURRENT,
2646: buff, sizeof(buff));
2647: if (err)
2648: return err;
1.1.1.2 misho 2649: }
1.1 misho 2650: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2651: if ((offset < 0) || (buff[offset + 1] < 0xa))
2652: return SIMPLE_ERR_BAD_RESP;
2653:
2654: if (enabled)
2655: enabled = 2;
2656: if (enabled == (buff[offset + 2] & 2))
2657: return 0; /* GLTSD already in wanted state so nothing to do */
2658:
2659: if (modese_len == 6)
2660: err = scsiModeSense(device, CONTROL_MODE_PAGE, 0,
2661: MPAGE_CONTROL_CHANGEABLE,
2662: ch_buff, sizeof(ch_buff));
2663: else
2664: err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0,
2665: MPAGE_CONTROL_CHANGEABLE,
2666: ch_buff, sizeof(ch_buff));
2667: if (err)
2668: return err;
2669: if (0 == (ch_buff[offset + 2] & 2))
2670: return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not chageable */
1.1.1.2 misho 2671:
1.1 misho 2672: if (10 == modese_len) {
2673: resp_len = (buff[0] << 8) + buff[1] + 2;
2674: buff[3] &= 0xef; /* for disks mask out DPOFUA bit */
2675: } else {
2676: resp_len = buff[0] + 1;
2677: buff[2] &= 0xef; /* for disks mask out DPOFUA bit */
2678: }
2679: sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */
2680: if (enabled)
2681: buff[offset + 2] |= 0x2; /* set GLTSD bit */
2682: else
2683: buff[offset + 2] &= 0xfd; /* clear GLTSD bit */
2684: if (10 == modese_len)
2685: err = scsiModeSelect10(device, sp, buff, resp_len);
2686: else if (6 == modese_len)
2687: err = scsiModeSelect(device, sp, buff, resp_len);
2688: return err;
2689: }
2690:
1.1.1.2 misho 2691: /* Returns a negative value if failed to fetch Protocol specific port mode
1.1 misho 2692: page or it was malformed. Returns transport protocol identifier when
2693: value >= 0 . */
1.1.1.2 misho 2694: int
2695: scsiFetchTransportProtocol(scsi_device * device, int modese_len)
1.1 misho 2696: {
2697: int err, offset;
2698: UINT8 buff[64];
2699:
2700: memset(buff, 0, sizeof(buff));
2701: if (modese_len <= 6) {
2702: if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
2703: MPAGE_CONTROL_CURRENT,
2704: buff, sizeof(buff)))) {
2705: if (SIMPLE_ERR_BAD_OPCODE == err)
2706: modese_len = 10;
2707: else
2708: return -EINVAL;
2709: } else if (0 == modese_len)
2710: modese_len = 6;
2711: }
2712: if (10 == modese_len) {
2713: err = scsiModeSense10(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0,
2714: MPAGE_CONTROL_CURRENT,
2715: buff, sizeof(buff));
2716: if (err)
2717: return -EINVAL;
1.1.1.2 misho 2718: }
1.1 misho 2719: offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
2720: if ((offset >= 0) && (buff[offset + 1] > 1)) {
2721: if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */
1.1.1.2 misho 2722: (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
1.1 misho 2723: return (buff[offset + 2] & 0xf);
2724: }
2725: return -EINVAL;
2726: }
1.1.1.2 misho 2727:
2728: const unsigned char *
2729: sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len,
2730: int desc_type)
2731: {
2732: int add_sen_len, add_len, desc_len, k;
2733: const unsigned char * descp;
2734:
2735: if ((sense_len < 8) || (0 == (add_sen_len = sensep[7])))
2736: return NULL;
2737: if ((sensep[0] < 0x72) || (sensep[0] > 0x73))
2738: return NULL;
2739: add_sen_len = (add_sen_len < (sense_len - 8)) ?
2740: add_sen_len : (sense_len - 8);
2741: descp = &sensep[8];
2742: for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
2743: descp += desc_len;
2744: add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
2745: desc_len = add_len + 2;
2746: if (descp[0] == desc_type)
2747: return descp;
2748: if (add_len < 0) /* short descriptor ?? */
2749: break;
2750: }
2751: return NULL;
2752: }
2753:
2754: // Convenience function for formatting strings from SCSI identify
2755: void
2756: scsi_format_id_string(char * out, const unsigned char * in, int n)
2757: {
2758: char tmp[65];
2759: n = n > 64 ? 64 : n;
2760: strncpy(tmp, (const char *)in, n);
2761: tmp[n] = '\0';
2762:
2763: // Find the first non-space character (maybe none).
2764: int first = -1;
2765: int i;
2766: for (i = 0; tmp[i]; i++)
2767: if (!isspace((int)tmp[i])) {
2768: first = i;
2769: break;
2770: }
2771:
2772: if (first == -1) {
2773: // There are no non-space characters.
2774: out[0] = '\0';
2775: return;
2776: }
2777:
2778: // Find the last non-space character.
2779: for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--);
2780: int last = i;
2781:
2782: strncpy(out, tmp+first, last-first+1);
2783: out[last-first+1] = '\0';
2784: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>