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