|
|
@ -62,6 +62,8 @@ struct diskwatch { |
|
|
|
|
|
|
|
static struct diskwatch diskwatch_glob; |
|
|
|
|
|
|
|
static int diskwatch_check_standby(struct disk_entry *entry); |
|
|
|
|
|
|
|
static int lcdpage_diskwatch(struct lcddev *lcd, int event, void *privdata) |
|
|
|
{ |
|
|
|
static struct disk_entry *entry; |
|
|
@ -104,6 +106,8 @@ static int lcdpage_diskwatch(struct lcddev *lcd, int event, void *privdata) |
|
|
|
|
|
|
|
snprintf(line1, sizeof(line1), "DISK(%s):", entry->device); |
|
|
|
if (entry->flags & F_PRESENT) { |
|
|
|
diskwatch_check_standby(entry); |
|
|
|
|
|
|
|
if (entry->flags & F_STANDBY) { |
|
|
|
snprintf(line2, sizeof(line2), "STANDBY"); |
|
|
|
} else { |
|
|
@ -125,7 +129,64 @@ static int lcdpage_diskwatch(struct lcddev *lcd, int event, void *privdata) |
|
|
|
return 1000; |
|
|
|
} |
|
|
|
|
|
|
|
static int diskwatch_check_cb(int timerid, void *privdata) |
|
|
|
static int diskwatch_check_standby(struct disk_entry *entry) |
|
|
|
{ |
|
|
|
if (!(entry->flags & F_PRESENT)) |
|
|
|
return 0; |
|
|
|
|
|
|
|
int fd = open(entry->device, O_RDONLY | O_NONBLOCK); |
|
|
|
if (fd < 0) { |
|
|
|
log_print(LOG_ERROR, "%s(): failed to open %s", __FUNCTION__, entry->device); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned char args[4] = { ATA_OP_CHECKPOWERMODE1, 0, 0, 0 }; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
args[0] = ATA_OP_CHECKPOWERMODE2; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
log_print(LOG_WARN, "%s: do_drive_cmd(ATA_OP_CHECKPOWERMODEx) failed on %s", __FUNCTION__, entry->device); |
|
|
|
close(fd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
time_t now = time(NULL); |
|
|
|
|
|
|
|
/* args[2]: |
|
|
|
* 0x00 - standby |
|
|
|
* 0x40 - NVcache_spindown |
|
|
|
* 0x41 - NVcache_spinup |
|
|
|
* 0x80 - idle |
|
|
|
* 0xFF - active/idle |
|
|
|
*/ |
|
|
|
/* drive is in standby */ |
|
|
|
if (args[2] == 0x00) { |
|
|
|
entry->flags |= F_STANDBY; |
|
|
|
|
|
|
|
/* drive was in standby, and is now active */ |
|
|
|
} else if (entry->flags & F_STANDBY) { |
|
|
|
entry->flags &= ~(F_STANDBY); |
|
|
|
entry->standby_timeout = now + entry->timeout_sec; |
|
|
|
|
|
|
|
/* drive is active, and timeout is up */ |
|
|
|
} else if (now >= entry->standby_timeout) { |
|
|
|
unsigned char args[4] = { ATA_OP_STANDBYNOW1, 0, 0, 0}; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
args[0] = ATA_OP_STANDBYNOW2; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
log_print(LOG_WARN, "%s: do_drive_cmd(ATA_OP_STANDBYNOWx) failed on %s", __FUNCTION__, entry->device); |
|
|
|
close(fd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
entry->flags |= F_STANDBY; |
|
|
|
} |
|
|
|
|
|
|
|
close(fd); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int diskwatch_check_stats(int timerid, void *privdata) |
|
|
|
{ |
|
|
|
struct diskwatch *dwatch = (struct diskwatch *)privdata; |
|
|
|
|
|
|
@ -189,6 +250,7 @@ static int diskwatch_check_cb(int timerid, void *privdata) |
|
|
|
if (entry->sectors_rd == val[2] && entry->sectors_wr == val[6]) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* sector counts changed, disk is not in standby */ |
|
|
|
entry->flags &= ~(F_STANDBY); |
|
|
|
entry->sectors_rd = val[2]; |
|
|
|
entry->sectors_wr = val[6]; |
|
|
@ -199,56 +261,7 @@ static int diskwatch_check_cb(int timerid, void *privdata) |
|
|
|
fclose(fp); |
|
|
|
|
|
|
|
list_for_each_entry(entry, &dwatch->disk_list, list) { |
|
|
|
if (!(entry->flags & F_PRESENT)) |
|
|
|
continue; |
|
|
|
|
|
|
|
int fd = open(entry->device, O_RDONLY | O_NONBLOCK); |
|
|
|
if (fd < 0) { |
|
|
|
log_print(LOG_ERROR, "%s(): failed to open %s", __FUNCTION__, entry->device); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned char args[4] = { ATA_OP_CHECKPOWERMODE1, 0, 0, 0 }; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
args[0] = ATA_OP_CHECKPOWERMODE2; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
log_print(LOG_WARN, "%s: do_drive_cmd(ATA_OP_CHECKPOWERMODEx) failed on %s", __FUNCTION__, entry->device); |
|
|
|
close(fd); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* args[2]: |
|
|
|
* 0x00 - standby |
|
|
|
* 0x40 - NVcache_spindown |
|
|
|
* 0x41 - NVcache_spinup |
|
|
|
* 0x80 - idle |
|
|
|
* 0xFF - active/idle |
|
|
|
*/ |
|
|
|
/* drive is in standby */ |
|
|
|
if (args[2] == 0x00) { |
|
|
|
entry->flags |= F_STANDBY; |
|
|
|
|
|
|
|
/* drive was in standby, and is now active (without change in sector counts */ |
|
|
|
} else if (entry->flags & F_STANDBY) { |
|
|
|
entry->flags &= ~(F_STANDBY); |
|
|
|
entry->standby_timeout = now + entry->timeout_sec; |
|
|
|
|
|
|
|
/* drive is active, and timeout is up */ |
|
|
|
} else if (now >= entry->standby_timeout) { |
|
|
|
unsigned char args[4] = { ATA_OP_STANDBYNOW1, 0, 0, 0}; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
args[0] = ATA_OP_STANDBYNOW2; |
|
|
|
if (do_drive_cmd(fd, args)) { |
|
|
|
log_print(LOG_WARN, "%s: do_drive_cmd(ATA_OP_STANDBYNOWx) failed on %s", __FUNCTION__, entry->device); |
|
|
|
close(fd); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
entry->flags |= F_STANDBY; |
|
|
|
} |
|
|
|
|
|
|
|
close(fd); |
|
|
|
diskwatch_check_standby(entry); |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
@ -312,11 +325,11 @@ int diskwatch_init(struct lcddev *lcd) |
|
|
|
if (diskcount <= 0) |
|
|
|
return 0; |
|
|
|
|
|
|
|
diskwatch_check_cb(0, dwatch); |
|
|
|
diskwatch_check_stats(0, dwatch); |
|
|
|
|
|
|
|
int check_interval = 0; |
|
|
|
config_get_int("diskwatch", "check_interval", &check_interval, 60); |
|
|
|
dwatch->check_timeout = event_add_timeout_ms(check_interval * 1000, diskwatch_check_cb, 0, dwatch); |
|
|
|
dwatch->check_timeout = event_add_timeout_ms(check_interval * 1000, diskwatch_check_stats, 0, dwatch); |
|
|
|
|
|
|
|
dwatch->lcd = lcd; |
|
|
|
if (dwatch->lcd != NULL) { |
|
|
|