From fbde61a065b5b1e74d181bf58145ad5a19b27a50 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 Jun 2008 22:51:55 +0200 Subject: implement smart read status call --- smart.c | 61 +++++++++++++++++++++++++++++++++++++++++++------------------ smart.h | 19 ++++++------------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/smart.c b/smart.c index 430785f..f0710c4 100644 --- a/smart.c +++ b/smart.c @@ -275,7 +275,7 @@ static int disk_passthrough_command(SkDisk *d, SkAtaCommand command, SkDirection cdb[6] = bytes[3]; cdb[8] = bytes[9]; /* LBA LOW */ - cdb[10] = bytes[8]; /* LBA MED */ + cdb[10] = bytes[8]; /* LBA MID */ cdb[12] = bytes[7]; /* LBA HIGH */ cdb[13] = bytes[10] & 0x4F; /* SELECT */ @@ -296,7 +296,7 @@ static int disk_passthrough_command(SkDisk *d, SkAtaCommand command, SkDirection bytes[3] = desc[5]; bytes[9] = desc[7]; bytes[8] = desc[9]; - bytes[7] = desc[10]; + bytes[7] = desc[11]; bytes[10] = desc[12]; bytes[11] = desc[13]; @@ -436,20 +436,38 @@ static int disk_smart_read_thresholds(SkDisk *d) { return ret; } -/* int disk_smart_status(SkDisk *d, SmartLogAddress a, gboolean *b) { */ -/* guint16 cmd[6]; */ +int sk_disk_smart_status(SkDisk *d, gboolean *good) { + guint16 cmd[6]; + int ret; + + if (!disk_smart_is_available(d)) { + errno = ENOTSUP; + return -1; + } -/* guint8 data[16]; */ + memset(cmd, 0, sizeof(cmd)); + + cmd[0] = GUINT16_TO_BE(SK_SMART_COMMAND_RETURN_STATUS); + cmd[1] = GUINT16_TO_BE(0x0000U); + cmd[3] = GUINT16_TO_BE(0x00C2U); + cmd[4] = GUINT16_TO_BE(0x4F00U); -/* cmd[0] = GUINT16_TO_BE(SMART_RETURN_STATUS); */ -/* cmd[1] = GUINT16_TO_BE(0x0000U); */ -/* cmd[3] = GUINT16_TO_BE(0x00C2U); */ -/* cmd[4] = GUINT16_TO_BE(0x4F00U | (guint16) a); */ + if ((ret = disk_command(d, SK_ATA_COMMAND_SMART, SK_DIRECTION_NONE, cmd, NULL, 0)) < 0) + return ret; -/* ret = disk_command(SK_ATA_SMART, cmd, sizeof(cmd), NULL, 0); */ + if (cmd[3] == GUINT16_TO_BE(0x00C2U) && + cmd[4] == GUINT16_TO_BE(0x4F00U)) + *good = TRUE; + else if (cmd[3] == GUINT16_TO_BE(0x002CU) && + cmd[4] == GUINT16_TO_BE(0xF400U)) + *good = FALSE; + else { + errno = EIO; + return -1; + } -/* return ret; */ -/* } */ + return ret; +} int sk_disk_smart_self_test(SkDisk *d, SkSmartSelfTest test) { guint16 cmd[6]; @@ -885,9 +903,9 @@ static void find_threshold(SkDisk *d, SkSmartAttributeParsedData *a) { a->threshold = p[1]; a->threshold_valid = TRUE; - a->bad = - a->worst_value <= a->threshold || - a->current_value <= a->threshold; + a->good = + a->worst_value > a->threshold && + a->current_value > a->threshold; } int sk_disk_smart_parse_attributes(SkDisk *d, SkSmartAttributeParseCallback cb, gpointer userdata) { @@ -1025,7 +1043,7 @@ static void disk_dump_attributes(SkDisk *d, const SkSmartAttributeParsedData *a, g_snprintf(t, sizeof(t), "%3u", a->threshold); - if (a->bad && isatty(1)) + if (!a->good && isatty(1)) fprintf(stderr, HIGHLIGHT); g_print("%3u %-27s %3u %3u %-3s %-11s %-7s %-7s %-3s\n", @@ -1037,9 +1055,9 @@ static void disk_dump_attributes(SkDisk *d, const SkSmartAttributeParsedData *a, print_value(pretty, sizeof(pretty), a), a->prefailure ? "prefail" : "old-age", a->online ? "online" : "offline", - yes_no(!a->bad)); + yes_no(a->good)); - if (a->bad && isatty(1)) + if (!a->good && isatty(1)) fprintf(stderr, ENDHIGHLIGHT); } @@ -1074,6 +1092,13 @@ int sk_disk_dump(SkDisk *d) { if (disk_smart_is_available(d)) { const SkSmartParsedData *spd; + gboolean good; + + if ((ret = sk_disk_smart_status(d, &good)) < 0) + return ret; + + g_print("Disk Health Good: %s\n", + yes_no(good)); if ((ret = sk_disk_smart_read_data(d)) < 0) return ret; diff --git a/smart.h b/smart.h index d4a64d3..0107d9b 100644 --- a/smart.h +++ b/smart.h @@ -123,7 +123,7 @@ typedef struct SkSmartAttributeParsedData { gboolean prefailure:1; /* Volatile data */ - gboolean bad:1; + gboolean good:1; guint8 current_value, worst_value; guint64 pretty_value; guint8 raw[6]; @@ -136,35 +136,28 @@ typedef struct SkDisk SkDisk; int sk_disk_open(const gchar *name, SkDisk **d); +int sk_disk_get_size(SkDisk *d, guint64 *bytes); + int sk_disk_check_sleep_mode(SkDisk *d, gboolean *awake); int sk_disk_identify_is_available(SkDisk *d, gboolean *b); int sk_disk_identify_parse(SkDisk *d, const SkIdentifyParsedData **data); -int sk_disk_smart_is_available(SkDisk *d, gboolean *b); +typedef void (*SkSmartAttributeParseCallback)(SkDisk *d, const SkSmartAttributeParsedData *a, gpointer userdata); +int sk_disk_smart_is_available(SkDisk *d, gboolean *b); +int sk_disk_smart_status(SkDisk *d, gboolean *good); /* Reading SMART data might cause the disk to wake up from * sleep. Hence from monitoring daemons make sure to call * sk_disk_check_power_mode() to check wether the disk is sleeping and * skip the read if so. */ int sk_disk_smart_read_data(SkDisk *d); - int sk_disk_smart_parse(SkDisk *d, const SkSmartParsedData **data); - -typedef void (*SkSmartAttributeParseCallback)(SkDisk *d, const SkSmartAttributeParsedData *a, gpointer userdata); int sk_disk_smart_parse_attributes(SkDisk *d, SkSmartAttributeParseCallback cb, gpointer userdata); - -int sk_disk_get_size(SkDisk *d, guint64 *bytes); - int sk_disk_smart_self_test(SkDisk *d, SkSmartSelfTest test); int sk_disk_dump(SkDisk *d); void sk_disk_free(SkDisk *d); -/* TODO: - * - * Smart status - */ - #endif -- cgit