Add ATA SMART reporting support from Ben Collver in kern/12787.
This commit is contained in:
parent
16cf89e5a5
commit
9e129fde67
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user