Module Name:    src
Committed By:   mrg
Date:           Wed Oct 31 20:00:56 UTC 2018

Modified Files:
        src/sbin/atactl: atactl.8 atactl.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 src/sbin/atactl/atactl.8
cvs rdiff -u -r1.77 -r1.78 src/sbin/atactl/atactl.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/atactl/atactl.8
diff -u src/sbin/atactl/atactl.8:1.24 src/sbin/atactl/atactl.8:1.25
--- src/sbin/atactl/atactl.8:1.24	Wed Jan  9 21:58:23 2013
+++ src/sbin/atactl/atactl.8	Wed Oct 31 20:00:56 2018
@@ -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 @@ 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 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 @@ 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 .
+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 @@ The
 .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.

Index: src/sbin/atactl/atactl.c
diff -u src/sbin/atactl/atactl.c:1.77 src/sbin/atactl/atactl.c:1.78
--- src/sbin/atactl/atactl.c:1.77	Tue Oct  4 21:37:46 2016
+++ src/sbin/atactl/atactl.c	Wed Oct 31 20:00:56 2018
@@ -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 @@ 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,15 @@ static const struct bitinfo ata_sata_fea
 	{ 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 @@ 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 +299,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 +341,42 @@ 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 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 @@ 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 +601,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 +625,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 +1361,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 +1416,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)

Reply via email to