Index: atactl.8 =================================================================== RCS file: /cvsroot/src/sbin/atactl/atactl.8,v retrieving revision 1.24 diff -p -u -u -r1.24 atactl.8 --- atactl.8 9 Jan 2013 21:58:23 -0000 1.24 +++ atactl.8 4 Oct 2018 20:33:45 -0000 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 9, 2013 +.Dd October 4, 2018 .Dt ATACTL 8 .Os .Sh NAME @@ -103,7 +103,7 @@ and other from 127 to 253. Per the specification, values of 127 and higher do not permit the device to spin down to save power. .El -.It Cm smart Bq Ar enable | disable | status | offline # | error-log | selftest-log +.It Cm smart Bq Ar enable | disable | status [ vendor ] | offline # | error-log | selftest-log Controls SMART feature set of the specified device. SMART stands for Self-Monitoring, Analysis, and Reporting Technology. It provides an early warning system by comparing subtle operation @@ -119,7 +119,7 @@ be preserved by the device across power .It Ar disable Disables access to SMART capabilities within the device. Attribute values will be saved, and will no longer be monitored. -.It Ar status +.It Ar status Ar Bq vendor Reports whether SMART is supported by the device, and whether SMART is enabled on the device (can only be determined on ATA6 or better devices). If SMART is enabled, then a table of attribute information is printed. @@ -153,6 +153,12 @@ The collect field indicates whether this device is online. The reliability field indicates whether the attribute value is within the acceptable threshold. +.Pp +If the +.Ar vendor +argument is supplied, a vendor-specific table will be used for SMART +information if known to +.Nm . .It Ar offline # Runs the numbered offline self-test on the drive. .It Ar error-log Index: atactl.c =================================================================== RCS file: /cvsroot/src/sbin/atactl/atactl.c,v retrieving revision 1.77 diff -p -u -u -r1.77 atactl.c --- atactl.c 4 Oct 2016 21:37:46 -0000 1.77 +++ atactl.c 4 Oct 2018 20:33:45 -0000 @@ -107,7 +107,7 @@ static void print_bitinfo(const char *, const struct bitinfo *); static void print_bitinfo2(const char *, const char *, u_int, u_int, const struct bitinfo *); -static void print_smart_status(void *, void *); +static void print_smart_status(void *, void *, const char *); static void print_error_entry(int, const struct ata_smart_error *); static void print_selftest_entry(int, const struct ata_smart_selftest *); @@ -143,7 +143,7 @@ static const struct command device_comma { "sleep", "", device_idle }, { "checkpower", "", device_checkpower }, { "smart", - "enable|disable|status|offline #|error-log|selftest-log", + "enable|disable|status [vendor]|offline #|error-log|selftest-log", device_smart }, { "security", "status|freeze|[setpass|unlock|disable|erase] [user|master]", @@ -255,8 +255,8 @@ static const struct bitinfo ata_sata_fea { 0, NULL }, }; -static const struct { - const int id; +static const struct attr_table { + const unsigned id; const char *name; void (*special)(const struct ata_smart_attr *, uint64_t); } smart_attrs[] = { @@ -279,7 +279,7 @@ static const struct { { 171, "Program Fail Count", NULL }, { 172, "Erase Fail Count", NULL }, { 173, "Wear Leveller Worst Case Erase Count", NULL }, - { 174, "Unexpected Power Loss", NULL }, + { 174, "Unexpected Power Loss Count", NULL }, { 175, "Program Fail Count", NULL }, { 176, "Erase Fail Count", NULL }, { 177, "Wear Leveling Count", NULL }, @@ -292,7 +292,7 @@ static const struct { { 184, "End-to-end error", NULL }, { 185, "Head Stability", NULL }, { 186, "Induced Op-Vibration Detection", NULL }, - { 187, "Reported uncorrect", NULL }, + { 187, "Reported Uncorrectable Errors", NULL }, { 188, "Command Timeout", NULL }, { 189, "High Fly Writes", NULL }, { 190, "Airflow Temperature", device_smart_temp }, @@ -334,13 +334,37 @@ static const struct { { 242, "Total LBAs Read", NULL }, { 246, "Total Host Sector Writes", NULL }, { 247, "Host Program NAND Pages Count", NULL }, - { 248, "FTL Program Pages Count ", NULL }, + { 248, "FTL Program Pages Count", NULL }, { 249, "Total Raw NAND Writes (1GiB units)", NULL }, { 250, "Read error retry rate", NULL }, { 254, "Free Fall Sensor", NULL }, { 0, "Unknown", NULL }, }; +/* + * Micron specific SMART attributes published by Micron in: + * "TN-FD-22: Client SATA SSD SMART Attribute Reference" + */ +static const struct attr_table micron_smart_names[] = { + { 5, "Reallocated NAND block count", NULL }, + { 173, "Average block erase count", NULL }, + { 184, "Error correctin count", NULL }, + { 197, "Current pending ECC count", NULL }, + { 198, "SMART offline scan uncorrectable error count", NULL }, + { 202, "Percent lifetime remaining", NULL }, + { 206, "Write error rate", NULL }, + { 247, "Number of NAND pages of data written by the host", NULL }, + { 248, "Number of NAND pages written by the FTL", NULL }, + { 0, "Unknown", NULL }, +}; + +const struct vendor_name_table { + const char *name; + const struct attr_table *table; +} vendor_smart_names[] = { + { .name = "Micron", .table = micron_smart_names }, +}; + static const struct bitinfo ata_sec_st[] = { { WDC_SEC_SUPP, "supported" }, { WDC_SEC_EN, "enabled" }, @@ -516,22 +540,36 @@ device_smart_temp(const struct ata_smart attr->raw[2], attr->raw[4]); } - /* * Print out SMART attribute thresholds and values */ static void -print_smart_status(void *vbuf, void *tbuf) +print_smart_status(void *vbuf, void *tbuf, const char *vendor) { const struct ata_smart_attributes *value_buf = vbuf; const struct ata_smart_thresholds *threshold_buf = tbuf; const struct ata_smart_attr *attr; uint64_t raw_value; int flags; - int i, j; - int aid; + unsigned i, j; + unsigned aid, vid; uint8_t checksum; + const struct attr_table *vendor_table = NULL; + void (*special)(const struct ata_smart_attr *, uint64_t); + + if (vendor) { + for (i = 0; i < __arraycount(vendor_smart_names); i++) { + if (strcasecmp(vendor, + vendor_smart_names[i].name) == 0) { + vendor_table = vendor_smart_names[i].table; + break; + } + } + if (vendor_table == NULL) + fprintf(stderr, + "SMART vendor '%s' has no special table\n", vendor); + } for (i = checksum = 0; i < 512; i++) checksum += ((const uint8_t *) value_buf)[i]; @@ -551,6 +589,7 @@ print_smart_status(void *vbuf, void *tbu " raw\n"); for (i = 0; i < 256; i++) { int thresh = 0; + const char *name = NULL; attr = NULL; @@ -574,20 +613,34 @@ print_smart_status(void *vbuf, void *tbu aid++) ; + if (vendor_table) { + for (vid = 0; + vendor_table[vid].id != i && vendor_table[vid].id != 0; + vid++) + ; + if (vendor_table[vid].id != 0) { + name = vendor_table[vid].name; + special = vendor_table[vid].special; + } + } + if (name == NULL) { + name = smart_attrs[aid].name; + special = smart_attrs[aid].special; + } + flags = le16toh(attr->flags); printf("%3d %3d %3d %-3s %-7s %stive %-27s ", i, attr->value, thresh, flags & WDSM_ATTR_ADVISORY ? "yes" : "no", flags & WDSM_ATTR_COLLECTIVE ? "online" : "offline", - attr->value > thresh ? "posi" : "nega", - smart_attrs[aid].name); + attr->value > thresh ? "posi" : "nega", name); for (j = 0, raw_value = 0; j < 6; j++) raw_value += ((uint64_t)attr->raw[j]) << (8*j); - if (smart_attrs[aid].special) - (*smart_attrs[aid].special)(attr, raw_value); + if (special) + (*special)(attr, raw_value); else printf("%" PRIu64, raw_value); printf("\n"); @@ -1296,6 +1349,7 @@ device_smart(int argc, char *argv[]) is_smart(); } else if (strcmp(argv[0], "status") == 0) { int rv; + char *vendor = argc > 1 ? argv[1] : NULL; rv = is_smart(); @@ -1350,7 +1404,7 @@ device_smart(int argc, char *argv[]) ata_command(&req); - print_smart_status(inbuf, inbuf2); + print_smart_status(inbuf, inbuf2, vendor); } else if (strcmp(argv[0], "offline") == 0) { if (argc != 2)