Annotation of embedaddon/smartmontools/atacmds.cpp, revision 1.1
1.1 ! misho 1: /*
! 2: * atacmds.cpp
! 3: *
! 4: * Home page of code is: http://smartmontools.sourceforge.net
! 5: *
! 6: * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
! 7: * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net>
! 8: * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
! 9: * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
! 10: *
! 11: * This program is free software; you can redistribute it and/or modify
! 12: * it under the terms of the GNU General Public License as published by
! 13: * the Free Software Foundation; either version 2, or (at your option)
! 14: * any later version.
! 15: *
! 16: * You should have received a copy of the GNU General Public License
! 17: * (for example COPYING); if not, write to the Free
! 18: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
! 19: *
! 20: * This code was originally developed as a Senior Thesis by Michael Cornwell
! 21: * at the Concurrent Systems Laboratory (now part of the Storage Systems
! 22: * Research Center), Jack Baskin School of Engineering, University of
! 23: * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
! 24: *
! 25: */
! 26:
! 27: #include <stdio.h>
! 28: #include <string.h>
! 29: #include <errno.h>
! 30: #include <stdlib.h>
! 31: #include <ctype.h>
! 32:
! 33: #include "config.h"
! 34: #include "int64.h"
! 35: #include "atacmds.h"
! 36: #include "utility.h"
! 37: #include "dev_ata_cmd_set.h" // for parsed_ata_device
! 38:
! 39: const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3411 2011-08-12 21:48:54Z chrfranke $"
! 40: ATACMDS_H_CVSID;
! 41:
! 42: // Print ATA debug messages?
! 43: unsigned char ata_debugmode = 0;
! 44:
! 45: // Suppress serial number?
! 46: // (also used in scsiprint.cpp)
! 47: bool dont_print_serial_number = false;
! 48:
! 49:
! 50: #define SMART_CYL_LOW 0x4F
! 51: #define SMART_CYL_HI 0xC2
! 52:
! 53: // SMART RETURN STATUS yields SMART_CYL_HI,SMART_CYL_LOW to indicate drive
! 54: // is healthy and SRET_STATUS_HI_EXCEEDED,SRET_STATUS_MID_EXCEEDED to
! 55: // indicate that a threshhold exceeded condition has been detected.
! 56: // Those values (byte pairs) are placed in ATA register "LBA 23:8".
! 57: #define SRET_STATUS_HI_EXCEEDED 0x2C
! 58: #define SRET_STATUS_MID_EXCEEDED 0xF4
! 59:
! 60: // These Drive Identity tables are taken from hdparm 5.2, and are also
! 61: // given in the ATA/ATAPI specs for the IDENTIFY DEVICE command. Note
! 62: // that SMART was first added into the ATA/ATAPI-3 Standard with
! 63: // Revision 3 of the document, July 25, 1995. Look at the "Document
! 64: // Status" revision commands at the beginning of
! 65: // http://www.t13.org/Documents/UploadedDocuments/project/d2008r7b-ATA-3.pdf
! 66: // to see this.
! 67: #define NOVAL_0 0x0000
! 68: #define NOVAL_1 0xffff
! 69: /* word 81: minor version number */
! 70: #define MINOR_MAX 0x22
! 71: static const char * const minor_str[] = { /* word 81 value: */
! 72: "Device does not report version", /* 0x0000 */
! 73: "ATA-1 X3T9.2 781D prior to revision 4", /* 0x0001 */
! 74: "ATA-1 published, ANSI X3.221-1994", /* 0x0002 */
! 75: "ATA-1 X3T9.2 781D revision 4", /* 0x0003 */
! 76: "ATA-2 published, ANSI X3.279-1996", /* 0x0004 */
! 77: "ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */
! 78: "ATA-3 X3T10 2008D revision 1", /* 0x0006 */ /* SMART NOT INCLUDED */
! 79: "ATA-2 X3T10 948D revision 2k", /* 0x0007 */
! 80: "ATA-3 X3T10 2008D revision 0", /* 0x0008 */
! 81: "ATA-2 X3T10 948D revision 3", /* 0x0009 */
! 82: "ATA-3 published, ANSI X3.298-199x", /* 0x000a */
! 83: "ATA-3 X3T10 2008D revision 6", /* 0x000b */ /* 1st VERSION WITH SMART */
! 84: "ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */
! 85: "ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */
! 86: "ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */
! 87: "ATA/ATAPI-4 X3T13 1153D revision 7", /* 0x000f */
! 88: "ATA/ATAPI-4 T13 1153D revision 18", /* 0x0010 */
! 89: "ATA/ATAPI-4 T13 1153D revision 15", /* 0x0011 */
! 90: "ATA/ATAPI-4 published, ANSI NCITS 317-1998", /* 0x0012 */
! 91: "ATA/ATAPI-5 T13 1321D revision 3", /* 0x0013 */
! 92: "ATA/ATAPI-4 T13 1153D revision 14", /* 0x0014 */
! 93: "ATA/ATAPI-5 T13 1321D revision 1", /* 0x0015 */
! 94: "ATA/ATAPI-5 published, ANSI NCITS 340-2000", /* 0x0016 */
! 95: "ATA/ATAPI-4 T13 1153D revision 17", /* 0x0017 */
! 96: "ATA/ATAPI-6 T13 1410D revision 0", /* 0x0018 */
! 97: "ATA/ATAPI-6 T13 1410D revision 3a", /* 0x0019 */
! 98: "ATA/ATAPI-7 T13 1532D revision 1", /* 0x001a */
! 99: "ATA/ATAPI-6 T13 1410D revision 2", /* 0x001b */
! 100: "ATA/ATAPI-6 T13 1410D revision 1", /* 0x001c */
! 101: "ATA/ATAPI-7 published, ANSI INCITS 397-2005",/* 0x001d */
! 102: "ATA/ATAPI-7 T13 1532D revision 0", /* 0x001e */
! 103: "reserved", /* 0x001f */
! 104: "reserved", /* 0x0020 */
! 105: "ATA/ATAPI-7 T13 1532D revision 4a", /* 0x0021 */
! 106: "ATA/ATAPI-6 published, ANSI INCITS 361-2002" /* 0x0022 */
! 107: };
! 108:
! 109: // NOTE ATA/ATAPI-4 REV 4 was the LAST revision where the device
! 110: // attribute structures were NOT completely vendor specific. So any
! 111: // disk that is ATA/ATAPI-4 or above can not be trusted to show the
! 112: // vendor values in sensible format.
! 113:
! 114: // Negative values below are because it doesn't support SMART
! 115: static const int actual_ver[] = {
! 116: /* word 81 value: */
! 117: 0, /* 0x0000 WARNING: */
! 118: 1, /* 0x0001 WARNING: */
! 119: 1, /* 0x0002 WARNING: */
! 120: 1, /* 0x0003 WARNING: */
! 121: 2, /* 0x0004 WARNING: This array */
! 122: 2, /* 0x0005 WARNING: corresponds */
! 123: -3, /*<== */ /* 0x0006 WARNING: *exactly* */
! 124: 2, /* 0x0007 WARNING: to the ATA/ */
! 125: -3, /*<== */ /* 0x0008 WARNING: ATAPI version */
! 126: 2, /* 0x0009 WARNING: listed in */
! 127: 3, /* 0x000a WARNING: the */
! 128: 3, /* 0x000b WARNING: minor_str */
! 129: 3, /* 0x000c WARNING: array */
! 130: 4, /* 0x000d WARNING: above. */
! 131: 4, /* 0x000e WARNING: */
! 132: 4, /* 0x000f WARNING: If you change */
! 133: 4, /* 0x0010 WARNING: that one, */
! 134: 4, /* 0x0011 WARNING: change this one */
! 135: 4, /* 0x0012 WARNING: too!!! */
! 136: 5, /* 0x0013 WARNING: */
! 137: 4, /* 0x0014 WARNING: */
! 138: 5, /* 0x0015 WARNING: */
! 139: 5, /* 0x0016 WARNING: */
! 140: 4, /* 0x0017 WARNING: */
! 141: 6, /* 0x0018 WARNING: */
! 142: 6, /* 0x0019 WARNING: */
! 143: 7, /* 0x001a WARNING: */
! 144: 6, /* 0x001b WARNING: */
! 145: 6, /* 0x001c WARNING: */
! 146: 7, /* 0x001d WARNING: */
! 147: 7, /* 0x001e WARNING: */
! 148: 0, /* 0x001f WARNING: */
! 149: 0, /* 0x0020 WARNING: */
! 150: 7, /* 0x0021 WARNING: */
! 151: 6 /* 0x0022 WARNING: */
! 152: };
! 153:
! 154: // Compile time check of above array sizes
! 155: typedef char assert_sizeof_minor_str [sizeof(minor_str) /sizeof(minor_str[0]) == MINOR_MAX+1 ? 1 : -1];
! 156: typedef char assert_sizeof_actual_ver[sizeof(actual_ver)/sizeof(actual_ver[0]) == MINOR_MAX+1 ? 1 : -1];
! 157:
! 158: // Get ID and increase flag of current pending or offline
! 159: // uncorrectable attribute.
! 160: unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs,
! 161: bool & increase)
! 162: {
! 163: unsigned char id = (!offline ? 197 : 198);
! 164: const ata_vendor_attr_defs::entry & def = defs[id];
! 165: if (def.flags & ATTRFLAG_INCREASING)
! 166: increase = true; // '-v 19[78],increasing' option
! 167: else if (def.name.empty() || (id == 198 && def.name == "Offline_Scan_UNC_SectCt"))
! 168: increase = false; // no or '-v 198,offlinescanuncsectorct' option
! 169: else
! 170: id = 0; // other '-v 19[78],...' option
! 171: return id;
! 172: }
! 173:
! 174: #if 0 // TODO: never used
! 175: // This are the meanings of the Self-test failure checkpoint byte.
! 176: // This is in the self-test log at offset 4 bytes into the self-test
! 177: // descriptor and in the SMART READ DATA structure at byte offset
! 178: // 371. These codes are not well documented. The meanings returned by
! 179: // this routine are used (at least) by Maxtor and IBM. Returns NULL if
! 180: // not recognized. Currently the maximum length is 15 bytes.
! 181: const char *SelfTestFailureCodeName(unsigned char which){
! 182:
! 183: switch (which) {
! 184: case 0:
! 185: return "Write_Test";
! 186: case 1:
! 187: return "Servo_Basic";
! 188: case 2:
! 189: return "Servo_Random";
! 190: case 3:
! 191: return "G-list_Scan";
! 192: case 4:
! 193: return "Handling_Damage";
! 194: case 5:
! 195: return "Read_Scan";
! 196: default:
! 197: return NULL;
! 198: }
! 199: }
! 200: #endif
! 201:
! 202:
! 203: // Table of raw print format names
! 204: struct format_name_entry
! 205: {
! 206: const char * name;
! 207: ata_attr_raw_format format;
! 208: };
! 209:
! 210: const format_name_entry format_names[] = {
! 211: {"raw8" , RAWFMT_RAW8},
! 212: {"raw16" , RAWFMT_RAW16},
! 213: {"raw48" , RAWFMT_RAW48},
! 214: {"hex48" , RAWFMT_HEX48},
! 215: {"raw64" , RAWFMT_RAW64},
! 216: {"hex64" , RAWFMT_HEX64},
! 217: {"raw16(raw16)" , RAWFMT_RAW16_OPT_RAW16},
! 218: {"raw16(avg16)" , RAWFMT_RAW16_OPT_AVG16},
! 219: {"raw24/raw24" , RAWFMT_RAW24_DIV_RAW24},
! 220: {"raw24/raw32" , RAWFMT_RAW24_DIV_RAW32},
! 221: {"sec2hour" , RAWFMT_SEC2HOUR},
! 222: {"min2hour" , RAWFMT_MIN2HOUR},
! 223: {"halfmin2hour" , RAWFMT_HALFMIN2HOUR},
! 224: {"msec24hour32" , RAWFMT_MSEC24_HOUR32},
! 225: {"tempminmax" , RAWFMT_TEMPMINMAX},
! 226: {"temp10x" , RAWFMT_TEMP10X},
! 227: };
! 228:
! 229: const unsigned num_format_names = sizeof(format_names)/sizeof(format_names[0]);
! 230:
! 231: // Table to map old to new '-v' option arguments
! 232: const char * map_old_vendor_opts[][2] = {
! 233: { "9,halfminutes" , "9,halfmin2hour,Power_On_Half_Minutes"},
! 234: { "9,minutes" , "9,min2hour,Power_On_Minutes"},
! 235: { "9,seconds" , "9,sec2hour,Power_On_Seconds"},
! 236: { "9,temp" , "9,tempminmax,Temperature_Celsius"},
! 237: {"192,emergencyretractcyclect" , "192,raw48,Emerg_Retract_Cycle_Ct"},
! 238: {"193,loadunload" , "193,raw24/raw24"},
! 239: {"194,10xCelsius" , "194,temp10x,Temperature_Celsius_x10"},
! 240: {"194,unknown" , "194,raw48,Unknown_Attribute"},
! 241: {"197,increasing" , "197,raw48+,Total_Pending_Sectors"}, // '+' sets flag
! 242: {"198,offlinescanuncsectorct" , "198,raw48,Offline_Scan_UNC_SectCt"}, // see also get_unc_attr_id() above
! 243: {"198,increasing" , "198,raw48+,Total_Offl_Uncorrectabl"}, // '+' sets flag
! 244: {"200,writeerrorcount" , "200,raw48,Write_Error_Count"},
! 245: {"201,detectedtacount" , "201,raw48,Detected_TA_Count"},
! 246: {"220,temp" , "220,raw48,Temperature_Celsius"},
! 247: };
! 248:
! 249: const unsigned num_old_vendor_opts = sizeof(map_old_vendor_opts)/sizeof(map_old_vendor_opts[0]);
! 250:
! 251: // Parse vendor attribute display def (-v option).
! 252: // Return false on error.
! 253: bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
! 254: ata_vendor_def_prior priority)
! 255: {
! 256: // Map old -> new options
! 257: unsigned i;
! 258: for (i = 0; i < num_old_vendor_opts; i++) {
! 259: if (!strcmp(opt, map_old_vendor_opts[i][0])) {
! 260: opt = map_old_vendor_opts[i][1];
! 261: break;
! 262: }
! 263: }
! 264:
! 265: // Parse option
! 266: int len = strlen(opt);
! 267: int id = 0, n1 = -1, n2 = -1;
! 268: char fmtname[32+1], attrname[32+1];
! 269: if (opt[0] == 'N') {
! 270: // "N,format"
! 271: if (!( sscanf(opt, "N,%32[^,]%n,%32[^,]%n", fmtname, &n1, attrname, &n2) >= 1
! 272: && (n1 == len || n2 == len)))
! 273: return false;
! 274: }
! 275: else {
! 276: // "id,format[+][,name]"
! 277: if (!( sscanf(opt, "%d,%32[^,]%n,%32[^,]%n", &id, fmtname, &n1, attrname, &n2) >= 2
! 278: && 1 <= id && id <= 255 && (n1 == len || n2 == len)))
! 279: return false;
! 280: }
! 281: if (n1 == len)
! 282: attrname[0] = 0;
! 283:
! 284: unsigned flags = 0;
! 285: // For "-v 19[78],increasing" above
! 286: if (fmtname[strlen(fmtname)-1] == '+') {
! 287: fmtname[strlen(fmtname)-1] = 0;
! 288: flags = ATTRFLAG_INCREASING;
! 289: }
! 290:
! 291: // Split "format[:byteorder]"
! 292: char byteorder[8+1] = "";
! 293: if (strchr(fmtname, ':')) {
! 294: if (!( sscanf(fmtname, "%*[^:]%n:%8[012345rvwz]%n", &n1, byteorder, &n2) >= 1
! 295: && n2 == (int)strlen(fmtname)))
! 296: return false;
! 297: fmtname[n1] = 0;
! 298: if (strchr(byteorder, 'v'))
! 299: flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL);
! 300: if (strchr(byteorder, 'w'))
! 301: flags |= ATTRFLAG_NO_WORSTVAL;
! 302: }
! 303:
! 304: // Find format name
! 305: for (i = 0; ; i++) {
! 306: if (i >= num_format_names)
! 307: return false; // Not found
! 308: if (!strcmp(fmtname, format_names[i].name))
! 309: break;
! 310: }
! 311: ata_attr_raw_format format = format_names[i].format;
! 312:
! 313: // 64-bit formats use the normalized and worst value bytes.
! 314: if (!*byteorder && (format == RAWFMT_RAW64 || format == RAWFMT_HEX64))
! 315: flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL);
! 316:
! 317: if (!id) {
! 318: // "N,format" -> set format for all entries
! 319: for (i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
! 320: if (defs[i].priority >= priority)
! 321: continue;
! 322: if (attrname[0])
! 323: defs[i].name = attrname;
! 324: defs[i].priority = priority;
! 325: defs[i].raw_format = format;
! 326: defs[i].flags = flags;
! 327: strcpy(defs[i].byteorder, byteorder);
! 328: }
! 329: }
! 330: else if (defs[id].priority <= priority) {
! 331: // "id,format[,name]"
! 332: if (attrname[0])
! 333: defs[id].name = attrname;
! 334: defs[id].raw_format = format;
! 335: defs[id].priority = priority;
! 336: defs[id].flags = flags;
! 337: strcpy(defs[id].byteorder, byteorder);
! 338: }
! 339:
! 340: return true;
! 341: }
! 342:
! 343:
! 344: // Return a multiline string containing a list of valid arguments for
! 345: // parse_attribute_def(). The strings are preceeded by tabs and followed
! 346: // (except for the last) by newlines.
! 347: std::string create_vendor_attribute_arg_list()
! 348: {
! 349: std::string s;
! 350: unsigned i;
! 351: for (i = 0; i < num_format_names; i++)
! 352: s += strprintf("%s\tN,%s[:012345rvwz][,ATTR_NAME]",
! 353: (i>0 ? "\n" : ""), format_names[i].name);
! 354: for (i = 0; i < num_old_vendor_opts; i++)
! 355: s += strprintf("\n\t%s", map_old_vendor_opts[i][0]);
! 356: return s;
! 357: }
! 358:
! 359: // swap two bytes. Point to low address
! 360: void swap2(char *location){
! 361: char tmp=*location;
! 362: *location=*(location+1);
! 363: *(location+1)=tmp;
! 364: return;
! 365: }
! 366:
! 367: // swap four bytes. Point to low address
! 368: void swap4(char *location){
! 369: char tmp=*location;
! 370: *location=*(location+3);
! 371: *(location+3)=tmp;
! 372: swap2(location+1);
! 373: return;
! 374: }
! 375:
! 376: // swap eight bytes. Points to low address
! 377: void swap8(char *location){
! 378: char tmp=*location;
! 379: *location=*(location+7);
! 380: *(location+7)=tmp;
! 381: tmp=*(location+1);
! 382: *(location+1)=*(location+6);
! 383: *(location+6)=tmp;
! 384: swap4(location+2);
! 385: return;
! 386: }
! 387:
! 388: // Invalidate serial number and WWN and adjust checksum in IDENTIFY data
! 389: static void invalidate_serno(ata_identify_device * id)
! 390: {
! 391: unsigned char sum = 0;
! 392: unsigned i;
! 393: for (i = 0; i < sizeof(id->serial_no); i++) {
! 394: sum += id->serial_no[i]; sum -= id->serial_no[i] = 'X';
! 395: }
! 396: unsigned char * b = (unsigned char *)id;
! 397: for (i = 2*108; i < 2*112; i++) { // words108-111: WWN
! 398: sum += b[i]; sum -= b[i] = 0x00;
! 399: }
! 400:
! 401: #ifndef __NetBSD__
! 402: bool must_swap = !!isbigendian();
! 403: if (must_swap)
! 404: swapx(id->words088_255+255-88);
! 405: #endif
! 406: if ((id->words088_255[255-88] & 0x00ff) == 0x00a5)
! 407: id->words088_255[255-88] += sum << 8;
! 408: #ifndef __NetBSD__
! 409: if (must_swap)
! 410: swapx(id->words088_255+255-88);
! 411: #endif
! 412: }
! 413:
! 414: static const char * const commandstrings[]={
! 415: "SMART ENABLE",
! 416: "SMART DISABLE",
! 417: "SMART AUTOMATIC ATTRIBUTE SAVE",
! 418: "SMART IMMEDIATE OFFLINE",
! 419: "SMART AUTO OFFLINE",
! 420: "SMART STATUS",
! 421: "SMART STATUS CHECK",
! 422: "SMART READ ATTRIBUTE VALUES",
! 423: "SMART READ ATTRIBUTE THRESHOLDS",
! 424: "SMART READ LOG",
! 425: "IDENTIFY DEVICE",
! 426: "IDENTIFY PACKET DEVICE",
! 427: "CHECK POWER MODE",
! 428: "SMART WRITE LOG",
! 429: "WARNING (UNDEFINED COMMAND -- CONTACT DEVELOPERS AT " PACKAGE_BUGREPORT ")\n"
! 430: };
! 431:
! 432:
! 433: static const char * preg(const ata_register & r, char * buf)
! 434: {
! 435: if (!r.is_set())
! 436: //return "n/a ";
! 437: return "....";
! 438: sprintf(buf, "0x%02x", r.val()); return buf;
! 439: }
! 440:
! 441: static void print_regs(const char * prefix, const ata_in_regs & r, const char * suffix = "\n")
! 442: {
! 443: char bufs[7][4+1+13];
! 444: pout("%s FR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, CMD=%s%s", prefix,
! 445: preg(r.features, bufs[0]), preg(r.sector_count, bufs[1]), preg(r.lba_low, bufs[2]),
! 446: preg(r.lba_mid, bufs[3]), preg(r.lba_high, bufs[4]), preg(r.device, bufs[5]),
! 447: preg(r.command, bufs[6]), suffix);
! 448: }
! 449:
! 450: static void print_regs(const char * prefix, const ata_out_regs & r, const char * suffix = "\n")
! 451: {
! 452: char bufs[7][4+1+13];
! 453: pout("%sERR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, STS=%s%s", prefix,
! 454: preg(r.error, bufs[0]), preg(r.sector_count, bufs[1]), preg(r.lba_low, bufs[2]),
! 455: preg(r.lba_mid, bufs[3]), preg(r.lba_high, bufs[4]), preg(r.device, bufs[5]),
! 456: preg(r.status, bufs[6]), suffix);
! 457: }
! 458:
! 459: static void prettyprint(const unsigned char *p, const char *name){
! 460: pout("\n===== [%s] DATA START (BASE-16) =====\n", name);
! 461: for (int i=0; i<512; i+=16, p+=16)
! 462: #define P(n) (' ' <= p[n] && p[n] <= '~' ? (int)p[n] : '.')
! 463: // print complete line to avoid slow tty output and extra lines in syslog.
! 464: pout("%03d-%03d: %02x %02x %02x %02x %02x %02x %02x %02x "
! 465: "%02x %02x %02x %02x %02x %02x %02x %02x"
! 466: " |%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c|"
! 467: "%c",
! 468: i, i+16-1,
! 469: p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7],
! 470: p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15],
! 471: P( 0), P( 1), P( 2), P( 3), P( 4), P( 5), P( 6), P( 7),
! 472: P( 8), P( 9), P(10), P(11), P(12), P(13), P(14), P(15),
! 473: '\n');
! 474: #undef P
! 475: pout("===== [%s] DATA END (512 Bytes) =====\n\n", name);
! 476: }
! 477:
! 478: // This function provides the pretty-print reporting for SMART
! 479: // commands: it implements the various -r "reporting" options for ATA
! 480: // ioctls.
! 481: int smartcommandhandler(ata_device * device, smart_command_set command, int select, char *data){
! 482: // TODO: Rework old stuff below
! 483: // This conditional is true for commands that return data
! 484: int getsdata=(command==PIDENTIFY ||
! 485: command==IDENTIFY ||
! 486: command==READ_LOG ||
! 487: command==READ_THRESHOLDS ||
! 488: command==READ_VALUES ||
! 489: command==CHECK_POWER_MODE);
! 490:
! 491: int sendsdata=(command==WRITE_LOG);
! 492:
! 493: // If reporting is enabled, say what the command will be before it's executed
! 494: if (ata_debugmode) {
! 495: // conditional is true for commands that use parameters
! 496: int usesparam=(command==READ_LOG ||
! 497: command==AUTO_OFFLINE ||
! 498: command==AUTOSAVE ||
! 499: command==IMMEDIATE_OFFLINE ||
! 500: command==WRITE_LOG);
! 501:
! 502: pout("\nREPORT-IOCTL: Device=%s Command=%s", device->get_dev_name(), commandstrings[command]);
! 503: if (usesparam)
! 504: pout(" InputParameter=%d\n", select);
! 505: else
! 506: pout("\n");
! 507: }
! 508:
! 509: if ((getsdata || sendsdata) && !data){
! 510: pout("REPORT-IOCTL: Unable to execute command %s : data destination address is NULL\n", commandstrings[command]);
! 511: return -1;
! 512: }
! 513:
! 514: // The reporting is cleaner, and we will find coding bugs faster, if
! 515: // the commands that failed clearly return empty (zeroed) data
! 516: // structures
! 517: if (getsdata) {
! 518: if (command==CHECK_POWER_MODE)
! 519: data[0]=0;
! 520: else
! 521: memset(data, '\0', 512);
! 522: }
! 523:
! 524:
! 525: // if requested, pretty-print the input data structure
! 526: if (ata_debugmode > 1 && sendsdata)
! 527: //pout("REPORT-IOCTL: Device=%s Command=%s\n", device->get_dev_name(), commandstrings[command]);
! 528: prettyprint((unsigned char *)data, commandstrings[command]);
! 529:
! 530: // now execute the command
! 531: int retval = -1;
! 532: {
! 533: ata_cmd_in in;
! 534: // Set common register values
! 535: switch (command) {
! 536: default: // SMART commands
! 537: in.in_regs.command = ATA_SMART_CMD;
! 538: in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW;
! 539: break;
! 540: case IDENTIFY: case PIDENTIFY: case CHECK_POWER_MODE: // Non SMART commands
! 541: break;
! 542: }
! 543: // Set specific values
! 544: switch (command) {
! 545: case IDENTIFY:
! 546: in.in_regs.command = ATA_IDENTIFY_DEVICE;
! 547: in.set_data_in(data, 1);
! 548: break;
! 549: case PIDENTIFY:
! 550: in.in_regs.command = ATA_IDENTIFY_PACKET_DEVICE;
! 551: in.set_data_in(data, 1);
! 552: break;
! 553: case CHECK_POWER_MODE:
! 554: in.in_regs.command = ATA_CHECK_POWER_MODE;
! 555: in.out_needed.sector_count = true; // Powermode returned here
! 556: break;
! 557: case READ_VALUES:
! 558: in.in_regs.features = ATA_SMART_READ_VALUES;
! 559: in.set_data_in(data, 1);
! 560: break;
! 561: case READ_THRESHOLDS:
! 562: in.in_regs.features = ATA_SMART_READ_THRESHOLDS;
! 563: in.in_regs.lba_low = 1; // TODO: CORRECT ???
! 564: in.set_data_in(data, 1);
! 565: break;
! 566: case READ_LOG:
! 567: in.in_regs.features = ATA_SMART_READ_LOG_SECTOR;
! 568: in.in_regs.lba_low = select;
! 569: in.set_data_in(data, 1);
! 570: break;
! 571: case WRITE_LOG:
! 572: in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR;
! 573: in.in_regs.lba_low = select;
! 574: in.set_data_out(data, 1);
! 575: break;
! 576: case ENABLE:
! 577: in.in_regs.features = ATA_SMART_ENABLE;
! 578: in.in_regs.lba_low = 1; // TODO: CORRECT ???
! 579: break;
! 580: case DISABLE:
! 581: in.in_regs.features = ATA_SMART_DISABLE;
! 582: in.in_regs.lba_low = 1; // TODO: CORRECT ???
! 583: break;
! 584: case STATUS_CHECK:
! 585: in.out_needed.lba_high = in.out_needed.lba_mid = true; // Status returned here
! 586: case STATUS:
! 587: in.in_regs.features = ATA_SMART_STATUS;
! 588: break;
! 589: case AUTO_OFFLINE:
! 590: in.in_regs.features = ATA_SMART_AUTO_OFFLINE;
! 591: in.in_regs.sector_count = select; // Caution: Non-DATA command!
! 592: break;
! 593: case AUTOSAVE:
! 594: in.in_regs.features = ATA_SMART_AUTOSAVE;
! 595: in.in_regs.sector_count = select; // Caution: Non-DATA command!
! 596: break;
! 597: case IMMEDIATE_OFFLINE:
! 598: in.in_regs.features = ATA_SMART_IMMEDIATE_OFFLINE;
! 599: in.in_regs.lba_low = select;
! 600: break;
! 601: default:
! 602: pout("Unrecognized command %d in smartcommandhandler()\n"
! 603: "Please contact " PACKAGE_BUGREPORT "\n", command);
! 604: device->set_err(ENOSYS);
! 605: return -1;
! 606: }
! 607:
! 608: if (ata_debugmode)
! 609: print_regs(" Input: ", in.in_regs,
! 610: (in.direction==ata_cmd_in::data_in ? " IN\n":
! 611: in.direction==ata_cmd_in::data_out ? " OUT\n":"\n"));
! 612:
! 613: ata_cmd_out out;
! 614: bool ok = device->ata_pass_through(in, out);
! 615:
! 616: if (ata_debugmode && out.out_regs.is_set())
! 617: print_regs(" Output: ", out.out_regs);
! 618:
! 619: if (ok) switch (command) {
! 620: default:
! 621: retval = 0;
! 622: break;
! 623: case CHECK_POWER_MODE:
! 624: if (out.out_regs.sector_count.is_set()) {
! 625: data[0] = out.out_regs.sector_count;
! 626: retval = 0;
! 627: }
! 628: else {
! 629: pout("CHECK POWER MODE: incomplete response, ATA output registers missing\n");
! 630: device->set_err(ENOSYS);
! 631: retval = -1;
! 632: }
! 633: break;
! 634: case STATUS_CHECK:
! 635: // Cyl low and Cyl high unchanged means "Good SMART status"
! 636: if ((out.out_regs.lba_high == SMART_CYL_HI) &&
! 637: (out.out_regs.lba_mid == SMART_CYL_LOW))
! 638: retval = 0;
! 639: // These values mean "Bad SMART status"
! 640: else if ((out.out_regs.lba_high == SRET_STATUS_HI_EXCEEDED) &&
! 641: (out.out_regs.lba_mid == SRET_STATUS_MID_EXCEEDED))
! 642: retval = 1;
! 643: else if (out.out_regs.lba_mid == SMART_CYL_LOW) {
! 644: retval = 0;
! 645: if (ata_debugmode)
! 646: pout("SMART STATUS RETURN: half healthy response sequence, "
! 647: "probable SAT/USB truncation\n");
! 648: } else if (out.out_regs.lba_mid == SRET_STATUS_MID_EXCEEDED) {
! 649: retval = 1;
! 650: if (ata_debugmode)
! 651: pout("SMART STATUS RETURN: half unhealthy response sequence, "
! 652: "probable SAT/USB truncation\n");
! 653: }
! 654: else if (!out.out_regs.is_set()) {
! 655: pout("SMART STATUS RETURN: incomplete response, ATA output registers missing\n");
! 656: device->set_err(ENOSYS);
! 657: retval = -1;
! 658: }
! 659: else {
! 660: // We haven't gotten output that makes sense; print out some debugging info
! 661: pout("Error SMART Status command failed\n");
! 662: pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE);
! 663: pout("Register values returned from SMART Status command are:\n");
! 664: print_regs(" ", out.out_regs);
! 665: device->set_err(EIO);
! 666: retval = -1;
! 667: }
! 668: break;
! 669: }
! 670: }
! 671:
! 672: // If requested, invalidate serial number before any printing is done
! 673: if ((command == IDENTIFY || command == PIDENTIFY) && !retval && dont_print_serial_number)
! 674: invalidate_serno((ata_identify_device *)data);
! 675:
! 676: // If reporting is enabled, say what output was produced by the command
! 677: if (ata_debugmode) {
! 678: if (device->get_errno())
! 679: pout("REPORT-IOCTL: Device=%s Command=%s returned %d errno=%d [%s]\n",
! 680: device->get_dev_name(), commandstrings[command], retval,
! 681: device->get_errno(), device->get_errmsg());
! 682: else
! 683: pout("REPORT-IOCTL: Device=%s Command=%s returned %d\n",
! 684: device->get_dev_name(), commandstrings[command], retval);
! 685:
! 686: // if requested, pretty-print the output data structure
! 687: if (ata_debugmode > 1 && getsdata) {
! 688: if (command==CHECK_POWER_MODE)
! 689: pout("Sector Count Register (BASE-16): %02x\n", (unsigned char)(*data));
! 690: else
! 691: prettyprint((unsigned char *)data, commandstrings[command]);
! 692: }
! 693: }
! 694:
! 695: return retval;
! 696: }
! 697:
! 698: // Get capacity and sector sizes from IDENTIFY data
! 699: void ata_get_size_info(const ata_identify_device * id, ata_size_info & sizes)
! 700: {
! 701: sizes.sectors = sizes.capacity = 0;
! 702: sizes.log_sector_size = sizes.phy_sector_size = 0;
! 703: sizes.log_sector_offset = 0;
! 704:
! 705: // Return if no LBA support
! 706: if (!(id->words047_079[49-47] & 0x0200))
! 707: return;
! 708:
! 709: // Determine 28-bit LBA capacity
! 710: unsigned lba28 = (unsigned)id->words047_079[61-47] << 16
! 711: | (unsigned)id->words047_079[60-47] ;
! 712:
! 713: // Determine 48-bit LBA capacity if supported
! 714: uint64_t lba48 = 0;
! 715: if ((id->command_set_2 & 0xc400) == 0x4400)
! 716: lba48 = (uint64_t)id->words088_255[103-88] << 48
! 717: | (uint64_t)id->words088_255[102-88] << 32
! 718: | (uint64_t)id->words088_255[101-88] << 16
! 719: | (uint64_t)id->words088_255[100-88] ;
! 720:
! 721: // Return if capacity unknown (ATAPI CD/DVD)
! 722: if (!(lba28 || lba48))
! 723: return;
! 724:
! 725: // Determine sector sizes
! 726: sizes.log_sector_size = sizes.phy_sector_size = 512;
! 727:
! 728: unsigned short word106 = id->words088_255[106-88];
! 729: if ((word106 & 0xc000) == 0x4000) {
! 730: // Long Logical/Physical Sectors (LLS/LPS) ?
! 731: if (word106 & 0x1000)
! 732: // Logical sector size is specified in 16-bit words
! 733: sizes.log_sector_size = sizes.phy_sector_size =
! 734: ((id->words088_255[118-88] << 16) | id->words088_255[117-88]) << 1;
! 735:
! 736: if (word106 & 0x2000)
! 737: // Physical sector size is multiple of logical sector size
! 738: sizes.phy_sector_size <<= (word106 & 0x0f);
! 739:
! 740: unsigned short word209 = id->words088_255[209-88];
! 741: if ((word209 & 0xc000) == 0x4000)
! 742: sizes.log_sector_offset = (word209 & 0x3fff) * sizes.log_sector_size;
! 743: }
! 744:
! 745: // Some early 4KiB LLS disks (Samsung N3U-3) return bogus lba28 value
! 746: if (lba48 >= lba28 || (lba48 && sizes.log_sector_size > 512))
! 747: sizes.sectors = lba48;
! 748: else
! 749: sizes.sectors = lba28;
! 750:
! 751: sizes.capacity = sizes.sectors * sizes.log_sector_size;
! 752: }
! 753:
! 754: // This function computes the checksum of a single disk sector (512
! 755: // bytes). Returns zero if checksum is OK, nonzero if the checksum is
! 756: // incorrect. The size (512) is correct for all SMART structures.
! 757: unsigned char checksum(const void * data)
! 758: {
! 759: unsigned char sum = 0;
! 760: for (int i = 0; i < 512; i++)
! 761: sum += ((const unsigned char *)data)[i];
! 762: return sum;
! 763: }
! 764:
! 765: // Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents
! 766: // bytes.
! 767: static void swapbytes(char * out, const char * in, size_t n)
! 768: {
! 769: for (size_t i = 0; i < n; i += 2) {
! 770: out[i] = in[i+1];
! 771: out[i+1] = in[i];
! 772: }
! 773: }
! 774:
! 775: // Copies in to out, but removes leading and trailing whitespace.
! 776: static void trim(char * out, const char * in)
! 777: {
! 778: // Find the first non-space character (maybe none).
! 779: int first = -1;
! 780: int i;
! 781: for (i = 0; in[i]; i++)
! 782: if (!isspace((int)in[i])) {
! 783: first = i;
! 784: break;
! 785: }
! 786:
! 787: if (first == -1) {
! 788: // There are no non-space characters.
! 789: out[0] = '\0';
! 790: return;
! 791: }
! 792:
! 793: // Find the last non-space character.
! 794: for (i = strlen(in)-1; i >= first && isspace((int)in[i]); i--)
! 795: ;
! 796: int last = i;
! 797:
! 798: strncpy(out, in+first, last-first+1);
! 799: out[last-first+1] = '\0';
! 800: }
! 801:
! 802: // Convenience function for formatting strings from ata_identify_device
! 803: void ata_format_id_string(char * out, const unsigned char * in, int n)
! 804: {
! 805: bool must_swap = true;
! 806: #ifdef __NetBSD__
! 807: /* NetBSD kernel delivers IDENTIFY data in host byte order (but all else is LE) */
! 808: // TODO: Handle NetBSD case in os_netbsd.cpp
! 809: if (isbigendian())
! 810: must_swap = !must_swap;
! 811: #endif
! 812:
! 813: char tmp[65];
! 814: n = n > 64 ? 64 : n;
! 815: if (!must_swap)
! 816: strncpy(tmp, (const char *)in, n);
! 817: else
! 818: swapbytes(tmp, (const char *)in, n);
! 819: tmp[n] = '\0';
! 820: trim(out, tmp);
! 821: }
! 822:
! 823: // returns -1 if command fails or the device is in Sleep mode, else
! 824: // value of Sector Count register. Sector Count result values:
! 825: // 00h device is in Standby mode.
! 826: // 80h device is in Idle mode.
! 827: // FFh device is in Active mode or Idle mode.
! 828:
! 829: int ataCheckPowerMode(ata_device * device) {
! 830: unsigned char result;
! 831:
! 832: if ((smartcommandhandler(device, CHECK_POWER_MODE, 0, (char *)&result)))
! 833: return -1;
! 834:
! 835: if (result!=0 && result!=0x80 && result!=0xff)
! 836: pout("ataCheckPowerMode(): ATA CHECK POWER MODE returned unknown Sector Count Register value %02x\n", result);
! 837:
! 838: return (int)result;
! 839: }
! 840:
! 841: // Reads current Device Identity info (512 bytes) into buf. Returns 0
! 842: // if all OK. Returns -1 if no ATA Device identity can be
! 843: // established. Returns >0 if Device is ATA Packet Device (not SMART
! 844: // capable). The value of the integer helps identify the type of
! 845: // Packet device, which is useful so that the user can connect the
! 846: // formal device number with whatever object is inside their computer.
! 847: int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id)
! 848: {
! 849: unsigned short *rawshort=(unsigned short *)buf;
! 850: unsigned char *rawbyte =(unsigned char *)buf;
! 851:
! 852: // See if device responds either to IDENTIFY DEVICE or IDENTIFY
! 853: // PACKET DEVICE
! 854: bool packet = false;
! 855: if ((smartcommandhandler(device, IDENTIFY, 0, (char *)buf))){
! 856: if (smartcommandhandler(device, PIDENTIFY, 0, (char *)buf)){
! 857: return -1;
! 858: }
! 859: packet = true;
! 860: }
! 861:
! 862: unsigned i;
! 863: if (fix_swapped_id) {
! 864: // Swap ID strings
! 865: for (i = 0; i < sizeof(buf->serial_no)-1; i += 2)
! 866: swap2((char *)(buf->serial_no+i));
! 867: for (i = 0; i < sizeof(buf->fw_rev)-1; i += 2)
! 868: swap2((char *)(buf->fw_rev+i));
! 869: for (i = 0; i < sizeof(buf->model)-1; i += 2)
! 870: swap2((char *)(buf->model+i));
! 871: }
! 872:
! 873: #ifndef __NetBSD__
! 874: // if machine is big-endian, swap byte order as needed
! 875: // NetBSD kernel delivers IDENTIFY data in host byte order
! 876: // TODO: Handle NetBSD case in os_netbsd.cpp
! 877: if (isbigendian()){
! 878:
! 879: // swap various capability words that are needed
! 880: for (i=0; i<33; i++)
! 881: swap2((char *)(buf->words047_079+i));
! 882:
! 883: for (i=80; i<=87; i++)
! 884: swap2((char *)(rawshort+i));
! 885:
! 886: for (i=0; i<168; i++)
! 887: swap2((char *)(buf->words088_255+i));
! 888: }
! 889: #endif
! 890:
! 891: // If there is a checksum there, validate it
! 892: if ((rawshort[255] & 0x00ff) == 0x00a5 && checksum(rawbyte))
! 893: checksumwarning("Drive Identity Structure");
! 894:
! 895: // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
! 896: // T13/1699-D Revision 6a (Final Draft), September 6, 2008.
! 897: // Sections 7.16.7 and 7.17.6:
! 898: //
! 899: // Word 0 of IDENTIFY DEVICE data:
! 900: // Bit 15 = 0 : ATA device
! 901: //
! 902: // Word 0 of IDENTIFY PACKET DEVICE data:
! 903: // Bits 15:14 = 10b : ATAPI device
! 904: // Bits 15:14 = 11b : Reserved
! 905: // Bits 12:8 : Device type (SPC-4, e.g 0x05 = CD/DVD)
! 906:
! 907: // CF+ and CompactFlash Specification Revision 4.0, May 24, 2006.
! 908: // Section 6.2.1.6:
! 909: //
! 910: // Word 0 of IDENTIFY DEVICE data:
! 911: // 848Ah = Signature for CompactFlash Storage Card
! 912: // 044Ah = Alternate value turns on ATA device while preserving all retired bits
! 913: // 0040h = Alternate value turns on ATA device while zeroing all retired bits
! 914:
! 915: // Assume ATA if IDENTIFY DEVICE returns CompactFlash Signature
! 916: if (!packet && rawbyte[1] == 0x84 && rawbyte[0] == 0x8a)
! 917: return 0;
! 918:
! 919: // If this is a PACKET DEVICE, return device type
! 920: if (rawbyte[1] & 0x80)
! 921: return 1+(rawbyte[1] & 0x1f);
! 922:
! 923: // Not a PACKET DEVICE
! 924: return 0;
! 925: }
! 926:
! 927: // Returns ATA version as an integer, and a pointer to a string
! 928: // describing which revision. Note that Revision 0 of ATA-3 does NOT
! 929: // support SMART. For this one case we return -3 rather than +3 as
! 930: // the version number. See notes above.
! 931: int ataVersionInfo(const char ** description, const ata_identify_device * drive, unsigned short * minor)
! 932: {
! 933: // get major and minor ATA revision numbers
! 934: unsigned short major = drive->major_rev_num;
! 935: *minor=drive->minor_rev_num;
! 936:
! 937: // First check if device has ANY ATA version information in it
! 938: if (major==NOVAL_0 || major==NOVAL_1) {
! 939: *description=NULL;
! 940: return 0; // No info found
! 941: }
! 942:
! 943: // The minor revision number has more information - try there first
! 944: if (*minor && (*minor<=MINOR_MAX)){
! 945: int std = actual_ver[*minor];
! 946: if (std) {
! 947: *description=minor_str[*minor];
! 948: return std;
! 949: }
! 950: }
! 951:
! 952: // Try new ATA-8 ACS minor revision numbers.
! 953: // Table 55 of T13/2015-D Revision 4a (ACS-2), December 9, 2010.
! 954: // (not in actual_ver/minor_str to avoid large sparse tables)
! 955: const char *desc;
! 956: switch (*minor) {
! 957: case 0x0027: desc = "ATA-8-ACS revision 3c"; break;
! 958: case 0x0028: desc = "ATA-8-ACS revision 6"; break;
! 959: case 0x0029: desc = "ATA-8-ACS revision 4"; break;
! 960: case 0x0031: desc = "ACS-2 revision 2"; break;
! 961: case 0x0033: desc = "ATA-8-ACS revision 3e"; break;
! 962: case 0x0039: desc = "ATA-8-ACS revision 4c"; break;
! 963: case 0x0042: desc = "ATA-8-ACS revision 3f"; break;
! 964: case 0x0052: desc = "ATA-8-ACS revision 3b"; break;
! 965: case 0x0107: desc = "ATA-8-ACS revision 2d"; break;
! 966: case 0x0110: desc = "ACS-2 revision 3"; break;
! 967: default: desc = 0; break;
! 968: }
! 969: if (desc) {
! 970: *description = desc;
! 971: return 8;
! 972: }
! 973:
! 974: // HDPARM has a very complicated algorithm from here on. Since SMART only
! 975: // exists on ATA-3 and later standards, let's punt on this. If you don't
! 976: // like it, please fix it. The code's in CVS.
! 977: int i;
! 978: for (i=15; i>0; i--)
! 979: if (major & (0x1<<i))
! 980: break;
! 981:
! 982: *description=NULL;
! 983: if (i==0)
! 984: return 1;
! 985: else
! 986: return i;
! 987: }
! 988:
! 989: // Get World Wide Name (WWN) fields.
! 990: // Return NAA field or -1 if WWN is unsupported.
! 991: // Table 34 of T13/1699-D Revision 6a (ATA8-ACS), September 6, 2008.
! 992: // (WWN was introduced in ATA/ATAPI-7 and is mandatory since ATA8-ACS Revision 3b)
! 993: int ata_get_wwn(const ata_identify_device * id, unsigned & oui, uint64_t & unique_id)
! 994: {
! 995: // Don't use word 84 to be compatible with some older ATA-7 disks
! 996: unsigned short word087 = id->csf_default;
! 997: if ((word087 & 0xc100) != 0x4100)
! 998: return -1; // word not valid or WWN support bit 8 not set
! 999:
! 1000: unsigned short word108 = id->words088_255[108-88];
! 1001: unsigned short word109 = id->words088_255[109-88];
! 1002: unsigned short word110 = id->words088_255[110-88];
! 1003: unsigned short word111 = id->words088_255[111-88];
! 1004:
! 1005: oui = ((word108 & 0x0fff) << 12) | (word109 >> 4);
! 1006: unique_id = ((uint64_t)(word109 & 0xf) << 32)
! 1007: | (unsigned)((word110 << 16) | word111);
! 1008: return (word108 >> 12);
! 1009: }
! 1010:
! 1011: // returns 1 if SMART supported, 0 if SMART unsupported, -1 if can't tell
! 1012: int ataSmartSupport(const ata_identify_device * drive)
! 1013: {
! 1014: unsigned short word82=drive->command_set_1;
! 1015: unsigned short word83=drive->command_set_2;
! 1016:
! 1017: // check if words 82/83 contain valid info
! 1018: if ((word83>>14) == 0x01)
! 1019: // return value of SMART support bit
! 1020: return word82 & 0x0001;
! 1021:
! 1022: // since we can're rely on word 82, we don't know if SMART supported
! 1023: return -1;
! 1024: }
! 1025:
! 1026: // returns 1 if SMART enabled, 0 if SMART disabled, -1 if can't tell
! 1027: int ataIsSmartEnabled(const ata_identify_device * drive)
! 1028: {
! 1029: unsigned short word85=drive->cfs_enable_1;
! 1030: unsigned short word87=drive->csf_default;
! 1031:
! 1032: // check if words 85/86/87 contain valid info
! 1033: if ((word87>>14) == 0x01)
! 1034: // return value of SMART enabled bit
! 1035: return word85 & 0x0001;
! 1036:
! 1037: // Since we can't rely word85, we don't know if SMART is enabled.
! 1038: return -1;
! 1039: }
! 1040:
! 1041:
! 1042: // Reads SMART attributes into *data
! 1043: int ataReadSmartValues(ata_device * device, struct ata_smart_values *data){
! 1044:
! 1045: if (smartcommandhandler(device, READ_VALUES, 0, (char *)data)){
! 1046: pout("Error SMART Values Read failed: %s\n", device->get_errmsg());
! 1047: return -1;
! 1048: }
! 1049:
! 1050: // compute checksum
! 1051: if (checksum(data))
! 1052: checksumwarning("SMART Attribute Data Structure");
! 1053:
! 1054: // swap endian order if needed
! 1055: if (isbigendian()){
! 1056: int i;
! 1057: swap2((char *)&(data->revnumber));
! 1058: swap2((char *)&(data->total_time_to_complete_off_line));
! 1059: swap2((char *)&(data->smart_capability));
! 1060: for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){
! 1061: struct ata_smart_attribute *x=data->vendor_attributes+i;
! 1062: swap2((char *)&(x->flags));
! 1063: }
! 1064: }
! 1065:
! 1066: return 0;
! 1067: }
! 1068:
! 1069:
! 1070: // This corrects some quantities that are byte reversed in the SMART
! 1071: // SELF TEST LOG
! 1072: static void fixsamsungselftestlog(ata_smart_selftestlog * data)
! 1073: {
! 1074: // bytes 508/509 (numbered from 0) swapped (swap of self-test index
! 1075: // with one byte of reserved.
! 1076: swap2((char *)&(data->mostrecenttest));
! 1077:
! 1078: // LBA low register (here called 'selftestnumber", containing
! 1079: // information about the TYPE of the self-test) is byte swapped with
! 1080: // Self-test execution status byte. These are bytes N, N+1 in the
! 1081: // entries.
! 1082: for (int i = 0; i < 21; i++)
! 1083: swap2((char *)&(data->selftest_struct[i].selftestnumber));
! 1084:
! 1085: return;
! 1086: }
! 1087:
! 1088: // Reads the Self Test Log (log #6)
! 1089: int ataReadSelfTestLog (ata_device * device, ata_smart_selftestlog * data,
! 1090: unsigned char fix_firmwarebug)
! 1091: {
! 1092:
! 1093: // get data from device
! 1094: if (smartcommandhandler(device, READ_LOG, 0x06, (char *)data)){
! 1095: pout("Error SMART Error Self-Test Log Read failed: %s\n", device->get_errmsg());
! 1096: return -1;
! 1097: }
! 1098:
! 1099: // compute its checksum, and issue a warning if needed
! 1100: if (checksum(data))
! 1101: checksumwarning("SMART Self-Test Log Structure");
! 1102:
! 1103: // fix firmware bugs in self-test log
! 1104: if (fix_firmwarebug == FIX_SAMSUNG)
! 1105: fixsamsungselftestlog(data);
! 1106:
! 1107: // swap endian order if needed
! 1108: if (isbigendian()){
! 1109: int i;
! 1110: swap2((char*)&(data->revnumber));
! 1111: for (i=0; i<21; i++){
! 1112: struct ata_smart_selftestlog_struct *x=data->selftest_struct+i;
! 1113: swap2((char *)&(x->timestamp));
! 1114: swap4((char *)&(x->lbafirstfailure));
! 1115: }
! 1116: }
! 1117:
! 1118: return 0;
! 1119: }
! 1120:
! 1121: // Print checksum warning for multi sector log
! 1122: static void check_multi_sector_sum(const void * data, unsigned nsectors, const char * msg)
! 1123: {
! 1124: unsigned errs = 0;
! 1125: for (unsigned i = 0; i < nsectors; i++) {
! 1126: if (checksum((const unsigned char *)data + i*512))
! 1127: errs++;
! 1128: }
! 1129: if (errs > 0) {
! 1130: if (nsectors == 1)
! 1131: checksumwarning(msg);
! 1132: else
! 1133: checksumwarning(strprintf("%s (%u/%u)", msg, errs, nsectors).c_str());
! 1134: }
! 1135: }
! 1136:
! 1137: // Read SMART Extended Self-test Log
! 1138: bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log,
! 1139: unsigned nsectors)
! 1140: {
! 1141: if (!ataReadLogExt(device, 0x07, 0x00, 0, log, nsectors))
! 1142: return false;
! 1143:
! 1144: check_multi_sector_sum(log, nsectors, "SMART Extended Self-test Log Structure");
! 1145:
! 1146: if (isbigendian()) {
! 1147: swapx(&log->log_desc_index);
! 1148: for (unsigned i = 0; i < nsectors; i++) {
! 1149: for (unsigned j = 0; j < 19; j++)
! 1150: swapx(&log->log_descs[i].timestamp);
! 1151: }
! 1152: }
! 1153: return true;
! 1154: }
! 1155:
! 1156:
! 1157: // Read GP Log page(s)
! 1158: bool ataReadLogExt(ata_device * device, unsigned char logaddr,
! 1159: unsigned char features, unsigned page,
! 1160: void * data, unsigned nsectors)
! 1161: {
! 1162: ata_cmd_in in;
! 1163: in.in_regs.command = ATA_READ_LOG_EXT;
! 1164: in.in_regs.features = features; // log specific
! 1165: in.set_data_in_48bit(data, nsectors);
! 1166: in.in_regs.lba_low = logaddr;
! 1167: in.in_regs.lba_mid_16 = page;
! 1168:
! 1169: if (!device->ata_pass_through(in)) { // TODO: Debug output
! 1170: if (nsectors <= 1) {
! 1171: pout("ATA_READ_LOG_EXT (addr=0x%02x:0x%02x, page=%u, n=%u) failed: %s\n",
! 1172: logaddr, features, page, nsectors, device->get_errmsg());
! 1173: return false;
! 1174: }
! 1175:
! 1176: // Recurse to retry with single sectors,
! 1177: // multi-sector reads may not be supported by ioctl.
! 1178: for (unsigned i = 0; i < nsectors; i++) {
! 1179: if (!ataReadLogExt(device, logaddr,
! 1180: features, page + i,
! 1181: (char *)data + 512*i, 1))
! 1182: return false;
! 1183: }
! 1184: }
! 1185:
! 1186: return true;
! 1187: }
! 1188:
! 1189: // Read SMART Log page(s)
! 1190: bool ataReadSmartLog(ata_device * device, unsigned char logaddr,
! 1191: void * data, unsigned nsectors)
! 1192: {
! 1193: ata_cmd_in in;
! 1194: in.in_regs.command = ATA_SMART_CMD;
! 1195: in.in_regs.features = ATA_SMART_READ_LOG_SECTOR;
! 1196: in.set_data_in(data, nsectors);
! 1197: in.in_regs.lba_high = SMART_CYL_HI;
! 1198: in.in_regs.lba_mid = SMART_CYL_LOW;
! 1199: in.in_regs.lba_low = logaddr;
! 1200:
! 1201: if (!device->ata_pass_through(in)) { // TODO: Debug output
! 1202: pout("ATA_SMART_READ_LOG failed: %s\n", device->get_errmsg());
! 1203: return false;
! 1204: }
! 1205: return true;
! 1206: }
! 1207:
! 1208:
! 1209:
! 1210: // Reads the SMART or GPL Log Directory (log #0)
! 1211: int ataReadLogDirectory(ata_device * device, ata_smart_log_directory * data, bool gpl)
! 1212: {
! 1213: if (!gpl) { // SMART Log directory
! 1214: if (smartcommandhandler(device, READ_LOG, 0x00, (char *)data))
! 1215: return -1;
! 1216: }
! 1217: else { // GP Log directory
! 1218: if (!ataReadLogExt(device, 0x00, 0x00, 0, data, 1))
! 1219: return -1;
! 1220: }
! 1221:
! 1222: // swap endian order if needed
! 1223: if (isbigendian())
! 1224: swapx(&data->logversion);
! 1225:
! 1226: return 0;
! 1227: }
! 1228:
! 1229:
! 1230: // Reads the selective self-test log (log #9)
! 1231: int ataReadSelectiveSelfTestLog(ata_device * device, struct ata_selective_self_test_log *data){
! 1232:
! 1233: // get data from device
! 1234: if (smartcommandhandler(device, READ_LOG, 0x09, (char *)data)){
! 1235: pout("Error SMART Read Selective Self-Test Log failed: %s\n", device->get_errmsg());
! 1236: return -1;
! 1237: }
! 1238:
! 1239: // compute its checksum, and issue a warning if needed
! 1240: if (checksum(data))
! 1241: checksumwarning("SMART Selective Self-Test Log Structure");
! 1242:
! 1243: // swap endian order if needed
! 1244: if (isbigendian()){
! 1245: int i;
! 1246: swap2((char *)&(data->logversion));
! 1247: for (i=0;i<5;i++){
! 1248: swap8((char *)&(data->span[i].start));
! 1249: swap8((char *)&(data->span[i].end));
! 1250: }
! 1251: swap8((char *)&(data->currentlba));
! 1252: swap2((char *)&(data->currentspan));
! 1253: swap2((char *)&(data->flags));
! 1254: swap2((char *)&(data->pendingtime));
! 1255: }
! 1256:
! 1257: if (data->logversion != 1)
! 1258: pout("Note: selective self-test log revision number (%d) not 1 implies that no selective self-test has ever been run\n", data->logversion);
! 1259:
! 1260: return 0;
! 1261: }
! 1262:
! 1263: // Writes the selective self-test log (log #9)
! 1264: int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args,
! 1265: const ata_smart_values * sv, uint64_t num_sectors,
! 1266: const ata_selective_selftest_args * prev_args)
! 1267: {
! 1268: // Disk size must be known
! 1269: if (!num_sectors) {
! 1270: pout("Disk size is unknown, unable to check selective self-test spans\n");
! 1271: return -1;
! 1272: }
! 1273:
! 1274: // Read log
! 1275: struct ata_selective_self_test_log sstlog, *data=&sstlog;
! 1276: unsigned char *ptr=(unsigned char *)data;
! 1277: if (ataReadSelectiveSelfTestLog(device, data)) {
! 1278: pout("Since Read failed, will not attempt to WRITE Selective Self-test Log\n");
! 1279: return -1;
! 1280: }
! 1281:
! 1282: // Set log version
! 1283: data->logversion = 1;
! 1284:
! 1285: // Host is NOT allowed to write selective self-test log if a selective
! 1286: // self-test is in progress.
! 1287: if (0<data->currentspan && data->currentspan<6 && ((sv->self_test_exec_status)>>4)==15) {
! 1288: pout("Error SMART Selective or other Self-Test in progress.\n");
! 1289: return -4;
! 1290: }
! 1291:
! 1292: // Set start/end values based on old spans for special -t select,... options
! 1293: int i;
! 1294: for (i = 0; i < args.num_spans; i++) {
! 1295: int mode = args.span[i].mode;
! 1296: uint64_t start = args.span[i].start;
! 1297: uint64_t end = args.span[i].end;
! 1298: if (mode == SEL_CONT) {// redo or next dependig on last test status
! 1299: switch (sv->self_test_exec_status >> 4) {
! 1300: case 1: case 2: // Aborted/Interrupted by host
! 1301: pout("Continue Selective Self-Test: Redo last span\n");
! 1302: mode = SEL_REDO;
! 1303: break;
! 1304: default: // All others
! 1305: pout("Continue Selective Self-Test: Start next span\n");
! 1306: mode = SEL_NEXT;
! 1307: break;
! 1308: }
! 1309: }
! 1310:
! 1311: if ( (mode == SEL_REDO || mode == SEL_NEXT)
! 1312: && prev_args && i < prev_args->num_spans
! 1313: && !data->span[i].start && !data->span[i].end) {
! 1314: // Some drives do not preserve the selective self-test log accross
! 1315: // power-cyles. If old span on drive is cleared use span provided
! 1316: // by caller. This is used by smartd (first span only).
! 1317: data->span[i].start = prev_args->span[i].start;
! 1318: data->span[i].end = prev_args->span[i].end;
! 1319: }
! 1320:
! 1321: switch (mode) {
! 1322: case SEL_RANGE: // -t select,START-END
! 1323: break;
! 1324: case SEL_REDO: // -t select,redo... => Redo current
! 1325: start = data->span[i].start;
! 1326: if (end > 0) { // -t select,redo+SIZE
! 1327: end--; end += start; // [oldstart, oldstart+SIZE)
! 1328: }
! 1329: else // -t select,redo
! 1330: end = data->span[i].end; // [oldstart, oldend]
! 1331: break;
! 1332: case SEL_NEXT: // -t select,next... => Do next
! 1333: if (data->span[i].end == 0) {
! 1334: start = end = 0; break; // skip empty spans
! 1335: }
! 1336: start = data->span[i].end + 1;
! 1337: if (start >= num_sectors)
! 1338: start = 0; // wrap around
! 1339: if (end > 0) { // -t select,next+SIZE
! 1340: end--; end += start; // (oldend, oldend+SIZE]
! 1341: }
! 1342: else { // -t select,next
! 1343: uint64_t oldsize = data->span[i].end - data->span[i].start + 1;
! 1344: end = start + oldsize - 1; // (oldend, oldend+oldsize]
! 1345: if (end >= num_sectors) {
! 1346: // Adjust size to allow round-robin testing without future size decrease
! 1347: uint64_t spans = (num_sectors + oldsize-1) / oldsize;
! 1348: uint64_t newsize = (num_sectors + spans-1) / spans;
! 1349: uint64_t newstart = num_sectors - newsize, newend = num_sectors - 1;
! 1350: pout("Span %d changed from %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n",
! 1351: i, start, end, oldsize);
! 1352: pout(" to %"PRIu64"-%"PRIu64" (%"PRIu64" sectors) (%"PRIu64" spans)\n",
! 1353: newstart, newend, newsize, spans);
! 1354: start = newstart; end = newend;
! 1355: }
! 1356: }
! 1357: break;
! 1358: default:
! 1359: pout("ataWriteSelectiveSelfTestLog: Invalid mode %d\n", mode);
! 1360: return -1;
! 1361: }
! 1362: // Range check
! 1363: if (start < num_sectors && num_sectors <= end) {
! 1364: if (end != ~(uint64_t)0) // -t select,N-max
! 1365: pout("Size of self-test span %d decreased according to disk size\n", i);
! 1366: end = num_sectors - 1;
! 1367: }
! 1368: if (!(start <= end && end < num_sectors)) {
! 1369: pout("Invalid selective self-test span %d: %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n",
! 1370: i, start, end, num_sectors);
! 1371: return -1;
! 1372: }
! 1373: // Return the actual mode and range to caller.
! 1374: args.span[i].mode = mode;
! 1375: args.span[i].start = start;
! 1376: args.span[i].end = end;
! 1377: }
! 1378:
! 1379: // Clear spans
! 1380: for (i=0; i<5; i++)
! 1381: memset(data->span+i, 0, sizeof(struct test_span));
! 1382:
! 1383: // Set spans for testing
! 1384: for (i = 0; i < args.num_spans; i++){
! 1385: data->span[i].start = args.span[i].start;
! 1386: data->span[i].end = args.span[i].end;
! 1387: }
! 1388:
! 1389: // host must initialize to zero before initiating selective self-test
! 1390: data->currentlba=0;
! 1391: data->currentspan=0;
! 1392:
! 1393: // Perform off-line scan after selective test?
! 1394: if (args.scan_after_select == 1)
! 1395: // NO
! 1396: data->flags &= ~SELECTIVE_FLAG_DOSCAN;
! 1397: else if (args.scan_after_select == 2)
! 1398: // YES
! 1399: data->flags |= SELECTIVE_FLAG_DOSCAN;
! 1400:
! 1401: // Must clear active and pending flags before writing
! 1402: data->flags &= ~(SELECTIVE_FLAG_ACTIVE);
! 1403: data->flags &= ~(SELECTIVE_FLAG_PENDING);
! 1404:
! 1405: // modify pending time?
! 1406: if (args.pending_time)
! 1407: data->pendingtime = (unsigned short)(args.pending_time-1);
! 1408:
! 1409: // Set checksum to zero, then compute checksum
! 1410: data->checksum=0;
! 1411: unsigned char cksum=0;
! 1412: for (i=0; i<512; i++)
! 1413: cksum+=ptr[i];
! 1414: cksum=~cksum;
! 1415: cksum+=1;
! 1416: data->checksum=cksum;
! 1417:
! 1418: // swap endian order if needed
! 1419: if (isbigendian()){
! 1420: swap2((char *)&(data->logversion));
! 1421: for (int b = 0; b < 5; b++) {
! 1422: swap8((char *)&(data->span[b].start));
! 1423: swap8((char *)&(data->span[b].end));
! 1424: }
! 1425: swap8((char *)&(data->currentlba));
! 1426: swap2((char *)&(data->currentspan));
! 1427: swap2((char *)&(data->flags));
! 1428: swap2((char *)&(data->pendingtime));
! 1429: }
! 1430:
! 1431: // write new selective self-test log
! 1432: if (smartcommandhandler(device, WRITE_LOG, 0x09, (char *)data)){
! 1433: pout("Error Write Selective Self-Test Log failed: %s\n", device->get_errmsg());
! 1434: return -3;
! 1435: }
! 1436:
! 1437: return 0;
! 1438: }
! 1439:
! 1440: // This corrects some quantities that are byte reversed in the SMART
! 1441: // ATA ERROR LOG.
! 1442: static void fixsamsungerrorlog(ata_smart_errorlog * data)
! 1443: {
! 1444: // FIXED IN SAMSUNG -25 FIRMWARE???
! 1445: // Device error count in bytes 452-3
! 1446: swap2((char *)&(data->ata_error_count));
! 1447:
! 1448: // FIXED IN SAMSUNG -22a FIRMWARE
! 1449: // step through 5 error log data structures
! 1450: for (int i = 0; i < 5; i++){
! 1451: // step through 5 command data structures
! 1452: for (int j = 0; j < 5; j++)
! 1453: // Command data structure 4-byte millisec timestamp. These are
! 1454: // bytes (N+8, N+9, N+10, N+11).
! 1455: swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp));
! 1456: // Error data structure two-byte hour life timestamp. These are
! 1457: // bytes (N+28, N+29).
! 1458: swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp));
! 1459: }
! 1460: return;
! 1461: }
! 1462:
! 1463: // NEEDED ONLY FOR SAMSUNG -22 (some) -23 AND -24?? FIRMWARE
! 1464: static void fixsamsungerrorlog2(ata_smart_errorlog * data)
! 1465: {
! 1466: // Device error count in bytes 452-3
! 1467: swap2((char *)&(data->ata_error_count));
! 1468: return;
! 1469: }
! 1470:
! 1471: // Reads the Summary SMART Error Log (log #1). The Comprehensive SMART
! 1472: // Error Log is #2, and the Extended Comprehensive SMART Error log is
! 1473: // #3
! 1474: int ataReadErrorLog (ata_device * device, ata_smart_errorlog *data,
! 1475: unsigned char fix_firmwarebug)
! 1476: {
! 1477:
! 1478: // get data from device
! 1479: if (smartcommandhandler(device, READ_LOG, 0x01, (char *)data)){
! 1480: pout("Error SMART Error Log Read failed: %s\n", device->get_errmsg());
! 1481: return -1;
! 1482: }
! 1483:
! 1484: // compute its checksum, and issue a warning if needed
! 1485: if (checksum(data))
! 1486: checksumwarning("SMART ATA Error Log Structure");
! 1487:
! 1488: // Some disks have the byte order reversed in some SMART Summary
! 1489: // Error log entries
! 1490: if (fix_firmwarebug == FIX_SAMSUNG)
! 1491: fixsamsungerrorlog(data);
! 1492: else if (fix_firmwarebug == FIX_SAMSUNG2)
! 1493: fixsamsungerrorlog2(data);
! 1494:
! 1495: // swap endian order if needed
! 1496: if (isbigendian()){
! 1497: int i,j;
! 1498:
! 1499: // Device error count in bytes 452-3
! 1500: swap2((char *)&(data->ata_error_count));
! 1501:
! 1502: // step through 5 error log data structures
! 1503: for (i=0; i<5; i++){
! 1504: // step through 5 command data structures
! 1505: for (j=0; j<5; j++)
! 1506: // Command data structure 4-byte millisec timestamp
! 1507: swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp));
! 1508: // Error data structure life timestamp
! 1509: swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp));
! 1510: }
! 1511: }
! 1512:
! 1513: return 0;
! 1514: }
! 1515:
! 1516: // Read Extended Comprehensive Error Log
! 1517: bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log,
! 1518: unsigned nsectors)
! 1519: {
! 1520: if (!ataReadLogExt(device, 0x03, 0x00, 0, log, nsectors))
! 1521: return false;
! 1522:
! 1523: check_multi_sector_sum(log, nsectors, "SMART Extended Comprehensive Error Log Structure");
! 1524:
! 1525: if (isbigendian()) {
! 1526: swapx(&log->device_error_count);
! 1527: swapx(&log->error_log_index);
! 1528:
! 1529: for (unsigned i = 0; i < nsectors; i++) {
! 1530: for (unsigned j = 0; j < 4; j++)
! 1531: swapx(&log->error_logs[i].commands[j].timestamp);
! 1532: swapx(&log->error_logs[i].error.timestamp);
! 1533: }
! 1534: }
! 1535:
! 1536: return true;
! 1537: }
! 1538:
! 1539:
! 1540: int ataReadSmartThresholds (ata_device * device, struct ata_smart_thresholds_pvt *data){
! 1541:
! 1542: // get data from device
! 1543: if (smartcommandhandler(device, READ_THRESHOLDS, 0, (char *)data)){
! 1544: pout("Error SMART Thresholds Read failed: %s\n", device->get_errmsg());
! 1545: return -1;
! 1546: }
! 1547:
! 1548: // compute its checksum, and issue a warning if needed
! 1549: if (checksum(data))
! 1550: checksumwarning("SMART Attribute Thresholds Structure");
! 1551:
! 1552: // swap endian order if needed
! 1553: if (isbigendian())
! 1554: swap2((char *)&(data->revnumber));
! 1555:
! 1556: return 0;
! 1557: }
! 1558:
! 1559: int ataEnableSmart (ata_device * device ){
! 1560: if (smartcommandhandler(device, ENABLE, 0, NULL)){
! 1561: pout("Error SMART Enable failed: %s\n", device->get_errmsg());
! 1562: return -1;
! 1563: }
! 1564: return 0;
! 1565: }
! 1566:
! 1567: int ataDisableSmart (ata_device * device ){
! 1568:
! 1569: if (smartcommandhandler(device, DISABLE, 0, NULL)){
! 1570: pout("Error SMART Disable failed: %s\n", device->get_errmsg());
! 1571: return -1;
! 1572: }
! 1573: return 0;
! 1574: }
! 1575:
! 1576: int ataEnableAutoSave(ata_device * device){
! 1577: if (smartcommandhandler(device, AUTOSAVE, 241, NULL)){
! 1578: pout("Error SMART Enable Auto-save failed: %s\n", device->get_errmsg());
! 1579: return -1;
! 1580: }
! 1581: return 0;
! 1582: }
! 1583:
! 1584: int ataDisableAutoSave(ata_device * device){
! 1585:
! 1586: if (smartcommandhandler(device, AUTOSAVE, 0, NULL)){
! 1587: pout("Error SMART Disable Auto-save failed: %s\n", device->get_errmsg());
! 1588: return -1;
! 1589: }
! 1590: return 0;
! 1591: }
! 1592:
! 1593: // In *ALL* ATA standards the Enable/Disable AutoOffline command is
! 1594: // marked "OBSOLETE". It is defined in SFF-8035i Revision 2, and most
! 1595: // vendors still support it for backwards compatibility. IBM documents
! 1596: // it for some drives.
! 1597: int ataEnableAutoOffline (ata_device * device){
! 1598:
! 1599: /* timer hard coded to 4 hours */
! 1600: if (smartcommandhandler(device, AUTO_OFFLINE, 248, NULL)){
! 1601: pout("Error SMART Enable Automatic Offline failed: %s\n", device->get_errmsg());
! 1602: return -1;
! 1603: }
! 1604: return 0;
! 1605: }
! 1606:
! 1607: // Another Obsolete Command. See comments directly above, associated
! 1608: // with the corresponding Enable command.
! 1609: int ataDisableAutoOffline (ata_device * device){
! 1610:
! 1611: if (smartcommandhandler(device, AUTO_OFFLINE, 0, NULL)){
! 1612: pout("Error SMART Disable Automatic Offline failed: %s\n", device->get_errmsg());
! 1613: return -1;
! 1614: }
! 1615: return 0;
! 1616: }
! 1617:
! 1618: // If SMART is enabled, supported, and working, then this call is
! 1619: // guaranteed to return 1, else zero. Note that it should return 1
! 1620: // regardless of whether the disk's SMART status is 'healthy' or
! 1621: // 'failing'.
! 1622: int ataDoesSmartWork(ata_device * device){
! 1623: int retval=smartcommandhandler(device, STATUS, 0, NULL);
! 1624:
! 1625: if (-1 == retval)
! 1626: return 0;
! 1627:
! 1628: return 1;
! 1629: }
! 1630:
! 1631: // This function uses a different interface (DRIVE_TASK) than the
! 1632: // other commands in this file.
! 1633: int ataSmartStatus2(ata_device * device){
! 1634: return smartcommandhandler(device, STATUS_CHECK, 0, NULL);
! 1635: }
! 1636:
! 1637: // This is the way to execute ALL tests: offline, short self-test,
! 1638: // extended self test, with and without captive mode, etc.
! 1639: // TODO: Move to ataprint.cpp ?
! 1640: int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest_args & selargs,
! 1641: const ata_smart_values * sv, uint64_t num_sectors)
! 1642: {
! 1643: char cmdmsg[128]; const char *type, *captive;
! 1644: int cap, retval, select=0;
! 1645:
! 1646: // Boolean, if set, says test is captive
! 1647: cap=testtype & CAPTIVE_MASK;
! 1648:
! 1649: // Set up strings that describe the type of test
! 1650: if (cap)
! 1651: captive="captive";
! 1652: else
! 1653: captive="off-line";
! 1654:
! 1655: if (testtype==OFFLINE_FULL_SCAN)
! 1656: type="off-line";
! 1657: else if (testtype==SHORT_SELF_TEST || testtype==SHORT_CAPTIVE_SELF_TEST)
! 1658: type="Short self-test";
! 1659: else if (testtype==EXTEND_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST)
! 1660: type="Extended self-test";
! 1661: else if (testtype==CONVEYANCE_SELF_TEST || testtype==CONVEYANCE_CAPTIVE_SELF_TEST)
! 1662: type="Conveyance self-test";
! 1663: else if ((select=(testtype==SELECTIVE_SELF_TEST || testtype==SELECTIVE_CAPTIVE_SELF_TEST)))
! 1664: type="Selective self-test";
! 1665: else
! 1666: type = 0;
! 1667:
! 1668: // If doing a selective self-test, first use WRITE_LOG to write the
! 1669: // selective self-test log.
! 1670: ata_selective_selftest_args selargs_io = selargs; // filled with info about actual spans
! 1671: if (select && (retval = ataWriteSelectiveSelfTestLog(device, selargs_io, sv, num_sectors))) {
! 1672: if (retval==-4)
! 1673: pout("Can't start selective self-test without aborting current test: use '-X' option to smartctl.\n");
! 1674: return retval;
! 1675: }
! 1676:
! 1677: // Print ouf message that we are sending the command to test
! 1678: if (testtype==ABORT_SELF_TEST)
! 1679: sprintf(cmdmsg,"Abort SMART off-line mode self-test routine");
! 1680: else if (!type)
! 1681: sprintf(cmdmsg, "SMART EXECUTE OFF-LINE IMMEDIATE subcommand 0x%02x", testtype);
! 1682: else
! 1683: sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive);
! 1684: pout("Sending command: \"%s\".\n",cmdmsg);
! 1685:
! 1686: if (select) {
! 1687: int i;
! 1688: pout("SPAN STARTING_LBA ENDING_LBA\n");
! 1689: for (i = 0; i < selargs_io.num_spans; i++)
! 1690: pout(" %d %20"PRId64" %20"PRId64"\n", i,
! 1691: selargs_io.span[i].start,
! 1692: selargs_io.span[i].end);
! 1693: }
! 1694:
! 1695: // Now send the command to test
! 1696: if (smartcommandhandler(device, IMMEDIATE_OFFLINE, testtype, NULL)) {
! 1697: if (!(cap && device->get_errno() == EIO)) {
! 1698: pout("Command \"%s\" failed: %s\n", cmdmsg, device->get_errmsg());
! 1699: return -1;
! 1700: }
! 1701: }
! 1702:
! 1703: // Since the command succeeded, tell user
! 1704: if (testtype==ABORT_SELF_TEST)
! 1705: pout("Self-testing aborted!\n");
! 1706: else {
! 1707: pout("Drive command \"%s\" successful.\n", cmdmsg);
! 1708: if (type)
! 1709: pout("Testing has begun.\n");
! 1710: }
! 1711: return 0;
! 1712: }
! 1713:
! 1714: /* Test Time Functions */
! 1715: int TestTime(const ata_smart_values *data, int testtype)
! 1716: {
! 1717: switch (testtype){
! 1718: case OFFLINE_FULL_SCAN:
! 1719: return (int) data->total_time_to_complete_off_line;
! 1720: case SHORT_SELF_TEST:
! 1721: case SHORT_CAPTIVE_SELF_TEST:
! 1722: return (int) data->short_test_completion_time;
! 1723: case EXTEND_SELF_TEST:
! 1724: case EXTEND_CAPTIVE_SELF_TEST:
! 1725: return (int) data->extend_test_completion_time;
! 1726: case CONVEYANCE_SELF_TEST:
! 1727: case CONVEYANCE_CAPTIVE_SELF_TEST:
! 1728: return (int) data->conveyance_test_completion_time;
! 1729: default:
! 1730: return 0;
! 1731: }
! 1732: }
! 1733:
! 1734: // This function tells you both about the ATA error log and the
! 1735: // self-test error log capability (introduced in ATA-5). The bit is
! 1736: // poorly documented in the ATA/ATAPI standard. Starting with ATA-6,
! 1737: // SMART error logging is also indicated in bit 0 of DEVICE IDENTIFY
! 1738: // word 84 and 87. Top two bits must match the pattern 01. BEFORE
! 1739: // ATA-6 these top two bits still had to match the pattern 01, but the
! 1740: // remaining bits were reserved (==0).
! 1741: int isSmartErrorLogCapable (const ata_smart_values * data, const ata_identify_device * identity)
! 1742: {
! 1743: unsigned short word84=identity->command_set_extension;
! 1744: unsigned short word87=identity->csf_default;
! 1745: int isata6=identity->major_rev_num & (0x01<<6);
! 1746: int isata7=identity->major_rev_num & (0x01<<7);
! 1747:
! 1748: if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x01))
! 1749: return 1;
! 1750:
! 1751: if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x01))
! 1752: return 1;
! 1753:
! 1754: // otherwise we'll use the poorly documented capability bit
! 1755: return data->errorlog_capability & 0x01;
! 1756: }
! 1757:
! 1758: // See previous function. If the error log exists then the self-test
! 1759: // log should (must?) also exist.
! 1760: int isSmartTestLogCapable (const ata_smart_values * data, const ata_identify_device *identity)
! 1761: {
! 1762: unsigned short word84=identity->command_set_extension;
! 1763: unsigned short word87=identity->csf_default;
! 1764: int isata6=identity->major_rev_num & (0x01<<6);
! 1765: int isata7=identity->major_rev_num & (0x01<<7);
! 1766:
! 1767: if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x02))
! 1768: return 1;
! 1769:
! 1770: if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x02))
! 1771: return 1;
! 1772:
! 1773:
! 1774: // otherwise we'll use the poorly documented capability bit
! 1775: return data->errorlog_capability & 0x01;
! 1776: }
! 1777:
! 1778:
! 1779: int isGeneralPurposeLoggingCapable(const ata_identify_device *identity)
! 1780: {
! 1781: unsigned short word84=identity->command_set_extension;
! 1782: unsigned short word87=identity->csf_default;
! 1783:
! 1784: // If bit 14 of word 84 is set to one and bit 15 of word 84 is
! 1785: // cleared to zero, the contents of word 84 contains valid support
! 1786: // information. If not, support information is not valid in this
! 1787: // word.
! 1788: if ((word84>>14) == 0x01)
! 1789: // If bit 5 of word 84 is set to one, the device supports the
! 1790: // General Purpose Logging feature set.
! 1791: return (word84 & (0x01 << 5));
! 1792:
! 1793: // If bit 14 of word 87 is set to one and bit 15 of word 87 is
! 1794: // cleared to zero, the contents of words (87:85) contain valid
! 1795: // information. If not, information is not valid in these words.
! 1796: if ((word87>>14) == 0x01)
! 1797: // If bit 5 of word 87 is set to one, the device supports
! 1798: // the General Purpose Logging feature set.
! 1799: return (word87 & (0x01 << 5));
! 1800:
! 1801: // not capable
! 1802: return 0;
! 1803: }
! 1804:
! 1805:
! 1806: // SMART self-test capability is also indicated in bit 1 of DEVICE
! 1807: // IDENTIFY word 87 (if top two bits of word 87 match pattern 01).
! 1808: // However this was only introduced in ATA-6 (but self-test log was in
! 1809: // ATA-5).
! 1810: int isSupportExecuteOfflineImmediate(const ata_smart_values *data)
! 1811: {
! 1812: return data->offline_data_collection_capability & 0x01;
! 1813: }
! 1814:
! 1815: // Note in the ATA-5 standard, the following bit is listed as "Vendor
! 1816: // Specific". So it may not be reliable. The only use of this that I
! 1817: // have found is in IBM drives, where it is well-documented. See for
! 1818: // example page 170, section 13.32.1.18 of the IBM Travelstar 40GNX
! 1819: // hard disk drive specifications page 164 Revision 1.1 22 Apr 2002.
! 1820: int isSupportAutomaticTimer(const ata_smart_values * data)
! 1821: {
! 1822: return data->offline_data_collection_capability & 0x02;
! 1823: }
! 1824: int isSupportOfflineAbort(const ata_smart_values *data)
! 1825: {
! 1826: return data->offline_data_collection_capability & 0x04;
! 1827: }
! 1828: int isSupportOfflineSurfaceScan(const ata_smart_values * data)
! 1829: {
! 1830: return data->offline_data_collection_capability & 0x08;
! 1831: }
! 1832: int isSupportSelfTest (const ata_smart_values * data)
! 1833: {
! 1834: return data->offline_data_collection_capability & 0x10;
! 1835: }
! 1836: int isSupportConveyanceSelfTest(const ata_smart_values * data)
! 1837: {
! 1838: return data->offline_data_collection_capability & 0x20;
! 1839: }
! 1840: int isSupportSelectiveSelfTest(const ata_smart_values * data)
! 1841: {
! 1842: return data->offline_data_collection_capability & 0x40;
! 1843: }
! 1844:
! 1845: // Get attribute state
! 1846: ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
! 1847: int attridx,
! 1848: const ata_smart_threshold_entry * thresholds,
! 1849: const ata_vendor_attr_defs & defs,
! 1850: unsigned char * threshval /* = 0 */)
! 1851: {
! 1852: if (!attr.id)
! 1853: return ATTRSTATE_NON_EXISTING;
! 1854:
! 1855: // Normalized values (current,worst,threshold) not valid
! 1856: // if specified by '-v' option.
! 1857: // (Some SSD disks uses these bytes to store raw value).
! 1858: if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL)
! 1859: return ATTRSTATE_NO_NORMVAL;
! 1860:
! 1861: // Normally threshold is at same index as attribute
! 1862: int i = attridx;
! 1863: if (thresholds[i].id != attr.id) {
! 1864: // Find threshold id in table
! 1865: for (i = 0; thresholds[i].id != attr.id; ) {
! 1866: if (++i >= NUMBER_ATA_SMART_ATTRIBUTES)
! 1867: // Threshold id missing or thresholds cannot be read
! 1868: return ATTRSTATE_NO_THRESHOLD;
! 1869: }
! 1870: }
! 1871: unsigned char threshold = thresholds[i].threshold;
! 1872:
! 1873: // Return threshold if requested
! 1874: if (threshval)
! 1875: *threshval = threshold;
! 1876:
! 1877: // Don't report a failed attribute if its threshold is 0.
! 1878: // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
! 1879: // threshold (Later ATA versions declare all thresholds as "obsolete").
! 1880: // In practice, threshold value 0 is often used for usage attributes.
! 1881: if (!threshold)
! 1882: return ATTRSTATE_OK;
! 1883:
! 1884: // Failed now if current value is below threshold
! 1885: if (attr.current <= threshold)
! 1886: return ATTRSTATE_FAILED_NOW;
! 1887:
! 1888: // Failed in the past if worst value is below threshold
! 1889: if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL) && attr.worst <= threshold)
! 1890: return ATTRSTATE_FAILED_PAST;
! 1891:
! 1892: return ATTRSTATE_OK;
! 1893: }
! 1894:
! 1895: // Get default raw value print format
! 1896: static ata_attr_raw_format get_default_raw_format(unsigned char id)
! 1897: {
! 1898: switch (id) {
! 1899: case 3: // Spin-up time
! 1900: return RAWFMT_RAW16_OPT_AVG16;
! 1901:
! 1902: case 5: // Reallocated sector count
! 1903: case 196: // Reallocated event count
! 1904: return RAWFMT_RAW16_OPT_RAW16;
! 1905:
! 1906: case 190: // Temperature
! 1907: case 194:
! 1908: return RAWFMT_TEMPMINMAX;
! 1909:
! 1910: default:
! 1911: return RAWFMT_RAW48;
! 1912: }
! 1913: }
! 1914:
! 1915: // Get attribute raw value.
! 1916: uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
! 1917: const ata_vendor_attr_defs & defs)
! 1918: {
! 1919: const ata_vendor_attr_defs::entry & def = defs[attr.id];
! 1920:
! 1921: // Use default byteorder if not specified
! 1922: const char * byteorder = def.byteorder;
! 1923: if (!*byteorder) {
! 1924: switch (def.raw_format) {
! 1925: case RAWFMT_RAW64:
! 1926: case RAWFMT_HEX64:
! 1927: byteorder = "543210wv"; break;
! 1928: case RAWFMT_RAW24_DIV_RAW32:
! 1929: case RAWFMT_MSEC24_HOUR32:
! 1930: byteorder = "r543210"; break;
! 1931: default:
! 1932: byteorder = "543210"; break;
! 1933: }
! 1934: }
! 1935:
! 1936: // Build 64-bit value from selected bytes
! 1937: uint64_t rawvalue = 0;
! 1938: for (int i = 0; byteorder[i]; i++) {
! 1939: unsigned char b;
! 1940: switch (byteorder[i]) {
! 1941: case '0': b = attr.raw[0]; break;
! 1942: case '1': b = attr.raw[1]; break;
! 1943: case '2': b = attr.raw[2]; break;
! 1944: case '3': b = attr.raw[3]; break;
! 1945: case '4': b = attr.raw[4]; break;
! 1946: case '5': b = attr.raw[5]; break;
! 1947: case 'r': b = attr.reserv; break;
! 1948: case 'v': b = attr.current; break;
! 1949: case 'w': b = attr.worst; break;
! 1950: default : b = 0; break;
! 1951: }
! 1952: rawvalue <<= 8; rawvalue |= b;
! 1953: }
! 1954:
! 1955: return rawvalue;
! 1956: }
! 1957:
! 1958:
! 1959: // Format attribute raw value.
! 1960: std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
! 1961: const ata_vendor_attr_defs & defs)
! 1962: {
! 1963: // Get 48 bit or 64 bit raw value
! 1964: uint64_t rawvalue = ata_get_attr_raw_value(attr, defs);
! 1965:
! 1966: // Split into bytes and words
! 1967: unsigned char raw[6];
! 1968: raw[0] = (unsigned char) rawvalue;
! 1969: raw[1] = (unsigned char)(rawvalue >> 8);
! 1970: raw[2] = (unsigned char)(rawvalue >> 16);
! 1971: raw[3] = (unsigned char)(rawvalue >> 24);
! 1972: raw[4] = (unsigned char)(rawvalue >> 32);
! 1973: raw[5] = (unsigned char)(rawvalue >> 40);
! 1974: unsigned word[3];
! 1975: word[0] = raw[0] | (raw[1] << 8);
! 1976: word[1] = raw[2] | (raw[3] << 8);
! 1977: word[2] = raw[4] | (raw[5] << 8);
! 1978:
! 1979: // Get print format
! 1980: ata_attr_raw_format format = defs[attr.id].raw_format;
! 1981: if (format == RAWFMT_DEFAULT)
! 1982: format = get_default_raw_format(attr.id);
! 1983:
! 1984: // Print
! 1985: std::string s;
! 1986: switch (format) {
! 1987: case RAWFMT_RAW8:
! 1988: s = strprintf("%d %d %d %d %d %d",
! 1989: raw[5], raw[4], raw[3], raw[2], raw[1], raw[0]);
! 1990: break;
! 1991:
! 1992: case RAWFMT_RAW16:
! 1993: s = strprintf("%u %u %u", word[2], word[1], word[0]);
! 1994: break;
! 1995:
! 1996: case RAWFMT_RAW48:
! 1997: case RAWFMT_RAW64:
! 1998: s = strprintf("%"PRIu64, rawvalue);
! 1999: break;
! 2000:
! 2001: case RAWFMT_HEX48:
! 2002: s = strprintf("0x%012"PRIx64, rawvalue);
! 2003: break;
! 2004:
! 2005: case RAWFMT_HEX64:
! 2006: s = strprintf("0x%016"PRIx64, rawvalue);
! 2007: break;
! 2008:
! 2009: case RAWFMT_RAW16_OPT_RAW16:
! 2010: s = strprintf("%u", word[0]);
! 2011: if (word[1] || word[2])
! 2012: s += strprintf(" (%u, %u)", word[2], word[1]);
! 2013: break;
! 2014:
! 2015: case RAWFMT_RAW16_OPT_AVG16:
! 2016: s = strprintf("%u", word[0]);
! 2017: if (word[1])
! 2018: s += strprintf(" (Average %u)", word[1]);
! 2019: break;
! 2020:
! 2021: case RAWFMT_RAW24_DIV_RAW24:
! 2022: s = strprintf("%u/%u",
! 2023: (unsigned)(rawvalue >> 24), (unsigned)(rawvalue & 0x00ffffffULL));
! 2024: break;
! 2025:
! 2026: case RAWFMT_RAW24_DIV_RAW32:
! 2027: s = strprintf("%u/%u",
! 2028: (unsigned)(rawvalue >> 32), (unsigned)(rawvalue & 0xffffffffULL));
! 2029: break;
! 2030:
! 2031: case RAWFMT_MIN2HOUR:
! 2032: {
! 2033: // minutes
! 2034: int64_t temp = word[0]+(word[1]<<16);
! 2035: int64_t tmp1 = temp/60;
! 2036: int64_t tmp2 = temp%60;
! 2037: s = strprintf("%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2);
! 2038: if (word[2])
! 2039: s += strprintf(" (%u)", word[2]);
! 2040: }
! 2041: break;
! 2042:
! 2043: case RAWFMT_SEC2HOUR:
! 2044: {
! 2045: // seconds
! 2046: int64_t hours = rawvalue/3600;
! 2047: int64_t minutes = (rawvalue-3600*hours)/60;
! 2048: int64_t seconds = rawvalue%60;
! 2049: s = strprintf("%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds);
! 2050: }
! 2051: break;
! 2052:
! 2053: case RAWFMT_HALFMIN2HOUR:
! 2054: {
! 2055: // 30-second counter
! 2056: int64_t hours = rawvalue/120;
! 2057: int64_t minutes = (rawvalue-120*hours)/2;
! 2058: s += strprintf("%"PRIu64"h+%02"PRIu64"m", hours, minutes);
! 2059: }
! 2060: break;
! 2061:
! 2062: case RAWFMT_MSEC24_HOUR32:
! 2063: {
! 2064: // hours + milliseconds
! 2065: unsigned hours = (unsigned)(rawvalue & 0xffffffffULL);
! 2066: unsigned milliseconds = (unsigned)(rawvalue >> 32);
! 2067: unsigned seconds = milliseconds / 1000;
! 2068: s = strprintf("%uh+%02um+%02u.%03us",
! 2069: hours, seconds / 60, seconds % 60, milliseconds % 1000);
! 2070: }
! 2071: break;
! 2072:
! 2073: case RAWFMT_TEMPMINMAX:
! 2074: // Temperature
! 2075: {
! 2076: // Search for possible min/max values
! 2077: // 00 HH 00 LL 00 TT (Hitachi/IBM)
! 2078: // 00 00 HH LL 00 TT (Maxtor, Samsung)
! 2079: // 00 00 00 HH LL TT (WDC)
! 2080: unsigned char lo = 0, hi = 0;
! 2081: int cnt = 0;
! 2082: for (int i = 1; i < 6; i++) {
! 2083: if (raw[i])
! 2084: switch (cnt++) {
! 2085: case 0:
! 2086: lo = raw[i];
! 2087: break;
! 2088: case 1:
! 2089: if (raw[i] < lo) {
! 2090: hi = lo; lo = raw[i];
! 2091: }
! 2092: else
! 2093: hi = raw[i];
! 2094: break;
! 2095: }
! 2096: }
! 2097:
! 2098: unsigned char t = raw[0];
! 2099: if (cnt == 0)
! 2100: s = strprintf("%d", t);
! 2101: else if (cnt == 2 && 0 < lo && lo <= t && t <= hi && hi < 128)
! 2102: s = strprintf("%d (Min/Max %d/%d)", t, lo, hi);
! 2103: else
! 2104: s = strprintf("%d (%d %d %d %d %d)", t, raw[5], raw[4], raw[3], raw[2], raw[1]);
! 2105: }
! 2106: break;
! 2107:
! 2108: case RAWFMT_TEMP10X:
! 2109: // ten times temperature in Celsius
! 2110: s = strprintf("%d.%d", word[0]/10, word[0]%10);
! 2111: break;
! 2112:
! 2113: default:
! 2114: s = "?"; // Should not happen
! 2115: break;
! 2116: }
! 2117:
! 2118: return s;
! 2119: }
! 2120:
! 2121: // Attribute names shouldn't be longer than 23 chars, otherwise they break the
! 2122: // output of smartctl.
! 2123: static const char * get_default_attr_name(unsigned char id)
! 2124: {
! 2125: switch (id) {
! 2126: case 1:
! 2127: return "Raw_Read_Error_Rate";
! 2128: case 2:
! 2129: return "Throughput_Performance";
! 2130: case 3:
! 2131: return "Spin_Up_Time";
! 2132: case 4:
! 2133: return "Start_Stop_Count";
! 2134: case 5:
! 2135: return "Reallocated_Sector_Ct";
! 2136: case 6:
! 2137: return "Read_Channel_Margin";
! 2138: case 7:
! 2139: return "Seek_Error_Rate";
! 2140: case 8:
! 2141: return "Seek_Time_Performance";
! 2142: case 9:
! 2143: return "Power_On_Hours";
! 2144: case 10:
! 2145: return "Spin_Retry_Count";
! 2146: case 11:
! 2147: return "Calibration_Retry_Count";
! 2148: case 12:
! 2149: return "Power_Cycle_Count";
! 2150: case 13:
! 2151: return "Read_Soft_Error_Rate";
! 2152: case 175:
! 2153: return "Program_Fail_Count_Chip";
! 2154: case 176:
! 2155: return "Erase_Fail_Count_Chip";
! 2156: case 177:
! 2157: return "Wear_Leveling_Count";
! 2158: case 178:
! 2159: return "Used_Rsvd_Blk_Cnt_Chip";
! 2160: case 179:
! 2161: return "Used_Rsvd_Blk_Cnt_Tot";
! 2162: case 180:
! 2163: return "Unused_Rsvd_Blk_Cnt_Tot";
! 2164: case 181:
! 2165: return "Program_Fail_Cnt_Total";
! 2166: case 182:
! 2167: return "Erase_Fail_Count_Total";
! 2168: case 183:
! 2169: return "Runtime_Bad_Block";
! 2170: case 184:
! 2171: return "End-to-End_Error";
! 2172: case 187:
! 2173: return "Reported_Uncorrect";
! 2174: case 188:
! 2175: return "Command_Timeout";
! 2176: case 189:
! 2177: return "High_Fly_Writes";
! 2178: case 190:
! 2179: // Western Digital uses this for temperature.
! 2180: // It's identical to Attribute 194 except that it
! 2181: // has a failure threshold set to correspond to the
! 2182: // max allowed operating temperature of the drive, which
! 2183: // is typically 55C. So if this attribute has failed
! 2184: // in the past, it indicates that the drive temp exceeded
! 2185: // 55C sometime in the past.
! 2186: return "Airflow_Temperature_Cel";
! 2187: case 191:
! 2188: return "G-Sense_Error_Rate";
! 2189: case 192:
! 2190: return "Power-Off_Retract_Count";
! 2191: case 193:
! 2192: return "Load_Cycle_Count";
! 2193: case 194:
! 2194: return "Temperature_Celsius";
! 2195: case 195:
! 2196: // Fujitsu: "ECC_On_The_Fly_Count";
! 2197: return "Hardware_ECC_Recovered";
! 2198: case 196:
! 2199: return "Reallocated_Event_Count";
! 2200: case 197:
! 2201: return "Current_Pending_Sector";
! 2202: case 198:
! 2203: return "Offline_Uncorrectable";
! 2204: case 199:
! 2205: return "UDMA_CRC_Error_Count";
! 2206: case 200:
! 2207: // Western Digital
! 2208: return "Multi_Zone_Error_Rate";
! 2209: case 201:
! 2210: return "Soft_Read_Error_Rate";
! 2211: case 202:
! 2212: // Fujitsu: "TA_Increase_Count"
! 2213: return "Data_Address_Mark_Errs";
! 2214: case 203:
! 2215: // Fujitsu
! 2216: return "Run_Out_Cancel";
! 2217: // Maxtor: ECC Errors
! 2218: case 204:
! 2219: // Fujitsu: "Shock_Count_Write_Opern"
! 2220: return "Soft_ECC_Correction";
! 2221: case 205:
! 2222: // Fujitsu: "Shock_Rate_Write_Opern"
! 2223: return "Thermal_Asperity_Rate";
! 2224: case 206:
! 2225: // Fujitsu
! 2226: return "Flying_Height";
! 2227: case 207:
! 2228: // Maxtor
! 2229: return "Spin_High_Current";
! 2230: case 208:
! 2231: // Maxtor
! 2232: return "Spin_Buzz";
! 2233: case 209:
! 2234: // Maxtor
! 2235: return "Offline_Seek_Performnce";
! 2236: case 220:
! 2237: return "Disk_Shift";
! 2238: case 221:
! 2239: return "G-Sense_Error_Rate";
! 2240: case 222:
! 2241: return "Loaded_Hours";
! 2242: case 223:
! 2243: return "Load_Retry_Count";
! 2244: case 224:
! 2245: return "Load_Friction";
! 2246: case 225:
! 2247: return "Load_Cycle_Count";
! 2248: case 226:
! 2249: return "Load-in_Time";
! 2250: case 227:
! 2251: return "Torq-amp_Count";
! 2252: case 228:
! 2253: return "Power-off_Retract_Count";
! 2254: case 230:
! 2255: // seen in IBM DTPA-353750
! 2256: return "Head_Amplitude";
! 2257: case 231:
! 2258: return "Temperature_Celsius";
! 2259: case 232:
! 2260: // seen in Intel X25-E SSD
! 2261: return "Available_Reservd_Space";
! 2262: case 233:
! 2263: // seen in Intel X25-E SSD
! 2264: return "Media_Wearout_Indicator";
! 2265: case 240:
! 2266: return "Head_Flying_Hours";
! 2267: case 241:
! 2268: return "Total_LBAs_Written";
! 2269: case 242:
! 2270: return "Total_LBAs_Read";
! 2271: case 250:
! 2272: return "Read_Error_Retry_Rate";
! 2273: case 254:
! 2274: return "Free_Fall_Sensor";
! 2275: default:
! 2276: return "Unknown_Attribute";
! 2277: }
! 2278: }
! 2279:
! 2280: // Get attribute name
! 2281: std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs)
! 2282: {
! 2283: if (!defs[id].name.empty())
! 2284: return defs[id].name;
! 2285: else
! 2286: return get_default_attr_name(id);
! 2287: }
! 2288:
! 2289: // Find attribute index for attribute id, -1 if not found.
! 2290: int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval)
! 2291: {
! 2292: if (!id)
! 2293: return -1;
! 2294: for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
! 2295: if (smartval.vendor_attributes[i].id == id)
! 2296: return i;
! 2297: }
! 2298: return -1;
! 2299: }
! 2300:
! 2301: // Return Temperature Attribute raw value selected according to possible
! 2302: // non-default interpretations. If the Attribute does not exist, return 0
! 2303: unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs)
! 2304: {
! 2305: for (int i = 0; i < 3; i++) {
! 2306: static const unsigned char ids[3] = {194, 9, 220};
! 2307: unsigned char id = ids[i];
! 2308: const ata_attr_raw_format format = defs[id].raw_format;
! 2309: if (!( (id == 194 && format == RAWFMT_DEFAULT)
! 2310: || format == RAWFMT_TEMPMINMAX || format == RAWFMT_TEMP10X))
! 2311: continue;
! 2312: int idx = ata_find_attr_index(id, *data);
! 2313: if (idx < 0)
! 2314: continue;
! 2315: uint64_t raw = ata_get_attr_raw_value(data->vendor_attributes[idx], defs);
! 2316: unsigned temp;
! 2317: // ignore possible min/max values in high words
! 2318: if (format == RAWFMT_TEMP10X) // -v N,temp10x
! 2319: temp = ((unsigned short)raw + 5) / 10;
! 2320: else
! 2321: temp = (unsigned char)raw;
! 2322: if (!(0 < temp && temp < 128))
! 2323: continue;
! 2324: return temp;
! 2325: }
! 2326: // No valid attribute found
! 2327: return 0;
! 2328: }
! 2329:
! 2330:
! 2331: // Read SCT Status
! 2332: int ataReadSCTStatus(ata_device * device, ata_sct_status_response * sts)
! 2333: {
! 2334: // read SCT status via SMART log 0xe0
! 2335: memset(sts, 0, sizeof(*sts));
! 2336: if (smartcommandhandler(device, READ_LOG, 0xe0, (char *)sts)){
! 2337: pout("Error Read SCT Status failed: %s\n", device->get_errmsg());
! 2338: return -1;
! 2339: }
! 2340:
! 2341: // swap endian order if needed
! 2342: if (isbigendian()){
! 2343: swapx(&sts->format_version);
! 2344: swapx(&sts->sct_version);
! 2345: swapx(&sts->sct_spec);
! 2346: swapx(&sts->ext_status_code);
! 2347: swapx(&sts->action_code);
! 2348: swapx(&sts->function_code);
! 2349: swapx(&sts->over_limit_count);
! 2350: swapx(&sts->under_limit_count);
! 2351: }
! 2352:
! 2353: // Check format version
! 2354: if (!(sts->format_version == 2 || sts->format_version == 3)) {
! 2355: pout("Error unknown SCT Status format version %u, should be 2 or 3.\n", sts->format_version);
! 2356: return -1;
! 2357: }
! 2358: return 0;
! 2359: }
! 2360:
! 2361: // Read SCT Temperature History Table and Status
! 2362: int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table * tmh,
! 2363: ata_sct_status_response * sts)
! 2364: {
! 2365: // Check initial status
! 2366: if (ataReadSCTStatus(device, sts))
! 2367: return -1;
! 2368:
! 2369: // Do nothing if other SCT command is executing
! 2370: if (sts->ext_status_code == 0xffff) {
! 2371: pout("Another SCT command is executing, abort Read Data Table\n"
! 2372: "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n",
! 2373: sts->ext_status_code, sts->action_code, sts->function_code);
! 2374: return -1;
! 2375: }
! 2376:
! 2377: ata_sct_data_table_command cmd; memset(&cmd, 0, sizeof(cmd));
! 2378: // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK)
! 2379: cmd.action_code = 5; // Data table command
! 2380: cmd.function_code = 1; // Read table
! 2381: cmd.table_id = 2; // Temperature History Table
! 2382:
! 2383: // swap endian order if needed
! 2384: if (isbigendian()) {
! 2385: swapx(&cmd.action_code);
! 2386: swapx(&cmd.function_code);
! 2387: swapx(&cmd.table_id);
! 2388: }
! 2389:
! 2390: // write command via SMART log page 0xe0
! 2391: if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){
! 2392: pout("Error Write SCT Data Table command failed: %s\n", device->get_errmsg());
! 2393: return -1;
! 2394: }
! 2395:
! 2396: // read SCT data via SMART log page 0xe1
! 2397: memset(tmh, 0, sizeof(*tmh));
! 2398: if (smartcommandhandler(device, READ_LOG, 0xe1, (char *)tmh)){
! 2399: pout("Error Read SCT Data Table failed: %s\n", device->get_errmsg());
! 2400: return -1;
! 2401: }
! 2402:
! 2403: // re-read and check SCT status
! 2404: if (ataReadSCTStatus(device, sts))
! 2405: return -1;
! 2406:
! 2407: if (!(sts->ext_status_code == 0 && sts->action_code == 5 && sts->function_code == 1)) {
! 2408: pout("Error unexpected SCT status 0x%04x (action_code=%u, function_code=%u)\n",
! 2409: sts->ext_status_code, sts->action_code, sts->function_code);
! 2410: return -1;
! 2411: }
! 2412:
! 2413: // swap endian order if needed
! 2414: if (isbigendian()){
! 2415: swapx(&tmh->format_version);
! 2416: swapx(&tmh->sampling_period);
! 2417: swapx(&tmh->interval);
! 2418: }
! 2419:
! 2420: // Check format version
! 2421: if (tmh->format_version != 2) {
! 2422: pout("Error unknown SCT Temperature History Format Version (%u), should be 2.\n", tmh->format_version);
! 2423: return -1;
! 2424: }
! 2425: return 0;
! 2426: }
! 2427:
! 2428: // Set SCT Temperature Logging Interval
! 2429: int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persistent)
! 2430: {
! 2431: // Check initial status
! 2432: ata_sct_status_response sts;
! 2433: if (ataReadSCTStatus(device, &sts))
! 2434: return -1;
! 2435:
! 2436: // Do nothing if other SCT command is executing
! 2437: if (sts.ext_status_code == 0xffff) {
! 2438: pout("Another SCT command is executing, abort Feature Control\n"
! 2439: "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n",
! 2440: sts.ext_status_code, sts.action_code, sts.function_code);
! 2441: return -1;
! 2442: }
! 2443:
! 2444: ata_sct_feature_control_command cmd; memset(&cmd, 0, sizeof(cmd));
! 2445: // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK)
! 2446: cmd.action_code = 4; // Feature Control command
! 2447: cmd.function_code = 1; // Set state
! 2448: cmd.feature_code = 3; // Temperature logging interval
! 2449: cmd.state = interval;
! 2450: cmd.option_flags = (persistent ? 0x01 : 0x00);
! 2451:
! 2452: // swap endian order if needed
! 2453: if (isbigendian()) {
! 2454: swapx(&cmd.action_code);
! 2455: swapx(&cmd.function_code);
! 2456: swapx(&cmd.feature_code);
! 2457: swapx(&cmd.state);
! 2458: swapx(&cmd.option_flags);
! 2459: }
! 2460:
! 2461: // write command via SMART log page 0xe0
! 2462: if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){
! 2463: pout("Error Write SCT Feature Control Command failed: %s\n", device->get_errmsg());
! 2464: return -1;
! 2465: }
! 2466:
! 2467: // re-read and check SCT status
! 2468: if (ataReadSCTStatus(device, &sts))
! 2469: return -1;
! 2470:
! 2471: if (!(sts.ext_status_code == 0 && sts.action_code == 4 && sts.function_code == 1)) {
! 2472: pout("Error unexcepted SCT status 0x%04x (action_code=%u, function_code=%u)\n",
! 2473: sts.ext_status_code, sts.action_code, sts.function_code);
! 2474: return -1;
! 2475: }
! 2476: return 0;
! 2477: }
! 2478:
! 2479: // Get/Set SCT Error Recovery Control
! 2480: static int ataGetSetSCTErrorRecoveryControltime(ata_device * device, unsigned type,
! 2481: bool set, unsigned short & time_limit)
! 2482: {
! 2483: // Check initial status
! 2484: ata_sct_status_response sts;
! 2485: if (ataReadSCTStatus(device, &sts))
! 2486: return -1;
! 2487:
! 2488: // Do nothing if other SCT command is executing
! 2489: if (sts.ext_status_code == 0xffff) {
! 2490: pout("Another SCT command is executing, abort Error Recovery Control\n"
! 2491: "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n",
! 2492: sts.ext_status_code, sts.action_code, sts.function_code);
! 2493: return -1;
! 2494: }
! 2495:
! 2496: ata_sct_error_recovery_control_command cmd; memset(&cmd, 0, sizeof(cmd));
! 2497: // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK)
! 2498: cmd.action_code = 3; // Error Recovery Control command
! 2499: cmd.function_code = (set ? 1 : 2); // 1=Set timer, 2=Get timer
! 2500: cmd.selection_code = type; // 1=Read timer, 2=Write timer
! 2501: if (set)
! 2502: cmd.time_limit = time_limit;
! 2503:
! 2504: // swap endian order if needed
! 2505: if (isbigendian()) {
! 2506: swapx(&cmd.action_code);
! 2507: swapx(&cmd.function_code);
! 2508: swapx(&cmd.selection_code);
! 2509: swapx(&cmd.time_limit);
! 2510: }
! 2511:
! 2512: // write command via SMART log page 0xe0
! 2513: // TODO: Debug output
! 2514: ata_cmd_in in;
! 2515: in.in_regs.command = ATA_SMART_CMD;
! 2516: in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW;
! 2517: in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR;
! 2518: in.in_regs.lba_low = 0xe0;
! 2519: in.set_data_out(&cmd, 1);
! 2520:
! 2521: if (!set)
! 2522: // Time limit returned in ATA registers
! 2523: in.out_needed.sector_count = in.out_needed.lba_low = true;
! 2524:
! 2525: ata_cmd_out out;
! 2526: if (!device->ata_pass_through(in, out)) {
! 2527: pout("Error Write SCT (%cet) Error Recovery Control Command failed: %s\n",
! 2528: (!set ? 'G' : 'S'), device->get_errmsg());
! 2529: return -1;
! 2530: }
! 2531:
! 2532: // re-read and check SCT status
! 2533: if (ataReadSCTStatus(device, &sts))
! 2534: return -1;
! 2535:
! 2536: if (!(sts.ext_status_code == 0 && sts.action_code == 3 && sts.function_code == (set ? 1 : 2))) {
! 2537: pout("Error unexcepted SCT status 0x%04x (action_code=%u, function_code=%u)\n",
! 2538: sts.ext_status_code, sts.action_code, sts.function_code);
! 2539: return -1;
! 2540: }
! 2541:
! 2542: if (!set) {
! 2543: // Check whether registers are properly returned by ioctl()
! 2544: if (!(out.out_regs.sector_count.is_set() && out.out_regs.lba_low.is_set())) {
! 2545: // TODO: Output register support should be checked within each ata_pass_through()
! 2546: // implementation before command is issued.
! 2547: pout("Error SMART WRITE LOG does not return COUNT and LBA_LOW register\n");
! 2548: return -1;
! 2549: }
! 2550: // Return value to caller
! 2551: time_limit = out.out_regs.sector_count | (out.out_regs.lba_low << 8);
! 2552: }
! 2553:
! 2554: return 0;
! 2555: }
! 2556:
! 2557: // Get SCT Error Recovery Control
! 2558: int ataGetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short & time_limit)
! 2559: {
! 2560: return ataGetSetSCTErrorRecoveryControltime(device, type, false/*get*/, time_limit);
! 2561: }
! 2562:
! 2563: // Set SCT Error Recovery Control
! 2564: int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short time_limit)
! 2565: {
! 2566: return ataGetSetSCTErrorRecoveryControltime(device, type, true/*set*/, time_limit);
! 2567: }
! 2568:
! 2569:
! 2570: // Print one self-test log entry.
! 2571: // Returns:
! 2572: // -1: self-test failed
! 2573: // 1: extended self-test completed without error
! 2574: // 0: otherwise
! 2575: int ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type,
! 2576: unsigned char test_status,
! 2577: unsigned short timestamp,
! 2578: uint64_t failing_lba,
! 2579: bool print_error_only, bool & print_header)
! 2580: {
! 2581: // Check status and type for return value
! 2582: int retval = 0;
! 2583: switch (test_status >> 4) {
! 2584: case 0x0:
! 2585: if ((test_type & 0x0f) == 0x02)
! 2586: retval = 1; // extended self-test completed without error
! 2587: break;
! 2588: case 0x3: case 0x4:
! 2589: case 0x5: case 0x6:
! 2590: case 0x7: case 0x8:
! 2591: retval = -1; // self-test failed
! 2592: break;
! 2593: }
! 2594:
! 2595: if (retval >= 0 && print_error_only)
! 2596: return retval;
! 2597:
! 2598: std::string msgtest;
! 2599: switch (test_type) {
! 2600: case 0x00: msgtest = "Offline"; break;
! 2601: case 0x01: msgtest = "Short offline"; break;
! 2602: case 0x02: msgtest = "Extended offline"; break;
! 2603: case 0x03: msgtest = "Conveyance offline"; break;
! 2604: case 0x04: msgtest = "Selective offline"; break;
! 2605: case 0x7f: msgtest = "Abort offline test"; break;
! 2606: case 0x81: msgtest = "Short captive"; break;
! 2607: case 0x82: msgtest = "Extended captive"; break;
! 2608: case 0x83: msgtest = "Conveyance captive"; break;
! 2609: case 0x84: msgtest = "Selective captive"; break;
! 2610: default:
! 2611: if ((0x40 <= test_type && test_type <= 0x7e) || 0x90 <= test_type)
! 2612: msgtest = strprintf("Vendor (0x%02x)", test_type);
! 2613: else
! 2614: msgtest = strprintf("Reserved (0x%02x)", test_type);
! 2615: }
! 2616:
! 2617: std::string msgstat;
! 2618: switch (test_status >> 4) {
! 2619: case 0x0: msgstat = "Completed without error"; break;
! 2620: case 0x1: msgstat = "Aborted by host"; break;
! 2621: case 0x2: msgstat = "Interrupted (host reset)"; break;
! 2622: case 0x3: msgstat = "Fatal or unknown error"; break;
! 2623: case 0x4: msgstat = "Completed: unknown failure"; break;
! 2624: case 0x5: msgstat = "Completed: electrical failure"; break;
! 2625: case 0x6: msgstat = "Completed: servo/seek failure"; break;
! 2626: case 0x7: msgstat = "Completed: read failure"; break;
! 2627: case 0x8: msgstat = "Completed: handling damage??"; break;
! 2628: case 0xf: msgstat = "Self-test routine in progress"; break;
! 2629: default: msgstat = strprintf("Unknown status (0x%x)", test_status >> 4);
! 2630: }
! 2631:
! 2632: // Print header once
! 2633: if (print_header) {
! 2634: print_header = false;
! 2635: pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n");
! 2636: }
! 2637:
! 2638: char msglba[32];
! 2639: if (retval < 0 && failing_lba < 0xffffffffffffULL)
! 2640: snprintf(msglba, sizeof(msglba), "%"PRIu64, failing_lba);
! 2641: else
! 2642: strcpy(msglba, "-");
! 2643:
! 2644: pout("#%2u %-19s %-29s %1d0%% %8u %s\n", testnum,
! 2645: msgtest.c_str(), msgstat.c_str(), test_status & 0x0f, timestamp, msglba);
! 2646:
! 2647: return retval;
! 2648: }
! 2649:
! 2650: // Print Smart self-test log, used by smartctl and smartd.
! 2651: // return value is:
! 2652: // bottom 8 bits: number of entries found where self-test showed an error
! 2653: // remaining bits: if nonzero, power on hours of last self-test where error was found
! 2654: int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries,
! 2655: unsigned char fix_firmwarebug)
! 2656: {
! 2657: if (allentries)
! 2658: pout("SMART Self-test log structure revision number %d\n",(int)data->revnumber);
! 2659: if ((data->revnumber!=0x0001) && allentries && fix_firmwarebug != FIX_SAMSUNG)
! 2660: pout("Warning: ATA Specification requires self-test log structure revision number = 1\n");
! 2661: if (data->mostrecenttest==0){
! 2662: if (allentries)
! 2663: pout("No self-tests have been logged. [To run self-tests, use: smartctl -t]\n\n");
! 2664: return 0;
! 2665: }
! 2666:
! 2667: bool noheaderprinted = true;
! 2668: int errcnt = 0, hours = 0, igncnt = 0;
! 2669: int testno = 0, ext_ok_testno = -1;
! 2670:
! 2671: // print log
! 2672: for (int i = 20; i >= 0; i--) {
! 2673: // log is a circular buffer
! 2674: int j = (i+data->mostrecenttest)%21;
! 2675: const ata_smart_selftestlog_struct * log = data->selftest_struct+j;
! 2676:
! 2677: if (nonempty(log, sizeof(*log))) {
! 2678: // count entry based on non-empty structures -- needed for
! 2679: // Seagate only -- other vendors don't have blank entries 'in
! 2680: // the middle'
! 2681: testno++;
! 2682:
! 2683: // T13/1321D revision 1c: (Data structure Rev #1)
! 2684:
! 2685: //The failing LBA shall be the LBA of the uncorrectable sector
! 2686: //that caused the test to fail. If the device encountered more
! 2687: //than one uncorrectable sector during the test, this field
! 2688: //shall indicate the LBA of the first uncorrectable sector
! 2689: //encountered. If the test passed or the test failed for some
! 2690: //reason other than an uncorrectable sector, the value of this
! 2691: //field is undefined.
! 2692:
! 2693: // This is true in ALL ATA-5 specs
! 2694: uint64_t lba48 = (log->lbafirstfailure < 0xffffffff ? log->lbafirstfailure : 0xffffffffffffULL);
! 2695:
! 2696: // Print entry
! 2697: int state = ataPrintSmartSelfTestEntry(testno,
! 2698: log->selftestnumber, log->selfteststatus,
! 2699: log->timestamp, lba48, !allentries, noheaderprinted);
! 2700:
! 2701: if (state < 0) {
! 2702: // Self-test showed an error
! 2703: if (ext_ok_testno < 0) {
! 2704: errcnt++;
! 2705:
! 2706: // keep track of time of most recent error
! 2707: if (!hours)
! 2708: hours = log->timestamp;
! 2709: }
! 2710: else
! 2711: // Newer successful extended self-test exits
! 2712: igncnt++;
! 2713: }
! 2714: else if (state > 0 && ext_ok_testno < 0) {
! 2715: // Latest successful extended self-test
! 2716: ext_ok_testno = testno;
! 2717: }
! 2718: }
! 2719: }
! 2720:
! 2721: if (igncnt)
! 2722: pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n",
! 2723: igncnt, igncnt+errcnt, ext_ok_testno);
! 2724:
! 2725: if (!allentries && !noheaderprinted)
! 2726: pout("\n");
! 2727:
! 2728: return ((hours << 8) | errcnt);
! 2729: }
! 2730:
! 2731:
! 2732: /////////////////////////////////////////////////////////////////////////////
! 2733: // Pseudo-device to parse "smartctl -r ataioctl,2 ..." output and simulate
! 2734: // an ATA device with same behaviour
! 2735:
! 2736: namespace {
! 2737:
! 2738: class parsed_ata_device
! 2739: : public /*implements*/ ata_device_with_command_set
! 2740: {
! 2741: public:
! 2742: parsed_ata_device(smart_interface * intf, const char * dev_name);
! 2743:
! 2744: virtual ~parsed_ata_device() throw();
! 2745:
! 2746: virtual bool is_open() const;
! 2747:
! 2748: virtual bool open();
! 2749:
! 2750: virtual bool close();
! 2751:
! 2752: virtual bool ata_identify_is_cached() const;
! 2753:
! 2754: protected:
! 2755: virtual int ata_command_interface(smart_command_set command, int select, char * data);
! 2756:
! 2757: private:
! 2758: // Table of parsed commands, return value, data
! 2759: struct parsed_ata_command
! 2760: {
! 2761: smart_command_set command;
! 2762: int select;
! 2763: int retval, errval;
! 2764: char * data;
! 2765: };
! 2766:
! 2767: enum { max_num_commands = 32 };
! 2768: parsed_ata_command m_command_table[max_num_commands];
! 2769:
! 2770: int m_num_commands;
! 2771: int m_next_replay_command;
! 2772: bool m_replay_out_of_sync;
! 2773: bool m_ata_identify_is_cached;
! 2774: };
! 2775:
! 2776: static const char * nextline(const char * s, int & lineno)
! 2777: {
! 2778: for (s += strcspn(s, "\r\n"); *s == '\r' || *s == '\n'; s++) {
! 2779: if (*s == '\r' && s[1] == '\n')
! 2780: s++;
! 2781: lineno++;
! 2782: }
! 2783: return s;
! 2784: }
! 2785:
! 2786: static int name2command(const char * s)
! 2787: {
! 2788: for (int i = 0; i < (int)(sizeof(commandstrings)/sizeof(commandstrings[0])); i++) {
! 2789: if (!strcmp(s, commandstrings[i]))
! 2790: return i;
! 2791: }
! 2792: return -1;
! 2793: }
! 2794:
! 2795: static bool matchcpy(char * dest, size_t size, const char * src, const regmatch_t & srcmatch)
! 2796: {
! 2797: if (srcmatch.rm_so < 0)
! 2798: return false;
! 2799: size_t n = srcmatch.rm_eo - srcmatch.rm_so;
! 2800: if (n >= size)
! 2801: n = size-1;
! 2802: memcpy(dest, src + srcmatch.rm_so, n);
! 2803: dest[n] = 0;
! 2804: return true;
! 2805: }
! 2806:
! 2807: static inline int matchtoi(const char * src, const regmatch_t & srcmatch, int defval)
! 2808: {
! 2809: if (srcmatch.rm_so < 0)
! 2810: return defval;
! 2811: return atoi(src + srcmatch.rm_so);
! 2812: }
! 2813:
! 2814: parsed_ata_device::parsed_ata_device(smart_interface * intf, const char * dev_name)
! 2815: : smart_device(intf, dev_name, "ata", ""),
! 2816: m_num_commands(0),
! 2817: m_next_replay_command(0),
! 2818: m_replay_out_of_sync(false),
! 2819: m_ata_identify_is_cached(false)
! 2820: {
! 2821: memset(m_command_table, 0, sizeof(m_command_table));
! 2822: }
! 2823:
! 2824: parsed_ata_device::~parsed_ata_device() throw()
! 2825: {
! 2826: close();
! 2827: }
! 2828:
! 2829: bool parsed_ata_device::is_open() const
! 2830: {
! 2831: return (m_num_commands > 0);
! 2832: }
! 2833:
! 2834: // Parse stdin and build command table
! 2835: bool parsed_ata_device::open()
! 2836: {
! 2837: const char * pathname = get_dev_name();
! 2838: if (strcmp(pathname, "-"))
! 2839: return set_err(EINVAL);
! 2840: pathname = "<stdin>";
! 2841: // Fill buffer
! 2842: char buffer[64*1024];
! 2843: int size = 0;
! 2844: while (size < (int)sizeof(buffer)) {
! 2845: int nr = fread(buffer, 1, sizeof(buffer), stdin);
! 2846: if (nr <= 0)
! 2847: break;
! 2848: size += nr;
! 2849: }
! 2850: if (size <= 0)
! 2851: return set_err(ENOENT, "%s: Unexpected EOF", pathname);
! 2852: if (size >= (int)sizeof(buffer))
! 2853: return set_err(EIO, "%s: Buffer overflow", pathname);
! 2854: buffer[size] = 0;
! 2855:
! 2856: // Regex to match output from "-r ataioctl,2"
! 2857: static const char pattern[] = "^"
! 2858: "(" // (1
! 2859: "REPORT-IOCTL: DeviceF?D?=[^ ]+ Command=([A-Z ]*[A-Z])" // (2)
! 2860: "(" // (3
! 2861: "( InputParameter=([0-9]+))?" // (4 (5))
! 2862: "|"
! 2863: "( returned (-?[0-9]+)( errno=([0-9]+)[^\r\n]*)?)" // (6 (7) (8 (9)))
! 2864: ")" // )
! 2865: "[\r\n]" // EOL match necessary to match optional parts above
! 2866: "|"
! 2867: "===== \\[([A-Z ]*[A-Z])\\] DATA START " // (10)
! 2868: "|"
! 2869: " *(En|Dis)abled status cached by OS, " // (11)
! 2870: ")"; // )
! 2871:
! 2872: // Compile regex
! 2873: const regular_expression regex(pattern, REG_EXTENDED);
! 2874:
! 2875: // Parse buffer
! 2876: const char * errmsg = 0;
! 2877: int i = -1, state = 0, lineno = 1;
! 2878: for (const char * line = buffer; *line; line = nextline(line, lineno)) {
! 2879: // Match line
! 2880: if (!(line[0] == 'R' || line[0] == '=' || line[0] == ' '))
! 2881: continue;
! 2882: const int nmatch = 1+11;
! 2883: regmatch_t match[nmatch];
! 2884: if (!regex.execute(line, nmatch, match))
! 2885: continue;
! 2886:
! 2887: char cmdname[40];
! 2888: if (matchcpy(cmdname, sizeof(cmdname), line, match[2])) { // "REPORT-IOCTL:... Command=%s ..."
! 2889: int nc = name2command(cmdname);
! 2890: if (nc < 0) {
! 2891: errmsg = "Unknown ATA command name"; break;
! 2892: }
! 2893: if (match[7].rm_so < 0) { // "returned %d"
! 2894: // Start of command
! 2895: if (!(state == 0 || state == 2)) {
! 2896: errmsg = "Missing REPORT-IOCTL result"; break;
! 2897: }
! 2898: if (++i >= max_num_commands) {
! 2899: errmsg = "Too many ATA commands"; break;
! 2900: }
! 2901: m_command_table[i].command = (smart_command_set)nc;
! 2902: m_command_table[i].select = matchtoi(line, match[5], 0); // "InputParameter=%d"
! 2903: state = 1;
! 2904: }
! 2905: else {
! 2906: // End of command
! 2907: if (!(state == 1 && (int)m_command_table[i].command == nc)) {
! 2908: errmsg = "Missing REPORT-IOCTL start"; break;
! 2909: }
! 2910: m_command_table[i].retval = matchtoi(line, match[7], -1); // "returned %d"
! 2911: m_command_table[i].errval = matchtoi(line, match[9], 0); // "errno=%d"
! 2912: state = 2;
! 2913: }
! 2914: }
! 2915: else if (matchcpy(cmdname, sizeof(cmdname), line, match[10])) { // "===== [%s] DATA START "
! 2916: // Start of sector hexdump
! 2917: int nc = name2command(cmdname);
! 2918: if (!(state == (nc == WRITE_LOG ? 1 : 2) && (int)m_command_table[i].command == nc)) {
! 2919: errmsg = "Unexpected DATA START"; break;
! 2920: }
! 2921: line = nextline(line, lineno);
! 2922: char * data = (char *)malloc(512);
! 2923: unsigned j;
! 2924: for (j = 0; j < 32; j++) {
! 2925: unsigned b[16];
! 2926: unsigned u1, u2; int n1 = -1;
! 2927: if (!(sscanf(line, "%3u-%3u: "
! 2928: "%2x %2x %2x %2x %2x %2x %2x %2x "
! 2929: "%2x %2x %2x %2x %2x %2x %2x %2x%n",
! 2930: &u1, &u2,
! 2931: b+ 0, b+ 1, b+ 2, b+ 3, b+ 4, b+ 5, b+ 6, b+ 7,
! 2932: b+ 8, b+ 9, b+10, b+11, b+12, b+13, b+14, b+15, &n1) == 18
! 2933: && n1 >= 56 && u1 == j*16 && u2 == j*16+15))
! 2934: break;
! 2935: for (unsigned k = 0; k < 16; k++)
! 2936: data[j*16+k] = b[k];
! 2937: line = nextline(line, lineno);
! 2938: }
! 2939: if (j < 32) {
! 2940: free(data);
! 2941: errmsg = "Incomplete sector hex dump"; break;
! 2942: }
! 2943: m_command_table[i].data = data;
! 2944: if (nc != WRITE_LOG)
! 2945: state = 0;
! 2946: }
! 2947: else if (match[11].rm_so > 0) { // "(En|Dis)abled status cached by OS"
! 2948: m_ata_identify_is_cached = true;
! 2949: }
! 2950: }
! 2951:
! 2952: if (!(state == 0 || state == 2))
! 2953: errmsg = "Missing REPORT-IOCTL result";
! 2954:
! 2955: if (!errmsg && i < 0)
! 2956: errmsg = "No information found";
! 2957:
! 2958: m_num_commands = i+1;
! 2959: m_next_replay_command = 0;
! 2960: m_replay_out_of_sync = false;
! 2961:
! 2962: if (errmsg) {
! 2963: close();
! 2964: return set_err(EIO, "%s(%d): Syntax error: %s", pathname, lineno, errmsg);
! 2965: }
! 2966: return true;
! 2967: }
! 2968:
! 2969: // Report warnings and free command table
! 2970: bool parsed_ata_device::close()
! 2971: {
! 2972: if (m_replay_out_of_sync)
! 2973: pout("REPLAY-IOCTL: Warning: commands replayed out of sync\n");
! 2974: else if (m_next_replay_command != 0)
! 2975: pout("REPLAY-IOCTL: Warning: %d command(s) not replayed\n", m_num_commands-m_next_replay_command);
! 2976:
! 2977: for (int i = 0; i < m_num_commands; i++) {
! 2978: if (m_command_table[i].data) {
! 2979: free(m_command_table[i].data); m_command_table[i].data = 0;
! 2980: }
! 2981: }
! 2982: m_num_commands = 0;
! 2983: m_next_replay_command = 0;
! 2984: m_replay_out_of_sync = false;
! 2985: return true;
! 2986: }
! 2987:
! 2988:
! 2989: bool parsed_ata_device::ata_identify_is_cached() const
! 2990: {
! 2991: return m_ata_identify_is_cached;
! 2992: }
! 2993:
! 2994:
! 2995: // Simulate ATA command from command table
! 2996: int parsed_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
! 2997: {
! 2998: // Find command, try round-robin if out of sync
! 2999: int i = m_next_replay_command;
! 3000: for (int j = 0; ; j++) {
! 3001: if (j >= m_num_commands) {
! 3002: pout("REPLAY-IOCTL: Warning: Command not found\n");
! 3003: errno = ENOSYS;
! 3004: return -1;
! 3005: }
! 3006: if (m_command_table[i].command == command && m_command_table[i].select == select)
! 3007: break;
! 3008: if (!m_replay_out_of_sync) {
! 3009: m_replay_out_of_sync = true;
! 3010: pout("REPLAY-IOCTL: Warning: Command #%d is out of sync\n", i+1);
! 3011: }
! 3012: if (++i >= m_num_commands)
! 3013: i = 0;
! 3014: }
! 3015: m_next_replay_command = i;
! 3016: if (++m_next_replay_command >= m_num_commands)
! 3017: m_next_replay_command = 0;
! 3018:
! 3019: // Return command data
! 3020: switch (command) {
! 3021: case IDENTIFY:
! 3022: case PIDENTIFY:
! 3023: case READ_VALUES:
! 3024: case READ_THRESHOLDS:
! 3025: case READ_LOG:
! 3026: if (m_command_table[i].data)
! 3027: memcpy(data, m_command_table[i].data, 512);
! 3028: break;
! 3029: case WRITE_LOG:
! 3030: if (!(m_command_table[i].data && !memcmp(data, m_command_table[i].data, 512)))
! 3031: pout("REPLAY-IOCTL: Warning: WRITE LOG data does not match\n");
! 3032: break;
! 3033: case CHECK_POWER_MODE:
! 3034: data[0] = (char)0xff;
! 3035: default:
! 3036: break;
! 3037: }
! 3038:
! 3039: if (m_command_table[i].errval)
! 3040: errno = m_command_table[i].errval;
! 3041: return m_command_table[i].retval;
! 3042: }
! 3043:
! 3044: } // namespace
! 3045:
! 3046: ata_device * get_parsed_ata_device(smart_interface * intf, const char * dev_name)
! 3047: {
! 3048: return new parsed_ata_device(intf, dev_name);
! 3049: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>