Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sbin/atactl extend "smart status" command to "smart status [...



details:   https://anonhg.NetBSD.org/src/rev/cd21f10ac1bf
branches:  trunk
changeset: 445525:cd21f10ac1bf
user:      mrg <mrg%NetBSD.org@localhost>
date:      Wed Oct 31 20:00:56 2018 +0000

description:
extend "smart status" command to "smart status [vendor]", and supply a
"Micron" (for Micron/Crucial) list with their documented values.

this allows the vendor-specific data to be used.

there appears to be no simple way to automatically determine the right
vendor to use -- identify data seems to be the only obvious way and
that data can be and is changed by OEMs.  (eg, a disk may be listed as
being "dell", but dell don't make disks.)  as such, no attempt is made
to automatically determine if a vendor list should be used.

diffstat:

 sbin/atactl/atactl.8 |   22 +++++++++--
 sbin/atactl/atactl.c |  102 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 102 insertions(+), 22 deletions(-)

diffs (282 lines):

diff -r 219ca7025a2b -r cd21f10ac1bf sbin/atactl/atactl.8
--- a/sbin/atactl/atactl.8      Wed Oct 31 18:35:04 2018 +0000
+++ b/sbin/atactl/atactl.8      Wed Oct 31 20:00:56 2018 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: atactl.8,v 1.24 2013/01/09 21:58:23 riastradh Exp $
+.\"    $NetBSD: atactl.8,v 1.25 2018/10/31 20:00:56 mrg Exp $
 .\"
 .\" Copyright (c) 1998 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -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 @@
 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 @@
 .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 Bq Ar 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,15 @@
 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 .
+Currently, only
+.Dq micron
+has a vendor-specific table.
 .It Ar offline #
 Runs the numbered offline self-test on the drive.
 .It Ar error-log
@@ -272,3 +281,8 @@
 .Nx
 kernel behaves poorly with drives that have passwords set and are
 locked.
+.Pp
+The
+.Cm smart status
+command is currently unable to automatically determine the vendor
+attribute name table to use, and must be specified manually.
diff -r 219ca7025a2b -r cd21f10ac1bf sbin/atactl/atactl.c
--- a/sbin/atactl/atactl.c      Wed Oct 31 18:35:04 2018 +0000
+++ b/sbin/atactl/atactl.c      Wed Oct 31 20:00:56 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atactl.c,v 1.77 2016/10/04 21:37:46 mrg Exp $  */
+/*     $NetBSD: atactl.c,v 1.78 2018/10/31 20:00:56 mrg Exp $  */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: atactl.c,v 1.77 2016/10/04 21:37:46 mrg Exp $");
+__RCSID("$NetBSD: atactl.c,v 1.78 2018/10/31 20:00:56 mrg Exp $");
 #endif
 
 
@@ -107,7 +107,7 @@
     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 @@
        { "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,15 @@
        { 0, NULL },
 };
 
-static const struct {
-       const int       id;
+/*
+ * Global SMART attribute table.  All known attributes should be defined
+ * here with overrides outside of the standard in a vendor specific table.
+ *
+ * XXX Some of these should be duplicated to vendor-specific tables now that
+ * XXX they exist and have non generic names.
+ */
+static const struct attr_table {
+       const unsigned  id;
        const char      *name;
        void (*special)(const struct ata_smart_attr *, uint64_t);
 } smart_attrs[] = {
@@ -279,7 +286,7 @@
        { 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 +299,7 @@
        { 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 +341,42 @@
        { 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 correction 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 },
+};
+
+/*
+ * Vendor-specific SMART attribute table.  Can be used to override
+ * a particular attribute name and special printer function, with the
+ * default is the main table.
+ */
+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 +552,36 @@
                    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 +601,7 @@
            "                 raw\n");
        for (i = 0; i < 256; i++) {
                int thresh = 0;
+               const char *name = NULL;
 
                attr = NULL;
 
@@ -574,20 +625,34 @@
                     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 +1361,7 @@
                is_smart();
        } else if (strcmp(argv[0], "status") == 0) {
                int rv;
+               char *vendor = argc > 1 ? argv[1] : NULL;
 
                rv = is_smart();
 
@@ -1350,7 +1416,7 @@
 
                ata_command(&req);
 
-               print_smart_status(inbuf, inbuf2);
+               print_smart_status(inbuf, inbuf2, vendor);
 
        } else if (strcmp(argv[0], "offline") == 0) {
                if (argc != 2)



Home | Main Index | Thread Index | Old Index