diff --git a/cmdline/device.c b/cmdline/device.c index c0480a35..970f7407 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -408,7 +408,7 @@ static double smart_afr_value(double* tab, unsigned step, uint64_t value) * we use the maximum rate reported, and we do not sum them, * because the attributes are not independent. */ -static double smart_afr(struct smart_struct* smart, const char* model) +static double smart_afr(struct smart_attr* smart, const char* model) { double afr = 0; uint64_t mask32 = 0xffffffffU; @@ -556,10 +556,31 @@ static void state_smart_log(devinfo_t* devinfo, double afr) if (afr != 0) log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_at_least_one_failure(afr)); - for (j = 0; j < 256; ++j) - if (devinfo->smart[j].raw != SMART_UNASSIGNED) { - log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%s\n", devinfo->file, devinfo->name, j, devinfo->smart[j].raw, devinfo->smart[j].raw, devinfo->smart[j].norm, devinfo->smart[j].worst, devinfo->smart[j].thresh, devinfo->smart[j].name); + for (j = 0; j < 256; ++j) { + struct smart_attr* attr = &devinfo->smart[j]; + if (attr->raw != SMART_UNASSIGNED) { + const char* type = "";; + const char* updated = ""; + const char* when_failed = ""; + + if (attr->flags & SMART_ATTR_TYPE_PREFAIL) + type = "prefail"; + else if (attr->flags & SMART_ATTR_TYPE_OLDAGE) + type = "oldage"; + if (attr->flags & SMART_ATTR_UPDATE_ALWAYS) + updated = "always"; + else if (attr->flags & SMART_ATTR_UPDATE_OFFLINE) + updated = "offline"; + if (attr->flags & SMART_ATTR_WHEN_FAILED_NOW) + when_failed = "now"; + else if (attr->flags & SMART_ATTR_WHEN_FAILED_PAST) + when_failed = "past"; + else if (attr->flags & SMART_ATTR_WHEN_FAILED_NEVER) + when_failed = "never"; + + log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 ":%" PRIu64 ":%" PRIu64 ":%" PRIu64 ":%s:%s:%s:%s\n", devinfo->file, devinfo->name, j, attr->raw, attr->raw, attr->norm, attr->worst, attr->thresh, attr->name, type, updated, when_failed); } + } int temp = smart_temp(devinfo); if (temp >= 0) diff --git a/cmdline/mingw.c b/cmdline/mingw.c index 4c6885ab..e6199c3a 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2506,7 +2506,7 @@ static int devscan(tommy_list* list) /** * Get SMART attributes. */ -static int devsmart(uint64_t device, const char* name, const char* smartctl, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* inter) +static int devsmart(uint64_t device, const char* name, const char* smartctl, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* inter) { char conv_buf[CONV_MAX]; WCHAR cmd[MAX_PATH + 128]; @@ -2738,7 +2738,7 @@ static void devattr(uint64_t device, const char* name, const char* wfile, uint64 /** * Get POWER state */ -static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interf) +static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf) { char conv_buf[CONV_MAX]; WCHAR cmd[MAX_PATH + 128]; diff --git a/cmdline/portable.h b/cmdline/portable.h index dd572020..223bd50c 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -502,6 +502,25 @@ int randomize(void* ptr, size_t size); */ #define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL +/** + * SMART Attribute flags + */ +#define SMART_ATTR_TYPE_PREFAIL 1 +#define SMART_ATTR_TYPE_OLDAGE 2 +#define SMART_ATTR_UPDATE_ALWAYS 4 +#define SMART_ATTR_UPDATE_OFFLINE 8 +#define SMART_ATTR_WHEN_FAILED_NOW 16 +#define SMART_ATTR_WHEN_FAILED_PAST 32 +#define SMART_ATTR_WHEN_FAILED_NEVER 64 + +struct smart_attr { + char name[128]; /**< SMART attribute name. */ + uint64_t raw; /**< SMART attributes raw. */ + uint64_t norm; /**< SMART attributes normalized. */ + uint64_t worst; /**< SMART attributes worst. */ + uint64_t thresh; /**< SMART attributes threshold. */ + int flags; /**< SMART_ATTR_* flags */ +}; /** * Power mode @@ -510,14 +529,6 @@ int randomize(void* ptr, size_t size); #define POWER_ACTIVE 1 #define POWER_UNKNOWN -1 -struct smart_struct { - char name[128]; /**< SMART attribute name. */ - uint64_t raw; /**< SMART attributes raw. */ - uint64_t norm; /**< SMART attributes normalized. */ - uint64_t worst; /**< SMART attributes worst. */ - uint64_t thresh; /**< SMART attributes threshold. */ -}; - /** * Device info entry. */ @@ -533,7 +544,7 @@ struct devinfo_struct { #endif struct devinfo_struct* parent; /**< Pointer at the parent if any. */ struct devinfo_struct* split; /**< Pointer at first split if any. */ - struct smart_struct smart[SMART_COUNT]; /**< All smart values. */ + struct smart_attr smart[SMART_COUNT]; /**< All smart values. */ uint64_t info[INFO_COUNT]; /**< Info attributes. */ uint64_t access_stat; /**< Access stat info. */ char serial[SMART_MAX]; /**< Serial number. */ diff --git a/cmdline/support.c b/cmdline/support.c index bd5edfd6..a1c9d243 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -1702,11 +1702,11 @@ static int smatch(const char* str, const char* pattern) return 0; } -int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* inter) +int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* inter) { unsigned i; int inside; - struct smart_struct dummy_smart[SMART_COUNT]; + struct smart_attr dummy_smart[SMART_COUNT]; uint64_t dummy_info[INFO_COUNT]; char dummy_serial[SMART_MAX]; char dummy_family[SMART_MAX]; @@ -1732,7 +1732,7 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart *family = 0; *model = 0; *inter = 0; - memset(smart, 0, sizeof(struct smart_struct) * SMART_COUNT); + memset(smart, 0, sizeof(struct smart_attr) * SMART_COUNT); for (i = 0; i < SMART_COUNT; ++i) smart[i].raw = SMART_UNASSIGNED; for (i = 0; i < INFO_COUNT; ++i) @@ -1851,11 +1851,16 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart inside = 1; } else if (inside) { char id_name[128] = { 0 }; + char type[64] = { 0 }; + char updated[64] = { 0 }; + char when_failed[64] = { 0 }; uint64_t min, max; int minmax; - if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %*s %*s %*s %" SCNu64 " (Min/Max %" SCNu64 "/%" SCNu64 ")", &id, id_name, &norm, &worst, &thresh, &raw, &min, &max) == 8) { + int flags; + + if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %63s %63s %63s %" SCNu64 " (Min/Max %" SCNu64 "/%" SCNu64 ")", &id, id_name, &norm, &worst, &thresh, type, updated, when_failed, &raw, &min, &max) == 11) { minmax = 1; - } else if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %*s %*s %*s %" SCNu64, &id, id_name, &norm, &worst, &thresh, &raw) == 6) { + } else if (sscanf(s, "%u %127s %*s %" SCNu64 " %" SCNu64 " %" SCNu64 " %63s %63s %63s %" SCNu64, &id, id_name, &norm, &worst, &thresh, type, updated, when_failed, &raw) == 9) { minmax = 0; } else { log_fatal(EEXTERNAL, "Invalid smartctl line '%s'.\n", s); @@ -1869,6 +1874,22 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart /* LCOV_EXCL_STOP */ } + flags = 0; + if (strcmp(type, "Pre-fail") == 0) + flags |= SMART_ATTR_TYPE_PREFAIL; + else if (strcmp(type, "Old_age") == 0) + flags |= SMART_ATTR_TYPE_OLDAGE; + if (strcmp(updated, "Always") == 0) + flags |= SMART_ATTR_UPDATE_ALWAYS; + else if (strcmp(updated, "Offline") == 0) + flags |= SMART_ATTR_UPDATE_OFFLINE; + if (strcmp(when_failed, "FAILING_NOW") == 0) + flags |= SMART_ATTR_WHEN_FAILED_NOW; + else if (strcmp(when_failed, "In_the_past") == 0) + flags |= SMART_ATTR_WHEN_FAILED_PAST; + else if (strcmp(when_failed, "-") == 0) + flags |= SMART_ATTR_WHEN_FAILED_NEVER; + /* revert the min/max decoding done by smartctl */ if (minmax && raw <= 0xFFFFUL @@ -1882,6 +1903,7 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart smart[id].norm = norm; smart[id].worst = worst; smart[id].thresh = thresh; + smart[id].flags = flags; pathcpy(smart[id].name, sizeof(smart[id].name), id_name); /* diff --git a/cmdline/support.h b/cmdline/support.h index e2cb5b22..bf3d6c02 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -453,7 +453,7 @@ void malloc_fail(size_t size); * Read smartctl attributes from a stream. * Return 0 on success. */ -int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interf); +int smartctl_attribute(FILE* f, const char* file, const char* name, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf); /** * Flush smartctl output from a stream. diff --git a/cmdline/unix.c b/cmdline/unix.c index d1192930..90eea103 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -1479,7 +1479,7 @@ static int devscan(tommy_list* list) * Get SMART attributes. */ #if HAVE_LINUX_DEVICE -static int devsmart(dev_t device, const char* name, const char* smartctl, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interface) +static int devsmart(dev_t device, const char* name, const char* smartctl, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interface) { char cmd[PATH_MAX + 64]; char file[PATH_MAX]; @@ -1717,7 +1717,7 @@ static void devattr(dev_t device, uint64_t* info, char* serial, char* family, ch * Get POWER state. */ #if HAVE_LINUX_DEVICE -static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, struct smart_struct* smart, uint64_t* info, char* serial, char* family, char* model, char* interface) +static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interface) { char cmd[PATH_MAX + 64]; char file[PATH_MAX]; diff --git a/doc/snapraid_log.1 b/doc/snapraid_log.1 index 60a5920b..ba322bb7 100644 --- a/doc/snapraid_log.1 +++ b/doc/snapraid_log.1 @@ -1794,7 +1794,7 @@ The raw flags value (uint, hexadecimal). .PD .RE .TP -.B attr::[/]::::::: +.B attr::[/]:::::::::: Logs the raw value of any assigned SMART attribute. .RS 4 .PD 0 @@ -1819,6 +1819,15 @@ The threshold value (uint). .HP 4 .I Name of the attribute. +.HP 4 +.I +Type of the attribute: \`prefail\` or \`oldage\`. +.HP 4 +.I +Update method of the attribute: \`always\` or \`offline\`. +.HP 4 +.I +If and when the attribute failed: \`never\` or \`past\` or \`now\`. .PD .RE .TP diff --git a/doc/snapraid_log.d b/doc/snapraid_log.d index cf312e36..38196ecc 100644 --- a/doc/snapraid_log.d +++ b/doc/snapraid_log.d @@ -1121,7 +1121,7 @@ Command Smart And Probe Tags - The raw flags value (uint, decimal). - The raw flags value (uint, hexadecimal). - =attr::[/]::::::: + =attr::[/]:::::::::: Logs the raw value of any assigned SMART attribute. - The SMART attribute ID (uint). @@ -1131,6 +1131,9 @@ Command Smart And Probe Tags - The worst value (uint). - The threshold value (uint). - Name of the attribute. + - Type of the attribute: `prefail` or `oldage`. + - Update method of the attribute: `always` or `offline`. + - If and when the attribute failed: `never` or `past` or `now`. =attr::[/]:power:active Logs that the device was confirmed to be in an active power diff --git a/doc/snapraid_log.txt b/doc/snapraid_log.txt index 8119e686..333e65ed 100644 --- a/doc/snapraid_log.txt +++ b/doc/snapraid_log.txt @@ -1167,7 +1167,7 @@ Tags logging specific disk identification and attribute values. - The raw flags value (uint, decimal). - The raw flags value (uint, hexadecimal). - attr::[/]::::::: + attr::[/]:::::::::: Logs the raw value of any assigned SMART attribute. - The SMART attribute ID (uint). @@ -1177,6 +1177,9 @@ Tags logging specific disk identification and attribute values. - The worst value (uint). - The threshold value (uint). - Name of the attribute. + - Type of the attribute: `prefail` or `oldage`. + - Update method of the attribute: `always` or `offline`. + - If and when the attribute failed: `never` or `past` or `now`. attr::[/]:power:active Logs that the device was confirmed to be in an active power