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

This commit is contained in:
soren 2002-08-05 23:29:27 +00:00
parent 16cf89e5a5
commit 9e129fde67
8 changed files with 328 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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 @@ seconds. A value of 0 will disable the Standby timer.
.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

View File

@ -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 @@ int main(int, char *[]);
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_identify(int, char *[]);
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 @@ struct command commands[] = {
{ "standby", "", device_idle },
{ "sleep", "", device_idle },
{ "checkpower", "", device_checkpower },
{ "smart", "enable|disable|info", device_smart },
{ NULL, NULL, NULL },
};
@ -262,6 +267,115 @@ print_bitinfo(const char *bf, const char *af, u_int bits, struct bitinfo *binfo)
printf("%s%s%s", bf, binfo->string, af);
}
/*
* 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 @@ device_checkpower(int argc, char *argv[])
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);
req.timeout = 1000;
ata_command(&req);
is_smart(0);
}
} else if (strcmp(argv[0], "info") == 0) {
if (is_smart(0)) {
memset(&inbuf, 0, sizeof(inbuf));
memset(&req, 0, sizeof(req));
req.features = WDSM_STATUS;
req.command = WDCC_SMART;
req.cylinder = htole16(WDSMART_CYL);
req.timeout = 1000;
ata_command(&req);
if (req.cylinder != htole16(WDSMART_CYL)) {
fprintf(stderr, "Threshold exceeds condition\n");
}
/* WDSM_RD_DATA and WDSM_RD_THRESHOLDS are optional
* features, the following ata_command()'s may error
* and exit().
*/
memset(&inbuf, 0, sizeof(inbuf));
memset(&req, 0, sizeof(req));
req.flags = ATACMD_READ;
req.features = WDSM_RD_DATA;
req.command = WDCC_SMART;
req.databuf = (caddr_t) inbuf;
req.datalen = sizeof(inbuf);
req.cylinder = htole16(WDSMART_CYL);
req.timeout = 1000;
ata_command(&req);
memset(&inbuf2, 0, sizeof(inbuf2));
memset(&req, 0, sizeof(req));
req.flags = ATACMD_READ;
req.features = WDSM_RD_THRESHOLDS;
req.command = WDCC_SMART;
req.databuf = (caddr_t) inbuf2;
req.datalen = sizeof(inbuf2);
req.cylinder = htole16(WDSMART_CYL);
req.timeout = 1000;
ata_command(&req);
print_smart_status(inbuf, inbuf2);
} else {
fprintf(stderr, "SMART not supported\n");
}
} else {
usage();
}
return;
}

View File

@ -1,8 +1,8 @@
# $NetBSD: Makefile,v 1.3 2001/04/11 19:07:36 jdolecek Exp $
# $NetBSD: Makefile,v 1.4 2002/08/05 23:29:30 soren Exp $
INCSDIR= /usr/include/dev/ata
# Only install includes which are used by userland
INCS= atareg.h
INCS= atareg.h atavar.h
.include <bsd.kinc.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: atareg.h,v 1.8 2002/01/13 17:24:30 christos Exp $ */
/* $NetBSD: atareg.h,v 1.9 2002/08/05 23:29:30 soren Exp $ */
/*
* Drive parameter structure for ATA/ATAPI.
@ -120,6 +120,7 @@ struct ataparams {
#define WDC_CMD1_SEC 0x0002
#define WDC_CMD1_SMART 0x0001
u_int16_t atap_cmd_set2; /* 83: command set supported */
#define ATA_CMD2_SMART 0x2000
#define WDC_CMD2_RMSN 0x0010
#define WDC_CMD2_DM 0x0001
#define ATA_CMD2_APM 0x0008

View File

@ -1,4 +1,4 @@
/* $NetBSD: atavar.h,v 1.25 2002/04/23 20:41:14 bouyer Exp $ */
/* $NetBSD: atavar.h,v 1.26 2002/08/05 23:29:30 soren Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@ -144,6 +144,56 @@ struct wdc_command {
void *callback_arg; /* argument passed to *callback() */
};
/*
* If WDSM_ATTR_ADVISORY, device exceeded intended design life period.
* If not WDSM_ATTR_ADVISORY, imminent data loss predicted.
*/
#define WDSM_ATTR_ADVISORY 1
/*
* If WDSM_ATTR_COLLECTIVE, attribute only updated in off-line testing.
* If not WDSM_ATTR_COLLECTIVE, attribute updated also in on-line testing.
*/
#define WDSM_ATTR_COLLECTIVE 2
struct ata_smart_attr {
u_int8_t id; /* attribute id number */
u_int16_t flags;
u_int8_t value; /* attribute value */
u_int8_t vendor_specific[8];
} __attribute__((packed));
struct ata_smart_attributes {
u_int16_t data_structure_revision;
struct ata_smart_attr attributes[30];
u_int8_t offline_data_collection_status;
u_int8_t self_test_exec_status;
u_int16_t total_time_to_complete_off_line;
u_int8_t vendor_specific_366;
u_int8_t offline_data_collection_capability;
u_int16_t smart_capability;
u_int8_t errorlog_capability;
u_int8_t vendor_specific_371;
u_int8_t short_test_completion_time;
u_int8_t extend_test_completion_time;
u_int8_t reserved_374_385[12];
u_int8_t vendor_specific_386_509[125];
int8_t checksum;
} __attribute__((packed));
struct ata_smart_thresh {
u_int8_t id;
u_int8_t value;
u_int8_t reserved[10];
} __attribute__((packed));
struct ata_smart_thresholds {
u_int16_t data_structure_revision;
struct ata_smart_thresh thresholds[30];
u_int8_t reserved[18];
u_int8_t vendor_specific[131];
int8_t checksum;
} __attribute__((packed));
int wdc_downgrade_mode __P((struct ata_drive_datas*));
struct ataparams;

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcreg.h,v 1.25 2002/03/31 19:47:39 bouyer Exp $ */
/* $NetBSD: wdcreg.h,v 1.26 2002/08/05 23:29:27 soren Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@ -167,6 +167,7 @@
/* Subcommands for SMART (features register) */
#define WDSM_RD_DATA 0xd0
#define WDSM_RD_THRESHOLDS 0xd1
#define WDSM_ATTR_AUTOSAVE_EN 0xd2
#define WDSM_SAVE_ATTR 0xd3
#define WDSM_EXEC_OFFL_IMM 0xd4
@ -174,9 +175,7 @@
#define WDSM_DISABLE_OPS 0xd9
#define WDSM_STATUS 0xda
#define WDSMART_CYL_LO 0x4f
#define WDSMART_CYL_HI 0xc2
#define WDSMART_CYL 0xc24f
/* parameters uploaded to device/heads register */
#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */