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

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

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