Source-Changes-HG archive

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

[src/trunk]: src Add ATA SMART reporting support from Ben Collver in kern/12787.



details:   https://anonhg.NetBSD.org/src/rev/88849f8fca76
branches:  trunk
changeset: 534889:88849f8fca76
user:      soren <soren%NetBSD.org@localhost>
date:      Mon Aug 05 23:29:27 2002 +0000

description:
Add ATA SMART reporting support from Ben Collver in kern/12787.

diffstat:

 distrib/sets/lists/comp/mi          |    3 +-
 distrib/sets/lists/comp/obsolete.mi |    3 +-
 sbin/atactl/atactl.8                |   54 ++++++++-
 sbin/atactl/atactl.c                |  215 +++++++++++++++++++++++++++++++++++-
 sys/dev/ata/Makefile                |    4 +-
 sys/dev/ata/atareg.h                |    3 +-
 sys/dev/ata/atavar.h                |   52 ++++++++-
 sys/dev/ic/wdcreg.h                 |    7 +-
 8 files changed, 328 insertions(+), 13 deletions(-)

diffs (truncated from 487 to 300 lines):

diff -r e53b65d81cee -r 88849f8fca76 distrib/sets/lists/comp/mi
--- a/distrib/sets/lists/comp/mi        Mon Aug 05 20:58:35 2002 +0000
+++ b/distrib/sets/lists/comp/mi        Mon Aug 05 23:29:27 2002 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: mi,v 1.462 2002/08/04 01:07:21 gmcgarry Exp $
+#      $NetBSD: mi,v 1.463 2002/08/05 23:29:27 soren Exp $
 ./sys                          comp-sysutil-root
 ./usr/bin/addr2line            comp-debug-bin
 ./usr/bin/ar                   comp-util-bin
@@ -120,6 +120,7 @@
 ./usr/include/db.h                     comp-c-include
 ./usr/include/dev/ata                  comp-c-include
 ./usr/include/dev/ata/atareg.h         comp-c-include
+./usr/include/dev/ata/atavar.h         comp-c-include
 ./usr/include/dev/ccdvar.h             comp-c-include
 ./usr/include/dev/dec                  comp-c-include
 ./usr/include/dev/dec/dec_boot.h       comp-c-include
diff -r e53b65d81cee -r 88849f8fca76 distrib/sets/lists/comp/obsolete.mi
--- a/distrib/sets/lists/comp/obsolete.mi       Mon Aug 05 20:58:35 2002 +0000
+++ b/distrib/sets/lists/comp/obsolete.mi       Mon Aug 05 23:29:27 2002 +0000
@@ -1,11 +1,10 @@
-# $NetBSD: obsolete.mi,v 1.71 2002/07/14 10:40:54 wiz Exp $
+# $NetBSD: obsolete.mi,v 1.72 2002/08/05 23:29:29 soren Exp $
 /usr/bin/genclass
 /usr/bin/gettextize
 /usr/include/bfd
 /usr/include/bfd/ansidecl.h
 /usr/include/bfd/bfd.h
 /usr/include/bfd/libiberty.h
-/usr/include/dev/ata/atavar.h
 /usr/include/dev/ata/wdvar.h
 /usr/include/dev/auconv.h
 /usr/include/dev/audio_if.h
diff -r e53b65d81cee -r 88849f8fca76 sbin/atactl/atactl.8
--- a/sbin/atactl/atactl.8      Mon Aug 05 20:58:35 2002 +0000
+++ b/sbin/atactl/atactl.8      Mon Aug 05 23:29:27 2002 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: atactl.8,v 1.9 2001/11/16 11:21:37 wiz Exp $
+.\"    $NetBSD: atactl.8,v 1.10 2002/08/05 23:29:29 soren Exp $
 .\"
 .\" Copyright (c) 1998 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -103,6 +103,58 @@
 .Pp
 Will print out if the device is in Active, Idle, or Standby power
 management mode.
