File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / scsiprint.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:32:16 2012 UTC (12 years, 4 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, v5_42, HEAD
smartmontools

    1: /*
    2:  * scsiprint.cpp
    3:  *
    4:  * Home page of code is: http://smartmontools.sourceforge.net
    5:  *
    6:  * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
    7:  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
    8:  *
    9:  * Additional SCSI work:
   10:  * Copyright (C) 2003-10 Douglas Gilbert <dgilbert@interlog.com>
   11:  *
   12:  * This program is free software; you can redistribute it and/or modify
   13:  * it under the terms of the GNU General Public License as published by
   14:  * the Free Software Foundation; either version 2, or (at your option)
   15:  * any later version.
   16:  *
   17:  * You should have received a copy of the GNU General Public License
   18:  * (for example COPYING); if not, write to the Free
   19:  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   20:  *
   21:  * This code was originally developed as a Senior Thesis by Michael Cornwell
   22:  * at the Concurrent Systems Laboratory (now part of the Storage Systems
   23:  * Research Center), Jack Baskin School of Engineering, University of
   24:  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
   25:  *
   26:  */
   27: 
   28: 
   29: #include <stdio.h>
   30: #include <string.h>
   31: #include <fcntl.h>
   32: #include <errno.h>
   33: 
   34: #include "config.h"
   35: #include "int64.h"
   36: #include "scsicmds.h"
   37: #include "atacmds.h" // smart_command_set
   38: #include "dev_interface.h"
   39: #include "scsiprint.h"
   40: #include "smartctl.h"
   41: #include "utility.h"
   42: 
   43: #define GBUF_SIZE 65535
   44: 
   45: const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp,v 1.1.1.1 2012/02/21 16:32:16 misho Exp $"
   46:                                  SCSIPRINT_H_CVSID;
   47: 
   48: 
   49: UINT8 gBuf[GBUF_SIZE];
   50: #define LOG_RESP_LEN 252
   51: #define LOG_RESP_LONG_LEN ((62 * 256) + 252)
   52: #define LOG_RESP_TAPE_ALERT_LEN 0x144
   53: 
   54: /* Log pages supported */
   55: static int gSmartLPage = 0;     /* Informational Exceptions log page */
   56: static int gTempLPage = 0;
   57: static int gSelfTestLPage = 0;
   58: static int gStartStopLPage = 0;
   59: static int gReadECounterLPage = 0;
   60: static int gWriteECounterLPage = 0;
   61: static int gVerifyECounterLPage = 0;
   62: static int gNonMediumELPage = 0;
   63: static int gLastNErrorLPage = 0;
   64: static int gBackgroundResultsLPage = 0;
   65: static int gProtocolSpecificLPage = 0;
   66: static int gTapeAlertsLPage = 0;
   67: static int gSSMediaLPage = 0;
   68: 
   69: /* Vendor specific log pages */
   70: static int gSeagateCacheLPage = 0;
   71: static int gSeagateFactoryLPage = 0;
   72: 
   73: /* Mode pages supported */
   74: static int gIecMPage = 1;     /* N.B. assume it until we know otherwise */
   75: 
   76: /* Remember last successful mode sense/select command */
   77: static int modese_len = 0;
   78: 
   79: static void scsiGetSupportedLogPages(scsi_device * device)
   80: {
   81:     int i, err;
   82: 
   83:     if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf,
   84:                             LOG_RESP_LEN, 0))) {
   85:         if (scsi_debugmode > 0)
   86:             pout("Log Sense for supported pages failed [%s]\n", 
   87:                  scsiErrString(err)); 
   88:         return;
   89:     } 
   90: 
   91:     for (i = 4; i < gBuf[3] + LOGPAGEHDRSIZE; i++) {
   92:         switch (gBuf[i])
   93:         {
   94:             case READ_ERROR_COUNTER_LPAGE:
   95:                 gReadECounterLPage = 1;
   96:                 break;
   97:             case WRITE_ERROR_COUNTER_LPAGE:
   98:                 gWriteECounterLPage = 1;
   99:                 break;
  100:             case VERIFY_ERROR_COUNTER_LPAGE:
  101:                 gVerifyECounterLPage = 1;
  102:                 break;
  103:             case LAST_N_ERROR_LPAGE:
  104:                 gLastNErrorLPage = 1;
  105:                 break;
  106:             case NON_MEDIUM_ERROR_LPAGE:
  107:                 gNonMediumELPage = 1;
  108:                 break;
  109:             case TEMPERATURE_LPAGE:
  110:                 gTempLPage = 1;
  111:                 break;
  112:             case STARTSTOP_CYCLE_COUNTER_LPAGE:
  113:                 gStartStopLPage = 1;
  114:                 break;
  115:             case SELFTEST_RESULTS_LPAGE:
  116:                 gSelfTestLPage = 1;
  117:                 break;
  118:             case IE_LPAGE:
  119:                 gSmartLPage = 1;
  120:                 break;
  121:             case BACKGROUND_RESULTS_LPAGE:
  122:                 gBackgroundResultsLPage = 1;
  123:                 break;
  124:             case PROTOCOL_SPECIFIC_LPAGE:
  125:                 gProtocolSpecificLPage = 1;
  126:                 break;
  127:             case TAPE_ALERTS_LPAGE:
  128:                 gTapeAlertsLPage = 1;
  129:                 break;
  130:             case SS_MEDIA_LPAGE:
  131:                 gSSMediaLPage = 1;
  132:                 break;
  133:             case SEAGATE_CACHE_LPAGE:
  134:                 gSeagateCacheLPage = 1;
  135:                 break;
  136:             case SEAGATE_FACTORY_LPAGE:
  137:                 gSeagateFactoryLPage = 1;
  138:                 break;
  139:             default:
  140:                 break;
  141:         }
  142:     }
  143: }
  144: 
  145: /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad
  146:    (or at least something to report). */
  147: static int scsiGetSmartData(scsi_device * device, bool attribs)
  148: {
  149:     UINT8 asc;
  150:     UINT8 ascq;
  151:     UINT8 currenttemp = 0;
  152:     UINT8 triptemp = 0;
  153:     const char * cp;
  154:     int err = 0;
  155: 
  156:     print_on();
  157:     if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq,
  158:                     &currenttemp, &triptemp)) {
  159:         /* error message already announced */
  160:         print_off();
  161:         return -1;
  162:     }
  163:     print_off();
  164:     cp = scsiGetIEString(asc, ascq);
  165:     if (cp) {
  166:         err = -2;
  167:         print_on();
  168:         pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq); 
  169:         print_off();
  170:     } else if (gIecMPage)
  171:         pout("SMART Health Status: OK\n");
  172: 
  173:     if (attribs && !gTempLPage) {
  174:         if (currenttemp || triptemp)
  175:             pout("\n");
  176:         if (currenttemp) {
  177:             if (255 != currenttemp)
  178:                 pout("Current Drive Temperature:     %d C\n", currenttemp);
  179:             else
  180:                 pout("Current Drive Temperature:     <not available>\n");
  181:         }
  182:         if (triptemp)
  183:             pout("Drive Trip Temperature:        %d C\n", triptemp);
  184:     }
  185:     return err;
  186: }
  187: 
  188: 
  189: // Returns number of logged errors or zero if none or -1 if fetching
  190: // TapeAlerts fails
  191: static const char * const severities = "CWI";
  192: 
  193: static int scsiGetTapeAlertsData(scsi_device * device, int peripheral_type)
  194: {
  195:     unsigned short pagelength;
  196:     unsigned short parametercode;
  197:     int i, err;
  198:     const char *s;
  199:     const char *ts;
  200:     int failures = 0;
  201: 
  202:     print_on();
  203:     if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf,
  204:                         LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) {
  205:         pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err));
  206:         print_off();
  207:         return -1;
  208:     }
  209:     if (gBuf[0] != 0x2e) {
  210:         pout("TapeAlerts Log Sense Failed\n");
  211:         print_off();
  212:         return -1;
  213:     }
  214:     pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];
  215: 
  216:     for (s=severities; *s; s++) {
  217:         for (i = 4; i < pagelength; i += 5) {
  218:             parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1];
  219: 
  220:             if (gBuf[i + 4]) {
  221:                 ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ?
  222:                     scsiTapeAlertsChangerDevice(parametercode) :
  223:                     scsiTapeAlertsTapeDevice(parametercode);
  224:                 if (*ts == *s) {
  225:                     if (!failures)
  226:                         pout("TapeAlert Errors (C=Critical, W=Warning, I=Informational):\n");
  227:                     pout("[0x%02x] %s\n", parametercode, ts);
  228:                     failures += 1; 
  229:                 }
  230:             }
  231:         }
  232:     }
  233:     print_off();
  234: 
  235:     if (! failures)
  236:         pout("TapeAlert: OK\n");
  237: 
  238:     return failures;
  239: }
  240: 
  241: static void scsiGetStartStopData(scsi_device * device)
  242: {
  243:     UINT32 u;
  244:     int err, len, k, extra, pc;
  245:     unsigned char * ucp;
  246: 
  247:     if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf,
  248:                             LOG_RESP_LEN, 0))) {
  249:         print_on();
  250:         pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err));
  251:         print_off();
  252:         return;
  253:     }
  254:     if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) {
  255:         print_on();
  256:         pout("StartStop Log Sense Failed, page mismatch\n");
  257:         print_off();
  258:         return;
  259:     }
  260:     len = ((gBuf[2] << 8) | gBuf[3]);
  261:     ucp = gBuf + 4;
  262:     for (k = len; k > 0; k -= extra, ucp += extra) {
  263:         if (k < 3) {
  264:             print_on();
  265:             pout("StartStop Log Sense Failed: short\n");
  266:             print_off();
  267:             return;
  268:         }
  269:         extra = ucp[3] + 4;
  270:         pc = (ucp[0] << 8) + ucp[1];
  271:         switch (pc) {
  272:         case 1:
  273:             if (10 == extra)
  274:                 pout("Manufactured in week %.2s of year %.4s\n", ucp + 8,
  275:                      ucp + 4);
  276:             break;
  277:         case 2:
  278:             /* ignore Accounting date */
  279:             break;
  280:         case 3:
  281:             if (extra > 7) {
  282:                 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
  283:                 if (0xffffffff != u)
  284:                     pout("Specified cycle count over device lifetime:  %u\n",
  285:                          u);
  286:             }
  287:             break;
  288:         case 4:
  289:             if (extra > 7) {
  290:                 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
  291:                 if (0xffffffff != u)
  292:                     pout("Accumulated start-stop cycles:  %u\n", u);
  293:             }
  294:             break;
  295:         case 5:
  296:             if (extra > 7) {
  297:                 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
  298:                 if (0xffffffff != u)
  299:                     pout("Specified load-unload count over device "
  300:                          "lifetime:  %u\n", u);
  301:             }
  302:             break;
  303:         case 6:
  304:             if (extra > 7) {
  305:                 u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7];
  306:                 if (0xffffffff != u)
  307:                     pout("Accumulated load-unload cycles:  %u\n", u);
  308:             }
  309:             break;
  310:         default:
  311:             /* ignore */
  312:             break;
  313:         }
  314:     }
  315: } 
  316: 
  317: static void scsiPrintGrownDefectListLen(scsi_device * device)
  318: {
  319:     int err, dl_format, dl_len, div;
  320: 
  321:     memset(gBuf, 0, 4);
  322:     if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */,
  323:                                 4 /* bytes from index */, gBuf, 4))) {
  324:         if (scsi_debugmode > 0) {
  325:             print_on();
  326:             pout("Read defect list (10) Failed: %s\n", scsiErrString(err));
  327:             print_off();
  328:         }
  329:         return;
  330:     }
  331:     if (0x8 != (gBuf[1] & 0x18)) {
  332:         print_on();
  333:         pout("Read defect list: asked for grown list but didn't get it\n");
  334:         print_off();
  335:         return;
  336:     }
  337:     div = 0;
  338:     dl_format = (gBuf[1] & 0x7);
  339:     switch (dl_format) {
  340:         case 0:     /* short block */
  341:             div = 4;
  342:             break;
  343:         case 3:     /* long block */
  344:         case 4:     /* bytes from index */
  345:         case 5:     /* physical sector */
  346:             div = 8;
  347:             break;
  348:         default:
  349:             print_on();
  350:             pout("defect list format %d unknown\n", dl_format);
  351:             print_off();
  352:             break;
  353:     }
  354:     dl_len = (gBuf[2] << 8) + gBuf[3];
  355:     if (0 == dl_len)
  356:         pout("Elements in grown defect list: 0\n");
  357:     else {
  358:         if (0 == div)
  359:             pout("Grown defect list length=%d bytes [unknown "
  360:                  "number of elements]\n", dl_len);
  361:         else
  362:             pout("Elements in grown defect list: %d\n", dl_len / div);
  363:     }
  364: }
  365: 
  366: static void scsiPrintSeagateCacheLPage(scsi_device * device)
  367: {
  368:     int k, j, num, pl, pc, err, len;
  369:     unsigned char * ucp;
  370:     unsigned char * xp;
  371:     uint64_t ull;
  372: 
  373:     if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf,
  374:                             LOG_RESP_LEN, 0))) {
  375:         print_on();
  376:         pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err));
  377:         print_off();
  378:         return;
  379:     }
  380:     if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) {
  381:         print_on();
  382:         pout("Seagate Cache Log Sense Failed, page mismatch\n");
  383:         print_off();
  384:         return;
  385:     }
  386:     len = ((gBuf[2] << 8) | gBuf[3]) + 4;
  387:     num = len - 4;
  388:     ucp = &gBuf[0] + 4;
  389:     while (num > 3) {
  390:         pc = (ucp[0] << 8) | ucp[1];
  391:         pl = ucp[3] + 4;
  392:         switch (pc) {
  393:         case 0: case 1: case 2: case 3: case 4:
  394:             break;
  395:         default: 
  396:             if (scsi_debugmode > 0) {
  397:                 print_on();
  398:                 pout("Vendor (Seagate) cache lpage has unexpected parameter"
  399:                      ", skip\n");
  400:                 print_off();
  401:             }
  402:             return;
  403:         }
  404:         num -= pl;
  405:         ucp += pl;
  406:     }
  407:     pout("Vendor (Seagate) cache information\n");
  408:     num = len - 4;
  409:     ucp = &gBuf[0] + 4;
  410:     while (num > 3) {
  411:         pc = (ucp[0] << 8) | ucp[1];
  412:         pl = ucp[3] + 4;
  413:         switch (pc) {
  414:         case 0: pout("  Blocks sent to initiator"); break;
  415:         case 1: pout("  Blocks received from initiator"); break;
  416:         case 2: pout("  Blocks read from cache and sent to initiator"); break;
  417:         case 3: pout("  Number of read and write commands whose size "
  418:                        "<= segment size"); break;
  419:         case 4: pout("  Number of read and write commands whose size "
  420:                        "> segment size"); break;
  421:         default: pout("  Unknown Seagate parameter code [0x%x]", pc); break;
  422:         }
  423:         k = pl - 4;
  424:         xp = ucp + 4;
  425:         if (k > (int)sizeof(ull)) {
  426:             xp += (k - (int)sizeof(ull));
  427:             k = (int)sizeof(ull);
  428:         }
  429:         ull = 0;
  430:         for (j = 0; j < k; ++j) {
  431:             if (j > 0)
  432:                 ull <<= 8;
  433:             ull |= xp[j];
  434:         }
  435:         pout(" = %"PRIu64"\n", ull);
  436:         num -= pl;
  437:         ucp += pl;
  438:     }
  439: }
  440: 
  441: static void scsiPrintSeagateFactoryLPage(scsi_device * device)
  442: {
  443:     int k, j, num, pl, pc, len, err, good, bad;
  444:     unsigned char * ucp;
  445:     unsigned char * xp;
  446:     uint64_t ull;
  447: 
  448:     if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf,
  449:                             LOG_RESP_LEN, 0))) {
  450:         print_on();
  451:         pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err));
  452:         print_off();
  453:         return;
  454:     }
  455:     if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) {
  456:         print_on();
  457:         pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n");
  458:         print_off();
  459:         return;
  460:     }
  461:     len = ((gBuf[2] << 8) | gBuf[3]) + 4;
  462:     num = len - 4;
  463:     ucp = &gBuf[0] + 4;
  464:     good = 0;
  465:     bad = 0;
  466:     while (num > 3) {
  467:         pc = (ucp[0] << 8) | ucp[1];
  468:         pl = ucp[3] + 4;
  469:         switch (pc) {
  470:         case 0: case 8:
  471:             ++good;
  472:             break;
  473:         default: 
  474:             ++bad;
  475:             break;
  476:         }
  477:         num -= pl;
  478:         ucp += pl;
  479:     }
  480:     if ((good < 2) || (bad > 4)) {  /* heuristic */
  481:         if (scsi_debugmode > 0) {
  482:             print_on();
  483:             pout("\nVendor (Seagate/Hitachi) factory lpage has too many "
  484:                  "unexpected parameters, skip\n");
  485:             print_off();
  486:         }
  487:         return;
  488:     }
  489:     pout("Vendor (Seagate/Hitachi) factory information\n");
  490:     num = len - 4;
  491:     ucp = &gBuf[0] + 4;
  492:     while (num > 3) {
  493:         pc = (ucp[0] << 8) | ucp[1];
  494:         pl = ucp[3] + 4;
  495:         good = 0;
  496:         switch (pc) {
  497:         case 0: pout("  number of hours powered up");
  498:             good = 1;
  499:             break;
  500:         case 8: pout("  number of minutes until next internal SMART test");
  501:             good = 1;
  502:             break;
  503:         default:
  504:             if (scsi_debugmode > 0) {
  505:                 print_on();
  506:                 pout("Vendor (Seagate/Hitachi) factory lpage: "
  507:                      "unknown parameter code [0x%x]\n", pc);
  508:                 print_off();
  509:             }
  510:             break;
  511:         }
  512:         if (good) {
  513:             k = pl - 4;
  514:             xp = ucp + 4;
  515:             if (k > (int)sizeof(ull)) {
  516:                 xp += (k - (int)sizeof(ull));
  517:                 k = (int)sizeof(ull);
  518:             }
  519:             ull = 0;
  520:             for (j = 0; j < k; ++j) {
  521:                 if (j > 0)
  522:                     ull <<= 8;
  523:                 ull |= xp[j];
  524:             }
  525:             if (0 == pc)
  526:                 pout(" = %.2f\n", ull / 60.0 );
  527:             else
  528:                 pout(" = %"PRIu64"\n", ull);
  529:         }
  530:         num -= pl;
  531:         ucp += pl;
  532:     }
  533: }
  534: 
  535: static void scsiPrintErrorCounterLog(scsi_device * device)
  536: {
  537:     struct scsiErrorCounter errCounterArr[3];
  538:     struct scsiErrorCounter * ecp;
  539:     struct scsiNonMediumError nme;
  540:     int found[3] = {0, 0, 0};
  541:     const char * pageNames[3] = {"read:   ", "write:  ", "verify: "};
  542:     double processed_gb;
  543: 
  544:     if (gReadECounterLPage && (0 == scsiLogSense(device,
  545:                 READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
  546:         scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]);
  547:         found[0] = 1;
  548:     }
  549:     if (gWriteECounterLPage && (0 == scsiLogSense(device,
  550:                 WRITE_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
  551:         scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]);
  552:         found[1] = 1;
  553:     }
  554:     if (gVerifyECounterLPage && (0 == scsiLogSense(device,
  555:                 VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
  556:         scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]);
  557:         ecp = &errCounterArr[2];
  558:         for (int k = 0; k < 7; ++k) {
  559:             if (ecp->gotPC[k] && ecp->counter[k]) {
  560:                 found[2] = 1;
  561:                 break;
  562:             }
  563:         }
  564:     }
  565:     if (found[0] || found[1] || found[2]) {
  566:         pout("\nError counter log:\n");
  567:         pout("           Errors Corrected by           Total   "
  568:              "Correction     Gigabytes    Total\n");
  569:         pout("               ECC          rereads/    errors   "
  570:              "algorithm      processed    uncorrected\n");
  571:         pout("           fast | delayed   rewrites  corrected  "
  572:              "invocations   [10^9 bytes]  errors\n");
  573:         for (int k = 0; k < 3; ++k) {
  574:             if (! found[k])
  575:                 continue;
  576:             ecp = &errCounterArr[k];
  577:             pout("%s%8"PRIu64" %8"PRIu64"  %8"PRIu64"  %8"PRIu64"   %8"PRIu64, 
  578:                  pageNames[k], ecp->counter[0], ecp->counter[1], 
  579:                  ecp->counter[2], ecp->counter[3], ecp->counter[4]);
  580:             processed_gb = ecp->counter[5] / 1000000000.0;
  581:             pout("   %12.3f    %8"PRIu64"\n", processed_gb, ecp->counter[6]);
  582:         }
  583:     }
  584:     else 
  585:         pout("\nError Counter logging not supported\n");
  586:     if (gNonMediumELPage && (0 == scsiLogSense(device,
  587:                 NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) {
  588:         scsiDecodeNonMediumErrPage(gBuf, &nme);
  589:         if (nme.gotPC0)
  590:             pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0);
  591:         if (nme.gotTFE_H)
  592:             pout("Track following error count [Hitachi]: %8"PRIu64"\n",
  593:                  nme.counterTFE_H);
  594:         if (nme.gotPE_H)
  595:             pout("Positioning error count [Hitachi]: %8"PRIu64"\n",
  596:                  nme.counterPE_H);
  597:     }
  598:     if (gLastNErrorLPage && (0 == scsiLogSense(device,
  599:                 LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) {
  600:         int num = (gBuf[2] << 8) + gBuf[3] + 4;
  601:         int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
  602:         if (truncated)
  603:             num = LOG_RESP_LONG_LEN;
  604:         unsigned char * ucp = gBuf + 4;
  605:         num -= 4;
  606:         if (num < 4)
  607:             pout("\nNo error events logged\n");
  608:         else {
  609:             pout("\nLast n error events log page\n");
  610:             for (int k = num, pl; k > 0; k -= pl, ucp += pl) {
  611:                 if (k < 3) {
  612:                     pout("  <<short Last n error events log page>>\n");
  613:                     break;
  614:                 }
  615:                 pl = ucp[3] + 4;
  616:                 int pc = (ucp[0] << 8) + ucp[1];
  617:                 if (pl > 4) {
  618:                     if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) {
  619:                         pout("  Error event %d:\n", pc);
  620:                         pout("    [binary]:\n");
  621:                         dStrHex((const char *)ucp + 4, pl - 4, 1);
  622:                     } else if (ucp[2] & 0x1) {
  623:                         pout("  Error event %d:\n", pc);
  624:                         pout("    %.*s\n", pl - 4, (const char *)(ucp + 4));
  625:                     } else {
  626:                         if (scsi_debugmode > 0) {
  627:                             pout("  Error event %d:\n", pc);
  628:                             pout("    [data counter??]:\n");
  629:                             dStrHex((const char *)ucp + 4, pl - 4, 1);
  630:                         }
  631:                     }
  632:                 }
  633:             }
  634:             if (truncated)
  635:                 pout(" >>>> log truncated, fetched %d of %d available "
  636:                      "bytes\n", LOG_RESP_LONG_LEN, truncated);
  637:         }
  638:     }
  639: }
  640: 
  641: static const char * self_test_code[] = {
  642:         "Default         ", 
  643:         "Background short", 
  644:         "Background long ", 
  645:         "Reserved(3)     ",
  646:         "Abort background", 
  647:         "Foreground short", 
  648:         "Foreground long ",
  649:         "Reserved(7)     "
  650: };
  651: 
  652: static const char * self_test_result[] = {
  653:         "Completed                ",
  654:         "Aborted (by user command)",
  655:         "Aborted (device reset ?) ",
  656:         "Unknown error, incomplete",
  657:         "Completed, segment failed",
  658:         "Failed in first segment  ",
  659:         "Failed in second segment ",
  660:         "Failed in segment -->    ",
  661:         "Reserved(8)              ", 
  662:         "Reserved(9)              ", 
  663:         "Reserved(10)             ", 
  664:         "Reserved(11)             ", 
  665:         "Reserved(12)             ", 
  666:         "Reserved(13)             ", 
  667:         "Reserved(14)             ",
  668:         "Self test in progress ..."
  669: };
  670: 
  671: // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 .
  672: // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
  673: // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
  674: // FAILSMART is returned.
  675: static int scsiPrintSelfTest(scsi_device * device)
  676: {
  677:     int num, k, n, res, err, durationSec;
  678:     int noheader = 1;
  679:     int retval = 0;
  680:     UINT8 * ucp;
  681:     uint64_t ull=0;
  682: 
  683:     if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf,
  684:                             LOG_RESP_SELF_TEST_LEN, 0))) {
  685:         print_on();
  686:         pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err));
  687:         print_off();
  688:         return FAILSMART;
  689:     }
  690:     if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) {
  691:         print_on();
  692:         pout("Self-test Log Sense Failed, page mismatch\n");
  693:         print_off();
  694:         return FAILSMART;
  695:     }
  696:     // compute page length
  697:     num = (gBuf[2] << 8) + gBuf[3];
  698:     // Log sense page length 0x190 bytes
  699:     if (num != 0x190) {
  700:         print_on();
  701:         pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num);
  702:         print_off();
  703:         return FAILSMART;
  704:     }
  705:     // loop through the twenty possible entries
  706:     for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) {
  707:         int i;
  708: 
  709:         // timestamp in power-on hours (or zero if test in progress)
  710:         n = (ucp[6] << 8) | ucp[7];
  711: 
  712:         // The spec says "all 20 bytes will be zero if no test" but
  713:         // DG has found otherwise.  So this is a heuristic.
  714:         if ((0 == n) && (0 == ucp[4]))
  715:             break;
  716: 
  717:         // only print header if needed
  718:         if (noheader) {
  719:             pout("\nSMART Self-test log\n");
  720:             pout("Num  Test              Status                 segment  "
  721:                    "LifeTime  LBA_first_err [SK ASC ASQ]\n");
  722:             pout("     Description                              number   "
  723:                    "(hours)\n");
  724:             noheader=0;
  725:         }
  726: 
  727:         // print parameter code (test number) & self-test code text
  728:         pout("#%2d  %s", (ucp[0] << 8) | ucp[1], 
  729:             self_test_code[(ucp[4] >> 5) & 0x7]);
  730: 
  731:         // check the self-test result nibble, using the self-test results
  732:         // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10:
  733:         switch ((res = ucp[4] & 0xf)) {
  734:         case 0x3:
  735:             // an unknown error occurred while the device server
  736:             // was processing the self-test and the device server
  737:             // was unable to complete the self-test
  738:             retval|=FAILSMART;
  739:             break;
  740:         case 0x4:
  741:             // the self-test completed with a failure in a test
  742:             // segment, and the test segment that failed is not
  743:             // known
  744:             retval|=FAILLOG;
  745:             break;
  746:         case 0x5:
  747:             // the first segment of the self-test failed
  748:             retval|=FAILLOG;
  749:             break;
  750:         case 0x6:
  751:             // the second segment of the self-test failed
  752:             retval|=FAILLOG;
  753:             break;
  754:         case 0x7:
  755:             // another segment of the self-test failed and which
  756:             // test is indicated by the contents of the SELF-TEST
  757:             // NUMBER field
  758:             retval|=FAILLOG;
  759:             break;
  760:         default:
  761:             break;
  762:         }
  763:         pout("  %s", self_test_result[res]);
  764: 
  765:         // self-test number identifies test that failed and consists
  766:         // of either the number of the segment that failed during
  767:         // the test, or the number of the test that failed and the
  768:         // number of the segment in which the test was run, using a
  769:         // vendor-specific method of putting both numbers into a
  770:         // single byte.
  771:         if (ucp[5])
  772:             pout(" %3d",  (int)ucp[5]);
  773:         else
  774:             pout("   -");
  775: 
  776:         // print time that the self-test was completed
  777:         if (n==0 && res==0xf)
  778:         // self-test in progress
  779:             pout("     NOW");
  780:         else   
  781:             pout("   %5d", n);
  782:           
  783:         // construct 8-byte integer address of first failure
  784:         for (i = 0; i < 8; i++) {
  785:             ull <<= 8;
  786:             ull |= ucp[i+8];
  787:         }
  788:         // print Address of First Failure, if sensible
  789:         if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) {
  790:             char buff[32];
  791: 
  792:             // was hex but change to decimal to conform with ATA
  793:             snprintf(buff, sizeof(buff), "%"PRIu64, ull);
  794:             // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull);
  795:             pout("%18s", buff);
  796:         } else
  797:             pout("                 -");
  798: 
  799:         // if sense key nonzero, then print it, along with
  800:         // additional sense code and additional sense code qualifier
  801:         if (ucp[16] & 0xf)
  802:             pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]);
  803:         else
  804:             pout(" [-   -    -]\n");
  805:     }
  806: 
  807:     // if header never printed, then there was no output
  808:     if (noheader)
  809:         pout("No self-tests have been logged\n");
  810:     else
  811:         pout("\n");
  812:     if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
  813:                         modese_len)) && (durationSec > 0)) {
  814:         pout("Long (extended) Self Test duration: %d seconds "
  815:              "[%.1f minutes]\n", durationSec, durationSec / 60.0);
  816:     }
  817:     return retval;
  818: }
  819: 
  820: static const char * bms_status[] = {
  821:     "no scans active",
  822:     "scan is active",
  823:     "pre-scan is active",
  824:     "halted due to fatal error",
  825:     "halted due to a vendor specific pattern of error",
  826:     "halted due to medium formatted without P-List",
  827:     "halted - vendor specific cause",
  828:     "halted due to temperature out of range",
  829:     "waiting until BMS interval timer expires", /* 8 */
  830: };
  831: 
  832: static const char * reassign_status[] = {
  833:     "Reserved [0x0]",
  834:     "Require Write or Reassign Blocks command",
  835:     "Successfully reassigned",
  836:     "Reserved [0x3]",
  837:     "Reassignment by disk failed",
  838:     "Recovered via rewrite in-place",
  839:     "Reassigned by app, has valid data",
  840:     "Reassigned by app, has no valid data",
  841:     "Unsuccessfully reassigned by app", /* 8 */
  842: };
  843: 
  844: // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 .
  845: // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
  846: // and up to 2048 events (although would hope to have less). May set
  847: // FAILLOG if serious errors detected (in the future).
  848: static int scsiPrintBackgroundResults(scsi_device * device)
  849: {
  850:     int num, j, m, err, pc, pl, truncated;
  851:     int noheader = 1;
  852:     int firstresult = 1;
  853:     int retval = 0;
  854:     UINT8 * ucp;
  855: 
  856:     if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf,
  857:                             LOG_RESP_LONG_LEN, 0))) {
  858:         print_on();
  859:         pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err));
  860:         print_off();
  861:         return FAILSMART;
  862:     }
  863:     if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) {
  864:         print_on();
  865:         pout("Background scan results Log Sense Failed, page mismatch\n");
  866:         print_off();
  867:         return FAILSMART;
  868:     }
  869:     // compute page length
  870:     num = (gBuf[2] << 8) + gBuf[3] + 4;
  871:     if (num < 20) {
  872:         print_on();
  873:         pout("Background scan results Log Sense length is %d, no scan "
  874:              "status\n", num);
  875:         print_off();
  876:         return FAILSMART;
  877:     }
  878:     truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
  879:     if (truncated)
  880:         num = LOG_RESP_LONG_LEN;
  881:     ucp = gBuf + 4;
  882:     num -= 4;
  883:     while (num > 3) {
  884:         pc = (ucp[0] << 8) | ucp[1];
  885:         // pcb = ucp[2];
  886:         pl = ucp[3] + 4;
  887:         switch (pc) {
  888:         case 0:
  889:             if (noheader) {
  890:                 noheader = 0;
  891:                 pout("\nBackground scan results log\n");
  892:             }
  893:             pout("  Status: ");
  894:             if ((pl < 16) || (num < 16)) {
  895:                 pout("\n");
  896:                 break;
  897:             }
  898:             j = ucp[9];
  899:             if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0])))
  900:                 pout("%s\n", bms_status[j]);
  901:             else
  902:                 pout("unknown [0x%x] background scan status value\n", j);
  903:             j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
  904:             pout("    Accumulated power on time, hours:minutes %d:%02d "
  905:                  "[%d minutes]\n", (j / 60), (j % 60), j);
  906:             pout("    Number of background scans performed: %d,  ",
  907:                  (ucp[10] << 8) + ucp[11]);
  908:             pout("scan progress: %.2f%%\n",
  909:                  (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0);
  910:             pout("    Number of background medium scans performed: %d\n",
  911:                  (ucp[14] << 8) + ucp[15]);
  912:             break;
  913:         default:
  914:             if (noheader) {
  915:                 noheader = 0;
  916:                 pout("\nBackground scan results log\n");
  917:             }
  918:             if (firstresult) {
  919:                 firstresult = 0;
  920:                 pout("\n   #  when        lba(hex)    [sk,asc,ascq]    "
  921:                      "reassign_status\n");
  922:             }
  923:             pout(" %3d ", pc);
  924:             if ((pl < 24) || (num < 24)) {
  925:                 if (pl < 24)
  926:                     pout("parameter length >= 24 expected, got %d\n", pl);
  927:                 break;
  928:             }
  929:             j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7];
  930:             pout("%4d:%02d  ", (j / 60), (j % 60));
  931:             for (m = 0; m < 8; ++m)
  932:                 pout("%02x", ucp[16 + m]);
  933:             pout("  [%x,%x,%x]   ", ucp[8] & 0xf, ucp[9], ucp[10]);
  934:             j = (ucp[8] >> 4) & 0xf;
  935:             if (j <
  936:                 (int)(sizeof(reassign_status) / sizeof(reassign_status[0])))
  937:                 pout("%s\n", reassign_status[j]);
  938:             else
  939:                 pout("Reassign status: reserved [0x%x]\n", j);
  940:             break;
  941:         }
  942:         num -= pl;
  943:         ucp += pl;
  944:     }
  945:     if (truncated)
  946:         pout(" >>>> log truncated, fetched %d of %d available "
  947:              "bytes\n", LOG_RESP_LONG_LEN, truncated);
  948:     return retval;
  949: }
  950: 
  951: // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 .
  952: // Returns 0 if ok else FAIL* bitmask. Note can have a status entry
  953: // and up to 2048 events (although would hope to have less). May set
  954: // FAILLOG if serious errors detected (in the future).
  955: static int scsiPrintSSMedia(scsi_device * device)
  956: {
  957:     int num, err, pc, pl, truncated;
  958:     int retval = 0;
  959:     UINT8 * ucp;
  960: 
  961:     if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf,
  962:                             LOG_RESP_LONG_LEN, 0))) {
  963:         print_on();
  964:         pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err));
  965:         print_off();
  966:         return FAILSMART;
  967:     }
  968:     if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) {
  969:         print_on();
  970:         pout("Solid state media Log Sense Failed, page mismatch\n");
  971:         print_off();
  972:         return FAILSMART;
  973:     }
  974:     // compute page length
  975:     num = (gBuf[2] << 8) + gBuf[3] + 4;
  976:     if (num < 12) {
  977:         print_on();
  978:         pout("Solid state media Log Sense length is %d, too short\n", num);
  979:         print_off();
  980:         return FAILSMART;
  981:     }
  982:     truncated = (num > LOG_RESP_LONG_LEN) ? num : 0;
  983:     if (truncated)
  984:         num = LOG_RESP_LONG_LEN;
  985:     ucp = gBuf + 4;
  986:     num -= 4;
  987:     while (num > 3) {
  988:         pc = (ucp[0] << 8) | ucp[1];
  989:         // pcb = ucp[2];
  990:         pl = ucp[3] + 4;
  991:         switch (pc) {
  992:         case 1:
  993: 	    if (pl < 8) {
  994:                 print_on();
  995:                 pout("Percentage used endurance indicator too short (pl=%d)\n", pl);
  996:                 print_off();
  997:                 return FAILSMART;
  998: 	    }
  999:             pout("SS Media used endurance indicator: %d%%\n", ucp[7]);
 1000:         default:	/* ignore other parameter codes */
 1001:             break;
 1002:         }
 1003:         num -= pl;
 1004:         ucp += pl;
 1005:     }
 1006:     return retval;
 1007: }
 1008: 
 1009: static void show_sas_phy_event_info(int peis, unsigned int val,
 1010:                                     unsigned thresh_val)
 1011: {
 1012:     unsigned int u;
 1013: 
 1014:     switch (peis) {
 1015:     case 0:
 1016:         pout("     No event\n");
 1017:         break;
 1018:     case 0x1:
 1019:         pout("     Invalid word count: %u\n", val);
 1020:         break;
 1021:     case 0x2:
 1022:         pout("     Running disparity error count: %u\n", val);
 1023:         break;
 1024:     case 0x3:
 1025:         pout("     Loss of dword synchronization count: %u\n", val);
 1026:         break;
 1027:     case 0x4:
 1028:         pout("     Phy reset problem count: %u\n", val);
 1029:         break;
 1030:     case 0x5:
 1031:         pout("     Elasticity buffer overflow count: %u\n", val);
 1032:         break;
 1033:     case 0x6:
 1034:         pout("     Received ERROR  count: %u\n", val);
 1035:         break;
 1036:     case 0x20:
 1037:         pout("     Received address frame error count: %u\n", val);
 1038:         break;
 1039:     case 0x21:
 1040:         pout("     Transmitted abandon-class OPEN_REJECT count: %u\n", val);
 1041:         break;
 1042:     case 0x22:
 1043:         pout("     Received abandon-class OPEN_REJECT count: %u\n", val);
 1044:         break;
 1045:     case 0x23:
 1046:         pout("     Transmitted retry-class OPEN_REJECT count: %u\n", val);
 1047:         break;
 1048:     case 0x24:
 1049:         pout("     Received retry-class OPEN_REJECT count: %u\n", val);
 1050:         break;
 1051:     case 0x25:
 1052:         pout("     Received AIP (WATING ON PARTIAL) count: %u\n", val);
 1053:         break;
 1054:     case 0x26:
 1055:         pout("     Received AIP (WAITING ON CONNECTION) count: %u\n", val);
 1056:         break;
 1057:     case 0x27:
 1058:         pout("     Transmitted BREAK count: %u\n", val);
 1059:         break;
 1060:     case 0x28:
 1061:         pout("     Received BREAK count: %u\n", val);
 1062:         break;
 1063:     case 0x29:
 1064:         pout("     Break timeout count: %u\n", val);
 1065:         break;
 1066:     case 0x2a:
 1067:         pout("     Connection count: %u\n", val);
 1068:         break;
 1069:     case 0x2b:
 1070:         pout("     Peak transmitted pathway blocked count: %u\n",
 1071:                val & 0xff);
 1072:         pout("         Peak value detector threshold: %u\n",
 1073:                thresh_val & 0xff);
 1074:         break;
 1075:     case 0x2c:
 1076:         u = val & 0xffff;
 1077:         if (u < 0x8000)
 1078:             pout("     Peak transmitted arbitration wait time (us): "
 1079:                    "%u\n", u);
 1080:         else
 1081:             pout("     Peak transmitted arbitration wait time (ms): "
 1082:                    "%u\n", 33 + (u - 0x8000));
 1083:         u = thresh_val & 0xffff;
 1084:         if (u < 0x8000)
 1085:             pout("         Peak value detector threshold (us): %u\n",
 1086:                    u);
 1087:         else
 1088:             pout("         Peak value detector threshold (ms): %u\n",
 1089:                    33 + (u - 0x8000));
 1090:         break;
 1091:     case 0x2d:
 1092:         pout("     Peak arbitration time (us): %u\n", val);
 1093:         pout("         Peak value detector threshold: %u\n", thresh_val);
 1094:         break;
 1095:     case 0x2e:
 1096:         pout("     Peak connection time (us): %u\n", val);
 1097:         pout("         Peak value detector threshold: %u\n", thresh_val);
 1098:         break;
 1099:     case 0x40:
 1100:         pout("     Transmitted SSP frame count: %u\n", val);
 1101:         break;
 1102:     case 0x41:
 1103:         pout("     Received SSP frame count: %u\n", val);
 1104:         break;
 1105:     case 0x42:
 1106:         pout("     Transmitted SSP frame error count: %u\n", val);
 1107:         break;
 1108:     case 0x43:
 1109:         pout("     Received SSP frame error count: %u\n", val);
 1110:         break;
 1111:     case 0x44:
 1112:         pout("     Transmitted CREDIT_BLOCKED count: %u\n", val);
 1113:         break;
 1114:     case 0x45:
 1115:         pout("     Received CREDIT_BLOCKED count: %u\n", val);
 1116:         break;
 1117:     case 0x50:
 1118:         pout("     Transmitted SATA frame count: %u\n", val);
 1119:         break;
 1120:     case 0x51:
 1121:         pout("     Received SATA frame count: %u\n", val);
 1122:         break;
 1123:     case 0x52:
 1124:         pout("     SATA flow control buffer overflow count: %u\n", val);
 1125:         break;
 1126:     case 0x60:
 1127:         pout("     Transmitted SMP frame count: %u\n", val);
 1128:         break;
 1129:     case 0x61:
 1130:         pout("     Received SMP frame count: %u\n", val);
 1131:         break;
 1132:     case 0x63:
 1133:         pout("     Received SMP frame error count: %u\n", val);
 1134:         break;
 1135:     default:
 1136:         break;
 1137:     }
 1138: }
 1139: 
 1140: static void show_sas_port_param(unsigned char * ucp, int param_len)
 1141: {
 1142:     int j, m, n, nphys, t, sz, spld_len;
 1143:     unsigned char * vcp;
 1144:     uint64_t ull;
 1145:     unsigned int ui;
 1146:     char s[64];
 1147: 
 1148:     sz = sizeof(s);
 1149:     // pcb = ucp[2];
 1150:     t = (ucp[0] << 8) | ucp[1];
 1151:     pout("relative target port id = %d\n", t);
 1152:     pout("  generation code = %d\n", ucp[6]);
 1153:     nphys = ucp[7];
 1154:     pout("  number of phys = %d\n", nphys);
 1155: 
 1156:     for (j = 0, vcp = ucp + 8; j < (param_len - 8);
 1157:          vcp += spld_len, j += spld_len) {
 1158:         pout("  phy identifier = %d\n", vcp[1]);
 1159:         spld_len = vcp[3];
 1160:         if (spld_len < 44)
 1161:             spld_len = 48;      /* in SAS-1 and SAS-1.1 vcp[3]==0 */
 1162:         else
 1163:             spld_len += 4;
 1164:         t = ((0x70 & vcp[4]) >> 4);
 1165:         switch (t) {
 1166:         case 0: snprintf(s, sz, "no device attached"); break;
 1167:         case 1: snprintf(s, sz, "end device"); break;
 1168:         case 2: snprintf(s, sz, "expander device"); break;
 1169:         case 3: snprintf(s, sz, "expander device (fanout)"); break;
 1170:         default: snprintf(s, sz, "reserved [%d]", t); break;
 1171:         }
 1172:         pout("    attached device type: %s\n", s);
 1173:         t = 0xf & vcp[4];
 1174:         switch (t) {
 1175:         case 0: snprintf(s, sz, "unknown"); break;
 1176:         case 1: snprintf(s, sz, "power on"); break;
 1177:         case 2: snprintf(s, sz, "hard reset"); break;
 1178:         case 3: snprintf(s, sz, "SMP phy control function"); break;
 1179:         case 4: snprintf(s, sz, "loss of dword synchronization"); break;
 1180:         case 5: snprintf(s, sz, "mux mix up"); break;
 1181:         case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
 1182:             break;
 1183:         case 7: snprintf(s, sz, "break timeout timer expired"); break;
 1184:         case 8: snprintf(s, sz, "phy test function stopped"); break;
 1185:         case 9: snprintf(s, sz, "expander device reduced functionality");
 1186:              break;
 1187:         default: snprintf(s, sz, "reserved [0x%x]", t); break;
 1188:         }
 1189:         pout("    attached reason: %s\n", s);
 1190:         t = (vcp[5] & 0xf0) >> 4;
 1191:         switch (t) {
 1192:         case 0: snprintf(s, sz, "unknown"); break;
 1193:         case 1: snprintf(s, sz, "power on"); break;
 1194:         case 2: snprintf(s, sz, "hard reset"); break;
 1195:         case 3: snprintf(s, sz, "SMP phy control function"); break;
 1196:         case 4: snprintf(s, sz, "loss of dword synchronization"); break;
 1197:         case 5: snprintf(s, sz, "mux mix up"); break;
 1198:         case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA");
 1199:             break;
 1200:         case 7: snprintf(s, sz, "break timeout timer expired"); break;
 1201:         case 8: snprintf(s, sz, "phy test function stopped"); break;
 1202:         case 9: snprintf(s, sz, "expander device reduced functionality");
 1203:              break;
 1204:         default: snprintf(s, sz, "reserved [0x%x]", t); break;
 1205:         }
 1206:         pout("    reason: %s\n", s);
 1207:         t = (0xf & vcp[5]);
 1208:         switch (t) {
 1209:         case 0: snprintf(s, sz, "phy enabled; unknown");
 1210:                      break;
 1211:         case 1: snprintf(s, sz, "phy disabled"); break;
 1212:         case 2: snprintf(s, sz, "phy enabled; speed negotiation failed");
 1213:                      break;
 1214:         case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state");
 1215:                      break;
 1216:         case 4: snprintf(s, sz, "phy enabled; port selector");
 1217:                      break;
 1218:         case 5: snprintf(s, sz, "phy enabled; reset in progress");
 1219:                      break;
 1220:         case 6: snprintf(s, sz, "phy enabled; unsupported phy attached");
 1221:                      break;
 1222:         case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break;
 1223:         case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break;
 1224:         case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break;
 1225:         default: snprintf(s, sz, "reserved [%d]", t); break;
 1226:         }
 1227:         pout("    negotiated logical link rate: %s\n", s);
 1228:         pout("    attached initiator port: ssp=%d stp=%d smp=%d\n",
 1229:                !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2));
 1230:         pout("    attached target port: ssp=%d stp=%d smp=%d\n",
 1231:                !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2));
 1232:         for (n = 0, ull = vcp[8]; n < 8; ++n) {
 1233:             ull <<= 8; ull |= vcp[8 + n];
 1234:         }
 1235:         pout("    SAS address = 0x%" PRIx64 "\n", ull);
 1236:         for (n = 0, ull = vcp[16]; n < 8; ++n) {
 1237:             ull <<= 8; ull |= vcp[16 + n];
 1238:         }
 1239:         pout("    attached SAS address = 0x%" PRIx64 "\n", ull);
 1240:         pout("    attached phy identifier = %d\n", vcp[24]);
 1241:         ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35];
 1242:         pout("    Invalid DWORD count = %u\n", ui);
 1243:         ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39];
 1244:         pout("    Running disparity error count = %u\n", ui);
 1245:         ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43];
 1246:         pout("    Loss of DWORD synchronization = %u\n", ui);
 1247:         ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47];
 1248:         pout("    Phy reset problem = %u\n", ui);
 1249:         if (spld_len > 51) {
 1250:             int num_ped, peis;
 1251:             unsigned char * xcp;
 1252:             unsigned int pvdt;
 1253: 
 1254:             num_ped = vcp[51];
 1255:             if (num_ped > 0)
 1256:                pout("    Phy event descriptors:\n");
 1257:             xcp = vcp + 52;
 1258:             for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) {
 1259:                 peis = xcp[3];
 1260:                 ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) |
 1261:                      xcp[7];
 1262:                 pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) |
 1263:                        xcp[11];
 1264:                 show_sas_phy_event_info(peis, ui, pvdt);
 1265:             }
 1266:         }
 1267:     }
 1268: }
 1269: 
 1270: // Returns 1 if okay, 0 if non SAS descriptors
 1271: static int show_protocol_specific_page(unsigned char * resp, int len)
 1272: {
 1273:     int k, num, param_len;
 1274:     unsigned char * ucp;
 1275: 
 1276:     num = len - 4;
 1277:     for (k = 0, ucp = resp + 4; k < num; ) {
 1278:         param_len = ucp[3] + 4;
 1279:         if (6 != (0xf & ucp[4]))
 1280:             return 0;   /* only decode SAS log page */
 1281:         if (0 == k)
 1282:             pout("Protocol Specific port log page for SAS SSP\n");
 1283:         show_sas_port_param(ucp, param_len);
 1284:         k += param_len;
 1285:         ucp += param_len;
 1286:     }
 1287:     return 1;
 1288: }
 1289: 
 1290: 
 1291: // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific
 1292: // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol
 1293: // Specific log page.
 1294: // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent
 1295: // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or
 1296: // FAILSMART is returned.
 1297: static int scsiPrintSasPhy(scsi_device * device, int reset)
 1298: {
 1299:     int num, err;
 1300: 
 1301:     if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf,
 1302:                             LOG_RESP_LONG_LEN, 0))) {
 1303:         print_on();
 1304:         pout("scsiPrintSasPhy Log Sense Failed [%s]\n", scsiErrString(err));
 1305:         print_off();
 1306:         return FAILSMART;
 1307:     }
 1308:     if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) {
 1309:         print_on();
 1310:         pout("Protocol specific Log Sense Failed, page mismatch\n");
 1311:         print_off();
 1312:         return FAILSMART;
 1313:     }
 1314:     // compute page length
 1315:     num = (gBuf[2] << 8) + gBuf[3];
 1316:     if (1 != show_protocol_specific_page(gBuf, num + 4)) {
 1317:         print_on();
 1318:         pout("Only support protocol specific log page on SAS devices\n");
 1319:         print_off();
 1320:         return FAILSMART;
 1321:     }
 1322:     if (reset) {
 1323:         if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */,
 1324:                                  PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) {
 1325:             print_on();
 1326:             pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n",
 1327:                  scsiErrString(err));
 1328:             print_off();
 1329:             return FAILSMART;
 1330:         }
 1331:     }
 1332:     return 0;
 1333: }
 1334: 
 1335: 
 1336: static const char * peripheral_dt_arr[] = {
 1337:         "disk",
 1338:         "tape",
 1339:         "printer",
 1340:         "processor",
 1341:         "optical disk(4)",
 1342:         "CD/DVD",
 1343:         "scanner",
 1344:         "optical disk(7)",
 1345:         "medium changer",
 1346:         "communications",
 1347:         "graphics(10)",
 1348:         "graphics(11)",
 1349:         "storage array",
 1350:         "enclosure",
 1351:         "simplified disk",
 1352:         "optical card reader"
 1353: };
 1354: 
 1355: static const char * transport_proto_arr[] = {
 1356:         "Fibre channel (FCP-2)",
 1357:         "Parallel SCSI (SPI-4)",
 1358:         "SSA",
 1359:         "IEEE 1394 (SBP-2)",
 1360:         "RDMA (SRP)",
 1361:         "iSCSI",
 1362:         "SAS",
 1363:         "ADT",
 1364:         "0x8",
 1365:         "0x9",
 1366:         "0xa",
 1367:         "0xb",
 1368:         "0xc",
 1369:         "0xd",
 1370:         "0xe",
 1371:         "0xf"
 1372: };
 1373: 
 1374: /* Returns 0 on success, 1 on general error and 2 for early, clean exit */
 1375: static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all)
 1376: {
 1377:     char timedatetz[DATEANDEPOCHLEN];
 1378:     struct scsi_iec_mode_page iec;
 1379:     int err, iec_err, len, req_len, avail_len;
 1380:     int is_tape = 0;
 1381:     int peri_dt = 0;
 1382:     int returnval = 0;
 1383:     int transport = -1;
 1384:         
 1385:     memset(gBuf, 0, 96);
 1386:     req_len = 36;
 1387:     if ((err = scsiStdInquiry(device, gBuf, req_len))) {
 1388:         print_on();
 1389:         pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err));
 1390:         pout("Retrying with a 64 byte Standard Inquiry\n");
 1391:         print_off();
 1392:         /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
 1393:         req_len = 64;
 1394:         if ((err = scsiStdInquiry(device, gBuf, req_len))) {
 1395:             print_on();
 1396:             pout("Standard Inquiry (64 bytes) failed [%s]\n",
 1397:                  scsiErrString(err));
 1398:             print_off();
 1399:             return 1;
 1400:         }
 1401:     }
 1402:     avail_len = gBuf[4] + 5;
 1403:     len = (avail_len < req_len) ? avail_len : req_len;
 1404:     peri_dt = gBuf[0] & 0x1f;
 1405:     if (peripheral_type)
 1406:         *peripheral_type = peri_dt;
 1407: 
 1408:     if (len < 36) {
 1409:         print_on();
 1410:         pout("Short INQUIRY response, skip product id\n");
 1411:         print_off();
 1412:         return 1;
 1413:     }
 1414:     if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) {
 1415:         pout("Vendor:               %.8s\n", (char *)&gBuf[8]);
 1416: 	pout("Product:              %.16s\n", (char *)&gBuf[16]);
 1417: 	if (gBuf[32] >= ' ')
 1418: 	    pout("Revision:             %.4s\n", (char *)&gBuf[32]);
 1419:     }
 1420: 
 1421:     if (!*device->get_req_type()/*no type requested*/ &&
 1422:                (0 == strncmp((char *)&gBuf[8], "ATA", 3))) {
 1423:         pout("\nProbable ATA device behind a SAT layer\n"
 1424:              "Try an additional '-d ata' or '-d sat' argument.\n");
 1425:         return 2;
 1426:     }
 1427:     if (! all)
 1428:         return 0;
 1429: 
 1430:     unsigned int lb_size;
 1431:     char cap_str[64];
 1432:     char si_str[64];
 1433:     char lb_str[16];
 1434:     uint64_t capacity = scsiGetSize(device, &lb_size);
 1435: 
 1436:     if (capacity) {
 1437:         format_with_thousands_sep(cap_str, sizeof(cap_str), capacity);
 1438:         format_capacity(si_str, sizeof(si_str), capacity);
 1439:         pout("User Capacity:        %s bytes [%s]\n", cap_str, si_str);
 1440:         snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size);
 1441:         pout("Logical block size:   %s bytes\n", lb_str);
 1442:     }
 1443: 
 1444:     /* Do this here to try and detect badly conforming devices (some USB
 1445:        keys) that will lock up on a InquiryVpd or log sense or ... */
 1446:     if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
 1447:         if (SIMPLE_ERR_BAD_RESP == iec_err) {
 1448:             pout(">> Terminate command early due to bad response to IEC "
 1449:                  "mode page\n");
 1450:             print_off();
 1451:             gIecMPage = 0;
 1452:             return 1;
 1453:         }
 1454:     } else
 1455:         modese_len = iec.modese_len;
 1456: 
 1457:     if (! dont_print_serial_number) {
 1458: 	if (0 == (err = scsiInquiryVpd(device, 0x83, gBuf, 200))) {
 1459: 	    char s[256];
 1460: 
 1461:             len = gBuf[3];
 1462: 	    scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport);
 1463: 	    if (strlen(s) > 0)
 1464:                 pout("Logical Unit id:      %s\n", s);
 1465:         } else if (scsi_debugmode > 0) {
 1466:             print_on();
 1467:             if (SIMPLE_ERR_BAD_RESP == err)
 1468:                 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
 1469:             else
 1470:                 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
 1471:             print_off();
 1472:         }
 1473: 	if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) {
 1474:             len = gBuf[3];
 1475:             gBuf[4 + len] = '\0';
 1476:             pout("Serial number:        %s\n", &gBuf[4]);
 1477:         } else if (scsi_debugmode > 0) {
 1478:             print_on();
 1479:             if (SIMPLE_ERR_BAD_RESP == err)
 1480:                 pout("Vital Product Data (VPD) bit ignored in INQUIRY\n");
 1481:             else
 1482:                 pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
 1483:             print_off();
 1484:         }
 1485:     }
 1486: 
 1487:     // print SCSI peripheral device type
 1488:     if (peri_dt < (int)(sizeof(peripheral_dt_arr) / 
 1489:                         sizeof(peripheral_dt_arr[0])))
 1490:         pout("Device type:          %s\n", peripheral_dt_arr[peri_dt]);
 1491:     else
 1492:         pout("Device type:          <%d>\n", peri_dt);
 1493: 
 1494:     // See if transport protocol is known
 1495:     if (transport < 0)
 1496:         transport = scsiFetchTransportProtocol(device, modese_len);
 1497:     if ((transport >= 0) && (transport <= 0xf))
 1498:         pout("Transport protocol:   %s\n", transport_proto_arr[transport]);
 1499: 
 1500:     // print current time and date and timezone
 1501:     dateandtimezone(timedatetz);
 1502:     pout("Local Time is:        %s\n", timedatetz);
 1503: 
 1504:     if ((SCSI_PT_SEQUENTIAL_ACCESS == *peripheral_type) ||
 1505:         (SCSI_PT_MEDIUM_CHANGER == *peripheral_type))
 1506:         is_tape = 1;
 1507:     // See if unit accepts SCSI commmands from us
 1508:     if ((err = scsiTestUnitReady(device))) {
 1509:         if (SIMPLE_ERR_NOT_READY == err) {
 1510:             print_on();
 1511:             if (!is_tape)
 1512:                 pout("device is NOT READY (e.g. spun down, busy)\n");
 1513:             else
 1514:                 pout("device is NOT READY (e.g. no tape)\n");
 1515:             print_off();
 1516:          } else if (SIMPLE_ERR_NO_MEDIUM == err) {
 1517:             print_on();
 1518:             pout("NO MEDIUM present on device\n");
 1519:             print_off();
 1520:          } else if (SIMPLE_ERR_BECOMING_READY == err) {
 1521:             print_on();
 1522:             pout("device becoming ready (wait)\n");
 1523:             print_off();
 1524:         } else {
 1525:             print_on();
 1526:             pout("device Test Unit Ready  [%s]\n", scsiErrString(err));
 1527:             print_off();
 1528:         }
 1529:         failuretest(MANDATORY_CMD, returnval|=FAILID);
 1530:     }
 1531:    
 1532:     if (iec_err) {
 1533:         if (!is_tape) {
 1534:             print_on();
 1535:             pout("Device does not support SMART");
 1536:             if (scsi_debugmode > 0)
 1537:                 pout(" [%s]\n", scsiErrString(iec_err));
 1538:             else
 1539:                 pout("\n");
 1540:             print_off();
 1541:         }
 1542:         gIecMPage = 0;
 1543:         return 0;
 1544:     }
 1545: 
 1546:     if (!is_tape)
 1547:         pout("Device supports SMART and is %s\n",
 1548:              (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
 1549:     pout("%s\n", (scsi_IsWarningEnabled(&iec)) ? 
 1550:                   "Temperature Warning Enabled" :
 1551:                   "Temperature Warning Disabled or Not Supported");
 1552:     return 0;
 1553: }
 1554: 
 1555: static int scsiSmartEnable(scsi_device * device)
 1556: {
 1557:     struct scsi_iec_mode_page iec;
 1558:     int err;
 1559: 
 1560:     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
 1561:         print_on();
 1562:         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
 1563:              scsiErrString(err));
 1564:         print_off();
 1565:         return 1;
 1566:     } else
 1567:         modese_len = iec.modese_len;
 1568: 
 1569:     if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) {
 1570:         print_on();
 1571:         pout("unable to enable Exception control and warning [%s]\n",
 1572:              scsiErrString(err));
 1573:         print_off();
 1574:         return 1;
 1575:     }
 1576:     /* Need to refetch 'iec' since could be modified by previous call */
 1577:     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
 1578:         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
 1579:              scsiErrString(err));
 1580:         return 1;
 1581:     } else
 1582:         modese_len = iec.modese_len;
 1583: 
 1584:     pout("Informational Exceptions (SMART) %s\n",
 1585:          scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
 1586:     pout("Temperature warning %s\n",
 1587:          scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
 1588:     return 0;
 1589: }
 1590:         
 1591: static int scsiSmartDisable(scsi_device * device)
 1592: {
 1593:     struct scsi_iec_mode_page iec;
 1594:     int err;
 1595: 
 1596:     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
 1597:         print_on();
 1598:         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
 1599:              scsiErrString(err));
 1600:         print_off();
 1601:         return 1;
 1602:     } else
 1603:         modese_len = iec.modese_len;
 1604: 
 1605:     if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) {
 1606:         print_on();
 1607:         pout("unable to disable Exception control and warning [%s]\n",
 1608:              scsiErrString(err));
 1609:         print_off();
 1610:         return 1;
 1611:     }
 1612:     /* Need to refetch 'iec' since could be modified by previous call */
 1613:     if ((err = scsiFetchIECmpage(device, &iec, modese_len))) {
 1614:         pout("unable to fetch IEC (SMART) mode page [%s]\n", 
 1615:              scsiErrString(err));
 1616:         return 1;
 1617:     } else
 1618:         modese_len = iec.modese_len;
 1619: 
 1620:     pout("Informational Exceptions (SMART) %s\n",
 1621:          scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled");
 1622:     pout("Temperature warning %s\n",
 1623:          scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled");
 1624:     return 0;
 1625: }
 1626: 
 1627: static void scsiPrintTemp(scsi_device * device)
 1628: {
 1629:     UINT8 temp = 0;
 1630:     UINT8 trip = 0;
 1631: 
 1632:     if (scsiGetTemp(device, &temp, &trip))
 1633:         return;
 1634:   
 1635:     if (temp) {
 1636:         if (255 != temp)
 1637:             pout("Current Drive Temperature:     %d C\n", temp);
 1638:         else
 1639:             pout("Current Drive Temperature:     <not available>\n");
 1640:     }
 1641:     if (trip)
 1642:         pout("Drive Trip Temperature:        %d C\n", trip);
 1643: }
 1644: 
 1645: /* Main entry point used by smartctl command. Return 0 for success */
 1646: int scsiPrintMain(scsi_device * device, const scsi_print_options & options)
 1647: {
 1648:     int checkedSupportedLogPages = 0;
 1649:     UINT8 peripheral_type = 0;
 1650:     int returnval = 0;
 1651:     int res, durationSec;
 1652: 
 1653:     bool any_output = options.drive_info;
 1654: 
 1655:     res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info);
 1656:     if (res) {
 1657:         if (2 == res)
 1658:             return 0;
 1659:         else
 1660:             failuretest(MANDATORY_CMD, returnval |= FAILID);
 1661: 	any_output = true;
 1662:     }
 1663: 
 1664:     if (options.smart_enable) {
 1665:         if (scsiSmartEnable(device))
 1666:             failuretest(MANDATORY_CMD, returnval |= FAILSMART);
 1667: 	any_output = true;
 1668:     }
 1669: 
 1670:     if (options.smart_disable) {
 1671:         if (scsiSmartDisable(device))
 1672:             failuretest(MANDATORY_CMD,returnval |= FAILSMART);
 1673: 	any_output = true;
 1674:     }
 1675:     
 1676:     if (options.smart_auto_save_enable) {
 1677:       if (scsiSetControlGLTSD(device, 0, modese_len)) {
 1678:         pout("Enable autosave (clear GLTSD bit) failed\n");
 1679:         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
 1680:       }
 1681:       any_output = true;
 1682:     }
 1683:     
 1684:     if (options.smart_auto_save_disable) {
 1685:       if (scsiSetControlGLTSD(device, 1, modese_len)) {
 1686:         pout("Disable autosave (set GLTSD bit) failed\n");
 1687:         failuretest(OPTIONAL_CMD,returnval |= FAILSMART);
 1688:       }
 1689:       any_output = true;
 1690:     }
 1691:     
 1692:     if (options.smart_check_status) {
 1693:         scsiGetSupportedLogPages(device);
 1694:         checkedSupportedLogPages = 1;
 1695:         if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) ||
 1696:             (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */
 1697:             if (gTapeAlertsLPage) {
 1698:                 if (options.drive_info)
 1699:                     pout("TapeAlert Supported\n");
 1700:                 if (-1 == scsiGetTapeAlertsData(device, peripheral_type))
 1701:                     failuretest(OPTIONAL_CMD, returnval |= FAILSMART);
 1702:             }
 1703:             else
 1704:                 pout("TapeAlert Not Supported\n");
 1705:         } else { /* disk, cd/dvd, enclosure, etc */
 1706:             if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) {
 1707:                 if (-2 == res)
 1708:                     returnval |= FAILSTATUS;
 1709:                 else
 1710:                     returnval |= FAILSMART;
 1711:             }
 1712:         }
 1713:         any_output = true;
 1714:     }   
 1715:     if (options.smart_ss_media_log) {
 1716:         if (! checkedSupportedLogPages)
 1717:             scsiGetSupportedLogPages(device);
 1718:         res = 0;
 1719:         if (gSSMediaLPage)
 1720:             res = scsiPrintSSMedia(device);
 1721:         if (0 != res)
 1722:             failuretest(OPTIONAL_CMD, returnval|=res);
 1723:         any_output = true;
 1724:     }
 1725:     if (options.smart_vendor_attrib) {
 1726:         if (! checkedSupportedLogPages)
 1727:             scsiGetSupportedLogPages(device);
 1728:         if (gTempLPage) {
 1729:             if (options.smart_check_status)
 1730:                 pout("\n");
 1731:             scsiPrintTemp(device);
 1732:         }
 1733:         if (gStartStopLPage)
 1734:             scsiGetStartStopData(device);
 1735:         if (SCSI_PT_DIRECT_ACCESS == peripheral_type) {
 1736:             scsiPrintGrownDefectListLen(device);
 1737:             if (gSeagateCacheLPage)
 1738:                 scsiPrintSeagateCacheLPage(device);
 1739:             if (gSeagateFactoryLPage)
 1740:                 scsiPrintSeagateFactoryLPage(device);
 1741:         }
 1742:         any_output = true;
 1743:     }
 1744:     if (options.smart_error_log) {
 1745:         if (! checkedSupportedLogPages)
 1746:             scsiGetSupportedLogPages(device);
 1747:         scsiPrintErrorCounterLog(device);
 1748:         if (1 == scsiFetchControlGLTSD(device, modese_len, 1))
 1749:             pout("\n[GLTSD (Global Logging Target Save Disable) set. "
 1750:                  "Enable Save with '-S on']\n");
 1751:         any_output = true;
 1752:     }
 1753:     if (options.smart_selftest_log) {
 1754:         if (! checkedSupportedLogPages)
 1755:             scsiGetSupportedLogPages(device);
 1756:         res = 0;
 1757:         if (gSelfTestLPage)
 1758:             res = scsiPrintSelfTest(device);
 1759:         else {
 1760:             pout("Device does not support Self Test logging\n");
 1761:             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 1762:         }
 1763:         if (0 != res)
 1764:             failuretest(OPTIONAL_CMD, returnval|=res);
 1765:         any_output = true;
 1766:     }
 1767:     if (options.smart_background_log) {
 1768:         if (! checkedSupportedLogPages)
 1769:             scsiGetSupportedLogPages(device);
 1770:         res = 0;
 1771:         if (gBackgroundResultsLPage)
 1772:             res = scsiPrintBackgroundResults(device);
 1773:         else {
 1774:             pout("Device does not support Background scan results logging\n");
 1775:             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 1776:         }
 1777:         if (0 != res)
 1778:             failuretest(OPTIONAL_CMD, returnval|=res);
 1779:         any_output = true;
 1780:     }
 1781:     if (options.smart_default_selftest) {
 1782:         if (scsiSmartDefaultSelfTest(device))
 1783:             return returnval | FAILSMART;
 1784:         pout("Default Self Test Successful\n");
 1785:         any_output = true;
 1786:     }
 1787:     if (options.smart_short_cap_selftest) {
 1788:         if (scsiSmartShortCapSelfTest(device))
 1789:             return returnval | FAILSMART;
 1790:         pout("Short Foreground Self Test Successful\n");
 1791:         any_output = true;
 1792:     }
 1793:     if (options.smart_short_selftest) {
 1794:         if (scsiSmartShortSelfTest(device))
 1795:             return returnval | FAILSMART;
 1796:         pout("Short Background Self Test has begun\n");
 1797:         pout("Use smartctl -X to abort test\n");
 1798:         any_output = true;
 1799:     }
 1800:     if (options.smart_extend_selftest) {
 1801:         if (scsiSmartExtendSelfTest(device))
 1802:             return returnval | FAILSMART;
 1803:         pout("Extended Background Self Test has begun\n");
 1804:         if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec,
 1805:                         modese_len)) && (durationSec > 0)) {
 1806:             time_t t = time(NULL);
 1807: 
 1808:             t += durationSec;
 1809:             pout("Please wait %d minutes for test to complete.\n", 
 1810:                  durationSec / 60);
 1811:             pout("Estimated completion time: %s\n", ctime(&t));
 1812:         }
 1813:         pout("Use smartctl -X to abort test\n");        
 1814:         any_output = true;
 1815:     }
 1816:     if (options.smart_extend_cap_selftest) {
 1817:         if (scsiSmartExtendCapSelfTest(device))
 1818:             return returnval | FAILSMART;
 1819:         pout("Extended Foreground Self Test Successful\n");
 1820:     }
 1821:     if (options.smart_selftest_abort) {
 1822:         if (scsiSmartSelfTestAbort(device))
 1823:             return returnval | FAILSMART;
 1824:         pout("Self Test returned without error\n");
 1825:         any_output = true;
 1826:     }           
 1827:     if (options.sasphy) {
 1828:         if (scsiPrintSasPhy(device, options.sasphy_reset))
 1829:             return returnval | FAILSMART;
 1830:         any_output = true;
 1831:     }           
 1832: 
 1833:     if (!any_output)
 1834:       pout("SCSI device successfully opened\n\n"
 1835:            "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
 1836: 
 1837:     return returnval;
 1838: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>