Annotation of embedaddon/smartmontools/scsiprint.cpp, revision 1.1.1.1

1.1       misho       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 3441 2011-10-12 17:22:15Z chrfranke $"
                     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>