+.Pp
+.Cm smart
+.Ar [enable | disable | info]
+.Pp
+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 characteristics to
+those determined in vendor testing to precede device failures.
+.Pp
+.Ar enable
+.Pp
+Enables access to SMART capabilities within the device.  Prior to being
+enabled, a SMART capable device neither monitors nor saves SMART
+attribute values.  The state of SMART, either enabled or disabled, will
+be preserved by the device across power cycles.
+.Pp
+.Ar disable
+.Pp
+Disables access to SMART capabilities within the device.  Attribute values
+will be saved, and will no longer be monitored.
+.Pp
+.Ar info
+.Pp
+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.
+Attributes are the specific performance or calibration parameters that
+are used in analyzing the status of the device.  The specific set of
+attributes being used and the identity of these attributes is vendor
+specific and proprietary.
+.Pp
+Attribute values are used to represent the relative reliability of
+individual performance or calibration parameters.  The valid range of
+attribute values is from 1 to 253 decimal.  Lower values indicate that the
+analysis algorithms being used by the device are predicting a higher
+probability of a degrading or faulty condition.
+.Pp
+Each attribute value has a corresponding threshold limit which is used for
+direct comparison to the attribute value to indicate the existence of a
+degrading or faulty conditon.  The numerical value of the attribute
+thresholds are determined by the device manufacturer through design and
+reliability testing and analysis.  Each attribute threshold represents the
+lowest limit to which its corresponding attribute value can equal while
+still retaining a positive reliability status.
+.Pp
+If the crit field is "yes" then negative reliability of this attribute
+predicts imminent data loss.  Otherwise it merely indicates that the
+intended design life period of usage or age has been exceeded.
+The collect field indicates whether this attribute is updated while the
+device is online.  The reliability field indicates whether the attribute
+value is within the acceptable threshold.
+.Pp
 .Sh SEE ALSO
 .Xr ioctl 2 ,
 .Xr wd 4
diff -r e53b65d81cee -r 88849f8fca76 sbin/atactl/atactl.c
--- a/sbin/atactl/atactl.c      Mon Aug 05 20:58:35 2002 +0000
+++ b/sbin/atactl/atactl.c      Mon Aug 05 23:29:27 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atactl.c,v 1.14 2001/09/07 16:33:50 simonb Exp $       */
+/*     $NetBSD: atactl.c,v 1.15 2002/08/05 23:29:29 soren Exp $        */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -52,6 +52,7 @@
 #include <util.h>
 
 #include <dev/ata/atareg.h>
+#include <dev/ata/atavar.h>
 #include <dev/ic/wdcreg.h>
 #include <sys/ataio.h>
 
@@ -70,6 +71,8 @@
 void   usage(void);
 void   ata_command(struct atareq *);
 void   print_bitinfo(const char *, const char *, u_int, struct bitinfo *);
+void   print_smart_status(void *vbuf, void *tbuf);
+int    is_smart(int silent);
 
 int    fd;                             /* file descriptor for device */
 const  char *dvname;                   /* device name */
@@ -81,6 +84,7 @@
 void   device_setidle(int, char *[]);
 void   device_idle(int, char *[]);
 void   device_checkpower(int, char *[]);
+void   device_smart(int, char *[]);
 
 struct command commands[] = {
        { "identify",   "",                     device_identify },
@@ -90,6 +94,7 @@
        { "standby",    "",                     device_idle },
        { "sleep",      "",                     device_idle },
        { "checkpower", "",                     device_checkpower },
+       { "smart",      "enable|disable|info",  device_smart },
        { NULL,         NULL,                   NULL },
 };
 
