From a90f8db3c09fa1d8d17de27342ad2a366713d513 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 13 Oct 2016 18:57:14 +0200 Subject: [PATCH] Ingnore the SMART Command Timeout for Seagate SMR disks --- HISTORY | 2 ++ cmdline/device.c | 26 ++++++++++++++++++++++---- cmdline/mingw.c | 6 +++--- cmdline/portable.h | 2 ++ cmdline/support.c | 4 +++- cmdline/support.h | 2 +- cmdline/unix.c | 6 +++--- 7 files changed, 36 insertions(+), 12 deletions(-) diff --git a/HISTORY b/HISTORY index cb273554..661e7104 100644 --- a/HISTORY +++ b/HISTORY @@ -39,6 +39,8 @@ SnapRAID HISTORY --test-io-advise-direct use direct/unbuffered mode (Linux/Windows) The new default mode is 'flush' in Linux (before it was 'sequential'), and 'sequential' in Windows (like before). + * For Seagate SMR (Shingled Magnetic Recording) ignore the SMART + attribute Command_Timeout 188 as not reliable. * Fixed running in Windows platforms that miss the RtlGenRandom() function. * Added the --test-io-cache=1 option to disable the multi-thread IO diff --git a/cmdline/device.c b/cmdline/device.c index 4279e63c..b00f91ee 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -464,7 +464,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(uint64_t* smart) +static double smart_afr(uint64_t* smart, const char* model) { double afr = 0; uint64_t mask32 = 0xffffffffU; @@ -484,7 +484,17 @@ static double smart_afr(uint64_t* smart) afr = r; } - if (smart[188] != SMART_UNASSIGNED) { + if ( + /** + * Don't check Command_Timeout (188) for Seagate SMR (Shingled + * Magnetic Recording) disks. + * + * It's reported by users to be a not significative test as + * this value increases too often also on sane disks. + */ + strcmp(model, "ST8000AS0002-1NA17Z") != 0 + && smart[188] != SMART_UNASSIGNED + ) { /* with Seagate disks, there are three different 16 bits value reported */ /* the lowest one is the most significant */ double r = smart_afr_value(SMART_188_R, SMART_188_STEP, smart[188] & mask16); @@ -706,7 +716,7 @@ static void state_smart(unsigned n, tommy_list* low) afr = 0; printf(" SSD"); } else { - afr = smart_afr(devinfo->smart); + afr = smart_afr(devinfo->smart, devinfo->smart_model); if (afr == 0) { /* this happens only if no data */ @@ -748,6 +758,10 @@ static void state_smart(unsigned n, tommy_list* low) log_tag("smart:%s:%s\n", devinfo->file, devinfo->name); if (devinfo->smart_serial[0]) log_tag("attr:%s:%s:serial:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_serial, esc_buffer)); + if (devinfo->smart_vendor[0]) + log_tag("attr:%s:%s:vendor:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_vendor, esc_buffer)); + if (devinfo->smart_model[0]) + log_tag("attr:%s:%s:model:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_model, esc_buffer)); if (afr != 0) log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_n_or_more_failures(afr, 1)); if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) @@ -854,12 +868,16 @@ static int devtest(tommy_list* low, int operation) if (c == 0) { entry->smart_serial[0] = 0; + entry->smart_vendor[0] = 0; + entry->smart_model[0] = 0; entry->file[0] = 0; entry->name[0] = 0; entry->smart[SMART_SIZE] = SMART_UNASSIGNED; entry->smart[SMART_ROTATION_RATE] = 0; } else { - snprintf(entry->smart_serial, sizeof(entry->smart_serial), "%u", c); + snprintf(entry->smart_serial, sizeof(entry->smart_serial), "S%u", c); + snprintf(entry->smart_vendor, sizeof(entry->smart_vendor), "V%u", c); + snprintf(entry->smart_model, sizeof(entry->smart_model), "M%u", c); pathcpy(entry->file, sizeof(entry->name), "file"); pathcpy(entry->name, sizeof(entry->name), "name"); entry->smart[SMART_SIZE] = c * TERA; diff --git a/cmdline/mingw.c b/cmdline/mingw.c index d9f66b3e..22194d5a 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2172,7 +2172,7 @@ static int devscan(tommy_list* list) /** * Get SMART attributes. */ -static int devsmart(uint64_t device, const char* name, const char* custom, uint64_t* smart, char* serial) +static int devsmart(uint64_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model) { char conv_buf[CONV_MAX]; WCHAR cmd[MAX_PATH + 128]; @@ -2205,7 +2205,7 @@ retry: /* LCOV_EXCL_STOP */ } - if (smartctl_attribute(f, file, name, smart, serial) != 0) { + if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); return -1; @@ -2434,7 +2434,7 @@ static void* thread_smart(void* arg) { devinfo_t* devinfo = arg; - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial) != 0) { + if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */ diff --git a/cmdline/portable.h b/cmdline/portable.h index f98d58a2..58826c60 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -460,6 +460,8 @@ struct devinfo_struct { struct devinfo_struct* parent; /**< Pointer at the parent if any. */ uint64_t smart[SMART_COUNT]; /**< SMART raw attributes. */ char smart_serial[SMART_MAX]; /**< SMART serial number. */ + char smart_vendor[SMART_MAX]; /**< SMART vendor. */ + char smart_model[SMART_MAX]; /**< SMART model. */ #if HAVE_PTHREAD pthread_t thread; #endif diff --git a/cmdline/support.c b/cmdline/support.c index bcb6685e..a3f2f487 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -1370,7 +1370,7 @@ static int smatch(const char* str, const char* pattern) return 0; } -int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial) +int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model) { unsigned i; int inside; @@ -1416,6 +1416,8 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* sm smart[SMART_SIZE] += attr[i] - '0'; } } + } else if (sscanf(s, "Device Model: %63s %63s", vendor, model) == 2) { + } else if (sscanf(s, "Device Model: %63s", model) == 1) { /* SCSI */ } else if (sscanf(s, "Serial number: %63s", serial) == 1) { /* note "n" of "number" lower case */ } else if (sscanf(s, "Elements in grown defect list: %" SCNu64, &smart[SMART_REALLOCATED_SECTOR_COUNT]) == 1) { diff --git a/cmdline/support.h b/cmdline/support.h index 25c1ad52..891045d4 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -389,7 +389,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, uint64_t* smart, char* serial); +int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model); /** * Flush smartctl output from a stream. diff --git a/cmdline/unix.c b/cmdline/unix.c index 97f94690..8d2391ac 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -950,7 +950,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* custom, uint64_t* smart, char* serial) +static int devsmart(dev_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model) { char cmd[128]; char file[128]; @@ -978,7 +978,7 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t /* LCOV_EXCL_STOP */ } - if (smartctl_attribute(f, file, name, smart, serial) != 0) { + if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) { /* LCOV_EXCL_START */ pclose(f); return -1; @@ -1175,7 +1175,7 @@ static void* thread_smart(void* arg) #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial) != 0) { + if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) { /* LCOV_EXCL_START */ return (void*)-1; /* LCOV_EXCL_STOP */