Retry smartctl command in Windows with -d sat if no info

This commit is contained in:
Andrea Mazzoleni 2015-04-07 21:59:09 +02:00
parent bb76d48ace
commit 9a10c94946
3 changed files with 44 additions and 10 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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. */