File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / ataprint.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:36:45 2012 UTC (11 years, 8 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, HEAD
smartmontools

    1: /*
    2:  * ataprint.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) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
    8:  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
    9:  *
   10:  * This program is free software; you can redistribute it and/or modify
   11:  * it under the terms of the GNU General Public License as published by
   12:  * the Free Software Foundation; either version 2, or (at your option)
   13:  * any later version.
   14:  *
   15:  * You should have received a copy of the GNU General Public License
   16:  * (for example COPYING); if not, write to the Free
   17:  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18:  *
   19:  * This code was originally developed as a Senior Thesis by Michael Cornwell
   20:  * at the Concurrent Systems Laboratory (now part of the Storage Systems
   21:  * Research Center), Jack Baskin School of Engineering, University of
   22:  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
   23:  *
   24:  */
   25: 
   26: #include "config.h"
   27: 
   28: #include <ctype.h>
   29: #include <errno.h>
   30: #include <stdio.h>
   31: #include <stdlib.h>
   32: #include <string.h>
   33: 
   34: #include "int64.h"
   35: #include "atacmdnames.h"
   36: #include "atacmds.h"
   37: #include "dev_interface.h"
   38: #include "ataprint.h"
   39: #include "smartctl.h"
   40: #include "utility.h"
   41: #include "knowndrives.h"
   42: 
   43: const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp,v 1.1.1.2 2012/10/09 09:36:45 misho Exp $"
   44:                                   ATAPRINT_H_CVSID;
   45: 
   46: 
   47: static const char * infofound(const char *output) {
   48:   return (*output ? output : "[No Information Found]");
   49: }
   50: 
   51: // Return true if '-T permissive' is specified,
   52: // used to ignore missing capabilities
   53: static bool is_permissive()
   54: {
   55:   if (!failuretest_permissive)
   56:     return false;
   57:   failuretest_permissive--;
   58:   return true;
   59: }
   60: 
   61: /* For the given Command Register (CR) and Features Register (FR), attempts
   62:  * to construct a string that describes the contents of the Status
   63:  * Register (ST) and Error Register (ER).  The caller passes the string
   64:  * buffer and the return value is a pointer to this string.  If the
   65:  * meanings of the flags of the error register are not known for the given
   66:  * command then it returns NULL.
   67:  *
   68:  * The meanings of the flags of the error register for all commands are
   69:  * described in the ATA spec and could all be supported here in theory.
   70:  * Currently, only a few commands are supported (those that have been seen
   71:  * to produce errors).  If many more are to be added then this function
   72:  * should probably be redesigned.
   73:  */
   74: 
   75: static const char * construct_st_er_desc(
   76:   char * s,
   77:   unsigned char CR, unsigned char FR,
   78:   unsigned char ST, unsigned char ER,
   79:   unsigned short SC,
   80:   const ata_smart_errorlog_error_struct * lba28_regs,
   81:   const ata_smart_exterrlog_error * lba48_regs
   82: )
   83: {
   84:   const char *error_flag[8];
   85:   int i, print_lba=0, print_sector=0;
   86: 
   87:   // Set of character strings corresponding to different error codes.
   88:   // Please keep in alphabetic order if you add more.
   89:   const char  *abrt  = "ABRT";  // ABORTED
   90:  const char   *amnf  = "AMNF";  // ADDRESS MARK NOT FOUND
   91:  const char   *ccto  = "CCTO";  // COMMAND COMPLETION TIMED OUT
   92:  const char   *eom   = "EOM";   // END OF MEDIA
   93:  const char   *icrc  = "ICRC";  // INTERFACE CRC ERROR
   94:  const char   *idnf  = "IDNF";  // ID NOT FOUND
   95:  const char   *ili   = "ILI";   // MEANING OF THIS BIT IS COMMAND-SET SPECIFIC
   96:  const char   *mc    = "MC";    // MEDIA CHANGED 
   97:  const char   *mcr   = "MCR";   // MEDIA CHANGE REQUEST
   98:  const char   *nm    = "NM";    // NO MEDIA
   99:  const char   *obs   = "obs";   // OBSOLETE
  100:  const char   *tk0nf = "TK0NF"; // TRACK 0 NOT FOUND
  101:  const char   *unc   = "UNC";   // UNCORRECTABLE
  102:  const char   *wp    = "WP";    // WRITE PROTECTED
  103: 
  104:   /* If for any command the Device Fault flag of the status register is
  105:    * not used then used_device_fault should be set to 0 (in the CR switch
  106:    * below)
  107:    */
  108:   int uses_device_fault = 1;
  109: 
  110:   /* A value of NULL means that the error flag isn't used */
  111:   for (i = 0; i < 8; i++)
  112:     error_flag[i] = NULL;
  113: 
  114:   switch (CR) {
  115:   case 0x10:  // RECALIBRATE
  116:     error_flag[2] = abrt;
  117:     error_flag[1] = tk0nf;
  118:     break;
  119:   case 0x20:  /* READ SECTOR(S) */
  120:   case 0x21:  // READ SECTOR(S)
  121:   case 0x24:  // READ SECTOR(S) EXT
  122:   case 0xC4:  /* READ MULTIPLE */
  123:   case 0x29:  // READ MULTIPLE EXT
  124:     error_flag[6] = unc;
  125:     error_flag[5] = mc;
  126:     error_flag[4] = idnf;
  127:     error_flag[3] = mcr;
  128:     error_flag[2] = abrt;
  129:     error_flag[1] = nm;
  130:     error_flag[0] = amnf;
  131:     print_lba=1;
  132:     break;
  133:   case 0x22:  // READ LONG (with retries)
  134:   case 0x23:  // READ LONG (without retries)
  135:     error_flag[4] = idnf;
  136:     error_flag[2] = abrt;
  137:     error_flag[0] = amnf;
  138:     print_lba=1;
  139:     break;
  140:   case 0x2a:  // READ STREAM DMA
  141:   case 0x2b:  // READ STREAM PIO
  142:     if (CR==0x2a)
  143:       error_flag[7] = icrc;
  144:     error_flag[6] = unc;
  145:     error_flag[5] = mc;
  146:     error_flag[4] = idnf;
  147:     error_flag[3] = mcr;
  148:     error_flag[2] = abrt;
  149:     error_flag[1] = nm;
  150:     error_flag[0] = ccto;
  151:     print_lba=1;
  152:     print_sector=SC;
  153:     break;
  154:   case 0x3A:  // WRITE STREAM DMA
  155:   case 0x3B:  // WRITE STREAM PIO
  156:     if (CR==0x3A)
  157:       error_flag[7] = icrc;
  158:     error_flag[6] = wp;
  159:     error_flag[5] = mc;
  160:     error_flag[4] = idnf;
  161:     error_flag[3] = mcr;
  162:     error_flag[2] = abrt;
  163:     error_flag[1] = nm;
  164:     error_flag[0] = ccto;
  165:     print_lba=1;
  166:     print_sector=SC;
  167:     break;
  168:   case 0x25:  // READ DMA EXT
  169:   case 0x26:  // READ DMA QUEUED EXT
  170:   case 0xC7:  // READ DMA QUEUED
  171:   case 0xC8:  // READ DMA (with retries)
  172:   case 0xC9:  // READ DMA (without retries, obsolete since ATA-5)
  173:   case 0x60:  // READ FPDMA QUEUED (NCQ)
  174:     error_flag[7] = icrc;
  175:     error_flag[6] = unc;
  176:     error_flag[5] = mc;
  177:     error_flag[4] = idnf;
  178:     error_flag[3] = mcr;
  179:     error_flag[2] = abrt;
  180:     error_flag[1] = nm;
  181:     error_flag[0] = amnf;
  182:     print_lba=1;
  183:     if (CR==0x25 || CR==0xC8)
  184:       print_sector=SC;
  185:     break;
  186:   case 0x30:  /* WRITE SECTOR(S) */
  187:   case 0x31:  // WRITE SECTOR(S)
  188:   case 0x34:  // WRITE SECTOR(S) EXT
  189:   case 0xC5:  /* WRITE MULTIPLE */
  190:   case 0x39:  // WRITE MULTIPLE EXT
  191:   case 0xCE:  // WRITE MULTIPLE FUA EXT
  192:     error_flag[6] = wp;
  193:     error_flag[5] = mc;
  194:     error_flag[4] = idnf;
  195:     error_flag[3] = mcr;
  196:     error_flag[2] = abrt;
  197:     error_flag[1] = nm;
  198:     print_lba=1;
  199:     break;
  200:   case 0x32:  // WRITE LONG (with retries)
  201:   case 0x33:  // WRITE LONG (without retries)
  202:     error_flag[4] = idnf;
  203:     error_flag[2] = abrt;
  204:     print_lba=1;
  205:     break;
  206:   case 0x3C:  // WRITE VERIFY
  207:     error_flag[6] = unc;
  208:     error_flag[4] = idnf;
  209:     error_flag[2] = abrt;
  210:     error_flag[0] = amnf;
  211:     print_lba=1;
  212:     break;
  213:   case 0x40: // READ VERIFY SECTOR(S) with retries
  214:   case 0x41: // READ VERIFY SECTOR(S) without retries
  215:   case 0x42: // READ VERIFY SECTOR(S) EXT
  216:     error_flag[6] = unc;
  217:     error_flag[5] = mc;
  218:     error_flag[4] = idnf;
  219:     error_flag[3] = mcr;
  220:     error_flag[2] = abrt;
  221:     error_flag[1] = nm;
  222:     error_flag[0] = amnf;
  223:     print_lba=1;
  224:     break;
  225:   case 0xA0:  /* PACKET */
  226:     /* Bits 4-7 are all used for sense key (a 'command packet set specific error
  227:      * indication' according to the ATA/ATAPI-7 standard), so "Sense key" will
  228:      * be repeated in the error description string if more than one of those
  229:      * bits is set.
  230:      */
  231:     error_flag[7] = "Sense key (bit 3)",
  232:     error_flag[6] = "Sense key (bit 2)",
  233:     error_flag[5] = "Sense key (bit 1)",
  234:     error_flag[4] = "Sense key (bit 0)",
  235:     error_flag[2] = abrt;
  236:     error_flag[1] = eom;
  237:     error_flag[0] = ili;
  238:     break;
  239:   case 0xA1:  /* IDENTIFY PACKET DEVICE */
  240:   case 0xEF:  /* SET FEATURES */
  241:   case 0x00:  /* NOP */
  242:   case 0xC6:  /* SET MULTIPLE MODE */
  243:     error_flag[2] = abrt;
  244:     break;
  245:   case 0x2F:  // READ LOG EXT
  246:     error_flag[6] = unc;
  247:     error_flag[4] = idnf;
  248:     error_flag[2] = abrt;
  249:     error_flag[0] = obs;
  250:     break;
  251:   case 0x3F:  // WRITE LOG EXT
  252:     error_flag[4] = idnf;
  253:     error_flag[2] = abrt;
  254:     error_flag[0] = obs;
  255:     break;
  256:   case 0xB0:  /* SMART */
  257:     switch(FR) {
  258:     case 0xD0:  // SMART READ DATA
  259:     case 0xD1:  // SMART READ ATTRIBUTE THRESHOLDS
  260:     case 0xD5:  /* SMART READ LOG */
  261:       error_flag[6] = unc;
  262:       error_flag[4] = idnf;
  263:       error_flag[2] = abrt;
  264:       error_flag[0] = obs;
  265:       break;
  266:     case 0xD6:  /* SMART WRITE LOG */
  267:       error_flag[4] = idnf;
  268:       error_flag[2] = abrt;
  269:       error_flag[0] = obs;
  270:       break;
  271:     case 0xD2:  // Enable/Disable Attribute Autosave
  272:     case 0xD3:  // SMART SAVE ATTRIBUTE VALUES (ATA-3)
  273:     case 0xD8:  // SMART ENABLE OPERATIONS
  274:     case 0xD9:  /* SMART DISABLE OPERATIONS */
  275:     case 0xDA:  /* SMART RETURN STATUS */
  276:     case 0xDB:  // Enable/Disable Auto Offline (SFF)
  277:       error_flag[2] = abrt;
  278:       break;
  279:     case 0xD4:  // SMART EXECUTE IMMEDIATE OFFLINE
  280:       error_flag[4] = idnf;
  281:       error_flag[2] = abrt;
  282:       break;
  283:     default:
  284:       return NULL;
  285:       break;
  286:     }
  287:     break;
  288:   case 0xB1:  /* DEVICE CONFIGURATION */
  289:     switch (FR) {
  290:     case 0xC0:  /* DEVICE CONFIGURATION RESTORE */
  291:       error_flag[2] = abrt;
  292:       break;
  293:     default:
  294:       return NULL;
  295:       break;
  296:     }
  297:     break;
  298:   case 0xCA:  // WRITE DMA (with retries)
  299:   case 0xCB:  // WRITE DMA (without retries, obsolete since ATA-5)
  300:   case 0x35:  // WRITE DMA EXT
  301:   case 0x3D:  // WRITE DMA FUA EXT
  302:   case 0xCC:  // WRITE DMA QUEUED
  303:   case 0x36:  // WRITE DMA QUEUED EXT
  304:   case 0x3E:  // WRITE DMA QUEUED FUA EXT
  305:   case 0x61:  // WRITE FPDMA QUEUED (NCQ)
  306:     error_flag[7] = icrc;
  307:     error_flag[6] = wp;
  308:     error_flag[5] = mc;
  309:     error_flag[4] = idnf;
  310:     error_flag[3] = mcr;
  311:     error_flag[2] = abrt;
  312:     error_flag[1] = nm;
  313:     error_flag[0] = amnf;
  314:     print_lba=1;
  315:     if (CR==0x35)
  316:       print_sector=SC;
  317:     break;
  318:   case 0xE4: // READ BUFFER
  319:   case 0xE8: // WRITE BUFFER
  320:     error_flag[2] = abrt;
  321:     break;
  322:   default:
  323:     return NULL;
  324:   }
  325: 
  326:   s[0] = '\0';
  327: 
  328:   /* We ignore any status flags other than Device Fault and Error */
  329: 
  330:   if (uses_device_fault && (ST & (1 << 5))) {
  331:     strcat(s, "Device Fault");
  332:     if (ST & 1)  // Error flag
  333:       strcat(s, "; ");
  334:   }
  335:   if (ST & 1) {  // Error flag
  336:     int count = 0;
  337: 
  338:     strcat(s, "Error: ");
  339:     for (i = 7; i >= 0; i--)
  340:       if ((ER & (1 << i)) && (error_flag[i])) {
  341:         if (count++ > 0)
  342:            strcat(s, ", ");
  343:         strcat(s, error_flag[i]);
  344:       }
  345:   }
  346: 
  347:   // If the error was a READ or WRITE error, print the Logical Block
  348:   // Address (LBA) at which the read or write failed.
  349:   if (print_lba) {
  350:     char tmp[128];
  351:     // print number of sectors, if known, and append to print string
  352:     if (print_sector) {
  353:       snprintf(tmp, 128, " %d sectors", print_sector);
  354:       strcat(s, tmp);
  355:     }
  356: 
  357:     if (lba28_regs) {
  358:       unsigned lba;
  359:       // bits 24-27: bits 0-3 of DH
  360:       lba   = 0xf & lba28_regs->drive_head;
  361:       lba <<= 8;
  362:       // bits 16-23: CH
  363:       lba  |= lba28_regs->cylinder_high;
  364:       lba <<= 8;
  365:       // bits 8-15:  CL
  366:       lba  |= lba28_regs->cylinder_low;
  367:       lba <<= 8;
  368:       // bits 0-7:   SN
  369:       lba  |= lba28_regs->sector_number;
  370:       snprintf(tmp, 128, " at LBA = 0x%08x = %u", lba, lba);
  371:       strcat(s, tmp);
  372:     }
  373:     else if (lba48_regs) {
  374:       // This assumes that upper LBA registers are 0 for 28-bit commands
  375:       // (TODO: detect 48-bit commands above)
  376:       uint64_t lba48;
  377:       lba48   = lba48_regs->lba_high_register_hi;
  378:       lba48 <<= 8;
  379:       lba48  |= lba48_regs->lba_mid_register_hi;
  380:       lba48 <<= 8;
  381:       lba48  |= lba48_regs->lba_low_register_hi;
  382:       lba48  |= lba48_regs->device_register & 0xf;
  383:       lba48 <<= 8;
  384:       lba48  |= lba48_regs->lba_high_register;
  385:       lba48 <<= 8;
  386:       lba48  |= lba48_regs->lba_mid_register;
  387:       lba48 <<= 8;
  388:       lba48  |= lba48_regs->lba_low_register;
  389:       snprintf(tmp, 128, " at LBA = 0x%08"PRIx64" = %"PRIu64, lba48, lba48);
  390:       strcat(s, tmp);
  391:     }
  392:   }
  393: 
  394:   return s;
  395: }
  396: 
  397: static inline const char * construct_st_er_desc(char * s,
  398:   const ata_smart_errorlog_struct * data)
  399: {
  400:   return construct_st_er_desc(s,
  401:     data->commands[4].commandreg,
  402:     data->commands[4].featuresreg,
  403:     data->error_struct.status,
  404:     data->error_struct.error_register,
  405:     data->error_struct.sector_count,
  406:     &data->error_struct, (const ata_smart_exterrlog_error *)0);
  407: }
  408: 
  409: static inline const char * construct_st_er_desc(char * s,
  410:   const ata_smart_exterrlog_error_log * data)
  411: {
  412:   return construct_st_er_desc(s,
  413:     data->commands[4].command_register,
  414:     data->commands[4].features_register,
  415:     data->error.status_register,
  416:     data->error.error_register,
  417:     data->error.count_register_hi << 8 | data->error.count_register,
  418:     (const ata_smart_errorlog_error_struct *)0, &data->error);
  419: }
  420: 
  421: static void print_drive_info(const ata_identify_device * drive,
  422:                              const ata_size_info & sizes,
  423:                              const drive_settings * dbentry)
  424: {
  425:   // format drive information (with byte swapping as needed)
  426:   char model[40+1], serial[20+1], firmware[8+1];
  427:   ata_format_id_string(model, drive->model, sizeof(model)-1);
  428:   ata_format_id_string(serial, drive->serial_no, sizeof(serial)-1);
  429:   ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1);
  430: 
  431:   // Print model family if known
  432:   if (dbentry && *dbentry->modelfamily)
  433:     pout("Model Family:     %s\n", dbentry->modelfamily);
  434: 
  435:   pout("Device Model:     %s\n", infofound(model));
  436:   if (!dont_print_serial_number) {
  437:     pout("Serial Number:    %s\n", infofound(serial));
  438: 
  439:     unsigned oui = 0; uint64_t unique_id = 0;
  440:     int naa = ata_get_wwn(drive, oui, unique_id);
  441:     if (naa >= 0)
  442:       pout("LU WWN Device Id: %x %06x %09"PRIx64"\n", naa, oui, unique_id);
  443:   }
  444:   pout("Firmware Version: %s\n", infofound(firmware));
  445: 
  446:   if (sizes.capacity) {
  447:     // Print capacity
  448:     char num[64], cap[32];
  449:     pout("User Capacity:    %s bytes [%s]\n",
  450:       format_with_thousands_sep(num, sizeof(num), sizes.capacity),
  451:       format_capacity(cap, sizeof(cap), sizes.capacity));
  452: 
  453:     // Print sector sizes.
  454:     if (sizes.phy_sector_size == sizes.log_sector_size)
  455:       pout("Sector Size:      %u bytes logical/physical\n", sizes.log_sector_size);
  456:     else {
  457:       pout("Sector Sizes:     %u bytes logical, %u bytes physical",
  458:          sizes.log_sector_size, sizes.phy_sector_size);
  459:       if (sizes.log_sector_offset)
  460:         pout(" (offset %u bytes)", sizes.log_sector_offset);
  461:       pout("\n");
  462:     }
  463:   }
  464: 
  465:   // See if drive is recognized
  466:   pout("Device is:        %s\n", !dbentry ?
  467:        "Not in smartctl database [for details use: -P showall]":
  468:        "In smartctl database [for details use: -P show]");
  469: 
  470:   // now get ATA version info
  471:   const char *description; unsigned short minorrev;
  472:   int version = ataVersionInfo(&description, drive, &minorrev);
  473: 
  474:   // SMART Support was first added into the ATA/ATAPI-3 Standard with
  475:   // Revision 3 of the document, July 25, 1995.  Look at the "Document
  476:   // Status" revision commands at the beginning of
  477:   // http://www.t13.org/Documents/UploadedDocuments/project/d2008r7b-ATA-3.pdf
  478:   // to see this.  So it's not enough to check if we are ATA-3.
  479:   // Version=-3 indicates ATA-3 BEFORE Revision 3.
  480:   // Version=0 indicates that no info is found. This may happen if
  481:   // the OS provides only part of the IDENTIFY data.
  482: 
  483:   std::string majorstr, minorstr;
  484:   if (version) {
  485:     if (version <= 8) {
  486:       majorstr = strprintf("%d", abs(version));
  487:       if (description)
  488:         minorstr = description;
  489:       else if (!minorrev)
  490:         minorstr = "Exact ATA specification draft version not indicated";
  491:       else
  492:         minorstr = strprintf("Not recognized. Minor revision code: 0x%04x", minorrev);
  493:     }
  494:     else {
  495:       // Bit 9 in word 80 of ATA IDENTIFY data does not mean "ATA-9" but "ACS-2"
  496:       // TODO: handle this in ataVersionInfo()
  497:       majorstr = "8";
  498:       if (description)
  499:         minorstr = description;
  500:       else if (!minorrev)
  501:         minorstr = strprintf("ACS-%d (revision not indicated)", version-9+2);
  502:       else
  503:         minorstr = strprintf("ACS-%d (unknown minor revision code: 0x%04x)", version-9+2, minorrev);
  504:     }
  505:   }
  506: 
  507:   pout("ATA Version is:   %s\n", infofound(majorstr.c_str()));
  508:   pout("ATA Standard is:  %s\n", infofound(minorstr.c_str()));
  509: 
  510:   // print current time and date and timezone
  511:   char timedatetz[DATEANDEPOCHLEN]; dateandtimezone(timedatetz);
  512:   pout("Local Time is:    %s\n", timedatetz);
  513: 
  514:   // Print warning message, if there is one
  515:   if (dbentry && *dbentry->warningmsg)
  516:     pout("\n==> WARNING: %s\n\n", dbentry->warningmsg);
  517: 
  518:   if (!version || version >= 3)
  519:     return;
  520:   
  521:   pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n");
  522:   pout("We will try to proceed in spite of this.\n");
  523: }
  524: 
  525: static const char *OfflineDataCollectionStatus(unsigned char status_byte)
  526: {
  527:   unsigned char stat=status_byte & 0x7f;
  528:   
  529:   switch(stat){
  530:   case 0x00:
  531:     return "was never started";
  532:   case 0x02:
  533:     return "was completed without error";
  534:   case 0x03:
  535:     if (status_byte == 0x03)
  536:       return "is in progress";
  537:     else
  538:       return "is in a Reserved state";
  539:   case 0x04:
  540:     return "was suspended by an interrupting command from host";
  541:   case 0x05:
  542:     return "was aborted by an interrupting command from host";
  543:   case 0x06:
  544:     return "was aborted by the device with a fatal error";
  545:   default:
  546:     if (stat >= 0x40)
  547:       return "is in a Vendor Specific state";
  548:     else
  549:       return "is in a Reserved state";
  550:   }
  551: }
  552:   
  553:   
  554: //  prints verbose value Off-line data collection status byte
  555: static void PrintSmartOfflineStatus(const ata_smart_values * data)
  556: {
  557:   pout("Offline data collection status:  (0x%02x)\t",
  558:        (int)data->offline_data_collection_status);
  559:     
  560:   // Off-line data collection status byte is not a reserved
  561:   // or vendor specific value
  562:   pout("Offline data collection activity\n"
  563:        "\t\t\t\t\t%s.\n", OfflineDataCollectionStatus(data->offline_data_collection_status));
  564:   
  565:   // Report on Automatic Data Collection Status.  Only IBM documents
  566:   // this bit.  See SFF 8035i Revision 2 for details.
  567:   if (data->offline_data_collection_status & 0x80)
  568:     pout("\t\t\t\t\tAuto Offline Data Collection: Enabled.\n");
  569:   else
  570:     pout("\t\t\t\t\tAuto Offline Data Collection: Disabled.\n");
  571:   
  572:   return;
  573: }
  574: 
  575: static void PrintSmartSelfExecStatus(const ata_smart_values * data,
  576:                                      unsigned char fix_firmwarebug)
  577: {
  578:    pout("Self-test execution status:      ");
  579:    
  580:    switch (data->self_test_exec_status >> 4)
  581:    {
  582:       case 0:
  583:         pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t",
  584:                 (int)data->self_test_exec_status);
  585:         pout("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n");
  586:         break;
  587:        case 1:
  588:          pout("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t",
  589:                  (int)data->self_test_exec_status);
  590:          pout("the host.\n");
  591:          break;
  592:        case 2:
  593:          pout("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t",
  594:                  (int)data->self_test_exec_status);
  595:          pout("by the host with a hard or soft reset.\n");
  596:          break;
  597:        case 3:
  598:           pout("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t",
  599:                   (int)data->self_test_exec_status);
  600:           pout("occurred while the device was executing\n\t\t\t\t\t");
  601:           pout("its self-test routine and the device \n\t\t\t\t\t");
  602:           pout("was unable to complete the self-test \n\t\t\t\t\t");
  603:           pout("routine.\n");
  604:           break;
  605:        case 4:
  606:           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
  607:                   (int)data->self_test_exec_status);
  608:           pout("a test element that failed and the test\n\t\t\t\t\t");
  609:           pout("element that failed is not known.\n");
  610:           break;
  611:        case 5:
  612:           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
  613:                   (int)data->self_test_exec_status);
  614:           pout("the electrical element of the test\n\t\t\t\t\t");
  615:           pout("failed.\n");
  616:           break;
  617:        case 6:
  618:           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
  619:                   (int)data->self_test_exec_status);
  620:           pout("the servo (and/or seek) element of the \n\t\t\t\t\t");
  621:           pout("test failed.\n");
  622:           break;
  623:        case 7:
  624:           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
  625:                   (int)data->self_test_exec_status);
  626:           pout("the read element of the test failed.\n");
  627:           break;
  628:        case 8:
  629:           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
  630:                   (int)data->self_test_exec_status);
  631:           pout("a test element that failed and the\n\t\t\t\t\t");
  632:           pout("device is suspected of having handling\n\t\t\t\t\t");
  633:           pout("damage.\n");
  634:           break;
  635:        case 15:
  636:           if (fix_firmwarebug == FIX_SAMSUNG3 && data->self_test_exec_status == 0xf0) {
  637:             pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t",
  638:                     (int)data->self_test_exec_status);
  639:             pout("with unknown result or self-test in\n\t\t\t\t\t");
  640:             pout("progress with less than 10%% remaining.\n");
  641:           }
  642:           else {
  643:             pout("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t",
  644:                     (int)data->self_test_exec_status);
  645:             pout("%1d0%% of test remaining.\n", 
  646:                   (int)(data->self_test_exec_status & 0x0f));
  647:           }
  648:           break;
  649:        default:
  650:           pout("(%4d)\tReserved.\n",
  651:                   (int)data->self_test_exec_status);
  652:           break;
  653:    }
  654:         
  655: }
  656: 
  657: static void PrintSmartTotalTimeCompleteOffline (const ata_smart_values * data)
  658: {
  659:   pout("Total time to complete Offline \n");
  660:   pout("data collection: \t\t(%5d) seconds.\n", 
  661:        (int)data->total_time_to_complete_off_line);
  662: }
  663: 
  664: static void PrintSmartOfflineCollectCap(const ata_smart_values *data)
  665: {
  666:   pout("Offline data collection\n");
  667:   pout("capabilities: \t\t\t (0x%02x) ",
  668:        (int)data->offline_data_collection_capability);
  669:   
  670:   if (data->offline_data_collection_capability == 0x00){
  671:     pout("\tOffline data collection not supported.\n");
  672:   } 
  673:   else {
  674:     pout( "%s\n", isSupportExecuteOfflineImmediate(data)?
  675:           "SMART execute Offline immediate." :
  676:           "No SMART execute Offline immediate.");
  677:     
  678:     pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? 
  679:           "Auto Offline data collection on/off support.":
  680:           "No Auto Offline data collection support.");
  681:     
  682:     pout( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? 
  683:           "Abort Offline collection upon new\n\t\t\t\t\tcommand.":
  684:           "Suspend Offline collection upon new\n\t\t\t\t\tcommand.");
  685:     
  686:     pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? 
  687:           "Offline surface scan supported.":
  688:           "No Offline surface scan supported.");
  689:     
  690:     pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? 
  691:           "Self-test supported.":
  692:           "No Self-test supported.");
  693: 
  694:     pout( "\t\t\t\t\t%s\n", isSupportConveyanceSelfTest(data)? 
  695:           "Conveyance Self-test supported.":
  696:           "No Conveyance Self-test supported.");
  697: 
  698:     pout( "\t\t\t\t\t%s\n", isSupportSelectiveSelfTest(data)? 
  699:           "Selective Self-test supported.":
  700:           "No Selective Self-test supported.");
  701:   }
  702: }
  703: 
  704: static void PrintSmartCapability(const ata_smart_values *data)
  705: {
  706:    pout("SMART capabilities:            ");
  707:    pout("(0x%04x)\t", (int)data->smart_capability);
  708:    
  709:    if (data->smart_capability == 0x00)
  710:    {
  711:        pout("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n");
  712:    } 
  713:    else 
  714:    {
  715:         
  716:       pout( "%s\n", (data->smart_capability & 0x01)? 
  717:               "Saves SMART data before entering\n\t\t\t\t\tpower-saving mode.":
  718:               "Does not save SMART data before\n\t\t\t\t\tentering power-saving mode.");
  719:                 
  720:       if ( data->smart_capability & 0x02 )
  721:       {
  722:           pout("\t\t\t\t\tSupports SMART auto save timer.\n");
  723:       }
  724:    }
  725: }
  726: 
  727: static void PrintSmartErrorLogCapability(const ata_smart_values * data, const ata_identify_device * identity)
  728: {
  729:    pout("Error logging capability:       ");
  730:     
  731:    if ( isSmartErrorLogCapable(data, identity) )
  732:    {
  733:       pout(" (0x%02x)\tError logging supported.\n",
  734:                (int)data->errorlog_capability);
  735:    }
  736:    else {
  737:        pout(" (0x%02x)\tError logging NOT supported.\n",
  738:                 (int)data->errorlog_capability);
  739:    }
  740: }
  741: 
  742: static void PrintSmartShortSelfTestPollingTime(const ata_smart_values * data)
  743: {
  744:   pout("Short self-test routine \n");
  745:   if (isSupportSelfTest(data))
  746:     pout("recommended polling time: \t (%4d) minutes.\n", 
  747:          (int)data->short_test_completion_time);
  748:   else
  749:     pout("recommended polling time: \t        Not Supported.\n");
  750: }
  751: 
  752: static void PrintSmartExtendedSelfTestPollingTime(const ata_smart_values * data)
  753: {
  754:   pout("Extended self-test routine\n");
  755:   if (isSupportSelfTest(data))
  756:     pout("recommended polling time: \t (%4d) minutes.\n", 
  757:          TestTime(data, EXTEND_SELF_TEST));
  758:   else
  759:     pout("recommended polling time: \t        Not Supported.\n");
  760: }
  761: 
  762: static void PrintSmartConveyanceSelfTestPollingTime(const ata_smart_values * data)
  763: {
  764:   pout("Conveyance self-test routine\n");
  765:   if (isSupportConveyanceSelfTest(data))
  766:     pout("recommended polling time: \t (%4d) minutes.\n", 
  767:          (int)data->conveyance_test_completion_time);
  768:   else
  769:     pout("recommended polling time: \t        Not Supported.\n");
  770: }
  771: 
  772: // Check SMART attribute table for Threshold failure
  773: // onlyfailed=0: are or were any age or prefailure attributes <= threshold
  774: // onlyfailed=1: are any prefailure attributes <= threshold now
  775: static int find_failed_attr(const ata_smart_values * data,
  776:                             const ata_smart_thresholds_pvt * thresholds,
  777:                             const ata_vendor_attr_defs & defs, int onlyfailed)
  778: {
  779:   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
  780:     const ata_smart_attribute & attr = data->vendor_attributes[i];
  781: 
  782:     ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs);
  783: 
  784:     if (!onlyfailed) {
  785:       if (state >= ATTRSTATE_FAILED_PAST)
  786:         return attr.id;
  787:     }
  788:     else {
  789:       if (state == ATTRSTATE_FAILED_NOW && ATTRIBUTE_FLAGS_PREFAILURE(attr.flags))
  790:         return attr.id;
  791:     }
  792:   }
  793:   return 0;
  794: }
  795: 
  796: // onlyfailed=0 : print all attribute values
  797: // onlyfailed=1:  just ones that are currently failed and have prefailure bit set
  798: // onlyfailed=2:  ones that are failed, or have failed with or without prefailure bit set
  799: static void PrintSmartAttribWithThres(const ata_smart_values * data,
  800:                                       const ata_smart_thresholds_pvt * thresholds,
  801:                                       const ata_vendor_attr_defs & defs,
  802:                                       int onlyfailed, unsigned char format)
  803: {
  804:   bool brief  = !!(format & ata_print_options::FMT_BRIEF);
  805:   bool hexid  = !!(format & ata_print_options::FMT_HEX_ID);
  806:   bool hexval = !!(format & ata_print_options::FMT_HEX_VAL);
  807:   bool needheader = true;
  808: 
  809:   // step through all vendor attributes
  810:   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
  811:     const ata_smart_attribute & attr = data->vendor_attributes[i];
  812: 
  813:     // Check attribute and threshold
  814:     unsigned char threshold = 0;
  815:     ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs, &threshold);
  816:     if (state == ATTRSTATE_NON_EXISTING)
  817:       continue;
  818: 
  819:     // These break out of the loop if we are only printing certain entries...
  820:     if (onlyfailed == 1 && !(ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) && state == ATTRSTATE_FAILED_NOW))
  821:       continue;
  822: 
  823:     if (onlyfailed == 2 && state < ATTRSTATE_FAILED_PAST)
  824:       continue;
  825: 
  826:     // print header only if needed
  827:     if (needheader) {
  828:       if (!onlyfailed) {
  829:         pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
  830:         pout("Vendor Specific SMART Attributes with Thresholds:\n");
  831:       }
  832:       if (!brief)
  833:         pout("ID#%s ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n",
  834:              (!hexid ? "" : " "));
  835:       else
  836:         pout("ID#%s ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n",
  837:              (!hexid ? "" : " "));
  838:       needheader = false;
  839:     }
  840: 
  841:     // Format value, worst, threshold
  842:     std::string valstr, worstr, threstr;
  843:     if (state > ATTRSTATE_NO_NORMVAL)
  844:       valstr = (!hexval ? strprintf("%.3d",   attr.current)
  845:                         : strprintf("0x%02x", attr.current));
  846:     else
  847:       valstr = (!hexval ? "---" : "----");
  848:     if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL))
  849:       worstr = (!hexval ? strprintf("%.3d",   attr.worst)
  850:                         : strprintf("0x%02x", attr.worst));
  851:     else
  852:       worstr = (!hexval ? "---" : "----");
  853:     if (state > ATTRSTATE_NO_THRESHOLD)
  854:       threstr = (!hexval ? strprintf("%.3d",   threshold)
  855:                          : strprintf("0x%02x", threshold));
  856:     else
  857:       threstr = (!hexval ? "---" : "----");
  858: 
  859:     // Print line for each valid attribute
  860:     std::string idstr = (!hexid ? strprintf("%3d",    attr.id)
  861:                                 : strprintf("0x%02x", attr.id));
  862:     std::string attrname = ata_get_smart_attr_name(attr.id, defs);
  863:     std::string rawstr = ata_format_attr_raw_value(attr, defs);
  864: 
  865:     if (!brief)
  866:       pout("%s %-24s0x%04x   %-4s  %-4s  %-4s   %-10s%-9s%-12s%s\n",
  867:            idstr.c_str(), attrname.c_str(), attr.flags,
  868:            valstr.c_str(), worstr.c_str(), threstr.c_str(),
  869:            (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) ? "Pre-fail" : "Old_age"),
  870:            (ATTRIBUTE_FLAGS_ONLINE(attr.flags)     ? "Always"   : "Offline"),
  871:            (state == ATTRSTATE_FAILED_NOW  ? "FAILING_NOW" :
  872:             state == ATTRSTATE_FAILED_PAST ? "In_the_past"
  873:                                            : "    -"        ) ,
  874:             rawstr.c_str());
  875:     else
  876:       pout("%s %-24s%c%c%c%c%c%c%c  %-4s  %-4s  %-4s   %-5s%s\n",
  877:            idstr.c_str(), attrname.c_str(),
  878:            (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags)     ? 'P' : '-'),
  879:            (ATTRIBUTE_FLAGS_ONLINE(attr.flags)         ? 'O' : '-'),
  880:            (ATTRIBUTE_FLAGS_PERFORMANCE(attr.flags)    ? 'S' : '-'),
  881:            (ATTRIBUTE_FLAGS_ERRORRATE(attr.flags)      ? 'R' : '-'),
  882:            (ATTRIBUTE_FLAGS_EVENTCOUNT(attr.flags)     ? 'C' : '-'),
  883:            (ATTRIBUTE_FLAGS_SELFPRESERVING(attr.flags) ? 'K' : '-'),
  884:            (ATTRIBUTE_FLAGS_OTHER(attr.flags)          ? '+' : ' '),
  885:            valstr.c_str(), worstr.c_str(), threstr.c_str(),
  886:            (state == ATTRSTATE_FAILED_NOW  ? "NOW"  :
  887:             state == ATTRSTATE_FAILED_PAST ? "Past"
  888:                                            : "-"     ),
  889:             rawstr.c_str());
  890: 
  891:   }
  892: 
  893:   if (!needheader) {
  894:     if (!onlyfailed && brief) {
  895:         int n = (!hexid ? 28 : 29);
  896:         pout("%*s||||||_ K auto-keep\n"
  897:              "%*s|||||__ C event count\n"
  898:              "%*s||||___ R error rate\n"
  899:              "%*s|||____ S speed/performance\n"
  900:              "%*s||_____ O updated online\n"
  901:              "%*s|______ P prefailure warning\n",
  902:              n, "", n, "", n, "", n, "", n, "", n, "");
  903:     }
  904:     pout("\n");
  905:   }
  906: }
  907: 
  908: // Print SMART related SCT capabilities
  909: static void ataPrintSCTCapability(const ata_identify_device *drive)
  910: {
  911:   unsigned short sctcaps = drive->words088_255[206-88];
  912:   if (!(sctcaps & 0x01))
  913:     return;
  914:   pout("SCT capabilities: \t       (0x%04x)\tSCT Status supported.\n", sctcaps);
  915:   if (sctcaps & 0x08)
  916:     pout("\t\t\t\t\tSCT Error Recovery Control supported.\n");
  917:   if (sctcaps & 0x10)
  918:     pout("\t\t\t\t\tSCT Feature Control supported.\n");
  919:   if (sctcaps & 0x20)
  920:     pout("\t\t\t\t\tSCT Data Table supported.\n");
  921: }
  922: 
  923: 
  924: static void PrintGeneralSmartValues(const ata_smart_values *data, const ata_identify_device *drive,
  925:                                     unsigned char fix_firmwarebug)
  926: {
  927:   pout("General SMART Values:\n");
  928:   
  929:   PrintSmartOfflineStatus(data); 
  930:   
  931:   if (isSupportSelfTest(data)){
  932:     PrintSmartSelfExecStatus(data, fix_firmwarebug);
  933:   }
  934:   
  935:   PrintSmartTotalTimeCompleteOffline(data);
  936:   PrintSmartOfflineCollectCap(data);
  937:   PrintSmartCapability(data);
  938:   
  939:   PrintSmartErrorLogCapability(data, drive);
  940: 
  941:   pout( "\t\t\t\t\t%s\n", isGeneralPurposeLoggingCapable(drive)?
  942:         "General Purpose Logging supported.":
  943:         "No General Purpose Logging support.");
  944: 
  945:   if (isSupportSelfTest(data)){
  946:     PrintSmartShortSelfTestPollingTime (data);
  947:     PrintSmartExtendedSelfTestPollingTime (data);
  948:   }
  949:   if (isSupportConveyanceSelfTest(data))
  950:     PrintSmartConveyanceSelfTestPollingTime (data);
  951: 
  952:   ataPrintSCTCapability(drive);
  953: 
  954:   pout("\n");
  955: }
  956: 
  957: // Get # sectors of a log addr, 0 if log does not exist.
  958: static unsigned GetNumLogSectors(const ata_smart_log_directory * logdir, unsigned logaddr, bool gpl)
  959: {
  960:   if (!logdir)
  961:     return 0;
  962:   if (logaddr > 0xff)
  963:     return 0;
  964:   if (logaddr == 0)
  965:     return 1;
  966:   unsigned n = logdir->entry[logaddr-1].numsectors;
  967:   if (gpl)
  968:     // GP logs may have >255 sectors
  969:     n |= logdir->entry[logaddr-1].reserved << 8;
  970:   return n;
  971: }
  972: 
  973: // Get name of log.
  974: // Table A.2 of T13/2161-D Revision 2 (ACS-3), February 21, 2012.
  975: static const char * GetLogName(unsigned logaddr)
  976: {
  977:     switch (logaddr) {
  978:       case 0x00: return "Log Directory";
  979:       case 0x01: return "Summary SMART error log";
  980:       case 0x02: return "Comprehensive SMART error log";
  981:       case 0x03: return "Ext. Comprehensive SMART error log";
  982:       case 0x04: return "Device Statistics log";
  983:       case 0x05: return "Reserved for the CFA"; // ACS-2
  984:       case 0x06: return "SMART self-test log";
  985:       case 0x07: return "Extended self-test log";
  986:       case 0x08: return "Power Conditions log"; // ACS-2
  987:       case 0x09: return "Selective self-test log";
  988:       case 0x0d: return "LPS Mis-alignment log"; // ACS-2
  989:       case 0x10: return "NCQ Command Error log";
  990:       case 0x11: return "SATA Phy Event Counters";
  991:       case 0x12: return "SATA NCQ Queue Management log"; // ACS-3
  992:       case 0x13: return "SATA NCQ Send and Receive log"; // ACS-3
  993:       case 0x14:
  994:       case 0x15:
  995:       case 0x16: return "Reserved for Serial ATA";
  996:       case 0x19: return "LBA Status log"; // ACS-3
  997:       case 0x20: return "Streaming performance log"; // Obsolete
  998:       case 0x21: return "Write stream error log";
  999:       case 0x22: return "Read stream error log";
 1000:       case 0x23: return "Delayed sector log"; // Obsolete
 1001:       case 0x24: return "Current Device Internal Status Data log"; // ACS-3
 1002:       case 0x25: return "Saved Device Internal Status Data log"; // ACS-3
 1003:       case 0x30: return "IDENTIFY DEVICE data log"; // ACS-3
 1004:       case 0xe0: return "SCT Command/Status";
 1005:       case 0xe1: return "SCT Data Transfer";
 1006:       default:
 1007:         if (0xa0 <= logaddr && logaddr <= 0xdf)
 1008:           return "Device vendor specific log";
 1009:         if (0x80 <= logaddr && logaddr <= 0x9f)
 1010:           return "Host vendor specific log";
 1011:         return "Reserved";
 1012:     }
 1013:     /*NOTREACHED*/
 1014: }
 1015: 
 1016: // Print SMART and/or GP Log Directory
 1017: static void PrintLogDirectories(const ata_smart_log_directory * gplogdir,
 1018:                                 const ata_smart_log_directory * smartlogdir)
 1019: {
 1020:   if (gplogdir)
 1021:     pout("General Purpose Log Directory Version %u\n", gplogdir->logversion);
 1022:   if (smartlogdir)
 1023:     pout("SMART %sLog Directory Version %u%s\n",
 1024:          (gplogdir ? "          " : ""), smartlogdir->logversion,
 1025:          (smartlogdir->logversion==1 ? " [multi-sector log support]" : ""));
 1026: 
 1027:   for (unsigned i = 0; i <= 0xff; i++) {
 1028:     // Get number of sectors
 1029:     unsigned smart_numsect = GetNumLogSectors(smartlogdir, i, false);
 1030:     unsigned gp_numsect    = GetNumLogSectors(gplogdir   , i, true );
 1031: 
 1032:     if (!(smart_numsect || gp_numsect))
 1033:       continue; // Log does not exist
 1034: 
 1035:     const char * name = GetLogName(i);
 1036: 
 1037:     // Print name and length of log.
 1038:     // If both SMART and GP exist, print separate entries if length differ.
 1039:     if (smart_numsect == gp_numsect)
 1040:       pout(  "GP/S  Log at address 0x%02x has %4d sectors [%s]\n", i, smart_numsect, name);
 1041:     else {
 1042:       if (gp_numsect)
 1043:         pout("GP %sLog at address 0x%02x has %4d sectors [%s]\n", (smartlogdir?"   ":""),
 1044:              i, gp_numsect, name);
 1045:       if (smart_numsect)
 1046:         pout("SMART Log at address 0x%02x has %4d sectors [%s]\n", i, smart_numsect, name);
 1047:     }
 1048:   }
 1049:   pout("\n");
 1050: }
 1051: 
 1052: // Print hexdump of log pages.
 1053: // Format is compatible with 'xxd -r'.
 1054: static void PrintLogPages(const char * type, const unsigned char * data,
 1055:                           unsigned char logaddr, unsigned page,
 1056:                           unsigned num_pages, unsigned max_pages)
 1057: {
 1058:   pout("%s Log 0x%02x [%s], Page %u-%u (of %u)\n",
 1059:     type, logaddr, GetLogName(logaddr), page, page+num_pages-1, max_pages);
 1060:   for (unsigned i = 0; i < num_pages * 512; i += 16) {
 1061:     const unsigned char * p = data+i;
 1062:     pout("%07x: %02x %02x %02x %02x %02x %02x %02x %02x "
 1063:                "%02x %02x %02x %02x %02x %02x %02x %02x ",
 1064:          (page * 512) + i,
 1065:          p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7],
 1066:          p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15]);
 1067: #define P(n) (' ' <= p[n] && p[n] <= '~' ? (int)p[n] : '.')
 1068:     pout("|%c%c%c%c%c%c%c%c"
 1069:           "%c%c%c%c%c%c%c%c|\n",
 1070:          P( 0), P( 1), P( 2), P( 3), P( 4), P( 5), P( 6), P( 7),
 1071:          P( 8), P( 9), P(10), P(11), P(12), P(13), P(14), P(15));
 1072: #undef P
 1073:     if ((i & 0x1ff) == 0x1f0)
 1074:       pout("\n");
 1075:   }
 1076: }
 1077: 
 1078: ///////////////////////////////////////////////////////////////////////
 1079: // Device statistics (Log 0x04)
 1080: 
 1081: // See Section A.5 of
 1082: //   ATA/ATAPI Command Set - 3 (ACS-3)
 1083: //   T13/2161-D Revision 2, February 21, 2012.
 1084: 
 1085: struct devstat_entry_info
 1086: {
 1087:   short size; // #bytes of value, -1 for signed char
 1088:   const char * name;
 1089: };
 1090: 
 1091: const devstat_entry_info devstat_info_0x00[] = {
 1092:   {  2, "List of supported log pages" },
 1093:   {  0, 0 }
 1094: };
 1095: 
 1096: const devstat_entry_info devstat_info_0x01[] = {
 1097:   {  2, "General Statistics" },
 1098:   {  4, "Lifetime Power-On Resets" },
 1099:   {  4, "Power-on Hours" }, // spec says no flags(?)
 1100:   {  6, "Logical Sectors Written" },
 1101:   {  6, "Number of Write Commands" },
 1102:   {  6, "Logical Sectors Read" },
 1103:   {  6, "Number of Read Commands" },
 1104:   {  6, "Date and Time TimeStamp" }, // ACS-3
 1105:   {  0, 0 }
 1106: };
 1107: 
 1108: const devstat_entry_info devstat_info_0x02[] = {
 1109:   {  2, "Free-Fall Statistics" },
 1110:   {  4, "Number of Free-Fall Events Detected" },
 1111:   {  4, "Overlimit Shock Events" },
 1112:   {  0, 0 }
 1113: };
 1114: 
 1115: const devstat_entry_info devstat_info_0x03[] = {
 1116:   {  2, "Rotating Media Statistics" },
 1117:   {  4, "Spindle Motor Power-on Hours" },
 1118:   {  4, "Head Flying Hours" },
 1119:   {  4, "Head Load Events" },
 1120:   {  4, "Number of Reallocated Logical Sectors" },
 1121:   {  4, "Read Recovery Attempts" },
 1122:   {  4, "Number of Mechanical Start Failures" },
 1123:   {  4, "Number of Realloc. Candidate Logical Sectors" }, // ACS-3
 1124:   {  0, 0 }
 1125: };
 1126: 
 1127: const devstat_entry_info devstat_info_0x04[] = {
 1128:   {  2, "General Errors Statistics" },
 1129:   {  4, "Number of Reported Uncorrectable Errors" },
 1130: //{  4, "Number of Resets Between Command Acceptance and Command Completion" },
 1131:   {  4, "Resets Between Cmd Acceptance and Completion" },
 1132:   {  0, 0 }
 1133: };
 1134: 
 1135: const devstat_entry_info devstat_info_0x05[] = {
 1136:   {  2, "Temperature Statistics" },
 1137:   { -1, "Current Temperature" },
 1138:   { -1, "Average Short Term Temperature" },
 1139:   { -1, "Average Long Term Temperature" },
 1140:   { -1, "Highest Temperature" },
 1141:   { -1, "Lowest Temperature" },
 1142:   { -1, "Highest Average Short Term Temperature" },
 1143:   { -1, "Lowest Average Short Term Temperature" },
 1144:   { -1, "Highest Average Long Term Temperature" },
 1145:   { -1, "Lowest Average Long Term Temperature" },
 1146:   {  4, "Time in Over-Temperature" },
 1147:   { -1, "Specified Maximum Operating Temperature" },
 1148:   {  4, "Time in Under-Temperature" },
 1149:   { -1, "Specified Minimum Operating Temperature" },
 1150:   {  0, 0 }
 1151: };
 1152: 
 1153: const devstat_entry_info devstat_info_0x06[] = {
 1154:   {  2, "Transport Statistics" },
 1155:   {  4, "Number of Hardware Resets" },
 1156:   {  4, "Number of ASR Events" },
 1157:   {  4, "Number of Interface CRC Errors" },
 1158:   {  0, 0 }
 1159: };
 1160: 
 1161: const devstat_entry_info devstat_info_0x07[] = {
 1162:   {  2, "Solid State Device Statistics" },
 1163:   {  1, "Percentage Used Endurance Indicator" },
 1164:   {  0, 0 }
 1165: };
 1166: 
 1167: const devstat_entry_info * devstat_infos[] = {
 1168:   devstat_info_0x00,
 1169:   devstat_info_0x01,
 1170:   devstat_info_0x02,
 1171:   devstat_info_0x03,
 1172:   devstat_info_0x04,
 1173:   devstat_info_0x05,
 1174:   devstat_info_0x06,
 1175:   devstat_info_0x07
 1176: };
 1177: 
 1178: const int num_devstat_infos = sizeof(devstat_infos)/sizeof(devstat_infos[0]);
 1179: 
 1180: static void print_device_statistics_page(const unsigned char * data, int page,
 1181:   bool & need_trailer)
 1182: {
 1183:   const devstat_entry_info * info = (page < num_devstat_infos ? devstat_infos[page] : 0);
 1184:   const char * name = (info ? info[0].name : "Unknown Statistics");
 1185: 
 1186:   // Check page number in header
 1187:   static const char line[] = "  =====  =                =  == ";
 1188:   if (!data[2]) {
 1189:     pout("%3d%s%s (empty) ==\n", page, line, name);
 1190:     return;
 1191:   }
 1192:   if (data[2] != page) {
 1193:     pout("%3d%s%s (invalid page %d in header) ==\n", page, line, name, data[2]);
 1194:     return;
 1195:   }
 1196: 
 1197:   pout("%3d%s%s (rev %d) ==\n", page, line, name, data[0]);
 1198: 
 1199:   // Print entries
 1200:   for (int i = 1, offset = 8; offset < 512-7; i++, offset+=8) {
 1201:     // Check for last known entry
 1202:     if (info && !info[i].size)
 1203:       info = 0;
 1204: 
 1205:     // Skip unsupported entries
 1206:     unsigned char flags = data[offset+7];
 1207:     if (!(flags & 0x80))
 1208:       continue;
 1209: 
 1210:     // Get value size, default to max if unknown
 1211:     int size = (info ? info[i].size : 7);
 1212: 
 1213:     // Format value
 1214:     char valstr[32];
 1215:     if (flags & 0x40) { // valid flag
 1216:       // Get value
 1217:       int64_t val;
 1218:       if (size < 0) {
 1219:         val = (signed char)data[offset];
 1220:       }
 1221:       else {
 1222:         val = 0;
 1223:         for (int j = 0; j < size; j++)
 1224:           val |= (int64_t)data[offset+j] << (j*8);
 1225:       }
 1226:       snprintf(valstr, sizeof(valstr), "%"PRId64, val);
 1227:     }
 1228:     else {
 1229:       // Value not known (yet)
 1230:       strcpy(valstr, "-");
 1231:     }
 1232: 
 1233:     pout("%3d  0x%03x  %d%c %15s%c %s\n",
 1234:       page, offset,
 1235:       abs(size),
 1236:       (flags & 0x1f ? '+' : ' '), // unknown flags
 1237:       valstr,
 1238:       (flags & 0x20 ? '~' : ' '), // normalized flag
 1239:       (info ? info[i].name : "Unknown"));
 1240:     if (flags & 0x20)
 1241:       need_trailer = true;
 1242:   }
 1243: }
 1244: 
 1245: static bool print_device_statistics(ata_device * device, unsigned nsectors,
 1246:   const std::vector<int> & single_pages, bool all_pages, bool ssd_page)
 1247: {
 1248:   // Read list of supported pages from page 0
 1249:   unsigned char page_0[512] = {0, };
 1250:   if (!ataReadLogExt(device, 0x04, 0, 0, page_0, 1))
 1251:     return false;
 1252: 
 1253:   unsigned char nentries = page_0[8];
 1254:   if (!(page_0[2] == 0 && nentries > 0)) {
 1255:     pout("Device Statistics page 0 is invalid (page=%d, nentries=%d)\n", page_0[2], nentries);
 1256:     return false;
 1257:   }
 1258: 
 1259:   // Prepare list of pages to print
 1260:   std::vector<int> pages;
 1261:   unsigned i;
 1262:   if (all_pages) {
 1263:     // Add all supported pages
 1264:     for (i = 0; i < nentries; i++) {
 1265:       int page = page_0[8+1+i];
 1266:       if (page)
 1267:         pages.push_back(page);
 1268:     }
 1269:     ssd_page = false;
 1270:   }
 1271:   // Add manually specified pages
 1272:   bool print_page_0 = false;
 1273:   for (i = 0; i < single_pages.size() || ssd_page; i++) {
 1274:     int page = (i < single_pages.size() ? single_pages[i] : 7);
 1275:     if (!page)
 1276:       print_page_0 = true;
 1277:     else if (page >= (int)nsectors)
 1278:       pout("Device Statistics Log has only %u pages\n", nsectors);
 1279:     else
 1280:       pages.push_back(page);
 1281:     if (page == 7)
 1282:       ssd_page = false;
 1283:   }
 1284: 
 1285:   // Print list of supported pages if requested
 1286:   if (print_page_0) {
 1287:     pout("Device Statistics (GP Log 0x04) supported pages\n");
 1288:     pout("Page Description\n");
 1289:     for (i = 0; i < nentries; i++) {
 1290:       int page = page_0[8+1+i];
 1291:       pout("%3d  %s\n", page,
 1292:         (page < num_devstat_infos ? devstat_infos[page][0].name : "Unknown Statistics"));
 1293:     }
 1294:     pout("\n");
 1295:   }
 1296: 
 1297:   // Read & print pages
 1298:   if (!pages.empty()) {
 1299:     pout("Device Statistics (GP Log 0x04)\n");
 1300:     pout("Page Offset Size         Value  Description\n");
 1301:     bool need_trailer = false;
 1302: 
 1303:     for (i = 0; i <  pages.size(); i++) {
 1304:       int page = pages[i];
 1305:       unsigned char page_n[512] = {0, };
 1306:       if (!ataReadLogExt(device, 0x04, 0, page, page_n, 1))
 1307:         return false;
 1308:       print_device_statistics_page(page_n, page, need_trailer);
 1309:     }
 1310: 
 1311:     if (need_trailer)
 1312:       pout("%30s|_ ~ normalized value\n", "");
 1313:     pout("\n");
 1314:   }
 1315: 
 1316:   return true;
 1317: }
 1318: 
 1319: 
 1320: ///////////////////////////////////////////////////////////////////////
 1321: 
 1322: // Print log 0x11
 1323: static void PrintSataPhyEventCounters(const unsigned char * data, bool reset)
 1324: {
 1325:   if (checksum(data))
 1326:     checksumwarning("SATA Phy Event Counters");
 1327:   pout("SATA Phy Event Counters (GP Log 0x11)\n");
 1328:   if (data[0] || data[1] || data[2] || data[3])
 1329:     pout("[Reserved: 0x%02x 0x%02x 0x%02x 0x%02x]\n",
 1330:     data[0], data[1], data[2], data[3]);
 1331:   pout("ID      Size     Value  Description\n");
 1332: 
 1333:   for (unsigned i = 4; ; ) {
 1334:     // Get counter id and size (bits 14:12)
 1335:     unsigned id = data[i] | (data[i+1] << 8);
 1336:     unsigned size = ((id >> 12) & 0x7) << 1;
 1337:     id &= 0x8fff;
 1338: 
 1339:     // End of counter table ?
 1340:     if (!id)
 1341:       break;
 1342:     i += 2;
 1343: 
 1344:     if (!(2 <= size && size <= 8 && i + size < 512)) {
 1345:       pout("0x%04x  %u: Invalid entry\n", id, size);
 1346:       break;
 1347:     }
 1348: 
 1349:     // Get value
 1350:     uint64_t val = 0, max_val = 0;
 1351:     for (unsigned j = 0; j < size; j+=2) {
 1352:         val |= (uint64_t)(data[i+j] | (data[i+j+1] << 8)) << (j*8);
 1353:         max_val |= (uint64_t)0xffffU << (j*8);
 1354:     }
 1355:     i += size;
 1356: 
 1357:     // Get name
 1358:     const char * name;
 1359:     switch (id) {
 1360:       case 0x001: name = "Command failed due to ICRC error"; break; // Mandatory
 1361:       case 0x002: name = "R_ERR response for data FIS"; break;
 1362:       case 0x003: name = "R_ERR response for device-to-host data FIS"; break;
 1363:       case 0x004: name = "R_ERR response for host-to-device data FIS"; break;
 1364:       case 0x005: name = "R_ERR response for non-data FIS"; break;
 1365:       case 0x006: name = "R_ERR response for device-to-host non-data FIS"; break;
 1366:       case 0x007: name = "R_ERR response for host-to-device non-data FIS"; break;
 1367:       case 0x008: name = "Device-to-host non-data FIS retries"; break;
 1368:       case 0x009: name = "Transition from drive PhyRdy to drive PhyNRdy"; break;
 1369:       case 0x00A: name = "Device-to-host register FISes sent due to a COMRESET"; break; // Mandatory
 1370:       case 0x00B: name = "CRC errors within host-to-device FIS"; break;
 1371:       case 0x00D: name = "Non-CRC errors within host-to-device FIS"; break;
 1372:       case 0x00F: name = "R_ERR response for host-to-device data FIS, CRC"; break;
 1373:       case 0x010: name = "R_ERR response for host-to-device data FIS, non-CRC"; break;
 1374:       case 0x012: name = "R_ERR response for host-to-device non-data FIS, CRC"; break;
 1375:       case 0x013: name = "R_ERR response for host-to-device non-data FIS, non-CRC"; break;
 1376:       default:    name = (id & 0x8000 ? "Vendor specific" : "Unknown"); break;
 1377:     }
 1378: 
 1379:     // Counters stop at max value, add '+' in this case
 1380:     pout("0x%04x  %u %12"PRIu64"%c %s\n", id, size, val,
 1381:       (val == max_val ? '+' : ' '), name);
 1382:   }
 1383:   if (reset)
 1384:     pout("All counters reset\n");
 1385:   pout("\n");
 1386: }
 1387: 
 1388: // Get description for 'state' value from SMART Error Logs
 1389: static const char * get_error_log_state_desc(unsigned state)
 1390: {
 1391:   state &= 0x0f;
 1392:   switch (state){
 1393:     case 0x0: return "in an unknown state";
 1394:     case 0x1: return "sleeping";
 1395:     case 0x2: return "in standby mode";
 1396:     case 0x3: return "active or idle";
 1397:     case 0x4: return "doing SMART Offline or Self-test";
 1398:   default:
 1399:     return (state < 0xb ? "in a reserved state"
 1400:                         : "in a vendor specific state");
 1401:   }
 1402: }
 1403: 
 1404: // returns number of errors
 1405: static int PrintSmartErrorlog(const ata_smart_errorlog *data,
 1406:                               unsigned char fix_firmwarebug)
 1407: {
 1408:   pout("SMART Error Log Version: %d\n", (int)data->revnumber);
 1409:   
 1410:   // if no errors logged, return
 1411:   if (!data->error_log_pointer){
 1412:     pout("No Errors Logged\n\n");
 1413:     return 0;
 1414:   }
 1415:   print_on();
 1416:   // If log pointer out of range, return
 1417:   if (data->error_log_pointer>5){
 1418:     pout("Invalid Error Log index = 0x%02x (T13/1321D rev 1c "
 1419:          "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n",
 1420:          (int)data->error_log_pointer);
 1421:     return 0;
 1422:   }
 1423: 
 1424:   // Some internal consistency checking of the data structures
 1425:   if ((data->ata_error_count-data->error_log_pointer)%5 && fix_firmwarebug != FIX_SAMSUNG2) {
 1426:     pout("Warning: ATA error count %d inconsistent with error log pointer %d\n\n",
 1427:          data->ata_error_count,data->error_log_pointer);
 1428:   }
 1429:   
 1430:   // starting printing error log info
 1431:   if (data->ata_error_count<=5)
 1432:     pout( "ATA Error Count: %d\n", (int)data->ata_error_count);
 1433:   else
 1434:     pout( "ATA Error Count: %d (device log contains only the most recent five errors)\n",
 1435:            (int)data->ata_error_count);
 1436:   print_off();
 1437:   pout("\tCR = Command Register [HEX]\n"
 1438:        "\tFR = Features Register [HEX]\n"
 1439:        "\tSC = Sector Count Register [HEX]\n"
 1440:        "\tSN = Sector Number Register [HEX]\n"
 1441:        "\tCL = Cylinder Low Register [HEX]\n"
 1442:        "\tCH = Cylinder High Register [HEX]\n"
 1443:        "\tDH = Device/Head Register [HEX]\n"
 1444:        "\tDC = Device Command Register [HEX]\n"
 1445:        "\tER = Error register [HEX]\n"
 1446:        "\tST = Status register [HEX]\n"
 1447:        "Powered_Up_Time is measured from power on, and printed as\n"
 1448:        "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n"
 1449:        "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n");
 1450:   
 1451:   // now step through the five error log data structures (table 39 of spec)
 1452:   for (int k = 4; k >= 0; k-- ) {
 1453: 
 1454:     // The error log data structure entries are a circular buffer
 1455:     int j, i=(data->error_log_pointer+k)%5;
 1456:     const ata_smart_errorlog_struct * elog = data->errorlog_struct+i;
 1457:     const ata_smart_errorlog_error_struct * summary = &(elog->error_struct);
 1458: 
 1459:     // Spec says: unused error log structures shall be zero filled
 1460:     if (nonempty(elog, sizeof(*elog))){
 1461:       // Table 57 of T13/1532D Volume 1 Revision 3
 1462:       const char *msgstate = get_error_log_state_desc(summary->state);
 1463:       int days = (int)summary->timestamp/24;
 1464: 
 1465:       // See table 42 of ATA5 spec
 1466:       print_on();
 1467:       pout("Error %d occurred at disk power-on lifetime: %d hours (%d days + %d hours)\n",
 1468:              (int)(data->ata_error_count+k-4), (int)summary->timestamp, days, (int)(summary->timestamp-24*days));
 1469:       print_off();
 1470:       pout("  When the command that caused the error occurred, the device was %s.\n\n",msgstate);
 1471:       pout("  After command completion occurred, registers were:\n"
 1472:            "  ER ST SC SN CL CH DH\n"
 1473:            "  -- -- -- -- -- -- --\n"
 1474:            "  %02x %02x %02x %02x %02x %02x %02x",
 1475:            (int)summary->error_register,
 1476:            (int)summary->status,
 1477:            (int)summary->sector_count,
 1478:            (int)summary->sector_number,
 1479:            (int)summary->cylinder_low,
 1480:            (int)summary->cylinder_high,
 1481:            (int)summary->drive_head);
 1482:       // Add a description of the contents of the status and error registers
 1483:       // if possible
 1484:       char descbuf[256];
 1485:       const char * st_er_desc = construct_st_er_desc(descbuf, elog);
 1486:       if (st_er_desc)
 1487:         pout("  %s", st_er_desc);
 1488:       pout("\n\n");
 1489:       pout("  Commands leading to the command that caused the error were:\n"
 1490:            "  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name\n"
 1491:            "  -- -- -- -- -- -- -- --  ----------------  --------------------\n");
 1492:       for ( j = 4; j >= 0; j--){
 1493:         const ata_smart_errorlog_command_struct * thiscommand = elog->commands+j;
 1494: 
 1495:         // Spec says: unused data command structures shall be zero filled
 1496:         if (nonempty(thiscommand, sizeof(*thiscommand))) {
 1497: 	  char timestring[32];
 1498: 	  
 1499: 	  // Convert integer milliseconds to a text-format string
 1500: 	  MsecToText(thiscommand->timestamp, timestring);
 1501: 	  
 1502:           pout("  %02x %02x %02x %02x %02x %02x %02x %02x  %16s  %s\n",
 1503:                (int)thiscommand->commandreg,
 1504:                (int)thiscommand->featuresreg,
 1505:                (int)thiscommand->sector_count,
 1506:                (int)thiscommand->sector_number,
 1507:                (int)thiscommand->cylinder_low,
 1508:                (int)thiscommand->cylinder_high,
 1509:                (int)thiscommand->drive_head,
 1510:                (int)thiscommand->devicecontrolreg,
 1511: 	       timestring,
 1512:                look_up_ata_command(thiscommand->commandreg, thiscommand->featuresreg));
 1513: 	}
 1514:       }
 1515:       pout("\n");
 1516:     }
 1517:   }
 1518:   print_on();
 1519:   if (printing_is_switchable)
 1520:     pout("\n");
 1521:   print_off();
 1522:   return data->ata_error_count;  
 1523: }
 1524: 
 1525: // Print SMART Extended Comprehensive Error Log (GP Log 0x03)
 1526: static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
 1527:                                  unsigned nsectors, unsigned max_errors)
 1528: {
 1529:   pout("SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n",
 1530:        log->version, nsectors);
 1531: 
 1532:   if (!log->device_error_count) {
 1533:     pout("No Errors Logged\n\n");
 1534:     return 0;
 1535:   }
 1536:   print_on();
 1537: 
 1538:   // Check index
 1539:   unsigned nentries = nsectors * 4;
 1540:   unsigned erridx = log->error_log_index;
 1541:   if (!(1 <= erridx && erridx <= nentries)){
 1542:     // Some Samsung disks (at least SP1614C/SW100-25, HD300LJ/ZT100-12) use the
 1543:     // former index from Summary Error Log (byte 1, now reserved) and set byte 2-3
 1544:     // to 0.
 1545:     if (!(erridx == 0 && 1 <= log->reserved1 && log->reserved1 <= nentries)) {
 1546:       pout("Invalid Error Log index = 0x%04x (reserved = 0x%02x)\n", erridx, log->reserved1);
 1547:       return 0;
 1548:     }
 1549:     pout("Invalid Error Log index = 0x%04x, trying reserved byte (0x%02x) instead\n", erridx, log->reserved1);
 1550:     erridx = log->reserved1;
 1551:   }
 1552: 
 1553:   // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a),
 1554:   // it is 1-based in practice.
 1555:   erridx--;
 1556: 
 1557:   // Calculate #errors to print
 1558:   unsigned errcnt = log->device_error_count;
 1559: 
 1560:   if (errcnt <= nentries)
 1561:     pout("Device Error Count: %u\n", log->device_error_count);
 1562:   else {
 1563:     errcnt = nentries;
 1564:     pout("Device Error Count: %u (device log contains only the most recent %u errors)\n",
 1565:          log->device_error_count, errcnt);
 1566:   }
 1567: 
 1568:   if (max_errors < errcnt)
 1569:     errcnt = max_errors;
 1570: 
 1571:   print_off();
 1572:   pout("\tCR     = Command Register\n"
 1573:        "\tFEATR  = Features Register\n"
 1574:        "\tCOUNT  = Count (was: Sector Count) Register\n"
 1575:        "\tLBA_48 = Upper bytes of LBA High/Mid/Low Registers ]  ATA-8\n"
 1576:        "\tLH     = LBA High (was: Cylinder High) Register    ]   LBA\n"
 1577:        "\tLM     = LBA Mid (was: Cylinder Low) Register      ] Register\n"
 1578:        "\tLL     = LBA Low (was: Sector Number) Register     ]\n"
 1579:        "\tDV     = Device (was: Device/Head) Register\n"
 1580:        "\tDC     = Device Control Register\n"
 1581:        "\tER     = Error register\n"
 1582:        "\tST     = Status register\n"
 1583:        "Powered_Up_Time is measured from power on, and printed as\n"
 1584:        "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n"
 1585:        "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n");
 1586: 
 1587:   // Iterate through circular buffer in reverse direction
 1588:   for (unsigned i = 0, errnum = log->device_error_count;
 1589:        i < errcnt; i++, errnum--, erridx = (erridx > 0 ? erridx - 1 : nentries - 1)) {
 1590: 
 1591:     const ata_smart_exterrlog_error_log & entry = log[erridx / 4].error_logs[erridx % 4];
 1592: 
 1593:     // Skip unused entries
 1594:     if (!nonempty(&entry, sizeof(entry))) {
 1595:       pout("Error %u [%u] log entry is empty\n", errnum, erridx);
 1596:       continue;
 1597:     }
 1598: 
 1599:     // Print error information
 1600:     print_on();
 1601:     const ata_smart_exterrlog_error & err = entry.error;
 1602:     pout("Error %u [%u] occurred at disk power-on lifetime: %u hours (%u days + %u hours)\n",
 1603:          errnum, erridx, err.timestamp, err.timestamp / 24, err.timestamp % 24);
 1604:     print_off();
 1605: 
 1606:     pout("  When the command that caused the error occurred, the device was %s.\n\n",
 1607:       get_error_log_state_desc(err.state));
 1608: 
 1609:     // Print registers
 1610:     pout("  After command completion occurred, registers were:\n"
 1611:          "  ER -- ST COUNT  LBA_48  LH LM LL DV DC\n"
 1612:          "  -- -- -- == -- == == == -- -- -- -- --\n"
 1613:          "  %02x -- %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 1614:          err.error_register,
 1615:          err.status_register,
 1616:          err.count_register_hi,
 1617:          err.count_register,
 1618:          err.lba_high_register_hi,
 1619:          err.lba_mid_register_hi,
 1620:          err.lba_low_register_hi,
 1621:          err.lba_high_register,
 1622:          err.lba_mid_register,
 1623:          err.lba_low_register,
 1624:          err.device_register,
 1625:          err.device_control_register);
 1626: 
 1627:     // Add a description of the contents of the status and error registers
 1628:     // if possible
 1629:     char descbuf[256];
 1630:     const char * st_er_desc = construct_st_er_desc(descbuf, &entry);
 1631:     if (st_er_desc)
 1632:       pout("  %s", st_er_desc);
 1633:     pout("\n\n");
 1634: 
 1635:     // Print command history
 1636:     pout("  Commands leading to the command that caused the error were:\n"
 1637:          "  CR FEATR COUNT  LBA_48  LH LM LL DV DC  Powered_Up_Time  Command/Feature_Name\n"
 1638:          "  -- == -- == -- == == == -- -- -- -- --  ---------------  --------------------\n");
 1639:     for (int ci = 4; ci >= 0; ci--) {
 1640:       const ata_smart_exterrlog_command & cmd = entry.commands[ci];
 1641: 
 1642:       // Skip unused entries
 1643:       if (!nonempty(&cmd, sizeof(cmd)))
 1644:         continue;
 1645: 
 1646:       // Print registers, timestamp and ATA command name
 1647:       char timestring[32];
 1648:       MsecToText(cmd.timestamp, timestring);
 1649: 
 1650:       pout("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %16s  %s\n",
 1651:            cmd.command_register,
 1652:            cmd.features_register_hi,
 1653:            cmd.features_register,
 1654:            cmd.count_register_hi,
 1655:            cmd.count_register,
 1656:            cmd.lba_high_register_hi,
 1657:            cmd.lba_mid_register_hi,
 1658:            cmd.lba_low_register_hi,
 1659:            cmd.lba_high_register,
 1660:            cmd.lba_mid_register,
 1661:            cmd.lba_low_register,
 1662:            cmd.device_register,
 1663:            cmd.device_control_register,
 1664:            timestring,
 1665:            look_up_ata_command(cmd.command_register, cmd.features_register));
 1666:     }
 1667:     pout("\n");
 1668:   }
 1669: 
 1670:   print_on();
 1671:   if (printing_is_switchable)
 1672:     pout("\n");
 1673:   print_off();
 1674:   return log->device_error_count;
 1675: }
 1676: 
 1677: // Print SMART Extended Self-test Log (GP Log 0x07)
 1678: static int PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
 1679:                                     unsigned nsectors, unsigned max_entries)
 1680: {
 1681:   pout("SMART Extended Self-test Log Version: %u (%u sectors)\n",
 1682:        log->version, nsectors);
 1683: 
 1684:   if (!log->log_desc_index){
 1685:     pout("No self-tests have been logged.  [To run self-tests, use: smartctl -t]\n\n");
 1686:     return 0;
 1687:   }
 1688: 
 1689:   // Check index
 1690:   unsigned nentries = nsectors * 19;
 1691:   unsigned logidx = log->log_desc_index;
 1692:   if (logidx > nentries) {
 1693:     pout("Invalid Self-test Log index = 0x%04x (reserved = 0x%02x)\n", logidx, log->reserved1);
 1694:     return 0;
 1695:   }
 1696: 
 1697:   // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a),
 1698:   // it is 1-based in practice.
 1699:   logidx--;
 1700: 
 1701:   bool print_header = true;
 1702:   int errcnt = 0, igncnt = 0;
 1703:   int ext_ok_testnum = -1;
 1704: 
 1705:   // Iterate through circular buffer in reverse direction
 1706:   for (unsigned i = 0, testnum = 1;
 1707:        i < nentries && testnum <= max_entries;
 1708:        i++, logidx = (logidx > 0 ? logidx - 1 : nentries - 1)) {
 1709: 
 1710:     const ata_smart_extselftestlog_desc & entry = log[logidx / 19].log_descs[logidx % 19];
 1711: 
 1712:     // Skip unused entries
 1713:     if (!nonempty(&entry, sizeof(entry)))
 1714:       continue;
 1715: 
 1716:     // Get LBA
 1717:     const unsigned char * b = entry.failing_lba;
 1718:     uint64_t lba48 = b[0]
 1719:         | (          b[1] <<  8)
 1720:         | (          b[2] << 16)
 1721:         | ((uint64_t)b[3] << 24)
 1722:         | ((uint64_t)b[4] << 32)
 1723:         | ((uint64_t)b[5] << 40);
 1724: 
 1725:     // Print entry
 1726:     int state = ataPrintSmartSelfTestEntry(testnum, entry.self_test_type,
 1727:       entry.self_test_status, entry.timestamp, lba48,
 1728:       false /*!print_error_only*/, print_header);
 1729: 
 1730:     if (state < 0) {
 1731:       // Self-test showed an error
 1732:       if (ext_ok_testnum < 0)
 1733:         errcnt++;
 1734:       else
 1735:         // Newer successful extended self-test exits
 1736:         igncnt++;
 1737:     }
 1738:     else if (state > 0 && ext_ok_testnum < 0) {
 1739:       // Latest successful extended self-test
 1740:       ext_ok_testnum = testnum;
 1741:     }
 1742:     testnum++;
 1743:   }
 1744: 
 1745:   if (igncnt)
 1746:     pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n",
 1747:       igncnt, igncnt+errcnt, ext_ok_testnum);
 1748: 
 1749:   pout("\n");
 1750:   return errcnt;
 1751: }
 1752: 
 1753: static void ataPrintSelectiveSelfTestLog(const ata_selective_self_test_log * log, const ata_smart_values * sv)
 1754: {
 1755:   int i,field1,field2;
 1756:   const char *msg;
 1757:   char tmp[64];
 1758:   uint64_t maxl=0,maxr=0;
 1759:   uint64_t current=log->currentlba;
 1760:   uint64_t currentend=current+65535;
 1761: 
 1762:   // print data structure revision number
 1763:   pout("SMART Selective self-test log data structure revision number %d\n",(int)log->logversion);
 1764:   if (1 != log->logversion)
 1765:     pout("Note: revision number not 1 implies that no selective self-test has ever been run\n");
 1766:   
 1767:   switch((sv->self_test_exec_status)>>4){
 1768:   case  0:msg="Completed";
 1769:     break;
 1770:   case  1:msg="Aborted_by_host";
 1771:     break;
 1772:   case  2:msg="Interrupted";
 1773:     break;
 1774:   case  3:msg="Fatal_error";
 1775:     break;
 1776:   case  4:msg="Completed_unknown_failure";
 1777:     break;
 1778:   case  5:msg="Completed_electrical_failure";
 1779:     break;
 1780:   case  6:msg="Completed_servo/seek_failure";
 1781:     break;
 1782:   case  7:msg="Completed_read_failure";
 1783:     break;
 1784:   case  8:msg="Completed_handling_damage??";
 1785:     break;
 1786:   case 15:msg="Self_test_in_progress";
 1787:     break;
 1788:   default:msg="Unknown_status ";
 1789:     break;
 1790:   }
 1791: 
 1792:   // find the number of columns needed for printing. If in use, the
 1793:   // start/end of span being read-scanned...
 1794:   if (log->currentspan>5) {
 1795:     maxl=current;
 1796:     maxr=currentend;
 1797:   }
 1798:   for (i=0; i<5; i++) {
 1799:     uint64_t start=log->span[i].start;
 1800:     uint64_t end  =log->span[i].end; 
 1801:     // ... plus max start/end of each of the five test spans.
 1802:     if (start>maxl)
 1803:       maxl=start;
 1804:     if (end > maxr)
 1805:       maxr=end;
 1806:   }
 1807:   
 1808:   // we need at least 7 characters wide fields to accomodate the
 1809:   // labels
 1810:   if ((field1=snprintf(tmp,64, "%"PRIu64, maxl))<7)
 1811:     field1=7;
 1812:   if ((field2=snprintf(tmp,64, "%"PRIu64, maxr))<7)
 1813:     field2=7;
 1814: 
 1815:   // now print the five test spans
 1816:   pout(" SPAN  %*s  %*s  CURRENT_TEST_STATUS\n", field1, "MIN_LBA", field2, "MAX_LBA");
 1817: 
 1818:   for (i=0; i<5; i++) {
 1819:     uint64_t start=log->span[i].start;
 1820:     uint64_t end=log->span[i].end;
 1821:     
 1822:     if ((i+1)==(int)log->currentspan)
 1823:       // this span is currently under test
 1824:       pout("    %d  %*"PRIu64"  %*"PRIu64"  %s [%01d0%% left] (%"PRIu64"-%"PRIu64")\n",
 1825: 	   i+1, field1, start, field2, end, msg,
 1826: 	   (int)(sv->self_test_exec_status & 0xf), current, currentend);
 1827:     else
 1828:       // this span is not currently under test
 1829:       pout("    %d  %*"PRIu64"  %*"PRIu64"  Not_testing\n",
 1830: 	   i+1, field1, start, field2, end);
 1831:   }  
 1832:   
 1833:   // if we are currently read-scanning, print LBAs and the status of
 1834:   // the read scan
 1835:   if (log->currentspan>5)
 1836:     pout("%5d  %*"PRIu64"  %*"PRIu64"  Read_scanning %s\n",
 1837: 	 (int)log->currentspan, field1, current, field2, currentend,
 1838: 	 OfflineDataCollectionStatus(sv->offline_data_collection_status));
 1839:   
 1840:   /* Print selective self-test flags.  Possible flag combinations are
 1841:      (numbering bits from 0-15):
 1842:      Bit-1 Bit-3   Bit-4
 1843:      Scan  Pending Active
 1844:      0     *       *       Don't scan
 1845:      1     0       0       Will carry out scan after selective test
 1846:      1     1       0       Waiting to carry out scan after powerup
 1847:      1     0       1       Currently scanning       
 1848:      1     1       1       Currently scanning
 1849:   */
 1850:   
 1851:   pout("Selective self-test flags (0x%x):\n", (unsigned int)log->flags);
 1852:   if (log->flags & SELECTIVE_FLAG_DOSCAN) {
 1853:     if (log->flags & SELECTIVE_FLAG_ACTIVE)
 1854:       pout("  Currently read-scanning the remainder of the disk.\n");
 1855:     else if (log->flags & SELECTIVE_FLAG_PENDING)
 1856:       pout("  Read-scan of remainder of disk interrupted; will resume %d min after power-up.\n",
 1857: 	   (int)log->pendingtime);
 1858:     else
 1859:       pout("  After scanning selected spans, read-scan remainder of disk.\n");
 1860:   }
 1861:   else
 1862:     pout("  After scanning selected spans, do NOT read-scan remainder of disk.\n");
 1863:   
 1864:   // print pending time
 1865:   pout("If Selective self-test is pending on power-up, resume after %d minute delay.\n",
 1866:        (int)log->pendingtime);
 1867: 
 1868:   return; 
 1869: }
 1870: 
 1871: // Format SCT Temperature value
 1872: static const char * sct_ptemp(signed char x, char * buf)
 1873: {
 1874:   if (x == -128 /*0x80 = unknown*/)
 1875:     strcpy(buf, " ?");
 1876:   else
 1877:     sprintf(buf, "%2d", x);
 1878:   return buf;
 1879: }
 1880: 
 1881: static const char * sct_pbar(int x, char * buf)
 1882: {
 1883:   if (x <= 19)
 1884:     x = 0;
 1885:   else
 1886:     x -= 19;
 1887:   bool ov = false;
 1888:   if (x > 40) {
 1889:     x = 40; ov = true;
 1890:   }
 1891:   if (x > 0) {
 1892:     memset(buf, '*', x);
 1893:     if (ov)
 1894:       buf[x-1] = '+';
 1895:     buf[x] = 0;
 1896:   }
 1897:   else {
 1898:     buf[0] = '-'; buf[1] = 0;
 1899:   }
 1900:   return buf;
 1901: }
 1902: 
 1903: static const char * sct_device_state_msg(unsigned char state)
 1904: {
 1905:   switch (state) {
 1906:     case 0: return "Active";
 1907:     case 1: return "Stand-by";
 1908:     case 2: return "Sleep";
 1909:     case 3: return "DST executing in background";
 1910:     case 4: return "SMART Off-line Data Collection executing in background";
 1911:     case 5: return "SCT command executing in background";
 1912:     default:return "Unknown";
 1913:   }
 1914: }
 1915: 
 1916: // Print SCT Status
 1917: static int ataPrintSCTStatus(const ata_sct_status_response * sts)
 1918: {
 1919:   pout("SCT Status Version:                  %u\n", sts->format_version);
 1920:   pout("SCT Version (vendor specific):       %u (0x%04x)\n", sts->sct_version, sts->sct_version);
 1921:   pout("SCT Support Level:                   %u\n", sts->sct_spec);
 1922:   pout("Device State:                        %s (%u)\n",
 1923:     sct_device_state_msg(sts->device_state), sts->device_state);
 1924:   char buf1[20], buf2[20];
 1925:   if (   !sts->min_temp && !sts->life_min_temp
 1926:       && !sts->under_limit_count && !sts->over_limit_count) {
 1927:     // "Reserved" fields not set, assume "old" format version 2
 1928:     // Table 11 of T13/1701DT-N (SMART Command Transport) Revision 5, February 2005
 1929:     // Table 54 of T13/1699-D (ATA8-ACS) Revision 3e, July 2006
 1930:     pout("Current Temperature:                 %s Celsius\n",
 1931:       sct_ptemp(sts->hda_temp, buf1));
 1932:     pout("Power Cycle Max Temperature:         %s Celsius\n",
 1933:       sct_ptemp(sts->max_temp, buf2));
 1934:     pout("Lifetime    Max Temperature:         %s Celsius\n",
 1935:       sct_ptemp(sts->life_max_temp, buf2));
 1936:   }
 1937:   else {
 1938:     // Assume "new" format version 2 or version 3
 1939:     // T13/e06152r0-3 (Additional SCT Temperature Statistics), August - October 2006
 1940:     // Table 60 of T13/1699-D (ATA8-ACS) Revision 3f, December 2006  (format version 2)
 1941:     // Table 80 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 (format version 3)
 1942:     pout("Current Temperature:                    %s Celsius\n",
 1943:       sct_ptemp(sts->hda_temp, buf1));
 1944:     pout("Power Cycle Min/Max Temperature:     %s/%s Celsius\n",
 1945:       sct_ptemp(sts->min_temp, buf1), sct_ptemp(sts->max_temp, buf2));
 1946:     pout("Lifetime    Min/Max Temperature:     %s/%s Celsius\n",
 1947:       sct_ptemp(sts->life_min_temp, buf1), sct_ptemp(sts->life_max_temp, buf2));
 1948:     signed char avg = sts->byte205; // Average Temperature from e06152r0-2, removed in e06152r3
 1949:     if (0 < avg && sts->life_min_temp <= avg && avg <= sts->life_max_temp)
 1950:       pout("Lifetime    Average Temperature:        %2d Celsius\n", avg);
 1951:     pout("Under/Over Temperature Limit Count:  %2u/%u\n",
 1952:       sts->under_limit_count, sts->over_limit_count);
 1953:   }
 1954:   return 0;
 1955: }
 1956: 
 1957: // Print SCT Temperature History Table
 1958: static int ataPrintSCTTempHist(const ata_sct_temperature_history_table * tmh)
 1959: {
 1960:   char buf1[20], buf2[80];
 1961:   pout("SCT Temperature History Version:     %u\n", tmh->format_version);
 1962:   pout("Temperature Sampling Period:         %u minute%s\n",
 1963:     tmh->sampling_period, (tmh->sampling_period==1?"":"s"));
 1964:   pout("Temperature Logging Interval:        %u minute%s\n",
 1965:     tmh->interval,        (tmh->interval==1?"":"s"));
 1966:   pout("Min/Max recommended Temperature:     %s/%s Celsius\n",
 1967:     sct_ptemp(tmh->min_op_limit, buf1), sct_ptemp(tmh->max_op_limit, buf2));
 1968:   pout("Min/Max Temperature Limit:           %s/%s Celsius\n",
 1969:     sct_ptemp(tmh->under_limit, buf1), sct_ptemp(tmh->over_limit, buf2));
 1970:   pout("Temperature History Size (Index):    %u (%u)\n", tmh->cb_size, tmh->cb_index);
 1971:   if (!(0 < tmh->cb_size && tmh->cb_size <= sizeof(tmh->cb) && tmh->cb_index < tmh->cb_size)) {
 1972:     pout("Error invalid Temperature History Size or Index\n");
 1973:     return 0;
 1974:   }
 1975: 
 1976:   // Print table
 1977:   pout("\nIndex    Estimated Time   Temperature Celsius\n");
 1978:   unsigned n = 0, i = (tmh->cb_index+1) % tmh->cb_size;
 1979:   unsigned interval = (tmh->interval > 0 ? tmh->interval : 1);
 1980:   time_t t = time(0) - (tmh->cb_size-1) * interval * 60;
 1981:   t -= t % (interval * 60);
 1982:   while (n < tmh->cb_size) {
 1983:     // Find range of identical temperatures
 1984:     unsigned n1 = n, n2 = n+1, i2 = (i+1) % tmh->cb_size;
 1985:     while (n2 < tmh->cb_size && tmh->cb[i2] == tmh->cb[i]) {
 1986:       n2++; i2 = (i2+1) % tmh->cb_size;
 1987:     }
 1988:     // Print range
 1989:     while (n < n2) {
 1990:       if (n == n1 || n == n2-1 || n2 <= n1+3) {
 1991:         char date[30];
 1992:         // TODO: Don't print times < boot time
 1993:         strftime(date, sizeof(date), "%Y-%m-%d %H:%M", localtime(&t));
 1994:         pout(" %3u    %s    %s  %s\n", i, date,
 1995:           sct_ptemp(tmh->cb[i], buf1), sct_pbar(tmh->cb[i], buf2));
 1996:       }
 1997:       else if (n == n1+1) {
 1998:         pout(" ...    ..(%3u skipped).    ..  %s\n",
 1999:           n2-n1-2, sct_pbar(tmh->cb[i], buf2));
 2000:       }
 2001:       t += interval * 60; i = (i+1) % tmh->cb_size; n++;
 2002:     }
 2003:   }
 2004:   //assert(n == tmh->cb_size && i == (tmh->cb_index+1) % tmh->cb_size);
 2005: 
 2006:   return 0;
 2007: }
 2008: 
 2009: // Print SCT Error Recovery Control timers
 2010: static void ataPrintSCTErrorRecoveryControl(bool set, unsigned short read_timer, unsigned short write_timer)
 2011: {
 2012:   pout("SCT Error Recovery Control%s:\n", (set ? " set to" : ""));
 2013:   if (!read_timer)
 2014:     pout("           Read: Disabled\n");
 2015:   else
 2016:     pout("           Read: %6d (%0.1f seconds)\n", read_timer, read_timer/10.0);
 2017:   if (!write_timer)
 2018:     pout("          Write: Disabled\n");
 2019:   else
 2020:     pout("          Write: %6d (%0.1f seconds)\n", write_timer, write_timer/10.0);
 2021: }
 2022: 
 2023: static void print_aam_level(const char * msg, int level, int recommended = -1)
 2024: {
 2025:   // Table 56 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008
 2026:   // Obsolete since T13/2015-D (ACS-2) Revision 4a, December 9, 2010
 2027:   const char * s;
 2028:   if (level == 0)
 2029:     s = "vendor specific";
 2030:   else if (level < 128)
 2031:     s = "unknown/retired";
 2032:   else if (level == 128)
 2033:     s = "quiet";
 2034:   else if (level < 254)
 2035:     s = "intermediate";
 2036:   else if (level == 254)
 2037:     s = "maximum performance";
 2038:   else
 2039:     s = "reserved";
 2040: 
 2041:   if (recommended >= 0)
 2042:     pout("%s%d (%s), recommended: %d\n", msg, level, s, recommended);
 2043:   else
 2044:     pout("%s%d (%s)\n", msg, level, s);
 2045: }
 2046: 
 2047: static void print_apm_level(const char * msg, int level)
 2048: {
 2049:   // Table 120 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
 2050:   const char * s;
 2051:   if (!(1 <= level && level <= 254))
 2052:     s = "reserved";
 2053:   else if (level == 1)
 2054:     s = "minimum power consumption with standby";
 2055:   else if (level < 128)
 2056:     s = "intermediate level with standby";
 2057:   else if (level == 128)
 2058:     s = "minimum power consumption without standby";
 2059:   else if (level < 254)
 2060:     s = "intermediate level without standby";
 2061:   else
 2062:     s = "maximum performance";
 2063: 
 2064:   pout("%s%d (%s)\n", msg, level, s);
 2065: }
 2066: 
 2067: static void print_ata_security_status(const char * msg, unsigned short state)
 2068: {
 2069:     const char * s1, * s2 = "", * s3 = "", * s4 = "";
 2070: 
 2071:     // Table 6 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
 2072:     if (!(state & 0x0001))
 2073:       s1 = "Unavailable";
 2074:     else if (!(state & 0x0002)) {
 2075:       s1 = "Disabled, ";
 2076:       if (!(state & 0x0008))
 2077:         s2 = "NOT FROZEN [SEC1]";
 2078:       else
 2079:         s2 = "frozen [SEC2]";
 2080:     }
 2081:     else {
 2082:       s1 = "ENABLED, PW level ";
 2083:       if (!(state & 0x0020))
 2084:         s2 = "HIGH";
 2085:       else
 2086:         s2 = "MAX";
 2087: 
 2088:       if (!(state & 0x0004)) {
 2089:          s3 = ", not locked, ";
 2090:         if (!(state & 0x0008))
 2091:           s4 = "not frozen [SEC5]";
 2092:         else
 2093:           s4 = "frozen [SEC6]";
 2094:       }
 2095:       else {
 2096:         s3 = ", **LOCKED** [SEC4]";
 2097:         if (state & 0x0010)
 2098:           s4 = ", PW ATTEMPTS EXCEEDED";
 2099:       }
 2100:     }
 2101: 
 2102:     pout("%s%s%s%s%s\n", msg, s1, s2, s3, s4);
 2103: }
 2104: 
 2105: static void print_standby_timer(const char * msg, int timer, const ata_identify_device & drive)
 2106: {
 2107:   const char * s1 = 0;
 2108:   int hours = 0, minutes = 0 , seconds = 0;
 2109: 
 2110:   // Table 63 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
 2111:   if (timer == 0)
 2112:     s1 = "disabled";
 2113:   else if (timer <= 240)
 2114:     seconds = timer * 5, minutes = seconds / 60, seconds %= 60;
 2115:   else if (timer <= 251)
 2116:     minutes = (timer - 240) * 30, hours = minutes / 60, minutes %= 60;
 2117:   else if (timer == 252)
 2118:     minutes = 21;
 2119:   else if (timer == 253)
 2120:     s1 = "between 8 hours and 12 hours";
 2121:   else if (timer == 255)
 2122:     minutes = 21, seconds = 15;
 2123:   else
 2124:     s1 = "reserved";
 2125: 
 2126:   const char * s2 = "", * s3 = "";
 2127:   if (!(drive.words047_079[49-47] & 0x2000))
 2128:     s2 = " or vendor-specific";
 2129:   if (timer > 0 && (drive.words047_079[50-47] & 0xc001) == 0x4001)
 2130:     s3 = ", a vendor-specific minimum applies";
 2131: 
 2132:   if (s1)
 2133:     pout("%s%d (%s%s%s)\n", msg, timer, s1, s2, s3);
 2134:   else
 2135:     pout("%s%d (%02d:%02d:%02d%s%s)\n", msg, timer, hours, minutes, seconds, s2, s3);
 2136: }
 2137: 
 2138: 
 2139: int ataPrintMain (ata_device * device, const ata_print_options & options)
 2140: {
 2141:   // If requested, check power mode first
 2142:   const char * powername = 0;
 2143:   bool powerchg = false;
 2144:   if (options.powermode) {
 2145:     unsigned char powerlimit = 0xff;
 2146:     int powermode = ataCheckPowerMode(device);
 2147:     switch (powermode) {
 2148:       case -1:
 2149:         if (device->is_syscall_unsup()) {
 2150:           pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break;
 2151:         }
 2152:         powername = "SLEEP";   powerlimit = 2;
 2153:         break;
 2154:       case 0:
 2155:         powername = "STANDBY"; powerlimit = 3; break;
 2156:       case 0x80:
 2157:         powername = "IDLE";    powerlimit = 4; break;
 2158:       case 0xff:
 2159:         powername = "ACTIVE or IDLE"; break;
 2160:       default:
 2161:         pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode);
 2162:         break;
 2163:     }
 2164:     if (powername) {
 2165:       if (options.powermode >= powerlimit) {
 2166:         pout("Device is in %s mode, exit(%d)\n", powername, FAILPOWER);
 2167:         return FAILPOWER;
 2168:       }
 2169:       powerchg = (powermode != 0xff); // SMART tests will spin up drives
 2170:     }
 2171:   }
 2172: 
 2173:   // SMART values needed ?
 2174:   bool need_smart_val = (
 2175:           options.smart_check_status
 2176:        || options.smart_general_values
 2177:        || options.smart_vendor_attrib
 2178:        || options.smart_error_log
 2179:        || options.smart_selftest_log
 2180:        || options.smart_selective_selftest_log
 2181:        || options.smart_ext_error_log
 2182:        || options.smart_ext_selftest_log
 2183:        || options.smart_auto_offl_enable
 2184:        || options.smart_auto_offl_disable
 2185:        || options.smart_selftest_type != -1
 2186:   );
 2187: 
 2188:   // SMART must be enabled ?
 2189:   bool need_smart_enabled = (
 2190:           need_smart_val
 2191:        || options.smart_auto_save_enable
 2192:        || options.smart_auto_save_disable
 2193:   );
 2194: 
 2195:   // SMART feature set needed ?
 2196:   bool need_smart_support = (
 2197:           need_smart_enabled
 2198:        || options.smart_enable
 2199:        || options.smart_disable
 2200:   );
 2201: 
 2202:   // SMART and GP log directories needed ?
 2203:   bool need_smart_logdir = options.smart_logdir;
 2204: 
 2205:   bool need_gp_logdir  = (
 2206:           options.gp_logdir
 2207:        || options.smart_ext_error_log
 2208:        || options.smart_ext_selftest_log
 2209:        || options.sataphy
 2210:        || options.devstat_all_pages
 2211:        || options.devstat_ssd_page
 2212:        || !options.devstat_pages.empty()
 2213:   );
 2214: 
 2215:   unsigned i;
 2216:   for (i = 0; i < options.log_requests.size(); i++) {
 2217:     if (options.log_requests[i].gpl)
 2218:       need_gp_logdir = true;
 2219:     else
 2220:       need_smart_logdir = true;
 2221:   }
 2222: 
 2223:   // SCT commands needed ?
 2224:   bool need_sct_support = (
 2225:           options.sct_temp_sts
 2226:        || options.sct_temp_hist
 2227:        || options.sct_temp_int
 2228:        || options.sct_erc_get
 2229:        || options.sct_erc_set
 2230:   );
 2231: 
 2232:   // Exit if no further options specified
 2233:   if (!(   options.drive_info || need_smart_support
 2234:         || need_smart_logdir  || need_gp_logdir
 2235:         || need_sct_support || options.get_set_used)) {
 2236:     if (powername)
 2237:       pout("Device is in %s mode\n", powername);
 2238:     else
 2239:       pout("ATA device successfully opened\n\n"
 2240:            "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
 2241:     return 0;
 2242:   }
 2243: 
 2244:   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
 2245:   int returnval = 0;
 2246:   ata_identify_device drive; memset(&drive, 0, sizeof(drive));
 2247:   device->clear_err();
 2248:   int retid = ata_read_identity(device, &drive, options.fix_swapped_id);
 2249:   if (retid < 0) {
 2250:     pout("Smartctl: Device Read Identity Failed: %s\n\n",
 2251:          (device->get_errno() ? device->get_errmsg() : "Unknown error"));
 2252:     failuretest(MANDATORY_CMD, returnval|=FAILID);
 2253:   }
 2254:   else if (!nonempty(&drive, sizeof(drive))) {
 2255:     pout("Smartctl: Device Read Identity Failed: empty IDENTIFY data\n\n");
 2256:     failuretest(MANDATORY_CMD, returnval|=FAILID);
 2257:   }
 2258: 
 2259:   // If requested, show which presets would be used for this drive and exit.
 2260:   if (options.show_presets) {
 2261:     show_presets(&drive);
 2262:     return 0;
 2263:   }
 2264: 
 2265:   // Use preset vendor attribute options unless user has requested otherwise.
 2266:   ata_vendor_attr_defs attribute_defs = options.attribute_defs;
 2267:   unsigned char fix_firmwarebug = options.fix_firmwarebug;
 2268:   const drive_settings * dbentry = 0;
 2269:   if (!options.ignore_presets)
 2270:     dbentry = lookup_drive_apply_presets(&drive, attribute_defs,
 2271:       fix_firmwarebug);
 2272: 
 2273:   // Get capacity and sector sizes
 2274:   ata_size_info sizes;
 2275:   ata_get_size_info(&drive, sizes);
 2276: 
 2277:   // Print most drive identity information if requested
 2278:   if (options.drive_info) {
 2279:     pout("=== START OF INFORMATION SECTION ===\n");
 2280:     print_drive_info(&drive, sizes, dbentry);
 2281:   }
 2282: 
 2283:   // Check and print SMART support and state
 2284:   int smart_supported = -1, smart_enabled = -1;
 2285:   if (need_smart_support || options.drive_info) {
 2286: 
 2287:     // Packet device ?
 2288:     if (retid > 0) {
 2289:       pout("SMART support is: Unavailable - Packet Interface Devices [this device: %s] don't support ATA SMART\n",
 2290:            packetdevicetype(retid-1));
 2291:     }
 2292:     else {
 2293:       // Disk device: SMART supported and enabled ?
 2294:       smart_supported = ataSmartSupport(&drive);
 2295:       smart_enabled = ataIsSmartEnabled(&drive);
 2296: 
 2297:       if (smart_supported < 0)
 2298:         pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 82-83 don't show if SMART supported.\n");
 2299:       if (smart_supported && smart_enabled < 0) {
 2300:         pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 85-87 don't show if SMART is enabled.\n");
 2301:         if (need_smart_support) {
 2302:           failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 2303:           // check SMART support by trying a command
 2304:           pout("                  Checking to be sure by trying SMART RETURN STATUS command.\n");
 2305:           if (ataDoesSmartWork(device))
 2306:             smart_supported = smart_enabled = 1;
 2307:         }
 2308:       }
 2309:       else if (smart_supported < 0 && (smart_enabled > 0 || dbentry))
 2310:         // Assume supported if enabled or in drive database
 2311:         smart_supported = 1;
 2312: 
 2313:       if (smart_supported < 0)
 2314:         pout("SMART support is: Unknown - Try option -s with argument 'on' to enable it.");
 2315:       else if (!smart_supported)
 2316:         pout("SMART support is: Unavailable - device lacks SMART capability.\n");
 2317:       else {
 2318:         if (options.drive_info)
 2319:           pout("SMART support is: Available - device has SMART capability.\n");
 2320:         if (smart_enabled >= 0) {
 2321:           if (device->ata_identify_is_cached()) {
 2322:             if (options.drive_info)
 2323:               pout("                  %sabled status cached by OS, trying SMART RETURN STATUS cmd.\n",
 2324:                       (smart_enabled?"En":"Dis"));
 2325:             smart_enabled = ataDoesSmartWork(device);
 2326:           }
 2327:           if (options.drive_info)
 2328:             pout("SMART support is: %s\n",
 2329:                   (smart_enabled ? "Enabled" : "Disabled"));
 2330:         }
 2331:       }
 2332:     }
 2333:   }
 2334: 
 2335:   // Print AAM status
 2336:   if (options.get_aam) {
 2337:     if ((drive.command_set_2 & 0xc200) != 0x4200) // word083
 2338:       pout("AAM feature is:   Unavailable\n");
 2339:     else if (!(drive.word086 & 0x0200))
 2340:       pout("AAM feature is:   Disabled\n");
 2341:     else
 2342:       print_aam_level("AAM level is:     ", drive.words088_255[94-88] & 0xff,
 2343:         drive.words088_255[94-88] >> 8);
 2344:   }
 2345: 
 2346:   // Print APM status
 2347:   if (options.get_apm) {
 2348:     if ((drive.command_set_2 & 0xc008) != 0x4008) // word083
 2349:       pout("APM feature is:   Unavailable\n");
 2350:     else if (!(drive.word086 & 0x0008))
 2351:       pout("APM feature is:   Disabled\n");
 2352:     else
 2353:       print_apm_level("APM level is:     ", drive.words088_255[91-88] & 0xff);
 2354:   }
 2355: 
 2356:   // Print read look-ahead status
 2357:   if (options.get_lookahead) {
 2358:     pout("Rd look-ahead is: %s\n",
 2359:       (   (drive.command_set_2 & 0xc000) != 0x4000 // word083
 2360:        || !(drive.command_set_1 & 0x0040)) ? "Unavailable" : // word082
 2361:        !(drive.cfs_enable_1 & 0x0040) ? "Disabled" : "Enabled"); // word085
 2362:   }
 2363: 
 2364:   // Print write cache status
 2365:   if (options.get_wcache) {
 2366:     pout("Write cache is:   %s\n",
 2367:       (   (drive.command_set_2 & 0xc000) != 0x4000 // word083
 2368:        || !(drive.command_set_1 & 0x0020)) ? "Unavailable" : // word082
 2369:        !(drive.cfs_enable_1 & 0x0020) ? "Disabled" : "Enabled"); // word085
 2370:   }
 2371: 
 2372:   // Print ATA security status
 2373:   if (options.get_security)
 2374:     print_ata_security_status("ATA Security is:  ", drive.words088_255[128-88]);
 2375: 
 2376:   // Print remaining drive info
 2377:   if (options.drive_info) {
 2378:     // Print the (now possibly changed) power mode if available
 2379:     if (powername)
 2380:       pout("Power mode %s   %s\n", (powerchg?"was:":"is: "), powername);
 2381:     pout("\n");
 2382:   }
 2383: 
 2384:   // Exit if SMART is not supported but must be available to proceed
 2385:   if (smart_supported <= 0 && need_smart_support)
 2386:     failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 2387: 
 2388:   // START OF THE ENABLE/DISABLE SECTION OF THE CODE
 2389:   if (   options.smart_disable           || options.smart_enable
 2390:       || options.smart_auto_save_disable || options.smart_auto_save_enable
 2391:       || options.smart_auto_offl_disable || options.smart_auto_offl_enable)
 2392:     pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
 2393:   
 2394:   // Enable/Disable AAM
 2395:   if (options.set_aam) {
 2396:     if (options.set_aam > 0) {
 2397:       if (!ata_set_features(device, ATA_ENABLE_AAM, options.set_aam-1)) {
 2398:         pout("AAM enable failed: %s\n", device->get_errmsg());
 2399:         returnval |= FAILSMART;
 2400:       }
 2401:       else
 2402:         print_aam_level("AAM set to level ", options.set_aam-1);
 2403:     }
 2404:     else {
 2405:       if (!ata_set_features(device, ATA_DISABLE_AAM)) {
 2406:         pout("AAM disable failed: %s\n", device->get_errmsg());
 2407:         returnval |= FAILSMART;
 2408:       }
 2409:       else
 2410:         pout("AAM disabled\n");
 2411:     }
 2412:   }
 2413: 
 2414:   // Enable/Disable APM
 2415:   if (options.set_apm) {
 2416:     if (options.set_apm > 0) {
 2417:       if (!ata_set_features(device, ATA_ENABLE_APM, options.set_apm-1)) {
 2418:         pout("APM enable failed: %s\n", device->get_errmsg());
 2419:         returnval |= FAILSMART;
 2420:       }
 2421:       else
 2422:         print_apm_level("APM set to level ", options.set_apm-1);
 2423:     }
 2424:     else {
 2425:       if (!ata_set_features(device, ATA_DISABLE_APM)) {
 2426:         pout("APM disable failed: %s\n", device->get_errmsg());
 2427:         returnval |= FAILSMART;
 2428:       }
 2429:       else
 2430:         pout("APM disabled\n");
 2431:     }
 2432:   }
 2433: 
 2434:   // Enable/Disable read look-ahead
 2435:   if (options.set_lookahead) {
 2436:     bool enable = (options.set_lookahead > 0);
 2437:     if (!ata_set_features(device, (enable ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD))) {
 2438:         pout("Read look-ahead %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
 2439:         returnval |= FAILSMART;
 2440:     }
 2441:     else
 2442:       pout("Read look-ahead %sabled\n", (enable ? "en" : "dis"));
 2443:   }
 2444: 
 2445:   // Enable/Disable write cache
 2446:   if (options.set_wcache) {
 2447:     bool enable = (options.set_wcache > 0);
 2448:     if (!ata_set_features(device, (enable ? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE))) {
 2449:         pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
 2450:         returnval |= FAILSMART;
 2451:     }
 2452:     else
 2453:       pout("Write cache %sabled\n", (enable ? "en" : "dis"));
 2454:   }
 2455: 
 2456:   // Freeze ATA security
 2457:   if (options.set_security_freeze) {
 2458:     if (!ata_nodata_command(device, ATA_SECURITY_FREEZE_LOCK)) {
 2459:         pout("ATA SECURITY FREEZE LOCK failed: %s\n", device->get_errmsg());
 2460:         returnval |= FAILSMART;
 2461:     }
 2462:     else
 2463:       pout("ATA Security set to frozen mode\n");
 2464:   }
 2465: 
 2466:   // Set standby timer
 2467:   if (options.set_standby) {
 2468:     if (!ata_nodata_command(device, ATA_IDLE, options.set_standby-1)) {
 2469:         pout("ATA IDLE command failed: %s\n", device->get_errmsg());
 2470:         returnval |= FAILSMART;
 2471:     }
 2472:     else
 2473:       print_standby_timer("Standby timer set to ", options.set_standby-1, drive);
 2474:   }
 2475: 
 2476:   // Enable/Disable SMART commands
 2477:   if (options.smart_enable) {
 2478:     if (ataEnableSmart(device)) {
 2479:       pout("Smartctl: SMART Enable Failed.\n\n");
 2480:       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 2481:     }
 2482:     else {
 2483:       pout("SMART Enabled.\n");
 2484:       smart_enabled = 1;
 2485:     }
 2486:   }
 2487: 
 2488:   // Turn off SMART on device
 2489:   if (options.smart_disable) {
 2490:     if (ataDisableSmart(device)) {
 2491:       pout( "Smartctl: SMART Disable Failed.\n\n");
 2492:       failuretest(MANDATORY_CMD,returnval|=FAILSMART);
 2493:     }
 2494:   }
 2495: 
 2496:   // Exit if SMART is disabled but must be enabled to proceed
 2497:   if (options.smart_disable || (smart_enabled <= 0 && need_smart_enabled)) {
 2498:     pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n");
 2499:     return returnval;
 2500:   }
 2501: 
 2502:   // Enable/Disable Auto-save attributes
 2503:   if (options.smart_auto_save_enable) {
 2504:     if (ataEnableAutoSave(device)){
 2505:       pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
 2506:       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 2507:     }
 2508:     else
 2509:       pout("SMART Attribute Autosave Enabled.\n");
 2510:   }
 2511: 
 2512:   if (options.smart_auto_save_disable) {
 2513:     if (ataDisableAutoSave(device)){
 2514:       pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
 2515:       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 2516:     }
 2517:     else
 2518:       pout("SMART Attribute Autosave Disabled.\n");
 2519:   }
 2520: 
 2521:   // Read SMART values and thresholds if necessary
 2522:   ata_smart_values smartval; memset(&smartval, 0, sizeof(smartval));
 2523:   ata_smart_thresholds_pvt smartthres; memset(&smartthres, 0, sizeof(smartthres));
 2524:   bool smart_val_ok = false, smart_thres_ok = false;
 2525: 
 2526:   if (need_smart_val) {
 2527:     if (ataReadSmartValues(device, &smartval)) {
 2528:       pout("Smartctl: SMART Read Values failed.\n\n");
 2529:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2530:     }
 2531:     else {
 2532:       smart_val_ok = true;
 2533: 
 2534:       if (options.smart_check_status || options.smart_vendor_attrib) {
 2535:         if (ataReadSmartThresholds(device, &smartthres)){
 2536:           pout("Smartctl: SMART Read Thresholds failed.\n\n");
 2537:           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2538:         }
 2539:         else
 2540:           smart_thres_ok = true;
 2541:       }
 2542:     }
 2543:   }
 2544: 
 2545:   // Enable/Disable Off-line testing
 2546:   bool needupdate = false;
 2547:   if (options.smart_auto_offl_enable) {
 2548:     if (!isSupportAutomaticTimer(&smartval)){
 2549:       pout("Warning: device does not support SMART Automatic Timers.\n\n");
 2550:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2551:     }
 2552:     needupdate = smart_val_ok;
 2553:     if (ataEnableAutoOffline(device)){
 2554:       pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
 2555:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2556:     }
 2557:     else
 2558:       pout("SMART Automatic Offline Testing Enabled every four hours.\n");
 2559:   }
 2560: 
 2561:   if (options.smart_auto_offl_disable) {
 2562:     if (!isSupportAutomaticTimer(&smartval)){
 2563:       pout("Warning: device does not support SMART Automatic Timers.\n\n");
 2564:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2565:     }
 2566:     needupdate = smart_val_ok;
 2567:     if (ataDisableAutoOffline(device)){
 2568:       pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
 2569:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2570:     }
 2571:     else
 2572:       pout("SMART Automatic Offline Testing Disabled.\n");
 2573:   }
 2574: 
 2575:   if (needupdate && ataReadSmartValues(device, &smartval)){
 2576:     pout("Smartctl: SMART Read Values failed.\n\n");
 2577:     failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2578:     smart_val_ok = false;
 2579:   }
 2580: 
 2581:   // all this for a newline!
 2582:   if (   options.smart_disable           || options.smart_enable
 2583:       || options.smart_auto_save_disable || options.smart_auto_save_enable
 2584:       || options.smart_auto_offl_disable || options.smart_auto_offl_enable)
 2585:     pout("\n");
 2586: 
 2587:   // START OF READ-ONLY OPTIONS APART FROM -V and -i
 2588:   if (   options.smart_check_status  || options.smart_general_values
 2589:       || options.smart_vendor_attrib || options.smart_error_log
 2590:       || options.smart_selftest_log  || options.smart_selective_selftest_log
 2591:       || options.smart_ext_error_log || options.smart_ext_selftest_log
 2592:       || options.sct_temp_sts        || options.sct_temp_hist               )
 2593:     pout("=== START OF READ SMART DATA SECTION ===\n");
 2594:   
 2595:   // Check SMART status
 2596:   if (options.smart_check_status) {
 2597: 
 2598:     switch (ataSmartStatus2(device)) {
 2599: 
 2600:     case 0:
 2601:       // The case where the disk health is OK
 2602:       pout("SMART overall-health self-assessment test result: PASSED\n");
 2603:       if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) {
 2604:         if (options.smart_vendor_attrib)
 2605:           pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
 2606:         else {
 2607:           print_on();
 2608:           pout("Please note the following marginal Attributes:\n");
 2609:           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2, options.output_format);
 2610:         } 
 2611:         returnval|=FAILAGE;
 2612:       }
 2613:       else
 2614:         pout("\n");
 2615:       break;
 2616:       
 2617:     case 1:
 2618:       // The case where the disk health is NOT OK
 2619:       print_on();
 2620:       pout("SMART overall-health self-assessment test result: FAILED!\n"
 2621:            "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
 2622:       print_off();
 2623:       if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
 2624:         returnval|=FAILATTR;
 2625:         if (options.smart_vendor_attrib)
 2626:           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
 2627:         else {
 2628:           print_on();
 2629:           pout("Failed Attributes:\n");
 2630:           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1, options.output_format);
 2631:         }
 2632:       }
 2633:       else
 2634:         pout("No failed Attributes found.\n\n");   
 2635:       returnval|=FAILSTATUS;
 2636:       print_off();
 2637:       break;
 2638: 
 2639:     case -1:
 2640:     default:
 2641:       // Something went wrong with the SMART STATUS command.
 2642:       // The ATA SMART RETURN STATUS command provides the result in the ATA output
 2643:       // registers. Buggy ATA/SATA drivers and SAT Layers often do not properly
 2644:       // return the registers values.
 2645:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2646:       if (!(smart_val_ok && smart_thres_ok)) {
 2647:         print_on();
 2648:         pout("SMART overall-health self-assessment test result: UNKNOWN!\n"
 2649:              "SMART Status, Attributes and Thresholds cannot be read.\n\n");
 2650:       }
 2651:       else if (find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
 2652:         print_on();
 2653:         pout("SMART overall-health self-assessment test result: FAILED!\n"
 2654:              "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
 2655:         print_off();
 2656:         returnval|=FAILATTR;
 2657:         returnval|=FAILSTATUS;
 2658:         if (options.smart_vendor_attrib)
 2659:           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
 2660:         else {
 2661:           print_on();
 2662:           pout("Failed Attributes:\n");
 2663:           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1, options.output_format);
 2664:         }
 2665:       }
 2666:       else {
 2667:         pout("SMART overall-health self-assessment test result: PASSED\n");
 2668:         pout("Warning: This result is based on an Attribute check.\n");
 2669:         if (find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) {
 2670:           if (options.smart_vendor_attrib)
 2671:             pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
 2672:           else {
 2673:             print_on();
 2674:             pout("Please note the following marginal Attributes:\n");
 2675:             PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2, options.output_format);
 2676:           } 
 2677:           returnval|=FAILAGE;
 2678:         }
 2679:         else
 2680:           pout("\n");
 2681:       } 
 2682:       print_off();
 2683:       break;
 2684:     } // end of switch statement
 2685:     
 2686:     print_off();
 2687:   } // end of checking SMART Status
 2688:   
 2689:   // Print general SMART values
 2690:   if (smart_val_ok && options.smart_general_values)
 2691:     PrintGeneralSmartValues(&smartval, &drive, fix_firmwarebug);
 2692: 
 2693:   // Print vendor-specific attributes
 2694:   if (smart_val_ok && options.smart_vendor_attrib) {
 2695:     print_on();
 2696:     PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs,
 2697:                               (printing_is_switchable ? 2 : 0), options.output_format);
 2698:     print_off();
 2699:   }
 2700: 
 2701:   // If GP Log is supported use smart log directory for
 2702:   // error and selftest log support check.
 2703:   if (   isGeneralPurposeLoggingCapable(&drive)
 2704:       && (   options.smart_error_log || options.smart_selftest_log
 2705:           || options.retry_error_log || options.retry_selftest_log))
 2706:     need_smart_logdir = true;
 2707: 
 2708:   ata_smart_log_directory smartlogdir_buf, gplogdir_buf;
 2709:   const ata_smart_log_directory * smartlogdir = 0, * gplogdir = 0;
 2710: 
 2711:   // Read SMART Log directory
 2712:   if (need_smart_logdir) {
 2713:     if (ataReadLogDirectory(device, &smartlogdir_buf, false)) {
 2714:       pout("Read SMART Log Directory failed.\n\n");
 2715:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2716:     }
 2717:     else
 2718:       smartlogdir = &smartlogdir_buf;
 2719:   }
 2720: 
 2721:   // Read GP Log directory
 2722:   if (need_gp_logdir) {
 2723:     if (ataReadLogDirectory(device, &gplogdir_buf, true)) {
 2724:       pout("Read GP Log Directory failed.\n\n");
 2725:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2726:     }
 2727:     else
 2728:       gplogdir = &gplogdir_buf;
 2729:   }
 2730: 
 2731:   // Print log directories
 2732:   if ((options.gp_logdir && gplogdir) || (options.smart_logdir && smartlogdir))
 2733:     PrintLogDirectories(gplogdir, smartlogdir);
 2734: 
 2735:   // Print log pages
 2736:   for (i = 0; i < options.log_requests.size(); i++) {
 2737:     const ata_log_request & req = options.log_requests[i];
 2738: 
 2739:     const char * type;
 2740:     unsigned max_nsectors;
 2741:     if (req.gpl) {
 2742:       type = "General Purpose";
 2743:       max_nsectors = GetNumLogSectors(gplogdir, req.logaddr, true);
 2744:     }
 2745:     else {
 2746:       type = "SMART";
 2747:       max_nsectors = GetNumLogSectors(smartlogdir, req.logaddr, false);
 2748:     }
 2749: 
 2750:     if (!max_nsectors) {
 2751:       if (!is_permissive()) {
 2752:         pout("%s Log 0x%02x does not exist (override with '-T permissive' option)\n", type, req.logaddr);
 2753:         continue;
 2754:       }
 2755:       max_nsectors = req.page+1;
 2756:     }
 2757:     if (max_nsectors <= req.page) {
 2758:       pout("%s Log 0x%02x has only %u sectors, output skipped\n", type, req.logaddr, max_nsectors);
 2759:       continue;
 2760:     }
 2761: 
 2762:     unsigned ns = req.nsectors;
 2763:     if (ns > max_nsectors - req.page) {
 2764:       if (req.nsectors != ~0U) // "FIRST-max"
 2765:         pout("%s Log 0x%02x has only %u sectors, output truncated\n", type, req.logaddr, max_nsectors);
 2766:       ns = max_nsectors - req.page;
 2767:     }
 2768: 
 2769:     // SMART log don't support sector offset, start with first sector
 2770:     unsigned offs = (req.gpl ? 0 : req.page);
 2771: 
 2772:     raw_buffer log_buf((offs + ns) * 512);
 2773:     bool ok;
 2774:     if (req.gpl)
 2775:       ok = ataReadLogExt(device, req.logaddr, 0x00, req.page, log_buf.data(), ns);
 2776:     else
 2777:       ok = ataReadSmartLog(device, req.logaddr, log_buf.data(), offs + ns);
 2778:     if (!ok)
 2779:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2780:     else
 2781:       PrintLogPages(type, log_buf.data() + offs*512, req.logaddr, req.page, ns, max_nsectors);
 2782:   }
 2783: 
 2784:   // Print SMART Extendend Comprehensive Error Log
 2785:   bool do_smart_error_log = options.smart_error_log;
 2786:   if (options.smart_ext_error_log) {
 2787:     bool ok = false;
 2788:     unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true);
 2789:     if (!nsectors)
 2790:       pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n");
 2791:     else if (nsectors >= 256)
 2792:       pout("SMART Extended Comprehensive Error Log size %u not supported\n", nsectors);
 2793:     else {
 2794:       raw_buffer log_03_buf(nsectors * 512);
 2795:       ata_smart_exterrlog * log_03 = (ata_smart_exterrlog *)log_03_buf.data();
 2796:       if (!ataReadExtErrorLog(device, log_03, nsectors))
 2797:         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2798:       else {
 2799:         if (PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log))
 2800:           returnval |= FAILERR;
 2801:         ok = true;
 2802:       }
 2803:     }
 2804: 
 2805:     if (!ok) {
 2806:       if (options.retry_error_log)
 2807:         do_smart_error_log = true;
 2808:       else if (!do_smart_error_log)
 2809:         pout("Try '-l [xerror,]error' to read traditional SMART Error Log\n");
 2810:     }
 2811:   }
 2812: 
 2813:   // Print SMART error log
 2814:   if (do_smart_error_log) {
 2815:     if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x01, false))
 2816:           || (!smartlogdir && isSmartErrorLogCapable(&smartval, &drive) )
 2817:           || is_permissive()                                             )) {
 2818:       pout("SMART Error Log not supported\n");
 2819:     }
 2820:     else {
 2821:       ata_smart_errorlog smarterror; memset(&smarterror, 0, sizeof(smarterror));
 2822:       if (ataReadErrorLog(device, &smarterror, fix_firmwarebug)) {
 2823:         pout("Smartctl: SMART Error Log Read Failed\n");
 2824:         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2825:       }
 2826:       else {
 2827:         // quiet mode is turned on inside PrintSmartErrorLog()
 2828:         if (PrintSmartErrorlog(&smarterror, fix_firmwarebug))
 2829: 	  returnval|=FAILERR;
 2830:         print_off();
 2831:       }
 2832:     }
 2833:   }
 2834: 
 2835:   // Print SMART Extendend Self-test Log
 2836:   bool do_smart_selftest_log = options.smart_selftest_log;
 2837:   if (options.smart_ext_selftest_log) {
 2838:     bool ok = false;
 2839:     unsigned nsectors = GetNumLogSectors(gplogdir, 0x07, true);
 2840:     if (!nsectors)
 2841:       pout("SMART Extended Self-test Log (GP Log 0x07) not supported\n");
 2842:     else if (nsectors >= 256)
 2843:       pout("SMART Extended Self-test Log size %u not supported\n", nsectors);
 2844:     else {
 2845:       raw_buffer log_07_buf(nsectors * 512);
 2846:       ata_smart_extselftestlog * log_07 = (ata_smart_extselftestlog *)log_07_buf.data();
 2847:       if (!ataReadExtSelfTestLog(device, log_07, nsectors))
 2848:         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2849:       else {
 2850:         if (PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log))
 2851:           returnval |= FAILLOG;
 2852:         ok = true;
 2853:       }
 2854:     }
 2855: 
 2856:     if (!ok) {
 2857:       if (options.retry_selftest_log)
 2858:         do_smart_selftest_log = true;
 2859:       else if (!do_smart_selftest_log)
 2860:         pout("Try '-l [xselftest,]selftest' to read traditional SMART Self Test Log\n");
 2861:     }
 2862:   }
 2863: 
 2864:   // Print SMART self-test log
 2865:   if (do_smart_selftest_log) {
 2866:     if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x06, false))
 2867:           || (!smartlogdir && isSmartTestLogCapable(&smartval, &drive)  )
 2868:           || is_permissive()                                             )) {
 2869:       pout("SMART Self-test Log not supported\n");
 2870:     }
 2871:     else {
 2872:       ata_smart_selftestlog smartselftest; memset(&smartselftest, 0, sizeof(smartselftest));
 2873:       if (ataReadSelfTestLog(device, &smartselftest, fix_firmwarebug)) {
 2874:         pout("Smartctl: SMART Self Test Log Read Failed\n");
 2875:         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2876:       }
 2877:       else {
 2878:         print_on();
 2879:         if (ataPrintSmartSelfTestlog(&smartselftest, !printing_is_switchable, fix_firmwarebug))
 2880:           returnval |= FAILLOG;
 2881:         print_off();
 2882:         pout("\n");
 2883:       }
 2884:     }
 2885:   }
 2886: 
 2887:   // Print SMART selective self-test log
 2888:   if (options.smart_selective_selftest_log) {
 2889:     ata_selective_self_test_log log;
 2890: 
 2891:     if (!isSupportSelectiveSelfTest(&smartval))
 2892:       pout("Device does not support Selective Self Tests/Logging\n");
 2893:     else if(ataReadSelectiveSelfTestLog(device, &log)) {
 2894:       pout("Smartctl: SMART Selective Self Test Log Read Failed\n");
 2895:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2896:     }
 2897:     else {
 2898:       print_on();
 2899:       // If any errors were found, they are logged in the SMART Self-test log.
 2900:       // So there is no need to print the Selective Self Test log in silent
 2901:       // mode.
 2902:       if (!printing_is_switchable)
 2903:         ataPrintSelectiveSelfTestLog(&log, &smartval);
 2904:       print_off();
 2905:       pout("\n");
 2906:     }
 2907:   }
 2908: 
 2909:   // SCT commands
 2910:   bool sct_ok = false;
 2911:   if (need_sct_support) {
 2912:     if (!isSCTCapable(&drive)) {
 2913:       pout("Warning: device does not support SCT Commands\n");
 2914:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2915:     }
 2916:     else
 2917:       sct_ok = true;
 2918:   }
 2919: 
 2920:   // Print SCT status and temperature history table
 2921:   if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) {
 2922:     for (;;) {
 2923:       if (options.sct_temp_sts || options.sct_temp_hist) {
 2924:         ata_sct_status_response sts;
 2925:         ata_sct_temperature_history_table tmh;
 2926:         if (!options.sct_temp_hist) {
 2927:           // Read SCT status only
 2928:           if (ataReadSCTStatus(device, &sts)) {
 2929:             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2930:             break;
 2931:           }
 2932:         }
 2933:         else {
 2934:           if (!isSCTDataTableCapable(&drive)) {
 2935:             pout("Warning: device does not support SCT Data Table command\n");
 2936:             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2937:             break;
 2938:           }
 2939:           // Read SCT status and temperature history
 2940:           if (ataReadSCTTempHist(device, &tmh, &sts)) {
 2941:             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2942:             break;
 2943:           }
 2944:         }
 2945:         if (options.sct_temp_sts)
 2946:           ataPrintSCTStatus(&sts);
 2947:         if (options.sct_temp_hist)
 2948:           ataPrintSCTTempHist(&tmh);
 2949:         pout("\n");
 2950:       }
 2951:       if (options.sct_temp_int) {
 2952:         // Set new temperature logging interval
 2953:         if (!isSCTFeatureControlCapable(&drive)) {
 2954:           pout("Warning: device does not support SCT Feature Control command\n");
 2955:           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2956:           break;
 2957:         }
 2958:         if (ataSetSCTTempInterval(device, options.sct_temp_int, options.sct_temp_int_pers)) {
 2959:           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2960:           break;
 2961:         }
 2962:         pout("Temperature Logging Interval set to %u minute%s (%s)\n",
 2963:           options.sct_temp_int, (options.sct_temp_int == 1 ? "" : "s"),
 2964:           (options.sct_temp_int_pers ? "persistent" : "volatile"));
 2965:       }
 2966:       break;
 2967:     }
 2968:   }
 2969: 
 2970:   // SCT Error Recovery Control
 2971:   if (sct_ok && (options.sct_erc_get || options.sct_erc_set)) {
 2972:     if (!isSCTErrorRecoveryControlCapable(&drive)) {
 2973:       pout("Warning: device does not support SCT Error Recovery Control command\n");
 2974:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2975:     }
 2976:     else {
 2977:       bool sct_erc_get = options.sct_erc_get;
 2978:       if (options.sct_erc_set) {
 2979:         // Set SCT Error Recovery Control
 2980:         if (   ataSetSCTErrorRecoveryControltime(device, 1, options.sct_erc_readtime )
 2981:             || ataSetSCTErrorRecoveryControltime(device, 2, options.sct_erc_writetime)) {
 2982:           pout("Warning: device does not support SCT (Set) Error Recovery Control command\n");
 2983:           if (!(   (options.sct_erc_readtime == 70 && options.sct_erc_writetime == 70)
 2984:                 || (options.sct_erc_readtime ==  0 && options.sct_erc_writetime ==  0)))
 2985:             pout("Retry with: 'scterc,70,70' to enable ERC or 'scterc,0,0' to disable\n");
 2986:           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 2987:           sct_erc_get = false;
 2988:         }
 2989:         else if (!sct_erc_get)
 2990:           ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
 2991:             options.sct_erc_writetime);
 2992:       }
 2993: 
 2994:       if (sct_erc_get) {
 2995:         // Print SCT Error Recovery Control
 2996:         unsigned short read_timer, write_timer;
 2997:         if (   ataGetSCTErrorRecoveryControltime(device, 1, read_timer )
 2998:             || ataGetSCTErrorRecoveryControltime(device, 2, write_timer)) {
 2999:           pout("Warning: device does not support SCT (Get) Error Recovery Control command\n");
 3000:           if (options.sct_erc_set) {
 3001:             pout("The previous SCT (Set) Error Recovery Control command succeeded\n");
 3002:             ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
 3003:               options.sct_erc_writetime);
 3004:           }
 3005:           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3006:         }
 3007:         else
 3008:           ataPrintSCTErrorRecoveryControl(false, read_timer, write_timer);
 3009:       }
 3010:       pout("\n");
 3011:     }
 3012:   }
 3013: 
 3014:   // Print Device Statistics
 3015:   if (options.devstat_all_pages || options.devstat_ssd_page || !options.devstat_pages.empty()) {
 3016:     unsigned nsectors = GetNumLogSectors(gplogdir, 0x04, true);
 3017:     if (!nsectors)
 3018:       pout("Device Statistics (GP Log 0x04) not supported\n");
 3019:     else if (!print_device_statistics(device, nsectors, options.devstat_pages,
 3020:                options.devstat_all_pages, options.devstat_ssd_page))
 3021:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3022:   }
 3023: 
 3024:   // Print SATA Phy Event Counters
 3025:   if (options.sataphy) {
 3026:     unsigned nsectors = GetNumLogSectors(gplogdir, 0x11, true);
 3027:     if (!nsectors)
 3028:       pout("SATA Phy Event Counters (GP Log 0x11) not supported\n");
 3029:     else if (nsectors != 1)
 3030:       pout("SATA Phy Event Counters with %u sectors not supported\n", nsectors);
 3031:     else {
 3032:       unsigned char log_11[512] = {0, };
 3033:       unsigned char features = (options.sataphy_reset ? 0x01 : 0x00);
 3034:       if (!ataReadLogExt(device, 0x11, features, 0, log_11, 1))
 3035:         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3036:       else
 3037:         PrintSataPhyEventCounters(log_11, options.sataphy_reset);
 3038:     }
 3039:   }
 3040: 
 3041:   // Set to standby (spindown) mode
 3042:   // (Above commands may spinup drive)
 3043:   if (options.set_standby_now) {
 3044:     if (!ata_nodata_command(device, ATA_STANDBY_IMMEDIATE)) {
 3045:         pout("ATA STANDBY IMMEDIATE command failed: %s\n", device->get_errmsg());
 3046:         returnval |= FAILSMART;
 3047:     }
 3048:     else
 3049:       pout("Device placed in STANDBY mode\n");
 3050:   }
 3051: 
 3052:   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
 3053:   if (!smart_val_ok || options.smart_selftest_type == -1)
 3054:     return returnval;
 3055:   
 3056:   pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
 3057:   // if doing a self-test, be sure it's supported by the hardware
 3058:   switch (options.smart_selftest_type) {
 3059:   case OFFLINE_FULL_SCAN:
 3060:     if (!isSupportExecuteOfflineImmediate(&smartval)){
 3061:       pout("Warning: device does not support Execute Offline Immediate function.\n\n");
 3062:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3063:     }
 3064:     break;
 3065:   case ABORT_SELF_TEST:
 3066:   case SHORT_SELF_TEST:
 3067:   case EXTEND_SELF_TEST:
 3068:   case SHORT_CAPTIVE_SELF_TEST:
 3069:   case EXTEND_CAPTIVE_SELF_TEST:
 3070:     if (!isSupportSelfTest(&smartval)){
 3071:       pout("Warning: device does not support Self-Test functions.\n\n");
 3072:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3073:     }
 3074:     break;
 3075:   case CONVEYANCE_SELF_TEST:
 3076:   case CONVEYANCE_CAPTIVE_SELF_TEST:
 3077:     if (!isSupportConveyanceSelfTest(&smartval)){
 3078:       pout("Warning: device does not support Conveyance Self-Test functions.\n\n");
 3079:       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3080:     }
 3081:     break;
 3082:   case SELECTIVE_SELF_TEST:
 3083:   case SELECTIVE_CAPTIVE_SELF_TEST:
 3084:     if (!isSupportSelectiveSelfTest(&smartval)){
 3085:       pout("Warning: device does not support Selective Self-Test functions.\n\n");
 3086:       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
 3087:     }
 3088:     break;
 3089:   default:
 3090:     break; // Vendor specific type
 3091:   }
 3092: 
 3093:   // Now do the test.  Note ataSmartTest prints its own error/success
 3094:   // messages
 3095:   if (ataSmartTest(device, options.smart_selftest_type, options.smart_selftest_force,
 3096:                    options.smart_selective_args, &smartval, sizes.sectors            ))
 3097:     failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3098:   else {  
 3099:     // Tell user how long test will take to complete.  This is tricky
 3100:     // because in the case of an Offline Full Scan, the completion
 3101:     // timer is volatile, and needs to be read AFTER the command is
 3102:     // given. If this will interrupt the Offline Full Scan, we don't
 3103:     // do it, just warn user.
 3104:     if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
 3105:       if (isSupportOfflineAbort(&smartval))
 3106: 	pout("Note: giving further SMART commands will abort Offline testing\n");
 3107:       else if (ataReadSmartValues(device, &smartval)){
 3108: 	pout("Smartctl: SMART Read Values failed.\n");
 3109: 	failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
 3110:       }
 3111:     }
 3112:     
 3113:     // Now say how long the test will take to complete
 3114:     int timewait = TestTime(&smartval, options.smart_selftest_type);
 3115:     if (timewait) {
 3116:       time_t t=time(NULL);
 3117:       if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
 3118: 	t+=timewait;
 3119: 	pout("Please wait %d seconds for test to complete.\n", (int)timewait);
 3120:       } else {
 3121: 	t+=timewait*60;
 3122: 	pout("Please wait %d minutes for test to complete.\n", (int)timewait);
 3123:       }
 3124:       pout("Test will complete after %s\n", ctime(&t));
 3125:       
 3126:       if (   options.smart_selftest_type != SHORT_CAPTIVE_SELF_TEST
 3127:           && options.smart_selftest_type != EXTEND_CAPTIVE_SELF_TEST
 3128:           && options.smart_selftest_type != CONVEYANCE_CAPTIVE_SELF_TEST
 3129:           && options.smart_selftest_type != SELECTIVE_CAPTIVE_SELF_TEST )
 3130:         pout("Use smartctl -X to abort test.\n");
 3131:     }
 3132:   }
 3133: 
 3134:   return returnval;
 3135: }

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