smartmontools SVN Rev 3317
Utility to control and monitor storage systems with "S.M.A.R.T."
ataprint.cpp
Go to the documentation of this file.
00001 /*
00002  * ataprint.cpp
00003  *
00004  * Home page of code is: http://smartmontools.sourceforge.net
00005  *
00006  * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
00007  * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
00008  * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * This code was originally developed as a Senior Thesis by Michael Cornwell
00019  * at the Concurrent Systems Laboratory (now part of the Storage Systems
00020  * Research Center), Jack Baskin School of Engineering, University of
00021  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
00022  *
00023  */
00024 
00025 #include "config.h"
00026 
00027 #include <ctype.h>
00028 #include <errno.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include "int64.h"
00034 #include "atacmdnames.h"
00035 #include "atacmds.h"
00036 #include "ataidentify.h"
00037 #include "dev_interface.h"
00038 #include "ataprint.h"
00039 #include "smartctl.h"
00040 #include "utility.h"
00041 #include "knowndrives.h"
00042 
00043 const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3880 2014-03-05 17:38:44Z chrfranke $"
00044                                   ATAPRINT_H_CVSID;
00045 
00046 
00047 static const char * infofound(const char *output) {
00048   return (*output ? output : "[No Information Found]");
00049 }
00050 
00051 // Return true if '-T permissive' is specified,
00052 // used to ignore missing capabilities
00053 static bool is_permissive()
00054 {
00055   if (!failuretest_permissive)
00056     return false;
00057   failuretest_permissive--;
00058   return true;
00059 }
00060 
00061 /* For the given Command Register (CR) and Features Register (FR), attempts
00062  * to construct a string that describes the contents of the Status
00063  * Register (ST) and Error Register (ER).  If the meanings of the flags of
00064  * the error register are not known for the given command then it returns an
00065  * empty string.
00066  *
00067  * The meanings of the flags of the error register for all commands are
00068  * described in the ATA spec and could all be supported here in theory.
00069  * Currently, only a few commands are supported (those that have been seen
00070  * to produce errors).  If many more are to be added then this function
00071  * should probably be redesigned.
00072  */
00073 
00074 static std::string format_st_er_desc(
00075   unsigned char CR, unsigned char FR,
00076   unsigned char ST, unsigned char ER,
00077   unsigned short SC,
00078   const ata_smart_errorlog_error_struct * lba28_regs,
00079   const ata_smart_exterrlog_error * lba48_regs
00080 )
00081 {
00082   const char *error_flag[8];
00083   int i, print_lba=0, print_sector=0;
00084 
00085   // Set of character strings corresponding to different error codes.
00086   // Please keep in alphabetic order if you add more.
00087   const char  *abrt  = "ABRT";  // ABORTED
00088  const char   *amnf  = "AMNF";  // ADDRESS MARK NOT FOUND
00089  const char   *ccto  = "CCTO";  // COMMAND COMPLETION TIMED OUT
00090  const char   *eom   = "EOM";   // END OF MEDIA
00091  const char   *icrc  = "ICRC";  // INTERFACE CRC ERROR
00092  const char   *idnf  = "IDNF";  // ID NOT FOUND
00093  const char   *ili   = "ILI";   // MEANING OF THIS BIT IS COMMAND-SET SPECIFIC
00094  const char   *mc    = "MC";    // MEDIA CHANGED 
00095  const char   *mcr   = "MCR";   // MEDIA CHANGE REQUEST
00096  const char   *nm    = "NM";    // NO MEDIA
00097  const char   *obs   = "obs";   // OBSOLETE
00098  const char   *tk0nf = "TK0NF"; // TRACK 0 NOT FOUND
00099  const char   *unc   = "UNC";   // UNCORRECTABLE
00100  const char   *wp    = "WP";    // WRITE PROTECTED
00101 
00102   /* If for any command the Device Fault flag of the status register is
00103    * not used then used_device_fault should be set to 0 (in the CR switch
00104    * below)
00105    */
00106   int uses_device_fault = 1;
00107 
00108   /* A value of NULL means that the error flag isn't used */
00109   for (i = 0; i < 8; i++)
00110     error_flag[i] = NULL;
00111 
00112   std::string str;
00113 
00114   switch (CR) {
00115   case 0x10:  // RECALIBRATE
00116     error_flag[2] = abrt;
00117     error_flag[1] = tk0nf;
00118     break;
00119   case 0x20:  /* READ SECTOR(S) */
00120   case 0x21:  // READ SECTOR(S)
00121   case 0x24:  // READ SECTOR(S) EXT
00122   case 0xC4:  /* READ MULTIPLE */
00123   case 0x29:  // READ MULTIPLE EXT
00124     error_flag[6] = unc;
00125     error_flag[5] = mc;
00126     error_flag[4] = idnf;
00127     error_flag[3] = mcr;
00128     error_flag[2] = abrt;
00129     error_flag[1] = nm;
00130     error_flag[0] = amnf;
00131     print_lba=1;
00132     break;
00133   case 0x22:  // READ LONG (with retries)
00134   case 0x23:  // READ LONG (without retries)
00135     error_flag[4] = idnf;
00136     error_flag[2] = abrt;
00137     error_flag[0] = amnf;
00138     print_lba=1;
00139     break;
00140   case 0x2a:  // READ STREAM DMA
00141   case 0x2b:  // READ STREAM PIO
00142     if (CR==0x2a)
00143       error_flag[7] = icrc;
00144     error_flag[6] = unc;
00145     error_flag[5] = mc;
00146     error_flag[4] = idnf;
00147     error_flag[3] = mcr;
00148     error_flag[2] = abrt;
00149     error_flag[1] = nm;
00150     error_flag[0] = ccto;
00151     print_lba=1;
00152     print_sector=SC;
00153     break;
00154   case 0x3A:  // WRITE STREAM DMA
00155   case 0x3B:  // WRITE STREAM PIO
00156     if (CR==0x3A)
00157       error_flag[7] = icrc;
00158     error_flag[6] = wp;
00159     error_flag[5] = mc;
00160     error_flag[4] = idnf;
00161     error_flag[3] = mcr;
00162     error_flag[2] = abrt;
00163     error_flag[1] = nm;
00164     error_flag[0] = ccto;
00165     print_lba=1;
00166     print_sector=SC;
00167     break;
00168   case 0x25:  // READ DMA EXT
00169   case 0x26:  // READ DMA QUEUED EXT
00170   case 0xC7:  // READ DMA QUEUED
00171   case 0xC8:  // READ DMA (with retries)
00172   case 0xC9:  // READ DMA (without retries, obsolete since ATA-5)
00173   case 0x60:  // READ FPDMA QUEUED (NCQ)
00174     error_flag[7] = icrc;
00175     error_flag[6] = unc;
00176     error_flag[5] = mc;
00177     error_flag[4] = idnf;
00178     error_flag[3] = mcr;
00179     error_flag[2] = abrt;
00180     error_flag[1] = nm;
00181     error_flag[0] = amnf;
00182     print_lba=1;
00183     if (CR==0x25 || CR==0xC8)
00184       print_sector=SC;
00185     break;
00186   case 0x30:  /* WRITE SECTOR(S) */
00187   case 0x31:  // WRITE SECTOR(S)
00188   case 0x34:  // WRITE SECTOR(S) EXT
00189   case 0xC5:  /* WRITE MULTIPLE */
00190   case 0x39:  // WRITE MULTIPLE EXT
00191   case 0xCE:  // WRITE MULTIPLE FUA EXT
00192     error_flag[6] = wp;
00193     error_flag[5] = mc;
00194     error_flag[4] = idnf;
00195     error_flag[3] = mcr;
00196     error_flag[2] = abrt;
00197     error_flag[1] = nm;
00198     print_lba=1;
00199     break;
00200   case 0x32:  // WRITE LONG (with retries)
00201   case 0x33:  // WRITE LONG (without retries)
00202     error_flag[4] = idnf;
00203     error_flag[2] = abrt;
00204     print_lba=1;
00205     break;
00206   case 0x3C:  // WRITE VERIFY
00207     error_flag[6] = unc;
00208     error_flag[4] = idnf;
00209     error_flag[2] = abrt;
00210     error_flag[0] = amnf;
00211     print_lba=1;
00212     break;
00213   case 0x40: // READ VERIFY SECTOR(S) with retries
00214   case 0x41: // READ VERIFY SECTOR(S) without retries
00215   case 0x42: // READ VERIFY SECTOR(S) EXT
00216     error_flag[6] = unc;
00217     error_flag[5] = mc;
00218     error_flag[4] = idnf;
00219     error_flag[3] = mcr;
00220     error_flag[2] = abrt;
00221     error_flag[1] = nm;
00222     error_flag[0] = amnf;
00223     print_lba=1;
00224     break;
00225   case 0xA0:  /* PACKET */
00226     /* Bits 4-7 are all used for sense key (a 'command packet set specific error
00227      * indication' according to the ATA/ATAPI-7 standard), so "Sense key" will
00228      * be repeated in the error description string if more than one of those
00229      * bits is set.
00230      */
00231     error_flag[7] = "Sense key (bit 3)",
00232     error_flag[6] = "Sense key (bit 2)",
00233     error_flag[5] = "Sense key (bit 1)",
00234     error_flag[4] = "Sense key (bit 0)",
00235     error_flag[2] = abrt;
00236     error_flag[1] = eom;
00237     error_flag[0] = ili;
00238     break;
00239   case 0xA1:  /* IDENTIFY PACKET DEVICE */
00240   case 0xEF:  /* SET FEATURES */
00241   case 0x00:  /* NOP */
00242   case 0xC6:  /* SET MULTIPLE MODE */
00243     error_flag[2] = abrt;
00244     break;
00245   case 0x2F:  // READ LOG EXT
00246     error_flag[6] = unc;
00247     error_flag[4] = idnf;
00248     error_flag[2] = abrt;
00249     error_flag[0] = obs;
00250     break;
00251   case 0x3F:  // WRITE LOG EXT
00252     error_flag[4] = idnf;
00253     error_flag[2] = abrt;
00254     error_flag[0] = obs;
00255     break;
00256   case 0xB0:  /* SMART */
00257     switch(FR) {
00258     case 0xD0:  // SMART READ DATA
00259     case 0xD1:  // SMART READ ATTRIBUTE THRESHOLDS
00260     case 0xD5:  /* SMART READ LOG */
00261       error_flag[6] = unc;
00262       error_flag[4] = idnf;
00263       error_flag[2] = abrt;
00264       error_flag[0] = obs;
00265       break;
00266     case 0xD6:  /* SMART WRITE LOG */
00267       error_flag[4] = idnf;
00268       error_flag[2] = abrt;
00269       error_flag[0] = obs;
00270       break;
00271     case 0xD2:  // Enable/Disable Attribute Autosave
00272     case 0xD3:  // SMART SAVE ATTRIBUTE VALUES (ATA-3)
00273     case 0xD8:  // SMART ENABLE OPERATIONS
00274     case 0xD9:  /* SMART DISABLE OPERATIONS */
00275     case 0xDA:  /* SMART RETURN STATUS */
00276     case 0xDB:  // Enable/Disable Auto Offline (SFF)
00277       error_flag[2] = abrt;
00278       break;
00279     case 0xD4:  // SMART EXECUTE IMMEDIATE OFFLINE
00280       error_flag[4] = idnf;
00281       error_flag[2] = abrt;
00282       break;
00283     default:
00284       return str; // ""
00285       break;
00286     }
00287     break;
00288   case 0xB1:  /* DEVICE CONFIGURATION */
00289     switch (FR) {
00290     case 0xC0:  /* DEVICE CONFIGURATION RESTORE */
00291       error_flag[2] = abrt;
00292       break;
00293     default:
00294       return str; // ""
00295       break;
00296     }
00297     break;
00298   case 0xCA:  // WRITE DMA (with retries)
00299   case 0xCB:  // WRITE DMA (without retries, obsolete since ATA-5)
00300   case 0x35:  // WRITE DMA EXT
00301   case 0x3D:  // WRITE DMA FUA EXT
00302   case 0xCC:  // WRITE DMA QUEUED
00303   case 0x36:  // WRITE DMA QUEUED EXT
00304   case 0x3E:  // WRITE DMA QUEUED FUA EXT
00305   case 0x61:  // WRITE FPDMA QUEUED (NCQ)
00306     error_flag[7] = icrc;
00307     error_flag[6] = wp;
00308     error_flag[5] = mc;
00309     error_flag[4] = idnf;
00310     error_flag[3] = mcr;
00311     error_flag[2] = abrt;
00312     error_flag[1] = nm;
00313     error_flag[0] = amnf;
00314     print_lba=1;
00315     if (CR==0x35)
00316       print_sector=SC;
00317     break;
00318   case 0xE4: // READ BUFFER
00319   case 0xE8: // WRITE BUFFER
00320     error_flag[2] = abrt;
00321     break;
00322   default:
00323     return str; // ""
00324   }
00325 
00326   /* We ignore any status flags other than Device Fault and Error */
00327 
00328   if (uses_device_fault && (ST & (1 << 5))) {
00329     str = "Device Fault";
00330     if (ST & 1)  // Error flag
00331       str += "; ";
00332   }
00333   if (ST & 1) {  // Error flag
00334     int count = 0;
00335 
00336     str += "Error: ";
00337     for (i = 7; i >= 0; i--)
00338       if ((ER & (1 << i)) && (error_flag[i])) {
00339         if (count++ > 0)
00340            str += ", ";
00341         str += error_flag[i];
00342       }
00343   }
00344 
00345   // If the error was a READ or WRITE error, print the Logical Block
00346   // Address (LBA) at which the read or write failed.
00347   if (print_lba) {
00348     // print number of sectors, if known, and append to print string
00349     if (print_sector)
00350       str += strprintf(" %d sectors", print_sector);
00351 
00352     if (lba28_regs) {
00353       unsigned lba;
00354       // bits 24-27: bits 0-3 of DH
00355       lba   = 0xf & lba28_regs->drive_head;
00356       lba <<= 8;
00357       // bits 16-23: CH
00358       lba  |= lba28_regs->cylinder_high;
00359       lba <<= 8;
00360       // bits 8-15:  CL
00361       lba  |= lba28_regs->cylinder_low;
00362       lba <<= 8;
00363       // bits 0-7:   SN
00364       lba  |= lba28_regs->sector_number;
00365       str += strprintf(" at LBA = 0x%08x = %u", lba, lba);
00366     }
00367     else if (lba48_regs) {
00368       // This assumes that upper LBA registers are 0 for 28-bit commands
00369       // (TODO: detect 48-bit commands above)
00370       uint64_t lba48;
00371       lba48   = lba48_regs->lba_high_register_hi;
00372       lba48 <<= 8;
00373       lba48  |= lba48_regs->lba_mid_register_hi;
00374       lba48 <<= 8;
00375       lba48  |= lba48_regs->lba_low_register_hi;
00376       lba48  |= lba48_regs->device_register & 0xf;
00377       lba48 <<= 8;
00378       lba48  |= lba48_regs->lba_high_register;
00379       lba48 <<= 8;
00380       lba48  |= lba48_regs->lba_mid_register;
00381       lba48 <<= 8;
00382       lba48  |= lba48_regs->lba_low_register;
00383       str += strprintf(" at LBA = 0x%08" PRIx64 " = %" PRIu64, lba48, lba48);
00384     }
00385   }
00386 
00387   return str;
00388 }
00389 
00390 static inline std::string format_st_er_desc(
00391   const ata_smart_errorlog_struct * data)
00392 {
00393   return format_st_er_desc(
00394     data->commands[4].commandreg,
00395     data->commands[4].featuresreg,
00396     data->error_struct.status,
00397     data->error_struct.error_register,
00398     data->error_struct.sector_count,
00399     &data->error_struct, (const ata_smart_exterrlog_error *)0);
00400 }
00401 
00402 static inline std::string format_st_er_desc(
00403   const ata_smart_exterrlog_error_log * data)
00404 {
00405   return format_st_er_desc(
00406     data->commands[4].command_register,
00407     data->commands[4].features_register,
00408     data->error.status_register,
00409     data->error.error_register,
00410     data->error.count_register_hi << 8 | data->error.count_register,
00411     (const ata_smart_errorlog_error_struct *)0, &data->error);
00412 }
00413 
00414 
00415 static int find_msb(unsigned short word)
00416 {
00417   for (int bit = 15; bit >= 0; bit--)
00418     if (word & (1 << bit))
00419       return bit;
00420   return -1;
00421 }
00422 
00423 static const char * get_ata_major_version(const ata_identify_device * drive)
00424 {
00425   switch (find_msb(drive->major_rev_num)) {
00426     case 10: return "ACS-3";
00427     case  9: return "ACS-2";
00428     case  8: return "ATA8-ACS";
00429     case  7: return "ATA/ATAPI-7";
00430     case  6: return "ATA/ATAPI-6";
00431     case  5: return "ATA/ATAPI-5";
00432     case  4: return "ATA/ATAPI-4";
00433     case  3: return "ATA-3";
00434     case  2: return "ATA-2";
00435     case  1: return "ATA-1";
00436     default: return 0;
00437   }
00438 }
00439 
00440 static const char * get_ata_minor_version(const ata_identify_device * drive)
00441 {
00442   switch (drive->minor_rev_num) {
00443     case 0x0001: return "ATA-1 X3T9.2/781D prior to revision 4";
00444     case 0x0002: return "ATA-1 published, ANSI X3.221-1994";
00445     case 0x0003: return "ATA-1 X3T9.2/781D revision 4";
00446     case 0x0004: return "ATA-2 published, ANSI X3.279-1996";
00447     case 0x0005: return "ATA-2 X3T10/948D prior to revision 2k";
00448     case 0x0006: return "ATA-3 X3T10/2008D revision 1";
00449     case 0x0007: return "ATA-2 X3T10/948D revision 2k";
00450     case 0x0008: return "ATA-3 X3T10/2008D revision 0";
00451     case 0x0009: return "ATA-2 X3T10/948D revision 3";
00452     case 0x000a: return "ATA-3 published, ANSI X3.298-1997";
00453     case 0x000b: return "ATA-3 X3T10/2008D revision 6"; // 1st ATA-3 revision with SMART
00454     case 0x000c: return "ATA-3 X3T13/2008D revision 7 and 7a";
00455     case 0x000d: return "ATA/ATAPI-4 X3T13/1153D revision 6";
00456     case 0x000e: return "ATA/ATAPI-4 T13/1153D revision 13";
00457     case 0x000f: return "ATA/ATAPI-4 X3T13/1153D revision 7";
00458     case 0x0010: return "ATA/ATAPI-4 T13/1153D revision 18";
00459     case 0x0011: return "ATA/ATAPI-4 T13/1153D revision 15";
00460     case 0x0012: return "ATA/ATAPI-4 published, ANSI NCITS 317-1998";
00461     case 0x0013: return "ATA/ATAPI-5 T13/1321D revision 3";
00462     case 0x0014: return "ATA/ATAPI-4 T13/1153D revision 14";
00463     case 0x0015: return "ATA/ATAPI-5 T13/1321D revision 1";
00464     case 0x0016: return "ATA/ATAPI-5 published, ANSI NCITS 340-2000";
00465     case 0x0017: return "ATA/ATAPI-4 T13/1153D revision 17";
00466     case 0x0018: return "ATA/ATAPI-6 T13/1410D revision 0";
00467     case 0x0019: return "ATA/ATAPI-6 T13/1410D revision 3a";
00468     case 0x001a: return "ATA/ATAPI-7 T13/1532D revision 1";
00469     case 0x001b: return "ATA/ATAPI-6 T13/1410D revision 2";
00470     case 0x001c: return "ATA/ATAPI-6 T13/1410D revision 1";
00471     case 0x001d: return "ATA/ATAPI-7 published, ANSI INCITS 397-2005";
00472     case 0x001e: return "ATA/ATAPI-7 T13/1532D revision 0";
00473     case 0x001f: return "ACS-3 T13/2161-D revision 3b";
00474 
00475     case 0x0021: return "ATA/ATAPI-7 T13/1532D revision 4a";
00476     case 0x0022: return "ATA/ATAPI-6 published, ANSI INCITS 361-2002";
00477 
00478     case 0x0027: return "ATA8-ACS T13/1699-D revision 3c";
00479     case 0x0028: return "ATA8-ACS T13/1699-D revision 6";
00480     case 0x0029: return "ATA8-ACS T13/1699-D revision 4";
00481 
00482     case 0x0031: return "ACS-2 T13/2015-D revision 2";
00483 
00484     case 0x0033: return "ATA8-ACS T13/1699-D revision 3e";
00485 
00486     case 0x0039: return "ATA8-ACS T13/1699-D revision 4c";
00487 
00488     case 0x0042: return "ATA8-ACS T13/1699-D revision 3f";
00489 
00490     case 0x0052: return "ATA8-ACS T13/1699-D revision 3b";
00491 
00492     case 0x0107: return "ATA8-ACS T13/1699-D revision 2d";
00493 
00494     case 0x0110: return "ACS-2 T13/2015-D revision 3";
00495 
00496     default:     return 0;
00497   }
00498 }
00499 
00500 static const char * get_sata_version(const ata_identify_device * drive)
00501 {
00502   unsigned short word222 = drive->words088_255[222-88];
00503   if ((word222 & 0xf000) != 0x1000)
00504     return 0;
00505   switch (find_msb(word222 & 0x0fff)) {
00506     default: return "SATA >3.1";
00507     case 6:  return "SATA 3.1";
00508     case 5:  return "SATA 3.0";
00509     case 4:  return "SATA 2.6";
00510     case 3:  return "SATA 2.5";
00511     case 2:  return "SATA II Ext";
00512     case 1:  return "SATA 1.0a";
00513     case 0:  return "ATA8-AST";
00514     case -1: return 0;
00515   }
00516 }
00517 
00518 static const char * get_sata_speed(int level)
00519 {
00520   if (level <= 0)
00521     return 0;
00522   switch (level) {
00523     default: return ">6.0 Gb/s";
00524     case 3:  return "6.0 Gb/s";
00525     case 2:  return "3.0 Gb/s";
00526     case 1:  return "1.5 Gb/s";
00527   }
00528 }
00529 
00530 static const char * get_sata_maxspeed(const ata_identify_device * drive)
00531 {
00532   unsigned short word076 = drive->words047_079[76-47];
00533   if (word076 & 0x0001)
00534     return 0;
00535   return get_sata_speed(find_msb(word076 & 0x00fe));
00536 }
00537 
00538 static const char * get_sata_curspeed(const ata_identify_device * drive)
00539 {
00540   unsigned short word077 = drive->words047_079[77-47];
00541   if (word077 & 0x0001)
00542     return 0;
00543   return get_sata_speed((word077 >> 1) & 0x7);
00544 }
00545 
00546 
00547 static void print_drive_info(const ata_identify_device * drive,
00548                              const ata_size_info & sizes, int rpm,
00549                              const drive_settings * dbentry)
00550 {
00551   // format drive information (with byte swapping as needed)
00552   char model[40+1], serial[20+1], firmware[8+1];
00553   ata_format_id_string(model, drive->model, sizeof(model)-1);
00554   ata_format_id_string(serial, drive->serial_no, sizeof(serial)-1);
00555   ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1);
00556 
00557   // Print model family if known
00558   if (dbentry && *dbentry->modelfamily)
00559     pout("Model Family:     %s\n", dbentry->modelfamily);
00560 
00561   pout("Device Model:     %s\n", infofound(model));
00562   if (!dont_print_serial_number) {
00563     pout("Serial Number:    %s\n", infofound(serial));
00564 
00565     unsigned oui = 0; uint64_t unique_id = 0;
00566     int naa = ata_get_wwn(drive, oui, unique_id);
00567     if (naa >= 0)
00568       pout("LU WWN Device Id: %x %06x %09" PRIx64 "\n", naa, oui, unique_id);
00569 
00570     // Additional Product Identifier (OEM Id) string in words 170-173
00571     // (e08130r1, added in ACS-2 Revision 1, December 17, 2008)
00572     if (0x2020 <= drive->words088_255[170-88] && drive->words088_255[170-88] <= 0x7e7e) {
00573       char add[8+1];
00574       ata_format_id_string(add, (const unsigned char *)(drive->words088_255+170-88), sizeof(add)-1);
00575       if (add[0])
00576         pout("Add. Product Id:  %s\n", add);
00577     }
00578   }
00579   pout("Firmware Version: %s\n", infofound(firmware));
00580 
00581   if (sizes.capacity) {
00582     // Print capacity
00583     char num[64], cap[32];
00584     pout("User Capacity:    %s bytes [%s]\n",
00585       format_with_thousands_sep(num, sizeof(num), sizes.capacity),
00586       format_capacity(cap, sizeof(cap), sizes.capacity));
00587 
00588     // Print sector sizes.
00589     if (sizes.phy_sector_size == sizes.log_sector_size)
00590       pout("Sector Size:      %u bytes logical/physical\n", sizes.log_sector_size);
00591     else {
00592       pout("Sector Sizes:     %u bytes logical, %u bytes physical",
00593          sizes.log_sector_size, sizes.phy_sector_size);
00594       if (sizes.log_sector_offset)
00595         pout(" (offset %u bytes)", sizes.log_sector_offset);
00596       pout("\n");
00597     }
00598   }
00599 
00600   // Print nominal media rotation rate if reported
00601   if (rpm) {
00602     if (rpm == 1)
00603       pout("Rotation Rate:    Solid State Device\n");
00604     else if (rpm > 1)
00605       pout("Rotation Rate:    %d rpm\n", rpm);
00606     else
00607       pout("Rotation Rate:    Unknown (0x%04x)\n", -rpm);
00608   }
00609 
00610   // See if drive is recognized
00611   pout("Device is:        %s\n", !dbentry ?
00612        "Not in smartctl database [for details use: -P showall]":
00613        "In smartctl database [for details use: -P show]");
00614 
00615   // Print ATA version
00616   std::string ataver;
00617   if (   (drive->major_rev_num != 0x0000 && drive->major_rev_num != 0xffff)
00618       || (drive->minor_rev_num != 0x0000 && drive->minor_rev_num != 0xffff)) {
00619     const char * majorver = get_ata_major_version(drive);
00620     const char * minorver = get_ata_minor_version(drive);
00621 
00622     if (majorver && minorver && str_starts_with(minorver, majorver)) {
00623       // Major and minor strings match, print minor string only
00624       ataver = minorver;
00625     }
00626     else {
00627       if (majorver)
00628         ataver = majorver;
00629       else
00630         ataver = strprintf("Unknown(0x%04x)", drive->major_rev_num);
00631 
00632       if (minorver)
00633         ataver += strprintf(", %s", minorver);
00634       else if (drive->minor_rev_num != 0x0000 && drive->minor_rev_num != 0xffff)
00635         ataver += strprintf(" (unknown minor revision code: 0x%04x)", drive->minor_rev_num);
00636       else
00637         ataver += " (minor revision not indicated)";
00638     }
00639   }
00640   pout("ATA Version is:   %s\n", infofound(ataver.c_str()));
00641 
00642   // If SATA drive print SATA version and speed
00643   const char * sataver = get_sata_version(drive);
00644   if (sataver) {
00645     const char * maxspeed = get_sata_maxspeed(drive);
00646     const char * curspeed = get_sata_curspeed(drive);
00647     pout("SATA Version is:  %s%s%s%s%s%s\n", sataver,
00648          (maxspeed ? ", " : ""), (maxspeed ? maxspeed : ""),
00649          (curspeed ? " (current: " : ""), (curspeed ? curspeed : ""),
00650          (curspeed ? ")" : ""));
00651   }
00652 
00653   // print current time and date and timezone
00654   char timedatetz[DATEANDEPOCHLEN]; dateandtimezone(timedatetz);
00655   pout("Local Time is:    %s\n", timedatetz);
00656 
00657   // Print warning message, if there is one
00658   if (dbentry && *dbentry->warningmsg)
00659     pout("\n==> WARNING: %s\n\n", dbentry->warningmsg);
00660 }
00661 
00662 static const char *OfflineDataCollectionStatus(unsigned char status_byte)
00663 {
00664   unsigned char stat=status_byte & 0x7f;
00665   
00666   switch(stat){
00667   case 0x00:
00668     return "was never started";
00669   case 0x02:
00670     return "was completed without error";
00671   case 0x03:
00672     if (status_byte == 0x03)
00673       return "is in progress";
00674     else
00675       return "is in a Reserved state";
00676   case 0x04:
00677     return "was suspended by an interrupting command from host";
00678   case 0x05:
00679     return "was aborted by an interrupting command from host";
00680   case 0x06:
00681     return "was aborted by the device with a fatal error";
00682   default:
00683     if (stat >= 0x40)
00684       return "is in a Vendor Specific state";
00685     else
00686       return "is in a Reserved state";
00687   }
00688 }
00689   
00690   
00691 //  prints verbose value Off-line data collection status byte
00692 static void PrintSmartOfflineStatus(const ata_smart_values * data)
00693 {
00694   pout("Offline data collection status:  (0x%02x)\t",
00695        (int)data->offline_data_collection_status);
00696     
00697   // Off-line data collection status byte is not a reserved
00698   // or vendor specific value
00699   pout("Offline data collection activity\n"
00700        "\t\t\t\t\t%s.\n", OfflineDataCollectionStatus(data->offline_data_collection_status));
00701   
00702   // Report on Automatic Data Collection Status.  Only IBM documents
00703   // this bit.  See SFF 8035i Revision 2 for details.
00704   if (data->offline_data_collection_status & 0x80)
00705     pout("\t\t\t\t\tAuto Offline Data Collection: Enabled.\n");
00706   else
00707     pout("\t\t\t\t\tAuto Offline Data Collection: Disabled.\n");
00708   
00709   return;
00710 }
00711 
00712 static void PrintSmartSelfExecStatus(const ata_smart_values * data,
00713                                      firmwarebug_defs firmwarebugs)
00714 {
00715    pout("Self-test execution status:      ");
00716    
00717    switch (data->self_test_exec_status >> 4)
00718    {
00719       case 0:
00720         pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t",
00721                 (int)data->self_test_exec_status);
00722         pout("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n");
00723         break;
00724        case 1:
00725          pout("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t",
00726                  (int)data->self_test_exec_status);
00727          pout("the host.\n");
00728          break;
00729        case 2:
00730          pout("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t",
00731                  (int)data->self_test_exec_status);
00732          pout("by the host with a hard or soft reset.\n");
00733          break;
00734        case 3:
00735           pout("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t",
00736                   (int)data->self_test_exec_status);
00737           pout("occurred while the device was executing\n\t\t\t\t\t");
00738           pout("its self-test routine and the device \n\t\t\t\t\t");
00739           pout("was unable to complete the self-test \n\t\t\t\t\t");
00740           pout("routine.\n");
00741           break;
00742        case 4:
00743           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
00744                   (int)data->self_test_exec_status);
00745           pout("a test element that failed and the test\n\t\t\t\t\t");
00746           pout("element that failed is not known.\n");
00747           break;
00748        case 5:
00749           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
00750                   (int)data->self_test_exec_status);
00751           pout("the electrical element of the test\n\t\t\t\t\t");
00752           pout("failed.\n");
00753           break;
00754        case 6:
00755           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
00756                   (int)data->self_test_exec_status);
00757           pout("the servo (and/or seek) element of the \n\t\t\t\t\t");
00758           pout("test failed.\n");
00759           break;
00760        case 7:
00761           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
00762                   (int)data->self_test_exec_status);
00763           pout("the read element of the test failed.\n");
00764           break;
00765        case 8:
00766           pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t",
00767                   (int)data->self_test_exec_status);
00768           pout("a test element that failed and the\n\t\t\t\t\t");
00769           pout("device is suspected of having handling\n\t\t\t\t\t");
00770           pout("damage.\n");
00771           break;
00772        case 15:
00773           if (firmwarebugs.is_set(BUG_SAMSUNG3) && data->self_test_exec_status == 0xf0) {
00774             pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t",
00775                     (int)data->self_test_exec_status);
00776             pout("with unknown result or self-test in\n\t\t\t\t\t");
00777             pout("progress with less than 10%% remaining.\n");
00778           }
00779           else {
00780             pout("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t",
00781                     (int)data->self_test_exec_status);
00782             pout("%1d0%% of test remaining.\n", 
00783                   (int)(data->self_test_exec_status & 0x0f));
00784           }
00785           break;
00786        default:
00787           pout("(%4d)\tReserved.\n",
00788                   (int)data->self_test_exec_status);
00789           break;
00790    }
00791         
00792 }
00793 
00794 static void PrintSmartTotalTimeCompleteOffline (const ata_smart_values * data)
00795 {
00796   pout("Total time to complete Offline \n");
00797   pout("data collection: \t\t(%5d) seconds.\n", 
00798        (int)data->total_time_to_complete_off_line);
00799 }
00800 
00801 static void PrintSmartOfflineCollectCap(const ata_smart_values *data)
00802 {
00803   pout("Offline data collection\n");
00804   pout("capabilities: \t\t\t (0x%02x) ",
00805        (int)data->offline_data_collection_capability);
00806   
00807   if (data->offline_data_collection_capability == 0x00){
00808     pout("\tOffline data collection not supported.\n");
00809   } 
00810   else {
00811     pout( "%s\n", isSupportExecuteOfflineImmediate(data)?
00812           "SMART execute Offline immediate." :
00813           "No SMART execute Offline immediate.");
00814     
00815     pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? 
00816           "Auto Offline data collection on/off support.":
00817           "No Auto Offline data collection support.");
00818     
00819     pout( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? 
00820           "Abort Offline collection upon new\n\t\t\t\t\tcommand.":
00821           "Suspend Offline collection upon new\n\t\t\t\t\tcommand.");
00822     
00823     pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? 
00824           "Offline surface scan supported.":
00825           "No Offline surface scan supported.");
00826     
00827     pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? 
00828           "Self-test supported.":
00829           "No Self-test supported.");
00830 
00831     pout( "\t\t\t\t\t%s\n", isSupportConveyanceSelfTest(data)? 
00832           "Conveyance Self-test supported.":
00833           "No Conveyance Self-test supported.");
00834 
00835     pout( "\t\t\t\t\t%s\n", isSupportSelectiveSelfTest(data)? 
00836           "Selective Self-test supported.":
00837           "No Selective Self-test supported.");
00838   }
00839 }
00840 
00841 static void PrintSmartCapability(const ata_smart_values *data)
00842 {
00843    pout("SMART capabilities:            ");
00844    pout("(0x%04x)\t", (int)data->smart_capability);
00845    
00846    if (data->smart_capability == 0x00)
00847    {
00848        pout("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n");
00849    } 
00850    else 
00851    {
00852         
00853       pout( "%s\n", (data->smart_capability & 0x01)? 
00854               "Saves SMART data before entering\n\t\t\t\t\tpower-saving mode.":
00855               "Does not save SMART data before\n\t\t\t\t\tentering power-saving mode.");
00856                 
00857       if ( data->smart_capability & 0x02 )
00858       {
00859           pout("\t\t\t\t\tSupports SMART auto save timer.\n");
00860       }
00861    }
00862 }
00863 
00864 static void PrintSmartErrorLogCapability(const ata_smart_values * data, const ata_identify_device * identity)
00865 {
00866    pout("Error logging capability:       ");
00867     
00868    if ( isSmartErrorLogCapable(data, identity) )
00869    {
00870       pout(" (0x%02x)\tError logging supported.\n",
00871                (int)data->errorlog_capability);
00872    }
00873    else {
00874        pout(" (0x%02x)\tError logging NOT supported.\n",
00875                 (int)data->errorlog_capability);
00876    }
00877 }
00878 
00879 static void PrintSmartShortSelfTestPollingTime(const ata_smart_values * data)
00880 {
00881   pout("Short self-test routine \n");
00882   if (isSupportSelfTest(data))
00883     pout("recommended polling time: \t (%4d) minutes.\n", 
00884          (int)data->short_test_completion_time);
00885   else
00886     pout("recommended polling time: \t        Not Supported.\n");
00887 }
00888 
00889 static void PrintSmartExtendedSelfTestPollingTime(const ata_smart_values * data)
00890 {
00891   pout("Extended self-test routine\n");
00892   if (isSupportSelfTest(data))
00893     pout("recommended polling time: \t (%4d) minutes.\n", 
00894          TestTime(data, EXTEND_SELF_TEST));
00895   else
00896     pout("recommended polling time: \t        Not Supported.\n");
00897 }
00898 
00899 static void PrintSmartConveyanceSelfTestPollingTime(const ata_smart_values * data)
00900 {
00901   pout("Conveyance self-test routine\n");
00902   if (isSupportConveyanceSelfTest(data))
00903     pout("recommended polling time: \t (%4d) minutes.\n", 
00904          (int)data->conveyance_test_completion_time);
00905   else
00906     pout("recommended polling time: \t        Not Supported.\n");
00907 }
00908 
00909 // Check SMART attribute table for Threshold failure
00910 // onlyfailed=0: are or were any age or prefailure attributes <= threshold
00911 // onlyfailed=1: are any prefailure attributes <= threshold now
00912 static int find_failed_attr(const ata_smart_values * data,
00913                             const ata_smart_thresholds_pvt * thresholds,
00914                             const ata_vendor_attr_defs & defs, int onlyfailed)
00915 {
00916   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
00917     const ata_smart_attribute & attr = data->vendor_attributes[i];
00918 
00919     ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs);
00920 
00921     if (!onlyfailed) {
00922       if (state >= ATTRSTATE_FAILED_PAST)
00923         return attr.id;
00924     }
00925     else {
00926       if (state == ATTRSTATE_FAILED_NOW && ATTRIBUTE_FLAGS_PREFAILURE(attr.flags))
00927         return attr.id;
00928     }
00929   }
00930   return 0;
00931 }
00932 
00933 // onlyfailed=0 : print all attribute values
00934 // onlyfailed=1:  just ones that are currently failed and have prefailure bit set
00935 // onlyfailed=2:  ones that are failed, or have failed with or without prefailure bit set
00936 static void PrintSmartAttribWithThres(const ata_smart_values * data,
00937                                       const ata_smart_thresholds_pvt * thresholds,
00938                                       const ata_vendor_attr_defs & defs, int rpm,
00939                                       int onlyfailed, unsigned char format)
00940 {
00941   bool brief  = !!(format & ata_print_options::FMT_BRIEF);
00942   bool hexid  = !!(format & ata_print_options::FMT_HEX_ID);
00943   bool hexval = !!(format & ata_print_options::FMT_HEX_VAL);
00944   bool needheader = true;
00945 
00946   // step through all vendor attributes
00947   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
00948     const ata_smart_attribute & attr = data->vendor_attributes[i];
00949 
00950     // Check attribute and threshold
00951     unsigned char threshold = 0;
00952     ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs, &threshold);
00953     if (state == ATTRSTATE_NON_EXISTING)
00954       continue;
00955 
00956     // These break out of the loop if we are only printing certain entries...
00957     if (onlyfailed == 1 && !(ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) && state == ATTRSTATE_FAILED_NOW))
00958       continue;
00959 
00960     if (onlyfailed == 2 && state < ATTRSTATE_FAILED_PAST)
00961       continue;
00962 
00963     // print header only if needed
00964     if (needheader) {
00965       if (!onlyfailed) {
00966         pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
00967         pout("Vendor Specific SMART Attributes with Thresholds:\n");
00968       }
00969       if (!brief)
00970         pout("ID#%s ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n",
00971              (!hexid ? "" : " "));
00972       else
00973         pout("ID#%s ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE\n",
00974              (!hexid ? "" : " "));
00975       needheader = false;
00976     }
00977 
00978     // Format value, worst, threshold
00979     std::string valstr, worstr, threstr;
00980     if (state > ATTRSTATE_NO_NORMVAL)
00981       valstr = (!hexval ? strprintf("%.3d",   attr.current)
00982                         : strprintf("0x%02x", attr.current));
00983     else
00984       valstr = (!hexval ? "---" : "----");
00985     if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL))
00986       worstr = (!hexval ? strprintf("%.3d",   attr.worst)
00987                         : strprintf("0x%02x", attr.worst));
00988     else
00989       worstr = (!hexval ? "---" : "----");
00990     if (state > ATTRSTATE_NO_THRESHOLD)
00991       threstr = (!hexval ? strprintf("%.3d",   threshold)
00992                          : strprintf("0x%02x", threshold));
00993     else
00994       threstr = (!hexval ? "---" : "----");
00995 
00996     // Print line for each valid attribute
00997     std::string idstr = (!hexid ? strprintf("%3d",    attr.id)
00998                                 : strprintf("0x%02x", attr.id));
00999     std::string attrname = ata_get_smart_attr_name(attr.id, defs, rpm);
01000     std::string rawstr = ata_format_attr_raw_value(attr, defs);
01001 
01002     if (!brief)
01003       pout("%s %-24s0x%04x   %-4s  %-4s  %-4s   %-10s%-9s%-12s%s\n",
01004            idstr.c_str(), attrname.c_str(), attr.flags,
01005            valstr.c_str(), worstr.c_str(), threstr.c_str(),
01006            (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) ? "Pre-fail" : "Old_age"),
01007            (ATTRIBUTE_FLAGS_ONLINE(attr.flags)     ? "Always"   : "Offline"),
01008            (state == ATTRSTATE_FAILED_NOW  ? "FAILING_NOW" :
01009             state == ATTRSTATE_FAILED_PAST ? "In_the_past"
01010                                            : "    -"        ) ,
01011             rawstr.c_str());
01012     else
01013       pout("%s %-24s%c%c%c%c%c%c%c  %-4s  %-4s  %-4s   %-5s%s\n",
01014            idstr.c_str(), attrname.c_str(),
01015            (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags)     ? 'P' : '-'),
01016            (ATTRIBUTE_FLAGS_ONLINE(attr.flags)         ? 'O' : '-'),
01017            (ATTRIBUTE_FLAGS_PERFORMANCE(attr.flags)    ? 'S' : '-'),
01018            (ATTRIBUTE_FLAGS_ERRORRATE(attr.flags)      ? 'R' : '-'),
01019            (ATTRIBUTE_FLAGS_EVENTCOUNT(attr.flags)     ? 'C' : '-'),
01020            (ATTRIBUTE_FLAGS_SELFPRESERVING(attr.flags) ? 'K' : '-'),
01021            (ATTRIBUTE_FLAGS_OTHER(attr.flags)          ? '+' : ' '),
01022            valstr.c_str(), worstr.c_str(), threstr.c_str(),
01023            (state == ATTRSTATE_FAILED_NOW  ? "NOW"  :
01024             state == ATTRSTATE_FAILED_PAST ? "Past"
01025                                            : "-"     ),
01026             rawstr.c_str());
01027 
01028   }
01029 
01030   if (!needheader) {
01031     if (!onlyfailed && brief) {
01032         int n = (!hexid ? 28 : 29);
01033         pout("%*s||||||_ K auto-keep\n"
01034              "%*s|||||__ C event count\n"
01035              "%*s||||___ R error rate\n"
01036              "%*s|||____ S speed/performance\n"
01037              "%*s||_____ O updated online\n"
01038              "%*s|______ P prefailure warning\n",
01039              n, "", n, "", n, "", n, "", n, "", n, "");
01040     }
01041     pout("\n");
01042   }
01043 }
01044 
01045 // Print SMART related SCT capabilities
01046 static void ataPrintSCTCapability(const ata_identify_device *drive)
01047 {
01048   unsigned short sctcaps = drive->words088_255[206-88];
01049   if (!(sctcaps & 0x01))
01050     return;
01051   pout("SCT capabilities: \t       (0x%04x)\tSCT Status supported.\n", sctcaps);
01052   if (sctcaps & 0x08)
01053     pout("\t\t\t\t\tSCT Error Recovery Control supported.\n");
01054   if (sctcaps & 0x10)
01055     pout("\t\t\t\t\tSCT Feature Control supported.\n");
01056   if (sctcaps & 0x20)
01057     pout("\t\t\t\t\tSCT Data Table supported.\n");
01058 }
01059 
01060 
01061 static void PrintGeneralSmartValues(const ata_smart_values *data, const ata_identify_device *drive,
01062                                     firmwarebug_defs firmwarebugs)
01063 {
01064   pout("General SMART Values:\n");
01065   
01066   PrintSmartOfflineStatus(data); 
01067   
01068   if (isSupportSelfTest(data)){
01069     PrintSmartSelfExecStatus(data, firmwarebugs);
01070   }
01071   
01072   PrintSmartTotalTimeCompleteOffline(data);
01073   PrintSmartOfflineCollectCap(data);
01074   PrintSmartCapability(data);
01075   
01076   PrintSmartErrorLogCapability(data, drive);
01077 
01078   pout( "\t\t\t\t\t%s\n", isGeneralPurposeLoggingCapable(drive)?
01079         "General Purpose Logging supported.":
01080         "No General Purpose Logging support.");
01081 
01082   if (isSupportSelfTest(data)){
01083     PrintSmartShortSelfTestPollingTime (data);
01084     PrintSmartExtendedSelfTestPollingTime (data);
01085   }
01086   if (isSupportConveyanceSelfTest(data))
01087     PrintSmartConveyanceSelfTestPollingTime (data);
01088 
01089   ataPrintSCTCapability(drive);
01090 
01091   pout("\n");
01092 }
01093 
01094 // Get # sectors of a log addr, 0 if log does not exist.
01095 static unsigned GetNumLogSectors(const ata_smart_log_directory * logdir, unsigned logaddr, bool gpl)
01096 {
01097   if (!logdir)
01098     return 0;
01099   if (logaddr > 0xff)
01100     return 0;
01101   if (logaddr == 0)
01102     return 1;
01103   unsigned n = logdir->entry[logaddr-1].numsectors;
01104   if (gpl)
01105     // GP logs may have >255 sectors
01106     n |= logdir->entry[logaddr-1].reserved << 8;
01107   return n;
01108 }
01109 
01110 // Get name of log.
01111 // Table A.2 of T13/2161-D (ACS-3) Revision 4, September 4, 2012
01112 static const char * GetLogName(unsigned logaddr)
01113 {
01114     switch (logaddr) {
01115       case 0x00: return "Log Directory";
01116       case 0x01: return "Summary SMART error log";
01117       case 0x02: return "Comprehensive SMART error log";
01118       case 0x03: return "Ext. Comprehensive SMART error log";
01119       case 0x04: return "Device Statistics log";
01120       case 0x05: return "Reserved for CFA"; // ACS-2
01121       case 0x06: return "SMART self-test log";
01122       case 0x07: return "Extended self-test log";
01123       case 0x08: return "Power Conditions log"; // ACS-2
01124       case 0x09: return "Selective self-test log";
01125       case 0x0a: return "Device Statistics Notification"; // ACS-3
01126       case 0x0b: return "Reserved for CFA"; // ACS-3
01127 
01128       case 0x0d: return "LPS Mis-alignment log"; // ACS-2
01129 
01130       case 0x10: return "NCQ Command Error log";
01131       case 0x11: return "SATA Phy Event Counters";
01132       case 0x12: return "SATA NCQ Queue Management log"; // ACS-3
01133       case 0x13: return "SATA NCQ Send and Receive log"; // ACS-3
01134       case 0x14:
01135       case 0x15:
01136       case 0x16: return "Reserved for Serial ATA";
01137 
01138       case 0x19: return "LBA Status log"; // ACS-3
01139 
01140       case 0x20: return "Streaming performance log [OBS-8]";
01141       case 0x21: return "Write stream error log";
01142       case 0x22: return "Read stream error log";
01143       case 0x23: return "Delayed sector log [OBS-8]";
01144       case 0x24: return "Current Device Internal Status Data log"; // ACS-3
01145       case 0x25: return "Saved Device Internal Status Data log"; // ACS-3
01146 
01147       case 0x30: return "IDENTIFY DEVICE data log"; // ACS-3
01148 
01149       case 0xe0: return "SCT Command/Status";
01150       case 0xe1: return "SCT Data Transfer";
01151       default:
01152         if (0xa0 <= logaddr && logaddr <= 0xdf)
01153           return "Device vendor specific log";
01154         if (0x80 <= logaddr && logaddr <= 0x9f)
01155           return "Host vendor specific log";
01156         return "Reserved";
01157     }
01158     /*NOTREACHED*/
01159 }
01160 
01161 // Get log access permissions
01162 static const char * get_log_rw(unsigned logaddr)
01163 {
01164    if (   (                   logaddr <= 0x08)
01165        || (0x0d == logaddr)
01166        || (0x10 <= logaddr && logaddr <= 0x13)
01167        || (0x19 == logaddr)
01168        || (0x20 <= logaddr && logaddr <= 0x25)
01169        || (0x30 == logaddr))
01170       return "R/O";
01171 
01172    if (   (0x09 <= logaddr && logaddr <= 0x0a)
01173        || (0x80 <= logaddr && logaddr <= 0x9f)
01174        || (0xe0 <= logaddr && logaddr <= 0xe1))
01175       return "R/W";
01176 
01177    if (0xa0 <= logaddr && logaddr <= 0xdf)
01178       return "VS"; // Vendor specific
01179 
01180    return "-"; // Unknown/Reserved
01181 }
01182 
01183 // Init a fake log directory, assume that standard logs are supported
01184 const ata_smart_log_directory * fake_logdir(ata_smart_log_directory * logdir,
01185   const ata_print_options & options)
01186 {
01187   memset(logdir, 0, sizeof(*logdir));
01188   logdir->logversion = 255;
01189   logdir->entry[0x01-1].numsectors = 1;
01190   logdir->entry[0x03-1].numsectors = (options.smart_ext_error_log + (4-1)) / 4;
01191   logdir->entry[0x04-1].numsectors = 8;
01192   logdir->entry[0x06-1].numsectors = 1;
01193   logdir->entry[0x07-1].numsectors = (options.smart_ext_selftest_log + (19-1)) / 19;
01194   logdir->entry[0x09-1].numsectors = 1;
01195   logdir->entry[0x11-1].numsectors = 1;
01196   return logdir;
01197 }
01198 
01199 // Print SMART and/or GP Log Directory
01200 static void PrintLogDirectories(const ata_smart_log_directory * gplogdir,
01201                                 const ata_smart_log_directory * smartlogdir)
01202 {
01203   if (gplogdir)
01204     pout("General Purpose Log Directory Version %u\n", gplogdir->logversion);
01205   if (smartlogdir)
01206     pout("SMART %sLog Directory Version %u%s\n",
01207          (gplogdir ? "          " : ""), smartlogdir->logversion,
01208          (smartlogdir->logversion==1 ? " [multi-sector log support]" : ""));
01209 
01210   pout("Address    Access  R/W   Size  Description\n");
01211 
01212   for (unsigned i = 0; i <= 0xff; i++) {
01213     // Get number of sectors
01214     unsigned smart_numsect = GetNumLogSectors(smartlogdir, i, false);
01215     unsigned gp_numsect    = GetNumLogSectors(gplogdir   , i, true );
01216 
01217     if (!(smart_numsect || gp_numsect))
01218       continue; // Log does not exist
01219 
01220     const char * acc; unsigned size;
01221     if (smart_numsect == gp_numsect) {
01222       acc = "GPL,SL"; size = gp_numsect;
01223     }
01224     else if (!smart_numsect) {
01225       acc = "GPL"; size = gp_numsect;
01226     }
01227     else if (!gp_numsect) {
01228       acc = "    SL"; size = smart_numsect;
01229     }
01230     else {
01231       acc = 0; size = 0;
01232     }
01233 
01234     unsigned i2 = i;
01235     if (acc && ((0x80 <= i && i < 0x9f) || (0xa0 <= i && i < 0xdf))) {
01236       // Find range of Host/Device vendor specific logs with same size
01237       unsigned imax = (i < 0x9f ? 0x9f : 0xdf);
01238       for (unsigned j = i+1; j <= imax; j++) {
01239           unsigned sn = GetNumLogSectors(smartlogdir, j, false);
01240           unsigned gn = GetNumLogSectors(gplogdir   , j, true );
01241 
01242           if (!(sn == smart_numsect && gn == gp_numsect))
01243             break;
01244           i2 = j;
01245       }
01246     }
01247 
01248     const char * name = GetLogName(i);
01249     const char * rw = get_log_rw(i);
01250 
01251     if (i2 > i) {
01252       pout("0x%02x-0x%02x  %-6s  %-3s  %5u  %s\n", i, i2, acc, rw, size, name);
01253       i = i2;
01254     }
01255     else if (acc)
01256       pout(  "0x%02x       %-6s  %-3s  %5u  %s\n", i, acc, rw, size, name);
01257     else {
01258       // GPL and SL support different sizes
01259       pout(  "0x%02x       %-6s  %-3s  %5u  %s\n", i, "GPL", rw, gp_numsect, name);
01260       pout(  "0x%02x       %-6s  %-3s  %5u  %s\n", i, "SL", rw, smart_numsect, name);
01261     }
01262   }
01263   pout("\n");
01264 }
01265 
01266 // Print hexdump of log pages.
01267 // Format is compatible with 'xxd -r'.
01268 static void PrintLogPages(const char * type, const unsigned char * data,
01269                           unsigned char logaddr, unsigned page,
01270                           unsigned num_pages, unsigned max_pages)
01271 {
01272   pout("%s Log 0x%02x [%s], Page %u-%u (of %u)\n",
01273     type, logaddr, GetLogName(logaddr), page, page+num_pages-1, max_pages);
01274   for (unsigned i = 0; i < num_pages * 512; i += 16) {
01275     const unsigned char * p = data+i;
01276     pout("%07x: %02x %02x %02x %02x %02x %02x %02x %02x "
01277                "%02x %02x %02x %02x %02x %02x %02x %02x ",
01278          (page * 512) + i,
01279          p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7],
01280          p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15]);
01281 #define P(n) (' ' <= p[n] && p[n] <= '~' ? (int)p[n] : '.')
01282     pout("|%c%c%c%c%c%c%c%c"
01283           "%c%c%c%c%c%c%c%c|\n",
01284          P( 0), P( 1), P( 2), P( 3), P( 4), P( 5), P( 6), P( 7),
01285          P( 8), P( 9), P(10), P(11), P(12), P(13), P(14), P(15));
01286 #undef P
01287     if ((i & 0x1ff) == 0x1f0)
01288       pout("\n");
01289   }
01290 }
01291 
01292 ///////////////////////////////////////////////////////////////////////
01293 // Device statistics (Log 0x04)
01294 
01295 // See Section A.5 of
01296 //   ATA/ATAPI Command Set - 3 (ACS-3)
01297 //   T13/2161-D Revision 2, February 21, 2012.
01298 
01299 struct devstat_entry_info
01300 {
01301   short size; // #bytes of value, -1 for signed char
01302   const char * name;
01303 };
01304 
01305 const devstat_entry_info devstat_info_0x00[] = {
01306   {  2, "List of supported log pages" },
01307   {  0, 0 }
01308 };
01309 
01310 const devstat_entry_info devstat_info_0x01[] = {
01311   {  2, "General Statistics" },
01312   {  4, "Lifetime Power-On Resets" },
01313   {  4, "Power-on Hours" }, // spec says no flags(?)
01314   {  6, "Logical Sectors Written" },
01315   {  6, "Number of Write Commands" },
01316   {  6, "Logical Sectors Read" },
01317   {  6, "Number of Read Commands" },
01318   {  6, "Date and Time TimeStamp" }, // ACS-3
01319   {  0, 0 }
01320 };
01321 
01322 const devstat_entry_info devstat_info_0x02[] = {
01323   {  2, "Free-Fall Statistics" },
01324   {  4, "Number of Free-Fall Events Detected" },
01325   {  4, "Overlimit Shock Events" },
01326   {  0, 0 }
01327 };
01328 
01329 const devstat_entry_info devstat_info_0x03[] = {
01330   {  2, "Rotating Media Statistics" },
01331   {  4, "Spindle Motor Power-on Hours" },
01332   {  4, "Head Flying Hours" },
01333   {  4, "Head Load Events" },
01334   {  4, "Number of Reallocated Logical Sectors" },
01335   {  4, "Read Recovery Attempts" },
01336   {  4, "Number of Mechanical Start Failures" },
01337   {  4, "Number of Realloc. Candidate Logical Sectors" }, // ACS-3
01338   {  0, 0 }
01339 };
01340 
01341 const devstat_entry_info devstat_info_0x04[] = {
01342   {  2, "General Errors Statistics" },
01343   {  4, "Number of Reported Uncorrectable Errors" },
01344 //{  4, "Number of Resets Between Command Acceptance and Command Completion" },
01345   {  4, "Resets Between Cmd Acceptance and Completion" },
01346   {  0, 0 }
01347 };
01348 
01349 const devstat_entry_info devstat_info_0x05[] = {
01350   {  2, "Temperature Statistics" },
01351   { -1, "Current Temperature" },
01352   { -1, "Average Short Term Temperature" },
01353   { -1, "Average Long Term Temperature" },
01354   { -1, "Highest Temperature" },
01355   { -1, "Lowest Temperature" },
01356   { -1, "Highest Average Short Term Temperature" },
01357   { -1, "Lowest Average Short Term Temperature" },
01358   { -1, "Highest Average Long Term Temperature" },
01359   { -1, "Lowest Average Long Term Temperature" },
01360   {  4, "Time in Over-Temperature" },
01361   { -1, "Specified Maximum Operating Temperature" },
01362   {  4, "Time in Under-Temperature" },
01363   { -1, "Specified Minimum Operating Temperature" },
01364   {  0, 0 }
01365 };
01366 
01367 const devstat_entry_info devstat_info_0x06[] = {
01368   {  2, "Transport Statistics" },
01369   {  4, "Number of Hardware Resets" },
01370   {  4, "Number of ASR Events" },
01371   {  4, "Number of Interface CRC Errors" },
01372   {  0, 0 }
01373 };
01374 
01375 const devstat_entry_info devstat_info_0x07[] = {
01376   {  2, "Solid State Device Statistics" },
01377   {  1, "Percentage Used Endurance Indicator" },
01378   {  0, 0 }
01379 };
01380 
01381 const devstat_entry_info * devstat_infos[] = {
01382   devstat_info_0x00,
01383   devstat_info_0x01,
01384   devstat_info_0x02,
01385   devstat_info_0x03,
01386   devstat_info_0x04,
01387   devstat_info_0x05,
01388   devstat_info_0x06,
01389   devstat_info_0x07
01390 };
01391 
01392 const int num_devstat_infos = sizeof(devstat_infos)/sizeof(devstat_infos[0]);
01393 
01394 static void print_device_statistics_page(const unsigned char * data, int page,
01395   bool & need_trailer)
01396 {
01397   const devstat_entry_info * info = (page < num_devstat_infos ? devstat_infos[page] : 0);
01398   const char * name = (info ? info[0].name : "Unknown Statistics");
01399 
01400   // Check page number in header
01401   static const char line[] = "  =====  =                =  == ";
01402   if (!data[2]) {
01403     pout("%3d%s%s (empty) ==\n", page, line, name);
01404     return;
01405   }
01406   if (data[2] != page) {
01407     pout("%3d%s%s (invalid page %d in header) ==\n", page, line, name, data[2]);
01408     return;
01409   }
01410 
01411   pout("%3d%s%s (rev %d) ==\n", page, line, name, data[0]);
01412 
01413   // Print entries
01414   for (int i = 1, offset = 8; offset < 512-7; i++, offset+=8) {
01415     // Check for last known entry
01416     if (info && !info[i].size)
01417       info = 0;
01418 
01419     // Skip unsupported entries
01420     unsigned char flags = data[offset+7];
01421     if (!(flags & 0x80))
01422       continue;
01423 
01424     // Get value size, default to max if unknown
01425     int size = (info ? info[i].size : 7);
01426 
01427     // Format value
01428     char valstr[32];
01429     if (flags & 0x40) { // valid flag
01430       // Get value
01431       int64_t val;
01432       if (size < 0) {
01433         val = (signed char)data[offset];
01434       }
01435       else {
01436         val = 0;
01437         for (int j = 0; j < size; j++)
01438           val |= (int64_t)data[offset+j] << (j*8);
01439       }
01440       snprintf(valstr, sizeof(valstr), "%" PRId64, val);
01441     }
01442     else {
01443       // Value not known (yet)
01444       valstr[0] = '-'; valstr[1] = 0;
01445     }
01446 
01447     pout("%3d  0x%03x  %d%c %15s%c %s\n",
01448       page, offset,
01449       abs(size),
01450       (flags & 0x1f ? '+' : ' '), // unknown flags
01451       valstr,
01452       (flags & 0x20 ? '~' : ' '), // normalized flag
01453       (info ? info[i].name : "Unknown"));
01454     if (flags & 0x20)
01455       need_trailer = true;
01456   }
01457 }
01458 
01459 static bool print_device_statistics(ata_device * device, unsigned nsectors,
01460   const std::vector<int> & single_pages, bool all_pages, bool ssd_page)
01461 {
01462   // Read list of supported pages from page 0
01463   unsigned char page_0[512] = {0, };
01464   if (!ataReadLogExt(device, 0x04, 0, 0, page_0, 1)) {
01465     pout("Read Device Statistics page 0 failed\n\n");
01466     return false;
01467   }
01468 
01469   unsigned char nentries = page_0[8];
01470   if (!(page_0[2] == 0 && nentries > 0)) {
01471     pout("Device Statistics page 0 is invalid (page=%d, nentries=%d)\n\n", page_0[2], nentries);
01472     return false;
01473   }
01474 
01475   // Prepare list of pages to print
01476   std::vector<int> pages;
01477   unsigned i;
01478   if (all_pages) {
01479     // Add all supported pages
01480     for (i = 0; i < nentries; i++) {
01481       int page = page_0[8+1+i];
01482       if (page)
01483         pages.push_back(page);
01484     }
01485     ssd_page = false;
01486   }
01487   // Add manually specified pages
01488   bool print_page_0 = false;
01489   for (i = 0; i < single_pages.size() || ssd_page; i++) {
01490     int page = (i < single_pages.size() ? single_pages[i] : 7);
01491     if (!page)
01492       print_page_0 = true;
01493     else if (page >= (int)nsectors)
01494       pout("Device Statistics Log has only %u pages\n", nsectors);
01495     else
01496       pages.push_back(page);
01497     if (page == 7)
01498       ssd_page = false;
01499   }
01500 
01501   // Print list of supported pages if requested
01502   if (print_page_0) {
01503     pout("Device Statistics (GP Log 0x04) supported pages\n");
01504     pout("Page Description\n");
01505     for (i = 0; i < nentries; i++) {
01506       int page = page_0[8+1+i];
01507       pout("%3d  %s\n", page,
01508         (page < num_devstat_infos ? devstat_infos[page][0].name : "Unknown Statistics"));
01509     }
01510     pout("\n");
01511   }
01512 
01513   // Read & print pages
01514   if (!pages.empty()) {
01515     pout("Device Statistics (GP Log 0x04)\n");
01516     pout("Page Offset Size         Value  Description\n");
01517     bool need_trailer = false;
01518 
01519     for (i = 0; i <  pages.size(); i++) {
01520       int page = pages[i];
01521       unsigned char page_n[512] = {0, };
01522       if (!ataReadLogExt(device, 0x04, 0, page, page_n, 1)) {
01523         pout("Read Device Statistics page %d failed\n\n", page);
01524         return false;
01525       }
01526       print_device_statistics_page(page_n, page, need_trailer);
01527     }
01528 
01529     if (need_trailer)
01530       pout("%30s|_ ~ normalized value\n", "");
01531     pout("\n");
01532   }
01533 
01534   return true;
01535 }
01536 
01537 
01538 ///////////////////////////////////////////////////////////////////////
01539 
01540 // Print log 0x11
01541 static void PrintSataPhyEventCounters(const unsigned char * data, bool reset)
01542 {
01543   if (checksum(data))
01544     checksumwarning("SATA Phy Event Counters");
01545   pout("SATA Phy Event Counters (GP Log 0x11)\n");
01546   if (data[0] || data[1] || data[2] || data[3])
01547     pout("[Reserved: 0x%02x 0x%02x 0x%02x 0x%02x]\n",
01548     data[0], data[1], data[2], data[3]);
01549   pout("ID      Size     Value  Description\n");
01550 
01551   for (unsigned i = 4; ; ) {
01552     // Get counter id and size (bits 14:12)
01553     unsigned id = data[i] | (data[i+1] << 8);
01554     unsigned size = ((id >> 12) & 0x7) << 1;
01555     id &= 0x8fff;
01556 
01557     // End of counter table ?
01558     if (!id)
01559       break;
01560     i += 2;
01561 
01562     if (!(2 <= size && size <= 8 && i + size < 512)) {
01563       pout("0x%04x  %u: Invalid entry\n", id, size);
01564       break;
01565     }
01566 
01567     // Get value
01568     uint64_t val = 0, max_val = 0;
01569     for (unsigned j = 0; j < size; j+=2) {
01570         val |= (uint64_t)(data[i+j] | (data[i+j+1] << 8)) << (j*8);
01571         max_val |= (uint64_t)0xffffU << (j*8);
01572     }
01573     i += size;
01574 
01575     // Get name
01576     const char * name;
01577     switch (id) {
01578       case 0x001: name = "Command failed due to ICRC error"; break; // Mandatory
01579       case 0x002: name = "R_ERR response for data FIS"; break;
01580       case 0x003: name = "R_ERR response for device-to-host data FIS"; break;
01581       case 0x004: name = "R_ERR response for host-to-device data FIS"; break;
01582       case 0x005: name = "R_ERR response for non-data FIS"; break;
01583       case 0x006: name = "R_ERR response for device-to-host non-data FIS"; break;
01584       case 0x007: name = "R_ERR response for host-to-device non-data FIS"; break;
01585       case 0x008: name = "Device-to-host non-data FIS retries"; break;
01586       case 0x009: name = "Transition from drive PhyRdy to drive PhyNRdy"; break;
01587       case 0x00A: name = "Device-to-host register FISes sent due to a COMRESET"; break; // Mandatory
01588       case 0x00B: name = "CRC errors within host-to-device FIS"; break;
01589       case 0x00D: name = "Non-CRC errors within host-to-device FIS"; break;
01590       case 0x00F: name = "R_ERR response for host-to-device data FIS, CRC"; break;
01591       case 0x010: name = "R_ERR response for host-to-device data FIS, non-CRC"; break;
01592       case 0x012: name = "R_ERR response for host-to-device non-data FIS, CRC"; break;
01593       case 0x013: name = "R_ERR response for host-to-device non-data FIS, non-CRC"; break;
01594       default:    name = (id & 0x8000 ? "Vendor specific" : "Unknown"); break;
01595     }
01596 
01597     // Counters stop at max value, add '+' in this case
01598     pout("0x%04x  %u %12" PRIu64 "%c %s\n", id, size, val,
01599       (val == max_val ? '+' : ' '), name);
01600   }
01601   if (reset)
01602     pout("All counters reset\n");
01603   pout("\n");
01604 }
01605 
01606 // Format milliseconds from error log entry as "DAYS+H:M:S.MSEC"
01607 static std::string format_milliseconds(unsigned msec)
01608 {
01609   unsigned days  = msec  / 86400000U;
01610   msec          -= days  * 86400000U;
01611   unsigned hours = msec  / 3600000U;
01612   msec          -= hours * 3600000U;
01613   unsigned min   = msec  / 60000U;
01614   msec          -= min   * 60000U;
01615   unsigned sec   = msec  / 1000U;
01616   msec          -= sec   * 1000U;
01617 
01618   std::string str;
01619   if (days)
01620     str = strprintf("%2ud+", days);
01621   str += strprintf("%02u:%02u:%02u.%03u", hours, min, sec, msec);
01622   return str;
01623 }
01624 
01625 // Get description for 'state' value from SMART Error Logs
01626 static const char * get_error_log_state_desc(unsigned state)
01627 {
01628   state &= 0x0f;
01629   switch (state){
01630     case 0x0: return "in an unknown state";
01631     case 0x1: return "sleeping";
01632     case 0x2: return "in standby mode";
01633     case 0x3: return "active or idle";
01634     case 0x4: return "doing SMART Offline or Self-test";
01635   default:
01636     return (state < 0xb ? "in a reserved state"
01637                         : "in a vendor specific state");
01638   }
01639 }
01640 
01641 // returns number of errors
01642 static int PrintSmartErrorlog(const ata_smart_errorlog *data,
01643                               firmwarebug_defs firmwarebugs)
01644 {
01645   pout("SMART Error Log Version: %d\n", (int)data->revnumber);
01646   
01647   // if no errors logged, return
01648   if (!data->error_log_pointer){
01649     pout("No Errors Logged\n\n");
01650     return 0;
01651   }
01652   print_on();
01653   // If log pointer out of range, return
01654   if (data->error_log_pointer>5){
01655     pout("Invalid Error Log index = 0x%02x (T13/1321D rev 1c "
01656          "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n",
01657          (int)data->error_log_pointer);
01658     return 0;
01659   }
01660 
01661   // Some internal consistency checking of the data structures
01662   if ((data->ata_error_count-data->error_log_pointer) % 5 && !firmwarebugs.is_set(BUG_SAMSUNG2)) {
01663     pout("Warning: ATA error count %d inconsistent with error log pointer %d\n\n",
01664          data->ata_error_count,data->error_log_pointer);
01665   }
01666   
01667   // starting printing error log info
01668   if (data->ata_error_count<=5)
01669     pout( "ATA Error Count: %d\n", (int)data->ata_error_count);
01670   else
01671     pout( "ATA Error Count: %d (device log contains only the most recent five errors)\n",
01672            (int)data->ata_error_count);
01673   print_off();
01674   pout("\tCR = Command Register [HEX]\n"
01675        "\tFR = Features Register [HEX]\n"
01676        "\tSC = Sector Count Register [HEX]\n"
01677        "\tSN = Sector Number Register [HEX]\n"
01678        "\tCL = Cylinder Low Register [HEX]\n"
01679        "\tCH = Cylinder High Register [HEX]\n"
01680        "\tDH = Device/Head Register [HEX]\n"
01681        "\tDC = Device Command Register [HEX]\n"
01682        "\tER = Error register [HEX]\n"
01683        "\tST = Status register [HEX]\n"
01684        "Powered_Up_Time is measured from power on, and printed as\n"
01685        "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n"
01686        "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n");
01687   
01688   // now step through the five error log data structures (table 39 of spec)
01689   for (int k = 4; k >= 0; k-- ) {
01690 
01691     // The error log data structure entries are a circular buffer
01692     int j, i=(data->error_log_pointer+k)%5;
01693     const ata_smart_errorlog_struct * elog = data->errorlog_struct+i;
01694     const ata_smart_errorlog_error_struct * summary = &(elog->error_struct);
01695 
01696     // Spec says: unused error log structures shall be zero filled
01697     if (nonempty(elog, sizeof(*elog))){
01698       // Table 57 of T13/1532D Volume 1 Revision 3
01699       const char *msgstate = get_error_log_state_desc(summary->state);
01700       int days = (int)summary->timestamp/24;
01701 
01702       // See table 42 of ATA5 spec
01703       print_on();
01704       pout("Error %d occurred at disk power-on lifetime: %d hours (%d days + %d hours)\n",
01705              (int)(data->ata_error_count+k-4), (int)summary->timestamp, days, (int)(summary->timestamp-24*days));
01706       print_off();
01707       pout("  When the command that caused the error occurred, the device was %s.\n\n",msgstate);
01708       pout("  After command completion occurred, registers were:\n"
01709            "  ER ST SC SN CL CH DH\n"
01710            "  -- -- -- -- -- -- --\n"
01711            "  %02x %02x %02x %02x %02x %02x %02x",
01712            (int)summary->error_register,
01713            (int)summary->status,
01714            (int)summary->sector_count,
01715            (int)summary->sector_number,
01716            (int)summary->cylinder_low,
01717            (int)summary->cylinder_high,
01718            (int)summary->drive_head);
01719       // Add a description of the contents of the status and error registers
01720       // if possible
01721       std::string st_er_desc = format_st_er_desc(elog);
01722       if (!st_er_desc.empty())
01723         pout("  %s", st_er_desc.c_str());
01724       pout("\n\n");
01725       pout("  Commands leading to the command that caused the error were:\n"
01726            "  CR FR SC SN CL CH DH DC   Powered_Up_Time  Command/Feature_Name\n"
01727            "  -- -- -- -- -- -- -- --  ----------------  --------------------\n");
01728       for ( j = 4; j >= 0; j--){
01729         const ata_smart_errorlog_command_struct * thiscommand = elog->commands+j;
01730 
01731         // Spec says: unused data command structures shall be zero filled
01732         if (nonempty(thiscommand, sizeof(*thiscommand))) {
01733           pout("  %02x %02x %02x %02x %02x %02x %02x %02x  %16s  %s\n",
01734                (int)thiscommand->commandreg,
01735                (int)thiscommand->featuresreg,
01736                (int)thiscommand->sector_count,
01737                (int)thiscommand->sector_number,
01738                (int)thiscommand->cylinder_low,
01739                (int)thiscommand->cylinder_high,
01740                (int)thiscommand->drive_head,
01741                (int)thiscommand->devicecontrolreg,
01742                format_milliseconds(thiscommand->timestamp).c_str(),
01743                look_up_ata_command(thiscommand->commandreg, thiscommand->featuresreg));
01744         }
01745       }
01746       pout("\n");
01747     }
01748   }
01749   print_on();
01750   if (printing_is_switchable)
01751     pout("\n");
01752   print_off();
01753   return data->ata_error_count;  
01754 }
01755 
01756 // Print SMART Extended Comprehensive Error Log (GP Log 0x03)
01757 static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log,
01758                                  unsigned nsectors, unsigned max_errors)
01759 {
01760   pout("SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n",
01761        log->version, nsectors);
01762 
01763   if (!log->device_error_count) {
01764     pout("No Errors Logged\n\n");
01765     return 0;
01766   }
01767   print_on();
01768 
01769   // Check index
01770   unsigned nentries = nsectors * 4;
01771   unsigned erridx = log->error_log_index;
01772   if (!(1 <= erridx && erridx <= nentries)){
01773     // Some Samsung disks (at least SP1614C/SW100-25, HD300LJ/ZT100-12) use the
01774     // former index from Summary Error Log (byte 1, now reserved) and set byte 2-3
01775     // to 0.
01776     if (!(erridx == 0 && 1 <= log->reserved1 && log->reserved1 <= nentries)) {
01777       pout("Invalid Error Log index = 0x%04x (reserved = 0x%02x)\n", erridx, log->reserved1);
01778       return 0;
01779     }
01780     pout("Invalid Error Log index = 0x%04x, trying reserved byte (0x%02x) instead\n", erridx, log->reserved1);
01781     erridx = log->reserved1;
01782   }
01783 
01784   // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a),
01785   // it is 1-based in practice.
01786   erridx--;
01787 
01788   // Calculate #errors to print
01789   unsigned errcnt = log->device_error_count;
01790 
01791   if (errcnt <= nentries)
01792     pout("Device Error Count: %u\n", log->device_error_count);
01793   else {
01794     errcnt = nentries;
01795     pout("Device Error Count: %u (device log contains only the most recent %u errors)\n",
01796          log->device_error_count, errcnt);
01797   }
01798 
01799   if (max_errors < errcnt)
01800     errcnt = max_errors;
01801 
01802   print_off();
01803   pout("\tCR     = Command Register\n"
01804        "\tFEATR  = Features Register\n"
01805        "\tCOUNT  = Count (was: Sector Count) Register\n"
01806        "\tLBA_48 = Upper bytes of LBA High/Mid/Low Registers ]  ATA-8\n"
01807        "\tLH     = LBA High (was: Cylinder High) Register    ]   LBA\n"
01808        "\tLM     = LBA Mid (was: Cylinder Low) Register      ] Register\n"
01809        "\tLL     = LBA Low (was: Sector Number) Register     ]\n"
01810        "\tDV     = Device (was: Device/Head) Register\n"
01811        "\tDC     = Device Control Register\n"
01812        "\tER     = Error register\n"
01813        "\tST     = Status register\n"
01814        "Powered_Up_Time is measured from power on, and printed as\n"
01815        "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n"
01816        "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n");
01817 
01818   // Iterate through circular buffer in reverse direction
01819   for (unsigned i = 0, errnum = log->device_error_count;
01820        i < errcnt; i++, errnum--, erridx = (erridx > 0 ? erridx - 1 : nentries - 1)) {
01821 
01822     const ata_smart_exterrlog_error_log & entry = log[erridx / 4].error_logs[erridx % 4];
01823 
01824     // Skip unused entries
01825     if (!nonempty(&entry, sizeof(entry))) {
01826       pout("Error %u [%u] log entry is empty\n", errnum, erridx);
01827       continue;
01828     }
01829 
01830     // Print error information
01831     print_on();
01832     const ata_smart_exterrlog_error & err = entry.error;
01833     pout("Error %u [%u] occurred at disk power-on lifetime: %u hours (%u days + %u hours)\n",
01834          errnum, erridx, err.timestamp, err.timestamp / 24, err.timestamp % 24);
01835     print_off();
01836 
01837     pout("  When the command that caused the error occurred, the device was %s.\n\n",
01838       get_error_log_state_desc(err.state));
01839 
01840     // Print registers
01841     pout("  After command completion occurred, registers were:\n"
01842          "  ER -- ST COUNT  LBA_48  LH LM LL DV DC\n"
01843          "  -- -- -- == -- == == == -- -- -- -- --\n"
01844          "  %02x -- %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
01845          err.error_register,
01846          err.status_register,
01847          err.count_register_hi,
01848          err.count_register,
01849          err.lba_high_register_hi,
01850          err.lba_mid_register_hi,
01851          err.lba_low_register_hi,
01852          err.lba_high_register,
01853          err.lba_mid_register,
01854          err.lba_low_register,
01855          err.device_register,
01856          err.device_control_register);
01857 
01858     // Add a description of the contents of the status and error registers
01859     // if possible
01860     std::string st_er_desc = format_st_er_desc(&entry);
01861     if (!st_er_desc.empty())
01862       pout("  %s", st_er_desc.c_str());
01863     pout("\n\n");
01864 
01865     // Print command history
01866     pout("  Commands leading to the command that caused the error were:\n"
01867          "  CR FEATR COUNT  LBA_48  LH LM LL DV DC  Powered_Up_Time  Command/Feature_Name\n"
01868          "  -- == -- == -- == == == -- -- -- -- --  ---------------  --------------------\n");
01869     for (int ci = 4; ci >= 0; ci--) {
01870       const ata_smart_exterrlog_command & cmd = entry.commands[ci];
01871 
01872       // Skip unused entries
01873       if (!nonempty(&cmd, sizeof(cmd)))
01874         continue;
01875 
01876       // Print registers, timestamp and ATA command name
01877       pout("  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %16s  %s\n",
01878            cmd.command_register,
01879            cmd.features_register_hi,
01880            cmd.features_register,
01881            cmd.count_register_hi,
01882            cmd.count_register,
01883            cmd.lba_high_register_hi,
01884            cmd.lba_mid_register_hi,
01885            cmd.lba_low_register_hi,
01886            cmd.lba_high_register,
01887            cmd.lba_mid_register,
01888            cmd.lba_low_register,
01889            cmd.device_register,
01890            cmd.device_control_register,
01891            format_milliseconds(cmd.timestamp).c_str(),
01892            look_up_ata_command(cmd.command_register, cmd.features_register));
01893     }
01894     pout("\n");
01895   }
01896 
01897   print_on();
01898   if (printing_is_switchable)
01899     pout("\n");
01900   print_off();
01901   return log->device_error_count;
01902 }
01903 
01904 // Print SMART Extended Self-test Log (GP Log 0x07)
01905 static int PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log,
01906                                     unsigned nsectors, unsigned max_entries)
01907 {
01908   pout("SMART Extended Self-test Log Version: %u (%u sectors)\n",
01909        log->version, nsectors);
01910 
01911   if (!log->log_desc_index){
01912     pout("No self-tests have been logged.  [To run self-tests, use: smartctl -t]\n\n");
01913     return 0;
01914   }
01915 
01916   // Check index
01917   unsigned nentries = nsectors * 19;
01918   unsigned logidx = log->log_desc_index;
01919   if (logidx > nentries) {
01920     pout("Invalid Self-test Log index = 0x%04x (reserved = 0x%02x)\n", logidx, log->reserved1);
01921     return 0;
01922   }
01923 
01924   // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a),
01925   // it is 1-based in practice.
01926   logidx--;
01927 
01928   bool print_header = true;
01929   int errcnt = 0, igncnt = 0;
01930   int ext_ok_testnum = -1;
01931 
01932   // Iterate through circular buffer in reverse direction
01933   for (unsigned i = 0, testnum = 1;
01934        i < nentries && testnum <= max_entries;
01935        i++, logidx = (logidx > 0 ? logidx - 1 : nentries - 1)) {
01936 
01937     const ata_smart_extselftestlog_desc & entry = log[logidx / 19].log_descs[logidx % 19];
01938 
01939     // Skip unused entries
01940     if (!nonempty(&entry, sizeof(entry)))
01941       continue;
01942 
01943     // Get LBA
01944     const unsigned char * b = entry.failing_lba;
01945     uint64_t lba48 = b[0]
01946         | (          b[1] <<  8)
01947         | (          b[2] << 16)
01948         | ((uint64_t)b[3] << 24)
01949         | ((uint64_t)b[4] << 32)
01950         | ((uint64_t)b[5] << 40);
01951 
01952     // Print entry
01953     int state = ataPrintSmartSelfTestEntry(testnum, entry.self_test_type,
01954       entry.self_test_status, entry.timestamp, lba48,
01955       false /*!print_error_only*/, print_header);
01956 
01957     if (state < 0) {
01958       // Self-test showed an error
01959       if (ext_ok_testnum < 0)
01960         errcnt++;
01961       else
01962         // Newer successful extended self-test exits
01963         igncnt++;
01964     }
01965     else if (state > 0 && ext_ok_testnum < 0) {
01966       // Latest successful extended self-test
01967       ext_ok_testnum = testnum;
01968     }
01969     testnum++;
01970   }
01971 
01972   if (igncnt)
01973     pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n",
01974       igncnt, igncnt+errcnt, ext_ok_testnum);
01975 
01976   pout("\n");
01977   return errcnt;
01978 }
01979 
01980 static void ataPrintSelectiveSelfTestLog(const ata_selective_self_test_log * log, const ata_smart_values * sv)
01981 {
01982   int i,field1,field2;
01983   const char *msg;
01984   char tmp[64];
01985   uint64_t maxl=0,maxr=0;
01986   uint64_t current=log->currentlba;
01987   uint64_t currentend=current+65535;
01988 
01989   // print data structure revision number
01990   pout("SMART Selective self-test log data structure revision number %d\n",(int)log->logversion);
01991   if (1 != log->logversion)
01992     pout("Note: revision number not 1 implies that no selective self-test has ever been run\n");
01993   
01994   switch((sv->self_test_exec_status)>>4){
01995   case  0:msg="Completed";
01996     break;
01997   case  1:msg="Aborted_by_host";
01998     break;
01999   case  2:msg="Interrupted";
02000     break;
02001   case  3:msg="Fatal_error";
02002     break;
02003   case  4:msg="Completed_unknown_failure";
02004     break;
02005   case  5:msg="Completed_electrical_failure";
02006     break;
02007   case  6:msg="Completed_servo/seek_failure";
02008     break;
02009   case  7:msg="Completed_read_failure";
02010     break;
02011   case  8:msg="Completed_handling_damage??";
02012     break;
02013   case 15:msg="Self_test_in_progress";
02014     break;
02015   default:msg="Unknown_status ";
02016     break;
02017   }
02018 
02019   // find the number of columns needed for printing. If in use, the
02020   // start/end of span being read-scanned...
02021   if (log->currentspan>5) {
02022     maxl=current;
02023     maxr=currentend;
02024   }
02025   for (i=0; i<5; i++) {
02026     uint64_t start=log->span[i].start;
02027     uint64_t end  =log->span[i].end; 
02028     // ... plus max start/end of each of the five test spans.
02029     if (start>maxl)
02030       maxl=start;
02031     if (end > maxr)
02032       maxr=end;
02033   }
02034   
02035   // we need at least 7 characters wide fields to accomodate the
02036   // labels
02037   if ((field1=snprintf(tmp,64, "%" PRIu64, maxl))<7)
02038     field1=7;
02039   if ((field2=snprintf(tmp,64, "%" PRIu64, maxr))<7)
02040     field2=7;
02041 
02042   // now print the five test spans
02043   pout(" SPAN  %*s  %*s  CURRENT_TEST_STATUS\n", field1, "MIN_LBA", field2, "MAX_LBA");
02044 
02045   for (i=0; i<5; i++) {
02046     uint64_t start=log->span[i].start;
02047     uint64_t end=log->span[i].end;
02048     
02049     if ((i+1)==(int)log->currentspan)
02050       // this span is currently under test
02051       pout("    %d  %*" PRIu64 "  %*" PRIu64 "  %s [%01d0%% left] (%" PRIu64 "-%" PRIu64 ")\n",
02052            i+1, field1, start, field2, end, msg,
02053            (int)(sv->self_test_exec_status & 0xf), current, currentend);
02054     else
02055       // this span is not currently under test
02056       pout("    %d  %*" PRIu64 "  %*" PRIu64 "  Not_testing\n",
02057            i+1, field1, start, field2, end);
02058   }  
02059   
02060   // if we are currently read-scanning, print LBAs and the status of
02061   // the read scan
02062   if (log->currentspan>5)
02063     pout("%5d  %*" PRIu64 "  %*" PRIu64 "  Read_scanning %s\n",
02064          (int)log->currentspan, field1, current, field2, currentend,
02065          OfflineDataCollectionStatus(sv->offline_data_collection_status));
02066   
02067   /* Print selective self-test flags.  Possible flag combinations are
02068      (numbering bits from 0-15):
02069      Bit-1 Bit-3   Bit-4
02070      Scan  Pending Active
02071      0     *       *       Don't scan
02072      1     0       0       Will carry out scan after selective test
02073      1     1       0       Waiting to carry out scan after powerup
02074      1     0       1       Currently scanning       
02075      1     1       1       Currently scanning
02076   */
02077   
02078   pout("Selective self-test flags (0x%x):\n", (unsigned int)log->flags);
02079   if (log->flags & SELECTIVE_FLAG_DOSCAN) {
02080     if (log->flags & SELECTIVE_FLAG_ACTIVE)
02081       pout("  Currently read-scanning the remainder of the disk.\n");
02082     else if (log->flags & SELECTIVE_FLAG_PENDING)
02083       pout("  Read-scan of remainder of disk interrupted; will resume %d min after power-up.\n",
02084            (int)log->pendingtime);
02085     else
02086       pout("  After scanning selected spans, read-scan remainder of disk.\n");
02087   }
02088   else
02089     pout("  After scanning selected spans, do NOT read-scan remainder of disk.\n");
02090   
02091   // print pending time
02092   pout("If Selective self-test is pending on power-up, resume after %d minute delay.\n",
02093        (int)log->pendingtime);
02094 
02095   return; 
02096 }
02097 
02098 // Format SCT Temperature value
02099 static const char * sct_ptemp(signed char x, char (& buf)[20])
02100 {
02101   if (x == -128 /*0x80 = unknown*/)
02102     return " ?";
02103   snprintf(buf, sizeof(buf), "%2d", x);
02104   return buf;
02105 }
02106 
02107 static const char * sct_pbar(int x, char (& buf)[64])
02108 {
02109   if (x <= 19)
02110     x = 0;
02111   else
02112     x -= 19;
02113   bool ov = false;
02114   if (x > 40) {
02115     x = 40; ov = true;
02116   }
02117   if (x > 0) {
02118     memset(buf, '*', x);
02119     if (ov)
02120       buf[x-1] = '+';
02121     buf[x] = 0;
02122   }
02123   else {
02124     buf[0] = '-'; buf[1] = 0;
02125   }
02126   return buf;
02127 }
02128 
02129 static const char * sct_device_state_msg(unsigned char state)
02130 {
02131   switch (state) {
02132     case 0: return "Active";
02133     case 1: return "Stand-by";
02134     case 2: return "Sleep";
02135     case 3: return "DST executing in background";
02136     case 4: return "SMART Off-line Data Collection executing in background";
02137     case 5: return "SCT command executing in background";
02138     default:return "Unknown";
02139   }
02140 }
02141 
02142 // Print SCT Status
02143 static int ataPrintSCTStatus(const ata_sct_status_response * sts)
02144 {
02145   pout("SCT Status Version:                  %u\n", sts->format_version);
02146   pout("SCT Version (vendor specific):       %u (0x%04x)\n", sts->sct_version, sts->sct_version);
02147   pout("SCT Support Level:                   %u\n", sts->sct_spec);
02148   pout("Device State:                        %s (%u)\n",
02149     sct_device_state_msg(sts->device_state), sts->device_state);
02150   char buf1[20], buf2[20];
02151   if (   !sts->min_temp && !sts->life_min_temp
02152       && !sts->under_limit_count && !sts->over_limit_count) {
02153     // "Reserved" fields not set, assume "old" format version 2
02154     // Table 11 of T13/1701DT-N (SMART Command Transport) Revision 5, February 2005
02155     // Table 54 of T13/1699-D (ATA8-ACS) Revision 3e, July 2006
02156     pout("Current Temperature:                 %s Celsius\n",
02157       sct_ptemp(sts->hda_temp, buf1));
02158     pout("Power Cycle Max Temperature:         %s Celsius\n",
02159       sct_ptemp(sts->max_temp, buf2));
02160     pout("Lifetime    Max Temperature:         %s Celsius\n",
02161       sct_ptemp(sts->life_max_temp, buf2));
02162   }
02163   else {
02164     // Assume "new" format version 2 or version 3
02165     // T13/e06152r0-3 (Additional SCT Temperature Statistics), August - October 2006
02166     // Table 60 of T13/1699-D (ATA8-ACS) Revision 3f, December 2006  (format version 2)
02167     // Table 80 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 (format version 3)
02168     pout("Current Temperature:                    %s Celsius\n",
02169       sct_ptemp(sts->hda_temp, buf1));
02170     pout("Power Cycle Min/Max Temperature:     %s/%s Celsius\n",
02171       sct_ptemp(sts->min_temp, buf1), sct_ptemp(sts->max_temp, buf2));
02172     pout("Lifetime    Min/Max Temperature:     %s/%s Celsius\n",
02173       sct_ptemp(sts->life_min_temp, buf1), sct_ptemp(sts->life_max_temp, buf2));
02174     signed char avg = sts->byte205; // Average Temperature from e06152r0-2, removed in e06152r3
02175     if (0 < avg && sts->life_min_temp <= avg && avg <= sts->life_max_temp)
02176       pout("Lifetime    Average Temperature:        %2d Celsius\n", avg);
02177     pout("Under/Over Temperature Limit Count:  %2u/%u\n",
02178       sts->under_limit_count, sts->over_limit_count);
02179   }
02180   return 0;
02181 }
02182 
02183 // Print SCT Temperature History Table
02184 static int ataPrintSCTTempHist(const ata_sct_temperature_history_table * tmh)
02185 {
02186   char buf1[20], buf2[20], buf3[64];
02187   pout("SCT Temperature History Version:     %u%s\n", tmh->format_version,
02188        (tmh->format_version != 2 ? " (Unknown, should be 2)" : ""));
02189   pout("Temperature Sampling Period:         %u minute%s\n",
02190     tmh->sampling_period, (tmh->sampling_period==1?"":"s"));
02191   pout("Temperature Logging Interval:        %u minute%s\n",
02192     tmh->interval,        (tmh->interval==1?"":"s"));
02193   pout("Min/Max recommended Temperature:     %s/%s Celsius\n",
02194     sct_ptemp(tmh->min_op_limit, buf1), sct_ptemp(tmh->max_op_limit, buf2));
02195   pout("Min/Max Temperature Limit:           %s/%s Celsius\n",
02196     sct_ptemp(tmh->under_limit, buf1), sct_ptemp(tmh->over_limit, buf2));
02197   pout("Temperature History Size (Index):    %u (%u)\n", tmh->cb_size, tmh->cb_index);
02198 
02199   if (!(0 < tmh->cb_size && tmh->cb_size <= sizeof(tmh->cb) && tmh->cb_index < tmh->cb_size)) {
02200     if (!tmh->cb_size)
02201       pout("Temperature History is empty\n");
02202     else
02203       pout("Invalid Temperature History Size or Index\n");
02204     return 0;
02205   }
02206 
02207   // Print table
02208   pout("\nIndex    Estimated Time   Temperature Celsius\n");
02209   unsigned n = 0, i = (tmh->cb_index+1) % tmh->cb_size;
02210   unsigned interval = (tmh->interval > 0 ? tmh->interval : 1);
02211   time_t t = time(0) - (tmh->cb_size-1) * interval * 60;
02212   t -= t % (interval * 60);
02213   while (n < tmh->cb_size) {
02214     // Find range of identical temperatures
02215     unsigned n1 = n, n2 = n+1, i2 = (i+1) % tmh->cb_size;
02216     while (n2 < tmh->cb_size && tmh->cb[i2] == tmh->cb[i]) {
02217       n2++; i2 = (i2+1) % tmh->cb_size;
02218     }
02219     // Print range
02220     while (n < n2) {
02221       if (n == n1 || n == n2-1 || n2 <= n1+3) {
02222         char date[30];
02223         // TODO: Don't print times < boot time
02224         strftime(date, sizeof(date), "%Y-%m-%d %H:%M", localtime(&t));
02225         pout(" %3u    %s    %s  %s\n", i, date,
02226           sct_ptemp(tmh->cb[i], buf1), sct_pbar(tmh->cb[i], buf3));
02227       }
02228       else if (n == n1+1) {
02229         pout(" ...    ..(%3u skipped).    ..  %s\n",
02230           n2-n1-2, sct_pbar(tmh->cb[i], buf3));
02231       }
02232       t += interval * 60; i = (i+1) % tmh->cb_size; n++;
02233     }
02234   }
02235   //assert(n == tmh->cb_size && i == (tmh->cb_index+1) % tmh->cb_size);
02236 
02237   return 0;
02238 }
02239 
02240 // Print SCT Error Recovery Control timers
02241 static void ataPrintSCTErrorRecoveryControl(bool set, unsigned short read_timer, unsigned short write_timer)
02242 {
02243   pout("SCT Error Recovery Control%s:\n", (set ? " set to" : ""));
02244   if (!read_timer)
02245     pout("           Read: Disabled\n");
02246   else
02247     pout("           Read: %6d (%0.1f seconds)\n", read_timer, read_timer/10.0);
02248   if (!write_timer)
02249     pout("          Write: Disabled\n");
02250   else
02251     pout("          Write: %6d (%0.1f seconds)\n", write_timer, write_timer/10.0);
02252 }
02253 
02254 static void print_aam_level(const char * msg, int level, int recommended = -1)
02255 {
02256   // Table 56 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008
02257   // Obsolete since T13/2015-D (ACS-2) Revision 4a, December 9, 2010
02258   const char * s;
02259   if (level == 0)
02260     s = "vendor specific";
02261   else if (level < 128)
02262     s = "unknown/retired";
02263   else if (level == 128)
02264     s = "quiet";
02265   else if (level < 254)
02266     s = "intermediate";
02267   else if (level == 254)
02268     s = "maximum performance";
02269   else
02270     s = "reserved";
02271 
02272   if (recommended >= 0)
02273     pout("%s%d (%s), recommended: %d\n", msg, level, s, recommended);
02274   else
02275     pout("%s%d (%s)\n", msg, level, s);
02276 }
02277 
02278 static void print_apm_level(const char * msg, int level)
02279 {
02280   // Table 120 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
02281   const char * s;
02282   if (!(1 <= level && level <= 254))
02283     s = "reserved";
02284   else if (level == 1)
02285     s = "minimum power consumption with standby";
02286   else if (level < 128)
02287     s = "intermediate level with standby";
02288   else if (level == 128)
02289     s = "minimum power consumption without standby";
02290   else if (level < 254)
02291     s = "intermediate level without standby";
02292   else
02293     s = "maximum performance";
02294 
02295   pout("%s%d (%s)\n", msg, level, s);
02296 }
02297 
02298 static void print_ata_security_status(const char * msg, unsigned short state)
02299 {
02300     const char * s1, * s2 = "", * s3 = "", * s4 = "";
02301 
02302     // Table 6 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
02303     if (!(state & 0x0001))
02304       s1 = "Unavailable";
02305     else if (!(state & 0x0002)) {
02306       s1 = "Disabled, ";
02307       if (!(state & 0x0008))
02308         s2 = "NOT FROZEN [SEC1]";
02309       else
02310         s2 = "frozen [SEC2]";
02311     }
02312     else {
02313       s1 = "ENABLED, PW level ";
02314       if (!(state & 0x0020))
02315         s2 = "HIGH";
02316       else
02317         s2 = "MAX";
02318 
02319       if (!(state & 0x0004)) {
02320          s3 = ", not locked, ";
02321         if (!(state & 0x0008))
02322           s4 = "not frozen [SEC5]";
02323         else
02324           s4 = "frozen [SEC6]";
02325       }
02326       else {
02327         s3 = ", **LOCKED** [SEC4]";
02328         if (state & 0x0010)
02329           s4 = ", PW ATTEMPTS EXCEEDED";
02330       }
02331     }
02332 
02333     pout("%s%s%s%s%s\n", msg, s1, s2, s3, s4);
02334 }
02335 
02336 static void print_standby_timer(const char * msg, int timer, const ata_identify_device & drive)
02337 {
02338   const char * s1 = 0;
02339   int hours = 0, minutes = 0 , seconds = 0;
02340 
02341   // Table 63 of T13/2015-D (ACS-2) Revision 7, June 22, 2011
02342   if (timer == 0)
02343     s1 = "disabled";
02344   else if (timer <= 240)
02345     seconds = timer * 5, minutes = seconds / 60, seconds %= 60;
02346   else if (timer <= 251)
02347     minutes = (timer - 240) * 30, hours = minutes / 60, minutes %= 60;
02348   else if (timer == 252)
02349     minutes = 21;
02350   else if (timer == 253)
02351     s1 = "between 8 hours and 12 hours";
02352   else if (timer == 255)
02353     minutes = 21, seconds = 15;
02354   else
02355     s1 = "reserved";
02356 
02357   const char * s2 = "", * s3 = "";
02358   if (!(drive.words047_079[49-47] & 0x2000))
02359     s2 = " or vendor-specific";
02360   if (timer > 0 && (drive.words047_079[50-47] & 0xc001) == 0x4001)
02361     s3 = ", a vendor-specific minimum applies";
02362 
02363   if (s1)
02364     pout("%s%d (%s%s%s)\n", msg, timer, s1, s2, s3);
02365   else
02366     pout("%s%d (%02d:%02d:%02d%s%s)\n", msg, timer, hours, minutes, seconds, s2, s3);
02367 }
02368 
02369 
02370 int ataPrintMain (ata_device * device, const ata_print_options & options)
02371 {
02372   // If requested, check power mode first
02373   const char * powername = 0;
02374   bool powerchg = false;
02375   if (options.powermode) {
02376     unsigned char powerlimit = 0xff;
02377     int powermode = ataCheckPowerMode(device);
02378     switch (powermode) {
02379       case -1:
02380         if (device->is_syscall_unsup()) {
02381           pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break;
02382         }
02383         powername = "SLEEP";   powerlimit = 2;
02384         break;
02385       case 0:
02386         powername = "STANDBY"; powerlimit = 3; break;
02387       case 0x80:
02388         powername = "IDLE";    powerlimit = 4; break;
02389       case 0xff:
02390         powername = "ACTIVE or IDLE"; break;
02391       default:
02392         pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode);
02393         break;
02394     }
02395     if (powername) {
02396       if (options.powermode >= powerlimit) {
02397         pout("Device is in %s mode, exit(%d)\n", powername, FAILPOWER);
02398         return FAILPOWER;
02399       }
02400       powerchg = (powermode != 0xff); // SMART tests will spin up drives
02401     }
02402   }
02403 
02404   // SMART values needed ?
02405   bool need_smart_val = (
02406           options.smart_check_status
02407        || options.smart_general_values
02408        || options.smart_vendor_attrib
02409        || options.smart_error_log
02410        || options.smart_selftest_log
02411        || options.smart_selective_selftest_log
02412        || options.smart_ext_error_log
02413        || options.smart_ext_selftest_log
02414        || options.smart_auto_offl_enable
02415        || options.smart_auto_offl_disable
02416        || options.smart_selftest_type != -1
02417   );
02418 
02419   // SMART must be enabled ?
02420   bool need_smart_enabled = (
02421           need_smart_val
02422        || options.smart_auto_save_enable
02423        || options.smart_auto_save_disable
02424   );
02425 
02426   // SMART feature set needed ?
02427   bool need_smart_support = (
02428           need_smart_enabled
02429        || options.smart_enable
02430        || options.smart_disable
02431   );
02432 
02433   // SMART and GP log directories needed ?
02434   bool need_smart_logdir = options.smart_logdir;
02435 
02436   bool need_gp_logdir  = (
02437           options.gp_logdir
02438        || options.smart_ext_error_log
02439        || options.smart_ext_selftest_log
02440        || options.devstat_all_pages
02441        || options.devstat_ssd_page
02442        || !options.devstat_pages.empty()
02443   );
02444 
02445   unsigned i;
02446   for (i = 0; i < options.log_requests.size(); i++) {
02447     if (options.log_requests[i].gpl)
02448       need_gp_logdir = true;
02449     else
02450       need_smart_logdir = true;
02451   }
02452 
02453   // SCT commands needed ?
02454   bool need_sct_support = (
02455           options.sct_temp_sts
02456        || options.sct_temp_hist
02457        || options.sct_temp_int
02458        || options.sct_erc_get
02459        || options.sct_erc_set
02460        || options.sct_wcache_reorder_get
02461        || options.sct_wcache_reorder_set
02462   );
02463 
02464   // Exit if no further options specified
02465   if (!(   options.drive_info || options.show_presets
02466         || need_smart_support || need_smart_logdir
02467         || need_gp_logdir     || need_sct_support
02468         || options.sataphy
02469         || options.identify_word_level >= 0
02470         || options.get_set_used                      )) {
02471     if (powername)
02472       pout("Device is in %s mode\n", powername);
02473     else
02474       pout("ATA device successfully opened\n\n"
02475            "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n");
02476     return 0;
02477   }
02478 
02479   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
02480   int returnval = 0;
02481   ata_identify_device drive; memset(&drive, 0, sizeof(drive));
02482   unsigned char raw_drive[sizeof(drive)]; memset(&raw_drive, 0, sizeof(raw_drive));
02483 
02484   device->clear_err();
02485   int retid = ata_read_identity(device, &drive, options.fix_swapped_id, raw_drive);
02486   if (retid < 0) {
02487     pout("Read Device Identity failed: %s\n\n",
02488          (device->get_errno() ? device->get_errmsg() : "Unknown error"));
02489     failuretest(MANDATORY_CMD, returnval|=FAILID);
02490   }
02491   else if (!nonempty(&drive, sizeof(drive))) {
02492     pout("Read Device Identity failed: empty IDENTIFY data\n\n");
02493     failuretest(MANDATORY_CMD, returnval|=FAILID);
02494   }
02495 
02496   // If requested, show which presets would be used for this drive and exit.
02497   if (options.show_presets) {
02498     show_presets(&drive);
02499     return 0;
02500   }
02501 
02502   // Use preset vendor attribute options unless user has requested otherwise.
02503   ata_vendor_attr_defs attribute_defs = options.attribute_defs;
02504   firmwarebug_defs firmwarebugs = options.firmwarebugs;
02505   const drive_settings * dbentry = 0;
02506   if (!options.ignore_presets)
02507     dbentry = lookup_drive_apply_presets(&drive, attribute_defs,
02508       firmwarebugs);
02509 
02510   // Get capacity, sector sizes and rotation rate
02511   ata_size_info sizes;
02512   ata_get_size_info(&drive, sizes);
02513   int rpm = ata_get_rotation_rate(&drive);
02514 
02515   // Print ATA IDENTIFY info if requested
02516   if (options.identify_word_level >= 0) {
02517     pout("=== ATA IDENTIFY DATA ===\n");
02518     // Pass raw data without endianness adjustments
02519     ata_print_identify_data(raw_drive, (options.identify_word_level > 0), options.identify_bit_level);
02520   }
02521 
02522   // Print most drive identity information if requested
02523   if (options.drive_info) {
02524     pout("=== START OF INFORMATION SECTION ===\n");
02525     print_drive_info(&drive, sizes, rpm, dbentry);
02526   }
02527 
02528   // Check and print SMART support and state
02529   int smart_supported = -1, smart_enabled = -1;
02530   if (need_smart_support || options.drive_info) {
02531 
02532     // Packet device ?
02533     if (retid > 0) {
02534       pout("SMART support is: Unavailable - Packet Interface Devices [this device: %s] don't support ATA SMART\n",
02535            packetdevicetype(retid-1));
02536     }
02537     else {
02538       // Disk device: SMART supported and enabled ?
02539       smart_supported = ataSmartSupport(&drive);
02540       smart_enabled = ataIsSmartEnabled(&drive);
02541 
02542       if (smart_supported < 0)
02543         pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 82-83 don't show if SMART supported.\n");
02544       if (smart_supported && smart_enabled < 0) {
02545         pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 85-87 don't show if SMART is enabled.\n");
02546         if (need_smart_support) {
02547           failuretest(MANDATORY_CMD, returnval|=FAILSMART);
02548           // check SMART support by trying a command
02549           pout("                  Checking to be sure by trying SMART RETURN STATUS command.\n");
02550           if (ataDoesSmartWork(device))
02551             smart_supported = smart_enabled = 1;
02552         }
02553       }
02554       else if (smart_supported < 0 && (smart_enabled > 0 || dbentry))
02555         // Assume supported if enabled or in drive database
02556         smart_supported = 1;
02557 
02558       if (smart_supported < 0)
02559         pout("SMART support is: Unknown - Try option -s with argument 'on' to enable it.");
02560       else if (!smart_supported)
02561         pout("SMART support is: Unavailable - device lacks SMART capability.\n");
02562       else {
02563         if (options.drive_info)
02564           pout("SMART support is: Available - device has SMART capability.\n");
02565         if (smart_enabled >= 0) {
02566           if (device->ata_identify_is_cached()) {
02567             if (options.drive_info)
02568               pout("                  %sabled status cached by OS, trying SMART RETURN STATUS cmd.\n",
02569                       (smart_enabled?"En":"Dis"));
02570             smart_enabled = ataDoesSmartWork(device);
02571           }
02572           if (options.drive_info)
02573             pout("SMART support is: %s\n",
02574                   (smart_enabled ? "Enabled" : "Disabled"));
02575         }
02576       }
02577     }
02578   }
02579 
02580   // Print AAM status
02581   if (options.get_aam) {
02582     if ((drive.command_set_2 & 0xc200) != 0x4200) // word083
02583       pout("AAM feature is:   Unavailable\n");
02584     else if (!(drive.word086 & 0x0200))
02585       pout("AAM feature is:   Disabled\n");
02586     else
02587       print_aam_level("AAM level is:     ", drive.words088_255[94-88] & 0xff,
02588         drive.words088_255[94-88] >> 8);
02589   }
02590 
02591   // Print APM status
02592   if (options.get_apm) {
02593     if ((drive.command_set_2 & 0xc008) != 0x4008) // word083
02594       pout("APM feature is:   Unavailable\n");
02595     else if (!(drive.word086 & 0x0008))
02596       pout("APM feature is:   Disabled\n");
02597     else
02598       print_apm_level("APM level is:     ", drive.words088_255[91-88] & 0xff);
02599   }
02600 
02601   // Print read look-ahead status
02602   if (options.get_lookahead) {
02603     pout("Rd look-ahead is: %s\n",
02604       (   (drive.command_set_2 & 0xc000) != 0x4000 // word083
02605        || !(drive.command_set_1 & 0x0040)) ? "Unavailable" : // word082
02606        !(drive.cfs_enable_1 & 0x0040) ? "Disabled" : "Enabled"); // word085
02607   }
02608 
02609   // Print write cache status
02610   if (options.get_wcache) {
02611     pout("Write cache is:   %s\n",
02612       (   (drive.command_set_2 & 0xc000) != 0x4000 // word083
02613        || !(drive.command_set_1 & 0x0020)) ? "Unavailable" : // word082
02614        !(drive.cfs_enable_1 & 0x0020) ? "Disabled" : "Enabled"); // word085
02615   }
02616 
02617   // Print ATA security status
02618   if (options.get_security)
02619     print_ata_security_status("ATA Security is:  ", drive.words088_255[128-88]);
02620 
02621   // Print write cache reordering status
02622   if (options.sct_wcache_reorder_get) {
02623     if (isSCTFeatureControlCapable(&drive)) {
02624       int wcache_reorder = ataGetSetSCTWriteCacheReordering(device,
02625         false /*enable*/, false /*persistent*/, false /*set*/);
02626 
02627       if (-1 <= wcache_reorder && wcache_reorder <= 2)
02628         pout("Wt Cache Reorder: %s\n",
02629           (wcache_reorder == -1 ? "Unknown (SCT Feature Control command failed)" :
02630            wcache_reorder == 0  ? "Unknown" : // not defined in standard but returned on some drives if not set
02631            wcache_reorder == 1  ? "Enabled" : "Disabled"));
02632       else
02633         pout("Wt Cache Reorder: Unknown (0x%02x)\n", wcache_reorder);
02634     }
02635     else
02636       pout("Wt Cache Reorder: Unavailable\n");
02637   }
02638 
02639   // Print remaining drive info
02640   if (options.drive_info) {
02641     // Print the (now possibly changed) power mode if available
02642     if (powername)
02643       pout("Power mode %s   %s\n", (powerchg?"was:":"is: "), powername);
02644     pout("\n");
02645   }
02646 
02647   // Exit if SMART is not supported but must be available to proceed
02648   if (smart_supported <= 0 && need_smart_support)
02649     failuretest(MANDATORY_CMD, returnval|=FAILSMART);
02650 
02651   // START OF THE ENABLE/DISABLE SECTION OF THE CODE
02652   if (   options.smart_disable           || options.smart_enable
02653       || options.smart_auto_save_disable || options.smart_auto_save_enable
02654       || options.smart_auto_offl_disable || options.smart_auto_offl_enable
02655       || options.set_aam || options.set_apm || options.set_lookahead
02656       || options.set_wcache || options.set_security_freeze || options.set_standby
02657       || options.sct_wcache_reorder_set)
02658     pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n");
02659   
02660   // Enable/Disable AAM
02661   if (options.set_aam) {
02662     if (options.set_aam > 0) {
02663       if (!ata_set_features(device, ATA_ENABLE_AAM, options.set_aam-1)) {
02664         pout("AAM enable failed: %s\n", device->get_errmsg());
02665         returnval |= FAILSMART;
02666       }
02667       else
02668         print_aam_level("AAM set to level ", options.set_aam-1);
02669     }
02670     else {
02671       if (!ata_set_features(device, ATA_DISABLE_AAM)) {
02672         pout("AAM disable failed: %s\n", device->get_errmsg());
02673         returnval |= FAILSMART;
02674       }
02675       else
02676         pout("AAM disabled\n");
02677     }
02678   }
02679 
02680   // Enable/Disable APM
02681   if (options.set_apm) {
02682     if (options.set_apm > 0) {
02683       if (!ata_set_features(device, ATA_ENABLE_APM, options.set_apm-1)) {
02684         pout("APM enable failed: %s\n", device->get_errmsg());
02685         returnval |= FAILSMART;
02686       }
02687       else
02688         print_apm_level("APM set to level ", options.set_apm-1);
02689     }
02690     else {
02691       if (!ata_set_features(device, ATA_DISABLE_APM)) {
02692         pout("APM disable failed: %s\n", device->get_errmsg());
02693         returnval |= FAILSMART;
02694       }
02695       else
02696         pout("APM disabled\n");
02697     }
02698   }
02699 
02700   // Enable/Disable read look-ahead
02701   if (options.set_lookahead) {
02702     bool enable = (options.set_lookahead > 0);
02703     if (!ata_set_features(device, (enable ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD))) {
02704         pout("Read look-ahead %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
02705         returnval |= FAILSMART;
02706     }
02707     else
02708       pout("Read look-ahead %sabled\n", (enable ? "en" : "dis"));
02709   }
02710 
02711   // Enable/Disable write cache
02712   if (options.set_wcache) {
02713     bool enable = (options.set_wcache > 0);
02714     if (!ata_set_features(device, (enable ? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE))) {
02715         pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
02716         returnval |= FAILSMART;
02717     }
02718     else
02719       pout("Write cache %sabled\n", (enable ? "en" : "dis"));
02720   }
02721 
02722   // Enable/Disable write cache reordering
02723   if (options.sct_wcache_reorder_set) {
02724     bool enable = (options.sct_wcache_reorder_set > 0);
02725     if (!isSCTFeatureControlCapable(&drive))
02726       pout("Write cache reordering %sable failed: SCT Feature Control command not supported\n",
02727         (enable ? "en" : "dis"));
02728     else if (ataGetSetSCTWriteCacheReordering(device,
02729                enable, false /*persistent*/, true /*set*/) < 0) {
02730       pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg());
02731       returnval |= FAILSMART;
02732     }
02733     else
02734       pout("Write cache reordering %sabled\n", (enable ? "en" : "dis"));
02735   }
02736 
02737   // Freeze ATA security
02738   if (options.set_security_freeze) {
02739     if (!ata_nodata_command(device, ATA_SECURITY_FREEZE_LOCK)) {
02740         pout("ATA SECURITY FREEZE LOCK failed: %s\n", device->get_errmsg());
02741         returnval |= FAILSMART;
02742     }
02743     else
02744       pout("ATA Security set to frozen mode\n");
02745   }
02746 
02747   // Set standby timer
02748   if (options.set_standby) {
02749     if (!ata_nodata_command(device, ATA_IDLE, options.set_standby-1)) {
02750         pout("ATA IDLE command failed: %s\n", device->get_errmsg());
02751         returnval |= FAILSMART;
02752     }
02753     else
02754       print_standby_timer("Standby timer set to ", options.set_standby-1, drive);
02755   }
02756 
02757   // Enable/Disable SMART commands
02758   if (options.smart_enable) {
02759     if (ataEnableSmart(device)) {
02760       pout("SMART Enable failed: %s\n\n", device->get_errmsg());
02761       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
02762     }
02763     else {
02764       pout("SMART Enabled.\n");
02765       smart_enabled = 1;
02766     }
02767   }
02768 
02769   // Turn off SMART on device
02770   if (options.smart_disable) {
02771     if (ataDisableSmart(device)) {
02772       pout("SMART Disable failed: %s\n\n", device->get_errmsg());
02773       failuretest(MANDATORY_CMD,returnval|=FAILSMART);
02774     }
02775   }
02776 
02777   // Exit if SMART is disabled but must be enabled to proceed
02778   if (options.smart_disable || (smart_enabled <= 0 && need_smart_enabled && !is_permissive())) {
02779     pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n");
02780     if (!options.smart_disable)
02781       pout("(override with '-T permissive' option)\n");
02782     return returnval;
02783   }
02784 
02785   // Enable/Disable Auto-save attributes
02786   if (options.smart_auto_save_enable) {
02787     if (ataEnableAutoSave(device)){
02788       pout("SMART Enable Attribute Autosave failed: %s\n\n", device->get_errmsg());
02789       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
02790     }
02791     else
02792       pout("SMART Attribute Autosave Enabled.\n");
02793   }
02794 
02795   if (options.smart_auto_save_disable) {
02796     if (ataDisableAutoSave(device)){
02797       pout("SMART Disable Attribute Autosave failed: %s\n\n", device->get_errmsg());
02798       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
02799     }
02800     else
02801       pout("SMART Attribute Autosave Disabled.\n");
02802   }
02803 
02804   // Read SMART values and thresholds if necessary
02805   ata_smart_values smartval; memset(&smartval, 0, sizeof(smartval));
02806   ata_smart_thresholds_pvt smartthres; memset(&smartthres, 0, sizeof(smartthres));
02807   bool smart_val_ok = false, smart_thres_ok = false;
02808 
02809   if (need_smart_val) {
02810     if (ataReadSmartValues(device, &smartval)) {
02811       pout("Read SMART Data failed: %s\n\n", device->get_errmsg());
02812       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02813     }
02814     else {
02815       smart_val_ok = true;
02816 
02817       if (options.smart_check_status || options.smart_vendor_attrib) {
02818         if (ataReadSmartThresholds(device, &smartthres)){
02819           pout("Read SMART Thresholds failed: %s\n\n", device->get_errmsg());
02820           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02821         }
02822         else
02823           smart_thres_ok = true;
02824       }
02825     }
02826   }
02827 
02828   // Enable/Disable Off-line testing
02829   bool needupdate = false;
02830   if (options.smart_auto_offl_enable) {
02831     if (!isSupportAutomaticTimer(&smartval)){
02832       pout("SMART Automatic Timers not supported\n\n");
02833       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02834     }
02835     needupdate = smart_val_ok;
02836     if (ataEnableAutoOffline(device)){
02837       pout("SMART Enable Automatic Offline failed: %s\n\n", device->get_errmsg());
02838       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02839     }
02840     else
02841       pout("SMART Automatic Offline Testing Enabled every four hours.\n");
02842   }
02843 
02844   if (options.smart_auto_offl_disable) {
02845     if (!isSupportAutomaticTimer(&smartval)){
02846       pout("SMART Automatic Timers not supported\n\n");
02847       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02848     }
02849     needupdate = smart_val_ok;
02850     if (ataDisableAutoOffline(device)){
02851       pout("SMART Disable Automatic Offline failed: %s\n\n", device->get_errmsg());
02852       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02853     }
02854     else
02855       pout("SMART Automatic Offline Testing Disabled.\n");
02856   }
02857 
02858   if (needupdate && ataReadSmartValues(device, &smartval)){
02859     pout("Read SMART Data failed: %s\n\n", device->get_errmsg());
02860     failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02861     smart_val_ok = false;
02862   }
02863 
02864   // all this for a newline!
02865   if (   options.smart_disable           || options.smart_enable
02866       || options.smart_auto_save_disable || options.smart_auto_save_enable
02867       || options.smart_auto_offl_disable || options.smart_auto_offl_enable
02868       || options.set_aam || options.set_apm || options.set_lookahead
02869       || options.set_wcache || options.set_security_freeze || options.set_standby
02870       || options.sct_wcache_reorder_set)
02871     pout("\n");
02872 
02873   // START OF READ-ONLY OPTIONS APART FROM -V and -i
02874   if (   options.smart_check_status  || options.smart_general_values
02875       || options.smart_vendor_attrib || options.smart_error_log
02876       || options.smart_selftest_log  || options.smart_selective_selftest_log
02877       || options.smart_ext_error_log || options.smart_ext_selftest_log
02878       || options.sct_temp_sts        || options.sct_temp_hist               )
02879     pout("=== START OF READ SMART DATA SECTION ===\n");
02880   
02881   // Check SMART status
02882   if (options.smart_check_status) {
02883 
02884     switch (ataSmartStatus2(device)) {
02885 
02886     case 0:
02887       // The case where the disk health is OK
02888       pout("SMART overall-health self-assessment test result: PASSED\n");
02889       if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) {
02890         if (options.smart_vendor_attrib)
02891           pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
02892         else {
02893           print_on();
02894           pout("Please note the following marginal Attributes:\n");
02895           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 2, options.output_format);
02896         } 
02897         returnval|=FAILAGE;
02898       }
02899       else
02900         pout("\n");
02901       break;
02902       
02903     case 1:
02904       // The case where the disk health is NOT OK
02905       print_on();
02906       pout("SMART overall-health self-assessment test result: FAILED!\n"
02907            "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
02908       print_off();
02909       if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
02910         returnval|=FAILATTR;
02911         if (options.smart_vendor_attrib)
02912           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
02913         else {
02914           print_on();
02915           pout("Failed Attributes:\n");
02916           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 1, options.output_format);
02917         }
02918       }
02919       else
02920         pout("No failed Attributes found.\n\n");   
02921       returnval|=FAILSTATUS;
02922       print_off();
02923       break;
02924 
02925     case -1:
02926     default:
02927       // Something went wrong with the SMART STATUS command.
02928       // The ATA SMART RETURN STATUS command provides the result in the ATA output
02929       // registers. Buggy ATA/SATA drivers and SAT Layers often do not properly
02930       // return the registers values.
02931       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
02932       if (!(smart_val_ok && smart_thres_ok)) {
02933         print_on();
02934         pout("SMART overall-health self-assessment test result: UNKNOWN!\n"
02935              "SMART Status, Attributes and Thresholds cannot be read.\n\n");
02936       }
02937       else if (find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) {
02938         print_on();
02939         pout("SMART overall-health self-assessment test result: FAILED!\n"
02940              "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
02941         print_off();
02942         returnval|=FAILATTR;
02943         returnval|=FAILSTATUS;
02944         if (options.smart_vendor_attrib)
02945           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
02946         else {
02947           print_on();
02948           pout("Failed Attributes:\n");
02949           PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 1, options.output_format);
02950         }
02951       }
02952       else {
02953         pout("SMART overall-health self-assessment test result: PASSED\n");
02954         pout("Warning: This result is based on an Attribute check.\n");
02955         if (find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) {
02956           if (options.smart_vendor_attrib)
02957             pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
02958           else {
02959             print_on();
02960             pout("Please note the following marginal Attributes:\n");
02961             PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 2, options.output_format);
02962           } 
02963           returnval|=FAILAGE;
02964         }
02965         else
02966           pout("\n");
02967       } 
02968       print_off();
02969       break;
02970     } // end of switch statement
02971     
02972     print_off();
02973   } // end of checking SMART Status
02974   
02975   // Print general SMART values
02976   if (smart_val_ok && options.smart_general_values)
02977     PrintGeneralSmartValues(&smartval, &drive, firmwarebugs);
02978 
02979   // Print vendor-specific attributes
02980   if (smart_val_ok && options.smart_vendor_attrib) {
02981     print_on();
02982     PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm,
02983                               (printing_is_switchable ? 2 : 0), options.output_format);
02984     print_off();
02985   }
02986 
02987   // If GP Log is supported use smart log directory for
02988   // error and selftest log support check.
02989   if (   isGeneralPurposeLoggingCapable(&drive)
02990       && (   options.smart_error_log || options.smart_selftest_log
02991           || options.retry_error_log || options.retry_selftest_log))
02992     need_smart_logdir = true;
02993 
02994   ata_smart_log_directory smartlogdir_buf, gplogdir_buf;
02995   const ata_smart_log_directory * smartlogdir = 0, * gplogdir = 0;
02996 
02997   // Read SMART Log directory
02998   if (need_smart_logdir) {
02999     if (firmwarebugs.is_set(BUG_NOLOGDIR))
03000       smartlogdir = fake_logdir(&smartlogdir_buf, options);
03001     else if (ataReadLogDirectory(device, &smartlogdir_buf, false)) {
03002       pout("Read SMART Log Directory failed: %s\n\n", device->get_errmsg());
03003       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03004     }
03005     else
03006       smartlogdir = &smartlogdir_buf;
03007   }
03008 
03009   // Read GP Log directory
03010   if (need_gp_logdir) {
03011     if (firmwarebugs.is_set(BUG_NOLOGDIR))
03012       gplogdir = fake_logdir(&gplogdir_buf, options);
03013     else if (ataReadLogDirectory(device, &gplogdir_buf, true)) {
03014       pout("Read GP Log Directory failed\n\n");
03015       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03016     }
03017     else
03018       gplogdir = &gplogdir_buf;
03019   }
03020 
03021   // Print log directories
03022   if ((options.gp_logdir && gplogdir) || (options.smart_logdir && smartlogdir)) {
03023     if (firmwarebugs.is_set(BUG_NOLOGDIR))
03024       pout("Log Directories not read due to '-F nologdir' option\n\n");
03025     else
03026       PrintLogDirectories(gplogdir, smartlogdir);
03027   }
03028 
03029   // Print log pages
03030   for (i = 0; i < options.log_requests.size(); i++) {
03031     const ata_log_request & req = options.log_requests[i];
03032 
03033     const char * type;
03034     unsigned max_nsectors;
03035     if (req.gpl) {
03036       type = "General Purpose";
03037       max_nsectors = GetNumLogSectors(gplogdir, req.logaddr, true);
03038     }
03039     else {
03040       type = "SMART";
03041       max_nsectors = GetNumLogSectors(smartlogdir, req.logaddr, false);
03042     }
03043 
03044     if (!max_nsectors) {
03045       if (!is_permissive()) {
03046         pout("%s Log 0x%02x does not exist (override with '-T permissive' option)\n", type, req.logaddr);
03047         continue;
03048       }
03049       max_nsectors = req.page+1;
03050     }
03051     if (max_nsectors <= req.page) {
03052       pout("%s Log 0x%02x has only %u sectors, output skipped\n", type, req.logaddr, max_nsectors);
03053       continue;
03054     }
03055 
03056     unsigned ns = req.nsectors;
03057     if (ns > max_nsectors - req.page) {
03058       if (req.nsectors != ~0U) // "FIRST-max"
03059         pout("%s Log 0x%02x has only %u sectors, output truncated\n", type, req.logaddr, max_nsectors);
03060       ns = max_nsectors - req.page;
03061     }
03062 
03063     // SMART log don't support sector offset, start with first sector
03064     unsigned offs = (req.gpl ? 0 : req.page);
03065 
03066     raw_buffer log_buf((offs + ns) * 512);
03067     bool ok;
03068     if (req.gpl)
03069       ok = ataReadLogExt(device, req.logaddr, 0x00, req.page, log_buf.data(), ns);
03070     else
03071       ok = ataReadSmartLog(device, req.logaddr, log_buf.data(), offs + ns);
03072     if (!ok)
03073       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03074     else
03075       PrintLogPages(type, log_buf.data() + offs*512, req.logaddr, req.page, ns, max_nsectors);
03076   }
03077 
03078   // Print SMART Extendend Comprehensive Error Log
03079   bool do_smart_error_log = options.smart_error_log;
03080   if (options.smart_ext_error_log) {
03081     bool ok = false;
03082     unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true);
03083     if (!nsectors)
03084       pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n\n");
03085     else if (nsectors >= 256)
03086       pout("SMART Extended Comprehensive Error Log size %u not supported\n\n", nsectors);
03087     else {
03088       raw_buffer log_03_buf(nsectors * 512);
03089       ata_smart_exterrlog * log_03 = (ata_smart_exterrlog *)log_03_buf.data();
03090       if (!ataReadExtErrorLog(device, log_03, nsectors, firmwarebugs)) {
03091         pout("Read SMART Extended Comprehensive Error Log failed\n\n");
03092         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03093       }
03094       else {
03095         if (PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log))
03096           returnval |= FAILERR;
03097         ok = true;
03098       }
03099     }
03100 
03101     if (!ok) {
03102       if (options.retry_error_log)
03103         do_smart_error_log = true;
03104       else if (!do_smart_error_log)
03105         pout("Try '-l [xerror,]error' to read traditional SMART Error Log\n");
03106     }
03107   }
03108 
03109   // Print SMART error log
03110   if (do_smart_error_log) {
03111     if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x01, false))
03112           || (!smartlogdir && isSmartErrorLogCapable(&smartval, &drive) )
03113           || is_permissive()                                             )) {
03114       pout("SMART Error Log not supported\n\n");
03115     }
03116     else {
03117       ata_smart_errorlog smarterror; memset(&smarterror, 0, sizeof(smarterror));
03118       if (ataReadErrorLog(device, &smarterror, firmwarebugs)) {
03119         pout("Read SMART Error Log failed: %s\n\n", device->get_errmsg());
03120         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03121       }
03122       else {
03123         // quiet mode is turned on inside PrintSmartErrorLog()
03124         if (PrintSmartErrorlog(&smarterror, firmwarebugs))
03125           returnval|=FAILERR;
03126         print_off();
03127       }
03128     }
03129   }
03130 
03131   // Print SMART Extendend Self-test Log
03132   bool do_smart_selftest_log = options.smart_selftest_log;
03133   if (options.smart_ext_selftest_log) {
03134     bool ok = false;
03135     unsigned nsectors = GetNumLogSectors(gplogdir, 0x07, true);
03136     if (!nsectors)
03137       pout("SMART Extended Self-test Log (GP Log 0x07) not supported\n\n");
03138     else if (nsectors >= 256)
03139       pout("SMART Extended Self-test Log size %u not supported\n\n", nsectors);
03140     else {
03141       raw_buffer log_07_buf(nsectors * 512);
03142       ata_smart_extselftestlog * log_07 = (ata_smart_extselftestlog *)log_07_buf.data();
03143       if (!ataReadExtSelfTestLog(device, log_07, nsectors)) {
03144         pout("Read SMART Extended Self-test Log failed\n\n");
03145         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03146       }
03147       else {
03148         if (PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log))
03149           returnval |= FAILLOG;
03150         ok = true;
03151       }
03152     }
03153 
03154     if (!ok) {
03155       if (options.retry_selftest_log)
03156         do_smart_selftest_log = true;
03157       else if (!do_smart_selftest_log)
03158         pout("Try '-l [xselftest,]selftest' to read traditional SMART Self Test Log\n");
03159     }
03160   }
03161 
03162   // Print SMART self-test log
03163   if (do_smart_selftest_log) {
03164     if (!(   ( smartlogdir && GetNumLogSectors(smartlogdir, 0x06, false))
03165           || (!smartlogdir && isSmartTestLogCapable(&smartval, &drive)  )
03166           || is_permissive()                                             )) {
03167       pout("SMART Self-test Log not supported\n\n");
03168     }
03169     else {
03170       ata_smart_selftestlog smartselftest; memset(&smartselftest, 0, sizeof(smartselftest));
03171       if (ataReadSelfTestLog(device, &smartselftest, firmwarebugs)) {
03172         pout("Read SMART Self-test Log failed: %s\n\n", device->get_errmsg());
03173         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03174       }
03175       else {
03176         print_on();
03177         if (ataPrintSmartSelfTestlog(&smartselftest, !printing_is_switchable, firmwarebugs))
03178           returnval |= FAILLOG;
03179         print_off();
03180         pout("\n");
03181       }
03182     }
03183   }
03184 
03185   // Print SMART selective self-test log
03186   if (options.smart_selective_selftest_log) {
03187     ata_selective_self_test_log log;
03188 
03189     if (!isSupportSelectiveSelfTest(&smartval))
03190       pout("Selective Self-tests/Logging not supported\n\n");
03191     else if(ataReadSelectiveSelfTestLog(device, &log)) {
03192       pout("Read SMART Selective Self-test Log failed: %s\n\n", device->get_errmsg());
03193       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03194     }
03195     else {
03196       print_on();
03197       // If any errors were found, they are logged in the SMART Self-test log.
03198       // So there is no need to print the Selective Self Test log in silent
03199       // mode.
03200       if (!printing_is_switchable)
03201         ataPrintSelectiveSelfTestLog(&log, &smartval);
03202       print_off();
03203       pout("\n");
03204     }
03205   }
03206 
03207   // Check if SCT commands available
03208   bool sct_ok = isSCTCapable(&drive);
03209   if(!sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int
03210                  || options.sct_erc_get || options.sct_erc_set                        ))
03211     pout("SCT Commands not supported\n\n");
03212 
03213   // Print SCT status and temperature history table
03214   if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) {
03215     for (;;) {
03216       if (options.sct_temp_sts || options.sct_temp_hist) {
03217         ata_sct_status_response sts;
03218         ata_sct_temperature_history_table tmh;
03219         if (!options.sct_temp_hist) {
03220           // Read SCT status only
03221           if (ataReadSCTStatus(device, &sts)) {
03222             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03223             break;
03224           }
03225         }
03226         else {
03227           if (!isSCTDataTableCapable(&drive)) {
03228             pout("SCT Data Table command not supported\n\n");
03229             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03230             break;
03231           }
03232           // Read SCT status and temperature history
03233           if (ataReadSCTTempHist(device, &tmh, &sts)) {
03234             pout("Read SCT Temperature History failed\n\n");
03235             failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03236             break;
03237           }
03238         }
03239         if (options.sct_temp_sts)
03240           ataPrintSCTStatus(&sts);
03241         if (options.sct_temp_hist)
03242           ataPrintSCTTempHist(&tmh);
03243         pout("\n");
03244       }
03245       if (options.sct_temp_int) {
03246         // Set new temperature logging interval
03247         if (!isSCTFeatureControlCapable(&drive)) {
03248           pout("SCT Feature Control command not supported\n\n");
03249           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03250           break;
03251         }
03252         if (ataSetSCTTempInterval(device, options.sct_temp_int, options.sct_temp_int_pers)) {
03253           pout("Write Temperature Logging Interval failed\n\n");
03254           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03255           break;
03256         }
03257         pout("Temperature Logging Interval set to %u minute%s (%s)\n",
03258           options.sct_temp_int, (options.sct_temp_int == 1 ? "" : "s"),
03259           (options.sct_temp_int_pers ? "persistent" : "volatile"));
03260       }
03261       break;
03262     }
03263   }
03264 
03265   // SCT Error Recovery Control
03266   if (sct_ok && (options.sct_erc_get || options.sct_erc_set)) {
03267     if (!isSCTErrorRecoveryControlCapable(&drive)) {
03268       pout("SCT Error Recovery Control command not supported\n\n");
03269       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03270     }
03271     else {
03272       bool sct_erc_get = options.sct_erc_get;
03273       if (options.sct_erc_set) {
03274         // Set SCT Error Recovery Control
03275         if (   ataSetSCTErrorRecoveryControltime(device, 1, options.sct_erc_readtime )
03276             || ataSetSCTErrorRecoveryControltime(device, 2, options.sct_erc_writetime)) {
03277           pout("SCT (Set) Error Recovery Control command failed\n");
03278           if (!(   (options.sct_erc_readtime == 70 && options.sct_erc_writetime == 70)
03279                 || (options.sct_erc_readtime ==  0 && options.sct_erc_writetime ==  0)))
03280             pout("Retry with: 'scterc,70,70' to enable ERC or 'scterc,0,0' to disable\n");
03281           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03282           sct_erc_get = false;
03283         }
03284         else if (!sct_erc_get)
03285           ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
03286             options.sct_erc_writetime);
03287       }
03288 
03289       if (sct_erc_get) {
03290         // Print SCT Error Recovery Control
03291         unsigned short read_timer, write_timer;
03292         if (   ataGetSCTErrorRecoveryControltime(device, 1, read_timer )
03293             || ataGetSCTErrorRecoveryControltime(device, 2, write_timer)) {
03294           pout("SCT (Get) Error Recovery Control command failed\n");
03295           if (options.sct_erc_set) {
03296             pout("The previous SCT (Set) Error Recovery Control command succeeded\n");
03297             ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime,
03298               options.sct_erc_writetime);
03299           }
03300           failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03301         }
03302         else
03303           ataPrintSCTErrorRecoveryControl(false, read_timer, write_timer);
03304       }
03305       pout("\n");
03306     }
03307   }
03308 
03309   // Print Device Statistics
03310   if (options.devstat_all_pages || options.devstat_ssd_page || !options.devstat_pages.empty()) {
03311     unsigned nsectors = GetNumLogSectors(gplogdir, 0x04, true);
03312     if (!nsectors)
03313       pout("Device Statistics (GP Log 0x04) not supported\n\n");
03314     else if (!print_device_statistics(device, nsectors, options.devstat_pages,
03315                options.devstat_all_pages, options.devstat_ssd_page))
03316       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03317   }
03318 
03319   // Print SATA Phy Event Counters
03320   if (options.sataphy) {
03321     unsigned nsectors = GetNumLogSectors(gplogdir, 0x11, true);
03322     // Packet interface devices do not provide a log directory, check support bit
03323     if (!nsectors && (drive.words047_079[76-47] & 0x0401) == 0x0400)
03324       nsectors = 1;
03325     if (!nsectors)
03326       pout("SATA Phy Event Counters (GP Log 0x11) not supported\n\n");
03327     else if (nsectors != 1)
03328       pout("SATA Phy Event Counters with %u sectors not supported\n\n", nsectors);
03329     else {
03330       unsigned char log_11[512] = {0, };
03331       unsigned char features = (options.sataphy_reset ? 0x01 : 0x00);
03332       if (!ataReadLogExt(device, 0x11, features, 0, log_11, 1)) {
03333         pout("Read SATA Phy Event Counters failed\n\n");
03334         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03335       }
03336       else
03337         PrintSataPhyEventCounters(log_11, options.sataphy_reset);
03338     }
03339   }
03340 
03341   // Set to standby (spindown) mode
03342   // (Above commands may spinup drive)
03343   if (options.set_standby_now) {
03344     if (!ata_nodata_command(device, ATA_STANDBY_IMMEDIATE)) {
03345         pout("ATA STANDBY IMMEDIATE command failed: %s\n", device->get_errmsg());
03346         returnval |= FAILSMART;
03347     }
03348     else
03349       pout("Device placed in STANDBY mode\n");
03350   }
03351 
03352   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
03353   if (!smart_val_ok || options.smart_selftest_type == -1)
03354     return returnval;
03355   
03356   pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
03357   // if doing a self-test, be sure it's supported by the hardware
03358   switch (options.smart_selftest_type) {
03359   case OFFLINE_FULL_SCAN:
03360     if (!isSupportExecuteOfflineImmediate(&smartval)){
03361       pout("Execute Offline Immediate function not supported\n\n");
03362       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03363     }
03364     break;
03365   case ABORT_SELF_TEST:
03366   case SHORT_SELF_TEST:
03367   case EXTEND_SELF_TEST:
03368   case SHORT_CAPTIVE_SELF_TEST:
03369   case EXTEND_CAPTIVE_SELF_TEST:
03370     if (!isSupportSelfTest(&smartval)){
03371       pout("Self-test functions not supported\n\n");
03372       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03373     }
03374     break;
03375   case CONVEYANCE_SELF_TEST:
03376   case CONVEYANCE_CAPTIVE_SELF_TEST:
03377     if (!isSupportConveyanceSelfTest(&smartval)){
03378       pout("Conveyance Self-test functions not supported\n\n");
03379       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03380     }
03381     break;
03382   case SELECTIVE_SELF_TEST:
03383   case SELECTIVE_CAPTIVE_SELF_TEST:
03384     if (!isSupportSelectiveSelfTest(&smartval)){
03385       pout("Selective Self-test functions not supported\n\n");
03386       failuretest(MANDATORY_CMD, returnval|=FAILSMART);
03387     }
03388     break;
03389   default:
03390     break; // Vendor specific type
03391   }
03392 
03393   // Now do the test.  Note ataSmartTest prints its own error/success
03394   // messages
03395   if (ataSmartTest(device, options.smart_selftest_type, options.smart_selftest_force,
03396                    options.smart_selective_args, &smartval, sizes.sectors            ))
03397     failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03398   else {  
03399     // Tell user how long test will take to complete.  This is tricky
03400     // because in the case of an Offline Full Scan, the completion
03401     // timer is volatile, and needs to be read AFTER the command is
03402     // given. If this will interrupt the Offline Full Scan, we don't
03403     // do it, just warn user.
03404     if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
03405       if (isSupportOfflineAbort(&smartval))
03406         pout("Note: giving further SMART commands will abort Offline testing\n");
03407       else if (ataReadSmartValues(device, &smartval)){
03408         pout("Read SMART Data failed: %s\n\n", device->get_errmsg());
03409         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
03410       }
03411     }
03412     
03413     // Now say how long the test will take to complete
03414     int timewait = TestTime(&smartval, options.smart_selftest_type);
03415     if (timewait) {
03416       time_t t=time(NULL);
03417       if (options.smart_selftest_type == OFFLINE_FULL_SCAN) {
03418         t+=timewait;
03419         pout("Please wait %d seconds for test to complete.\n", (int)timewait);
03420       } else {
03421         t+=timewait*60;
03422         pout("Please wait %d minutes for test to complete.\n", (int)timewait);
03423       }
03424       pout("Test will complete after %s\n", ctime(&t));
03425       
03426       if (   options.smart_selftest_type != SHORT_CAPTIVE_SELF_TEST
03427           && options.smart_selftest_type != EXTEND_CAPTIVE_SELF_TEST
03428           && options.smart_selftest_type != CONVEYANCE_CAPTIVE_SELF_TEST
03429           && options.smart_selftest_type != SELECTIVE_CAPTIVE_SELF_TEST )
03430         pout("Use smartctl -X to abort test.\n");
03431     }
03432   }
03433 
03434   return returnval;
03435 }