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