diff --git a/cmdline/device.c b/cmdline/device.c index d6c6aebf..513b08a9 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -800,8 +800,6 @@ static void state_smart(unsigned n, tommy_list* low) printf("%8" PRIu64, devinfo->smart[SMART_ERROR]); else if (flag & (SMARTCTL_FLAG_ERROR | SMARTCTL_FLAG_ERROR_LOGGED)) printf(" ERROR"); - else if (flag & (SMARTCTL_FLAG_UNSUPPORTED | SMARTCTL_FLAG_OPEN)) - printf(" -"); else if (devinfo->smart[SMART_ERROR] == 0) printf(" 0"); else @@ -814,7 +812,11 @@ static void state_smart(unsigned n, tommy_list* low) if (flag & (SMARTCTL_FLAG_UNSUPPORTED | SMARTCTL_FLAG_OPEN)) { /* if error running smartctl, skip AFR estimation */ afr = 0; - printf(" -"); + printf(" n/a"); + } else if (devinfo->smart[SMART_ROTATION_RATE] == SMART_UNASSIGNED) { + /* if no rotation rate, we don't know if it's SSD or not */ + afr = 0; + printf(" n/k"); } else if (devinfo->smart[SMART_ROTATION_RATE] == 0) { /* if SSD, skip AFR estimation as data is from not SSD disks */ afr = 0; @@ -822,11 +824,16 @@ static void state_smart(unsigned n, tommy_list* low) } else { afr = smart_afr(devinfo->smart); - /* use only the disks in the array */ - if (devinfo->parent != 0 || !have_parent) - array_failure_rate += afr; + if (afr == 0) { + /* this happens only if no data */ + printf(" -"); + } else { + /* use only the disks in the array */ + if (devinfo->parent != 0 || !have_parent) + array_failure_rate += afr; - printf("%4.0f%%", poisson_prob_n_or_more_failures(afr, 1) * 100); + printf("%4.0f%%", poisson_prob_n_or_more_failures(afr, 1) * 100); + } } if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED) diff --git a/cmdline/mingw.c b/cmdline/mingw.c index f8a09a0e..4ab238da 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2078,9 +2078,12 @@ static int devsmart(uint64_t device, uint64_t* smart, char* serial) WCHAR cmd[MAX_PATH + 128]; FILE* f; int ret; + int retry; snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a /dev/pd%" PRIu64, exedir, device); + retry = 0; +loop: f = _wpopen(cmd, L"rt"); if (!f) { /* LCOV_EXCL_START */ @@ -2104,7 +2107,31 @@ static int devsmart(uint64_t device, uint64_t* smart, char* serial) /* LCOV_EXCL_STOP */ } - /* store the return smartctl return value */ + if (retry == 0) { + /* + * Handle some common cases in Windows. + * + * Sometimes the "type" autodetection is wrong, and the command fails at identification + * stage, returning with error 2, or even with error 0, and with no info at all. + * We detect this conditon checking the PowerOnHours, Size and RotationRate attributes. + * + * In such conditions we retry using the "sat" type, that often allow to proceed. + * + * Note that getting error 4 is instead very common, even with full info gathering. + */ + if ((ret == 0 || ret == 2) + && smart[9] == SMART_UNASSIGNED + && smart[SMART_SIZE] == SMART_UNASSIGNED + && smart[SMART_ROTATION_RATE] == SMART_UNASSIGNED + ) { + /* retry using the "sat" type */ + snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a /dev/pd%" PRIu64 " -d sat", exedir, device); + ++retry; + goto loop; + } + } + + /* store the smartctl return value */ smart[SMART_FLAGS] = ret; return 0; diff --git a/cmdline/portable.h b/cmdline/portable.h index 71c8dab9..a3b647c6 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -363,8 +363,8 @@ int randomize(void* ptr, size_t size); * Flags returned by smartctl. */ #define SMARTCTL_FLAG_UNSUPPORTED (1 << 0) /**< Device not recognized, requiring the -d option. */ -#define SMARTCTL_FLAG_OPEN (1 << 1) /**< Device open failed. */ -#define SMARTCTL_FLAG_COMMAND (1 << 2) /**< Some SMART or other ATA command to the disk failed. */ +#define SMARTCTL_FLAG_OPEN (1 << 1) /**< Device open or identification failed. */ +#define SMARTCTL_FLAG_COMMAND (1 << 2) /**< Some SMART or ATA commands failed. This is a common error, also happening with full info gathering. */ #define SMARTCTL_FLAG_FAIL (1 << 3) /**< SMART status check returned "DISK FAILING". */ #define SMARTCTL_FLAG_PREFAIL (1 << 4) /**< We found prefail Attributes <= threshold. */ #define SMARTCTL_FLAG_PREFAIL_LOGGED (1 << 5) /**< SMART status check returned "DISK OK" but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past. */