Index: apps/plugin.c =================================================================== --- apps/plugin.c (revision 14293) +++ apps/plugin.c (working copy) @@ -219,6 +219,7 @@ settings_parseline, #ifndef SIMULATOR ata_sleep, + ata_wakeup, ata_disk_is_active, #endif ata_spindown, Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 14293) +++ apps/plugin.h (working copy) @@ -306,6 +306,7 @@ bool (*settings_parseline)(char* line, char** name, char** value); #ifndef SIMULATOR void (*ata_sleep)(void); + void (*ata_wakeup)(void); bool (*ata_disk_is_active)(void); #endif void (*ata_spindown)(int seconds); Index: firmware/export/ata.h =================================================================== --- firmware/export/ata.h (revision 14293) +++ firmware/export/ata.h (working copy) @@ -40,6 +40,7 @@ extern void ata_spindown(int seconds); extern void ata_sleep(void); extern void ata_sleepnow(void); +extern void ata_wakeup(void); extern bool ata_disk_is_active(void); extern int ata_hard_reset(void); extern int ata_soft_reset(void); Index: firmware/drivers/ata.c =================================================================== --- firmware/drivers/ata.c (revision 14293) +++ firmware/drivers/ata.c (working copy) @@ -59,6 +59,7 @@ #define CMD_SECURITY_FREEZE_LOCK 0xF5 #define Q_SLEEP 0 +#define Q_WAKEUP 1 #define READ_TIMEOUT 5*HZ @@ -105,6 +106,7 @@ #endif static int ata_power_on(void); +static int ata_perform_wakeup(void); static int perform_soft_reset(void); static int set_multiple_mode(int sectors); static int set_features(void); @@ -228,7 +230,6 @@ long timeout; int count; void* buf; - long spinup_start; #ifndef MAX_PHYS_SECTOR_SIZE #ifdef HAVE_MULTIVOLUME @@ -238,38 +239,19 @@ #endif last_disk_activity = current_tick; - spinup_start = current_tick; ata_led(true); - if ( sleeping ) { - spinup = true; - if (poweroff) { - if (ata_power_on()) { - spinlock_unlock(&ata_mtx); - ata_led(false); - return -1; - } - } - else { - if (perform_soft_reset()) { - spinlock_unlock(&ata_mtx); - ata_led(false); - return -1; - } - } - } - - timeout = current_tick + READ_TIMEOUT; - - SET_REG(ATA_SELECT, ata_device); - if (!wait_for_rdy()) + ret = ata_perform_wakeup(); + if (ret) { spinlock_unlock(&ata_mtx); ata_led(false); - return -2; + return ret; } + timeout = current_tick + READ_TIMEOUT; + retry: buf = inbuf; count = incount; @@ -328,13 +310,6 @@ goto retry; } - if (spinup) { - ata_spinup_time = current_tick - spinup_start; - spinup = false; - sleeping = false; - poweroff = false; - } - /* read the status register exactly once per loop */ status = ATA_STATUS; @@ -433,7 +408,6 @@ { int i; int ret = 0; - long spinup_start; if (start == 0) panicf("Writing on sector 0\n"); @@ -446,34 +420,15 @@ #endif last_disk_activity = current_tick; - spinup_start = current_tick; ata_led(true); - if ( sleeping ) { - spinup = true; - if (poweroff) { - if (ata_power_on()) { - spinlock_unlock(&ata_mtx); - ata_led(false); - return -1; - } - } - else { - if (perform_soft_reset()) { - spinlock_unlock(&ata_mtx); - ata_led(false); - return -1; - } - } - } - - SET_REG(ATA_SELECT, ata_device); - if (!wait_for_rdy()) + ret = ata_perform_wakeup(); + if (ret) { spinlock_unlock(&ata_mtx); ata_led(false); - return -2; + return ret; } #ifdef HAVE_LBA48 @@ -508,13 +463,6 @@ break; } - if (spinup) { - ata_spinup_time = current_tick - spinup_start; - spinup = false; - sleeping = false; - poweroff = false; - } - copy_write_sectors(buf, SECTOR_SIZE/2); #ifdef USE_INTERRUPT @@ -763,6 +711,33 @@ return !sleeping; } +static int ata_perform_wakeup(void) +{ + long spinup_start = current_tick; + + if ( sleeping ) { + spinup = true; + if (poweroff) { + if (ata_power_on()) + return -1; + } + else { + if (perform_soft_reset()) + return -1; + } + } + + SET_REG(ATA_SELECT, ata_device); + if (!wait_for_rdy()) + return -2; + + ata_spinup_time = current_tick - spinup_start; + spinup = false; + sleeping = false; + poweroff = false; + return 0; +} + static int ata_perform_sleep(void) { int ret = 0; @@ -804,6 +779,11 @@ } } +void ata_wakeup(void) +{ + queue_post(&ata_queue, Q_WAKEUP, 0); +} + void ata_spin(void) { last_user_activity = current_tick; @@ -877,6 +857,12 @@ call_ata_idle_notifys(false); last_disk_activity = current_tick - sleep_timeout + (HZ/2); break; + case Q_WAKEUP: + spinlock_lock(&ata_mtx); + ata_led(true); + ata_perform_wakeup(); + ata_led(false); + spinlock_unlock(&ata_mtx); } } }