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

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

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