diff --git a/cmdline/device.c b/cmdline/device.c index 828a2e6d..ee45a859 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -973,6 +973,7 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte case DEVICE_LIST : ope = "Device listing"; break; case DEVICE_SMART : ope = "Smart"; break; case DEVICE_PROBE : ope = "Probe"; break; + case DEVICE_DOWNIFUP : ope = "Spindown"; break; } log_fatal("%s is unsupported in this platform.\n", ope); } else { diff --git a/cmdline/mingw.c b/cmdline/mingw.c index ffaa93c4..36954c2f 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -2747,6 +2747,22 @@ retry: return 0; } +/** + * Spin down a specific device if it's up + */ +static int devdownifup(uint64_t device, const char* name, const char* smartctl, int* power) +{ + *power = POWER_UNKNOWN; + + if (devprobe(device, name, smartctl, power) != 0) + return -1; + + if (*power == POWER_ACTIVE) + return devdown(device, name, smartctl); + + return 0; +} + /** * Spin up a device. */ @@ -2845,6 +2861,29 @@ static void* thread_spindown(void* arg) return 0; } +/** + * Thread for spinning down. + */ +static void* thread_spindownifup(void* arg) +{ + devinfo_t* devinfo = arg; + uint64_t start; + int power; + + start = tick_ms(); + + if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, &power) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } + + if (power == POWER_ACTIVE) + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, tick_ms() - start); + + return 0; +} + /** * Thread for getting smart info. */ @@ -2949,6 +2988,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) case DEVICE_DOWN : func = thread_spindown; break; case DEVICE_SMART : func = thread_smart; break; case DEVICE_PROBE : func = thread_probe; break; + case DEVICE_DOWNIFUP : func = thread_spindownifup; break; } if (!func) diff --git a/cmdline/portable.h b/cmdline/portable.h index a7688e70..80b655f8 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -523,6 +523,7 @@ typedef struct devinfo_struct devinfo_t; #define DEVICE_UP 2 #define DEVICE_SMART 3 #define DEVICE_PROBE 4 +#define DEVICE_DOWNIFUP 5 /** * Query all the "high" level devices with the specified operation, diff --git a/cmdline/thermal.c b/cmdline/thermal.c index 31583928..38e5eef4 100644 --- a/cmdline/thermal.c +++ b/cmdline/thermal.c @@ -301,7 +301,7 @@ int state_thermal_alarm(struct snapraid_state* state) void state_thermal_cooldown(struct snapraid_state* state) { - unsigned sleep_time = state->thermal_cooldown_time; + int sleep_time = state->thermal_cooldown_time; if (sleep_time == 0) sleep_time = 5 * 60; /* default sleep time */ @@ -321,7 +321,13 @@ void state_thermal_cooldown(struct snapraid_state* state) log_flush(); - sleep(sleep_time); + /* every 30 seconds spin down any disk that was spunup */ + while (sleep_time > 0) { + state_device(state, DEVICE_DOWNIFUP, 0); + + sleep(30); + sleep_time -= 30; + } if (!global_interrupt) { /* don't wake-up if we are interrupting */ log_tag("thermal:spinup\n"); diff --git a/cmdline/unix.c b/cmdline/unix.c index 6add6ddb..fa17aaee 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -1350,6 +1350,24 @@ static int devdown(dev_t device, const char* name, const char* smartctl) } #endif +/** + * Spin down a specific device if it's up. + */ +#if HAVE_LINUX_DEVICE +static int devdownifup(dev_t device, const char* name, const char* smartctl, int* power) +{ + *power = POWER_UNKNOWN; + + if (devprobe(device, name, smartctl, power) != 0) + return -1; + + if (*power == POWER_ACTIVE) + return devdown(device, name, smartctl); + + return 0; +} +#endif + /** * Spin up a specific device. */ @@ -1465,6 +1483,34 @@ static void* thread_spindown(void* arg) #endif } +/** + * Thread for spinning down. + */ +static void* thread_spindownifup(void* arg) +{ +#if HAVE_LINUX_DEVICE + devinfo_t* devinfo = arg; + uint64_t start; + int power; + + start = tick_ms(); + + if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, &power) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } + + if (power == POWER_ACTIVE) + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, tick_ms() - start); + + return 0; +#else + (void)arg; + return (void*)-1; +#endif +} + /** * Thread for getting smart info. */ @@ -1620,6 +1666,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) case DEVICE_DOWN : func = thread_spindown; break; case DEVICE_SMART : func = thread_smart; break; case DEVICE_PROBE : func = thread_probe; break; + case DEVICE_DOWNIFUP : func = thread_spindownifup; break; } if (!func)