@@ -263,6 +268,115 @@
 }
 
 /*
+ * Print out SMART attribute thresholds and values
+ */
+
+void
+print_smart_status(void *vbuf, void *tbuf)
+{
+       struct ata_smart_attributes *value_buf = vbuf;
+       struct ata_smart_thresholds *threshold_buf = tbuf;
+       int values[256];
+       int thresholds[256];
+       int flags[256];
+       int i;
+       int id;
+       int8_t checksum;
+
+       for (i = checksum = 0; i < 511; i++)
+               checksum += ((int8_t *) value_buf)[i];
+       checksum *= -1;
+       if (checksum != value_buf->checksum) {
+               fprintf(stderr, "SMART attribute values checksum error\n");
+               return;
+       }
+
+       for (i = checksum = 0; i < 511; i++)
+               checksum += ((int8_t *) threshold_buf)[i];
+       checksum *= -1;
+       if (checksum != threshold_buf->checksum) {
+               fprintf(stderr, "SMART attribute thresholds checksum error\n");
+               return;
+       }
+
+       memset(values, 0, sizeof(values));
+       memset(thresholds, 0, sizeof(thresholds));
+       memset(flags, 0, sizeof(flags));
+
+       for (i = 0; i < 30; i++) {
+               id = value_buf->attributes[i].id;
+               values[id] = value_buf->attributes[i].value;
+               flags[id] = value_buf->attributes[i].flags;
+               id = threshold_buf->thresholds[i].id;
+               thresholds[id] = threshold_buf->thresholds[i].value;
+       }
+
+       printf("id\tvalue\tthresh\tcrit\tcollect\treliability\n");
+       for (i = 0; i < 256; i++) {
+               if (values[i] != 00 && values[i] != 0xFE && values[i] != 0xFF) {
+                       printf("%2d\t%3d\t%3d\t%s\t%sline\t%stive\n",
+                              i, values[i], thresholds[i],
+                              flags[i] & WDSM_ATTR_ADVISORY ? "yes" : "no",
+                              flags[i] & WDSM_ATTR_COLLECTIVE ? "on" : "off",
+                              values[i] > thresholds[i] ? "posi" : "nega");
+               }
+       }
+}
+
+/*
+ * is_smart:
+ *
+ *     Detect whether device supports SMART and SMART is enabled.
+ */
+
+int
+is_smart(int silent)
+{
+       int retval = 0;
+       struct atareq req;
+       unsigned char inbuf[DEV_BSIZE];
+       struct ataparams *inqbuf;
+       char *status;
+
+       memset(&inbuf, 0, sizeof(inbuf));
+       memset(&req, 0, sizeof(req));
+
+       inqbuf = (struct ataparams *) inbuf;
+
+       req.flags = ATACMD_READ;
+       req.command = WDCC_IDENTIFY;
+       req.databuf = (caddr_t) inbuf;
+       req.datalen = sizeof(inbuf);
+       req.timeout = 1000;
+
+       ata_command(&req);
+
+       if (inqbuf->atap_cmd_def != 0 && inqbuf->atap_cmd_def != 0xffff) {
+               if (!(inqbuf->atap_cmd_set1 & WDC_CMD1_SMART)) {
+                       fprintf(stderr, "SMART unsupported\n");
+               } else {
+                       if (inqbuf->atap_ata_major <= WDC_VER_ATA5 ||
+                           inqbuf->atap_cmd_set2 == 0xffff ||
+                           inqbuf->atap_cmd_set2 == 0x0000) {
+                               status = "status unknown";
+                               retval = 2;
+                       } else {
+                               if (inqbuf->atap_cmd_set2 & ATA_CMD2_SMART) {
+                                       status = "enabled";
+                                       retval = 1;
+                               } else {
+                                       status = "disabled";
+                               }
+                       }
+                       if (!silent || retval == 0) {
+                               printf("SMART supported, SMART %s\n", status);
+                       }
+               }
+       }
+       return retval;
+}
+                                       
+/*
  * DEVICE COMMANDS
  */
 
@@ -517,3 +631,102 @@
 
        return;
 }
+
+/*
+ * device_smart:
+ *
+ *     Display SMART status
+ */
+void
+device_smart(int argc, char *argv[])
+{
+       struct atareq req;
+       unsigned char inbuf[DEV_BSIZE];
+       unsigned char inbuf2[DEV_BSIZE];
+
+       /* Only one argument */
+       if (argc != 1)
+               usage();
+
+       if (strcmp(argv[0], "enable") == 0) {
+               if (is_smart(1)) {
+                       memset(&req, 0, sizeof(req));
+
+                       req.features = WDSM_ENABLE_OPS;
+                       req.command = WDCC_SMART;
+                       req.cylinder = htole16(WDSMART_CYL);
+                       req.timeout = 1000;
+
+                       ata_command(&req);
+
+                       is_smart(0);
+               }
+       } else if (strcmp(argv[0], "disable") == 0) {
+               if (is_smart(1)) {
+                       memset(&req, 0, sizeof(req));
+
+                       req.features = WDSM_DISABLE_OPS;
+                       req.command = WDCC_SMART;
+                       req.cylinder = htole16(WDSMART_CYL);



Home | Main Index | Thread Index | Old Index