File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / scsicmds.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:17:35 2013 UTC (10 years, 11 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v6_1p0, v6_1, HEAD
6.1

    1: /*
    2:  * scsicmds.cpp
    3:  *
    4:  * Home page of code is: http://smartmontools.sourceforge.net
    5:  *
    6:  * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
    7:  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
    8:  *
    9:  * Additional SCSI work:
   10:  * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com>
   11:  *
   12:  * This program is free software; you can redistribute it and/or modify
   13:  * it under the terms of the GNU General Public License as published by
   14:  * the Free Software Foundation; either version 2, or (at your option)
   15:  * any later version.
   16:  *
   17:  * You should have received a copy of the GNU General Public License
   18:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
   19:  *
   20:  * This code was originally developed as a Senior Thesis by Michael Cornwell
   21:  * at the Concurrent Systems Laboratory (now part of the Storage Systems
   22:  * Research Center), Jack Baskin School of Engineering, University of
   23:  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
   24:  *
   25:  *
   26:  * In the SCSI world "SMART" is a dead or withdrawn standard. In recent
   27:  * SCSI standards (since SCSI-3) it goes under the awkward name of
   28:  * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")].
   29:  * The relevant information is spread around several SCSI draft
   30:  * standards available at http://www.t10.org . Reference is made in the
   31:  * code to the following acronyms:
   32:  *      - SAM [SCSI Architectural model, versions 2 or 3]
   33:  *      - SPC [SCSI Primary commands, versions 2 or 3]
   34:  *      - SBC [SCSI Block commands, versions 2]
   35:  *
   36:  * Some SCSI disk vendors have snippets of "SMART" information in their
   37:  * product manuals.
   38:  */
   39: 
   40: #include <stdio.h>
   41: #include <string.h>
   42: #include <errno.h>
   43: 
   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: 
   51: const char *scsicmds_c_cvsid="$Id: scsicmds.cpp,v 1.1.1.2 2013/07/22 01:17:35 misho Exp $"
   52:   SCSICMDS_H_CVSID;
   53: 
   54: // Print SCSI debug messages?
   55: unsigned char scsi_debugmode = 0;
   56: 
   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: 
   88: /* output binary in hex and optionally ascii */
   89: void
   90: dStrHex(const char* str, int len, int no_ascii)
   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;
  101: 
  102:     if (len <= 0) return;
  103:     memset(buff,' ',80);
  104:     buff[80]='\0';
  105:     k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
  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++;
  116:         snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (int)(unsigned char)c);
  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);
  132:             k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a);
  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 */
  167:     {READ_DEFECT_12, "read defect list(12)"},   /* 0xb7 */
  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 */
  174: const char *
  175: scsi_get_opcode_name(UINT8 opcode)
  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: 
  193: void
  194: scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf,
  195:                      struct scsi_sense_disect * out)
  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);
  202:         out->resp_code = resp_code;
  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: 
  217: int
  218: scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo)
  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:
  225:         if (SCSI_ASC_NO_MEDIUM == sinfo->asc)
  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;
  240:         else if (SCSI_ASC_INVALID_FIELD == sinfo->asc)
  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: 
  255: const char *
  256: scsiErrString(int scsiErr)
  257: {
  258:     if (scsiErr < 0)
  259:         return strerror(-scsiErr);
  260:     switch (scsiErr) {
  261:         case SIMPLE_NO_ERROR:
  262:             return "no error";
  263:         case SIMPLE_ERR_NOT_READY:
  264:             return "device not ready";
  265:         case SIMPLE_ERR_BAD_OPCODE:
  266:             return "unsupported scsi opcode";
  267:         case SIMPLE_ERR_BAD_FIELD:
  268:             return "unsupported field in scsi command";
  269:         case SIMPLE_ERR_BAD_PARAM:
  270:             return "badly formed scsi parameters";
  271:         case SIMPLE_ERR_BAD_RESP:
  272:             return "scsi response fails sanity test";
  273:         case SIMPLE_ERR_NO_MEDIUM:
  274:             return "no medium present";
  275:         case SIMPLE_ERR_BECOMING_READY:
  276:             return "device will be ready soon";
  277:         case SIMPLE_ERR_TRY_AGAIN:
  278:             return "unit attention reported, try again";
  279:         case SIMPLE_ERR_MEDIUM_HARDWARE:
  280:             return "medium or hardware error (serious)";
  281:         case SIMPLE_ERR_UNKNOWN:
  282:             return "unknown error (unexpected sense key)";
  283:         case SIMPLE_ERR_ABORTED_COMMAND:
  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. */
  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)
  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. */
  328: int
  329: scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen,
  330:                       int * transport)
  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;
  335:     int si = 0;
  336: 
  337:     if (transport)
  338:         *transport = -1;
  339:     if (slen < 32) {
  340:         if (slen > 0)
  341:             s[0] = '\0';
  342:         return -1;
  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) {
  351:             snprintf(s+si, slen-si, "error: designator length");
  352:             return -1;
  353:         }
  354:         assoc = ((ucp[1] >> 4) & 0x3);
  355:         if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0))
  356:             *transport = (ucp[0] >> 4) & 0xf;
  357:         if (0 != assoc)
  358:             continue;
  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)) {
  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");
  375:             for (m = 0; m < i_len; ++m)
  376:                 si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
  377:             break;
  378:         case 3: /* NAA */
  379:             if (1 != c_set) {
  380:                 snprintf(s+si, slen-si, "error: NAA bad code_set");
  381:                 return -1;
  382:             }
  383:             naa = (ip[0] >> 4) & 0xff;
  384:             if ((naa < 2) || (naa > 6) || (4 == naa)) {
  385:                 snprintf(s+si, slen-si, "error: unexpected NAA");
  386:                 return -1;
  387:             }
  388:             if (have_scsi_ns)
  389:                 si = 0;
  390:             if (2 == naa) {             /* NAA IEEE Extended */
  391:                 if (8 != i_len) {
  392:                     snprintf(s+si, slen-si, "error: NAA 2 length");
  393:                     return -1;
  394:                 }
  395:                 si += snprintf(s+si, slen-si, "0x");
  396:                 for (m = 0; m < 8; ++m)
  397:                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
  398:             } else if ((3 == naa ) || (5 == naa)) {
  399:                 /* NAA=3 Locally assigned; NAA=5 IEEE Registered */
  400:                 if (8 != i_len) {
  401:                     snprintf(s+si, slen-si, "error: NAA 3 or 5 length");
  402:                     return -1;
  403:                 }
  404:                 si += snprintf(s+si, slen-si, "0x");
  405:                 for (m = 0; m < 8; ++m)
  406:                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
  407:             } else if (6 == naa) {      /* NAA IEEE Registered extended */
  408:                 if (16 != i_len) {
  409:                     snprintf(s+si, slen-si, "error: NAA 6 length");
  410:                     return -1;
  411:                 }
  412:                 si += snprintf(s+si, slen-si, "0x");
  413:                 for (m = 0; m < 16; ++m)
  414:                     si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]);
  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) {
  424:                 snprintf(s+si, slen-si, "error: SCSI name string");
  425:                 return -1;
  426:             }
  427:             /* does %s print out UTF-8 ok?? */
  428:             if (si == 0) {
  429:                 si += snprintf(s+si, slen-si, "%s", (const char *)ip);
  430:                 ++have_scsi_ns;
  431:             }
  432:             break;
  433:         default: /* reserved */
  434:             break;
  435:         }
  436:     }
  437:     if (-2 == u) {
  438:         snprintf(s+si, slen-si, "error: bad structure");
  439:         return -1;
  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
  451:    requesting the deduced response length. This protects certain fragile
  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. */
  454: int
  455: scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf,
  456:              int bufLen, int known_resp_len)
  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)
  508:             pageLen += 1;
  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) */
  547: int
  548: scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum,
  549:               int subpagenum, UINT8 *pBuf, int bufLen)
  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),
  581:  * 3 if field in command not supported or returns negated errno.
  582:  * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */
  583: int
  584: scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc,
  585:               UINT8 *pBuf, int bufLen)
  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,
  636:  * 2 if command not supported (then MODE SELECT(10) may be supported),
  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) */
  639: int
  640: scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
  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: 
  677: /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command
  678:  * not supported (then MODE SENSE(6) might be supported), 3 if field in
  679:  * command not supported or returns negated errno.
  680:  * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */
  681: int
  682: scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc,
  683:                 UINT8 *pBuf, int bufLen)
  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
  732:  * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if
  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) */
  736: int
  737: scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen)
  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;
  752:     pBuf[0] = 0;
  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) */
  778: int
  779: scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen)
  780: {
  781:     struct scsi_sense_disect sinfo;
  782:     struct scsi_cmnd_io io_hdr;
  783:     UINT8 cdb[6];
  784:     UINT8 sense[32];
  785: 
  786:     if ((bufLen < 0) || (bufLen > 1023))
  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;
  794:     cdb[3] = (bufLen >> 8) & 0xff;
  795:     cdb[4] = (bufLen & 0xff);
  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
  809:  * (unlikely), 2 if command not supported, 3 if field in command not
  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) */
  812: int
  813: scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen)
  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: 
  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))
  828:         return -EINVAL;
  829: try_again:
  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;
  840:     cdb[3] = (bufLen >> 8) & 0xff;
  841:     cdb[4] = (bufLen & 0xff);
  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);
  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: 
  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) */
  874: int
  875: scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info)
  876: {
  877:     struct scsi_cmnd_io io_hdr;
  878:     UINT8 cdb[6];
  879:     UINT8 sense[32];
  880:     UINT8 buff[18];
  881:     int len;
  882:     UINT8 resp_code;
  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) {
  900:         resp_code = buff[0] & 0x7f;
  901:         sense_info->resp_code = resp_code;
  902:         sense_info->sense_key = buff[2] & 0xf;
  903:         sense_info->asc = 0;
  904:         sense_info->ascq = 0;
  905:         if ((0x70 == resp_code) || (0x71 == resp_code)) {
  906:             len = buff[7] + 8;
  907:             if (len > 13) {
  908:                 sense_info->asc = buff[12];
  909:                 sense_info->ascq = buff[13];
  910:             }
  911:         }
  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:       }
  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) */
  955: int
  956: scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf,
  957:                    int bufLen)
  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;
  984: 
  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) */
  994: int
  995: scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf,
  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) */
 1026: static int
 1027: _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo)
 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 */
 1053: int
 1054: scsiTestUnitReady(scsi_device * device)
 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 */
 1065:         status = _testunitready(device, &sinfo);
 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) */
 1076: int
 1077: scsiReadDefect10(scsi_device * device, int req_plist, int req_glist,
 1078:                  int dl_format, UINT8 *pBuf, int bufLen)
 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: 
 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: 
 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) */
 1150: int
 1151: scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap,
 1152:                    unsigned int * lb_sizep)
 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) */
 1192: int
 1193: scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen)
 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. */
 1226: uint64_t
 1227: scsiGetSize(scsi_device * device, unsigned int * lb_sizep,
 1228:             int * lb_per_pb_expp)
 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) {
 1237:         if (scsi_debugmode)
 1238:             pout("scsiGetSize: READ CAPACITY(10) failed, res=%d\n", res);
 1239:         return 0;
 1240:     }
 1241:     if (0xffffffff == last_lba) {
 1242:         res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp));
 1243:         if (res) {
 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)
 1250:                 ret_val <<= 8;
 1251:             ret_val |= rc16resp[k + 0];
 1252:         }
 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:     }
 1260:     if (lb_sizep)
 1261:         *lb_sizep = lb_size;
 1262:     ++ret_val;  /* last_lba is origin 0 so need to bump to get number of */
 1263:     return ret_val * lb_size;
 1264: }
 1265: 
 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: }
 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 */
 1290: int
 1291: scsiModePageOffset(const UINT8 * resp, int len, int modese_len)
 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. */
 1333: int
 1334: scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp,
 1335:                   int modese_len)
 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:         }
 1363:     }
 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)
 1371:         err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE,
 1372:                             0, MPAGE_CONTROL_CHANGEABLE,
 1373:                             iecp->raw_chg, sizeof(iecp->raw_chg));
 1374:     if (err)
 1375:         return err;
 1376:     iecp->gotChangeable = 1;
 1377:     return 0;
 1378: }
 1379: 
 1380: int
 1381: scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
 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: 
 1396: int
 1397: scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp)
 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 */
 1413: #define SCSI_IEC_MP_BYTE2_ENABLED 0x10
 1414: #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4
 1415: /* exception/warning via an unrequested REQUEST SENSE command */
 1416: #define SCSI_IEC_MP_MRIE 6
 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). */
 1427: int
 1428: scsiSetExceptionControlAndWarning(scsi_device * device, int enabled,
 1429:                                   const struct scsi_iec_mode_page *iecp)
 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:         }
 1487:         if (wEnabled)
 1488:             rout[offset + 2] &= EWASC_DISABLE;
 1489:         if (eCEnabled) {
 1490:             if (iecp->gotChangeable &&
 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: 
 1503: int
 1504: scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp)
 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. */
 1526: int
 1527: scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage,
 1528:             UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp)
 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;
 1536: 
 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
 1550:         pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4;
 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) {
 1556:             sense_info.asc = tBuf[8];
 1557:             sense_info.ascq = tBuf[9];
 1558:             if (! hasTempLogPage) {
 1559:                 if (tBuf[7] > 2)
 1560:                     *currenttemp = tBuf[10];
 1561:                 if (tBuf[7] > 3)        /* IBM extension in SMART (IE) lpage */
 1562:                     *triptemp = tBuf[11];
 1563:             }
 1564:         }
 1565:     }
 1566:     if (0 == sense_info.asc) {
 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
 1585: static const char * TapeAlertsMessageTable[]= {
 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: 
 1809: const char *
 1810: scsiTapeAlertsTapeDevice(unsigned short code)
 1811: {
 1812:     const int num = sizeof(TapeAlertsMessageTable) /
 1813:                         sizeof(TapeAlertsMessageTable[0]);
 1814: 
 1815:     return (code < num) ?  TapeAlertsMessageTable[code] : "Unknown Alert";
 1816: }
 1817: 
 1818: // The first character (W, C, I) tells the severity
 1819: static const char * ChangerTapeAlertsMessageTable[]= {
 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: 
 1945: const char *
 1946: scsiTapeAlertsChangerDevice(unsigned short code)
 1947: {
 1948:     const int num = sizeof(ChangerTapeAlertsMessageTable) /
 1949:                         sizeof(ChangerTapeAlertsMessageTable[0]);
 1950: 
 1951:     return (code < num) ?  ChangerTapeAlertsMessageTable[code] : "Unknown Alert";
 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: 
 2080: const char *
 2081: scsiGetIEString(UINT8 asc, UINT8 ascq)
 2082: {
 2083:     const char * rp;
 2084: 
 2085:     if (SCSI_ASC_IMPENDING_FAILURE == asc) {
 2086:         if (ascq == 0xff)
 2087:             return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)";
 2088:         else if (ascq <
 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. */
 2112: int
 2113: scsiSmartIBMOfflineTest(scsi_device * device)
 2114: {
 2115:     UINT8 tBuf[256];
 2116:     int res;
 2117: 
 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: 
 2134: int
 2135: scsiSmartDefaultSelfTest(scsi_device * device)
 2136: {
 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: 
 2145: int
 2146: scsiSmartShortSelfTest(scsi_device * device)
 2147: {
 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: 
 2156: int
 2157: scsiSmartExtendSelfTest(scsi_device * device)
 2158: {
 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: 
 2168: int
 2169: scsiSmartShortCapSelfTest(scsi_device * device)
 2170: {
 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: 
 2179: int
 2180: scsiSmartExtendCapSelfTest(scsi_device * device)
 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: 
 2191: int
 2192: scsiSmartSelfTestAbort(scsi_device * device)
 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. */
 2204: int
 2205: scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec,
 2206:                               int modese_len)
 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,
 2225:                               MPAGE_CONTROL_CURRENT,
 2226:                               buff, sizeof(buff));
 2227:         if (err)
 2228:             return err;
 2229:     }
 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: 
 2242: void
 2243: scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp)
 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) {
 2257:             case 0:
 2258:             case 1:
 2259:             case 2:
 2260:             case 3:
 2261:             case 4:
 2262:             case 5:
 2263:             case 6:
 2264:                 ecp->gotPC[pc] = 1;
 2265:                 ullp = &ecp->counter[pc];
 2266:                 break;
 2267:         default:
 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: 
 2289: void
 2290: scsiDecodeNonMediumErrPage(unsigned char *resp,
 2291:                            struct scsiNonMediumError *nmep)
 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) {
 2305:             case 0:
 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;
 2320:             case 0x8009:
 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;
 2335:             case 0x8015:
 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;
 2350:         default:
 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
 2364:    tests (typically by the user) and self tests in progress are not
 2365:    considered failures. See Working Draft SCSI Primary Commands - 3
 2366:    (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */
 2367: int
 2368: scsiCountFailedSelfTests(scsi_device * fd, int noisy)
 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++;
 2408:             if (1 == fails)
 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. */
 2417: int
 2418: scsiSelfTestInProgress(scsi_device * fd, int * inProgress)
 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. */
 2445: int
 2446: scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current)
 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;
 2468:     }
 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: 
 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: 
 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). */
 2623: int
 2624: scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len)
 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;
 2648:     }
 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 */
 2670: 
 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: 
 2690: /* Returns a negative value if failed to fetch Protocol specific port mode
 2691:    page or it was malformed. Returns transport protocol identifier when
 2692:    value >= 0 . */
 2693: int
 2694: scsiFetchTransportProtocol(scsi_device * device, int modese_len)
 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;
 2717:     }
 2718:     offset = scsiModePageOffset(buff, sizeof(buff), modese_len);
 2719:     if ((offset >= 0) && (buff[offset + 1] > 1)) {
 2720:         if ((0 == (buff[offset] & 0x40)) &&       /* SPF==0 */
 2721:             (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f)))
 2722:                 return (buff[offset + 2] & 0xf);
 2723:     }
 2724:     return -EINVAL;
 2725: }
 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>