diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-10-23 14:16:15 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-10-31 12:51:54 -0400 |
commit | e829ea9a5ea05c6dedd91f741f91cb8723e50b19 (patch) | |
tree | bb554a4ec31b3b5501189993de990d2419306c2f /firmware/drivers/ata.c | |
parent | 825e4069655065ffd49bcc9ec64b53f1225e8186 (diff) | |
download | rockbox-e829ea9a5ea05c6dedd91f741f91cb8723e50b19.tar.gz rockbox-e829ea9a5ea05c6dedd91f741f91cb8723e50b19.zip |
ata: Rework how flushing, sleeping, and power off interacts
* FLUSH_EXT is used if featureflag is set and we are using LBA48
(unconditionally used for CE-ATA on ipod6g)
* FLUSH is used if featureflag is set (ATA6+) or if device claims to be ATA5+
* Rename ata_disk_can_power_off() to ata_disk_can_sleep() as that is
what it actually tests for. Only use it to gate issuing the
STANDBY IMMEDIATE command.
* Restore behavior of ata_disk_is_active() to return 1 if drive is
"spinning" or powered up.
* Allow poweroff if drive claims PM support OR we are able to issue
FLUSH/FLUSH_EXT commands.
* Added ata_flush() to explicitly trigger a flush operation, and hook it
up to storage_flush() in the device shutdown path. (Flushes were
only previously used in the storage device power management path)
* After issuing all settings, re-issue IDENTIFY_DEVICE to make sure
it reflects everything we've enabled.
* Update manual section on Flash/SSD mods.
Change-Id: I6770a54ef3a87f4c47120bcb96c944a6652f1bf4
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r-- | firmware/drivers/ata.c | 52 |
1 files changed, 37 insertions, 15 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index c995f6de85..8df9acb9da 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -103,6 +103,7 @@ static long sleep_timeout = 5*HZ; | |||
103 | #ifdef HAVE_LBA48 | 103 | #ifdef HAVE_LBA48 |
104 | static bool lba48 = false; /* set for 48 bit addressing */ | 104 | static bool lba48 = false; /* set for 48 bit addressing */ |
105 | #endif | 105 | #endif |
106 | static bool canflush = true; | ||
106 | 107 | ||
107 | static long last_disk_activity = -1; | 108 | static long last_disk_activity = -1; |
108 | #ifdef HAVE_ATA_POWER_OFF | 109 | #ifdef HAVE_ATA_POWER_OFF |
@@ -141,11 +142,6 @@ static inline void keep_ata_active(void) | |||
141 | last_disk_activity = current_tick; | 142 | last_disk_activity = current_tick; |
142 | } | 143 | } |
143 | 144 | ||
144 | static inline void schedule_ata_sleep(long from_now) | ||
145 | { | ||
146 | last_disk_activity = current_tick - sleep_timeout + from_now; | ||
147 | } | ||
148 | |||
149 | static inline bool ata_sleep_timed_out(void) | 145 | static inline bool ata_sleep_timed_out(void) |
150 | { | 146 | { |
151 | return sleep_timeout && | 147 | return sleep_timeout && |
@@ -223,7 +219,7 @@ static int ata_perform_wakeup(int state) | |||
223 | static int ata_perform_sleep(void) | 219 | static int ata_perform_sleep(void) |
224 | { | 220 | { |
225 | /* If device doesn't support PM features, don't try to sleep. */ | 221 | /* If device doesn't support PM features, don't try to sleep. */ |
226 | if (!ata_disk_can_poweroff()) | 222 | if (!ata_disk_can_sleep()) |
227 | return 0; // XXX or return a failure? | 223 | return 0; // XXX or return a failure? |
228 | 224 | ||
229 | logf("ata SLEEP %ld", current_tick); | 225 | logf("ata SLEEP %ld", current_tick); |
@@ -257,13 +253,18 @@ static int ata_perform_flush_cache(void) | |||
257 | { | 253 | { |
258 | uint8_t cmd; | 254 | uint8_t cmd; |
259 | 255 | ||
260 | if (identify_info[83] & (1 << 13)) { | 256 | if (!canflush) { |
261 | cmd = CMD_FLUSH_CACHE_EXT; | 257 | return 0; |
258 | } else if (lba48 && identify_info[83] & (1 << 13)) { | ||
259 | cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices */ | ||
262 | } else if (identify_info[83] & (1 << 12)) { | 260 | } else if (identify_info[83] & (1 << 12)) { |
263 | cmd = CMD_FLUSH_CACHE; | 261 | cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ |
262 | } else if (identify_info[80] >= (1 << 5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ | ||
263 | cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ | ||
264 | } else { | 264 | } else { |
265 | /* If neither (mandatory!) command is supported | 265 | /* If neither (mandatory!) command is supported |
266 | then don't issue it. */ | 266 | then don't issue it. */ |
267 | canflush = 0; | ||
267 | return 0; | 268 | return 0; |
268 | } | 269 | } |
269 | 270 | ||
@@ -286,6 +287,16 @@ static int ata_perform_flush_cache(void) | |||
286 | return 0; | 287 | return 0; |
287 | } | 288 | } |
288 | 289 | ||
290 | int ata_flush(void) | ||
291 | { | ||
292 | if (ata_state >= ATA_SPINUP) { | ||
293 | mutex_lock(&ata_mtx); | ||
294 | ata_perform_flush_cache(); | ||
295 | mutex_unlock(&ata_mtx); | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
289 | static ICODE_ATTR int wait_for_start_of_transfer(void) | 300 | static ICODE_ATTR int wait_for_start_of_transfer(void) |
290 | { | 301 | { |
291 | if (!wait_for_bsy()) | 302 | if (!wait_for_bsy()) |
@@ -844,7 +855,7 @@ void ata_spindown(int seconds) | |||
844 | 855 | ||
845 | bool ata_disk_is_active(void) | 856 | bool ata_disk_is_active(void) |
846 | { | 857 | { |
847 | return ata_disk_can_poweroff() ? (ata_state >= ATA_SPINUP) : 0; | 858 | return (ata_state >= ATA_SPINUP); |
848 | } | 859 | } |
849 | 860 | ||
850 | void ata_sleepnow(void) | 861 | void ata_sleepnow(void) |
@@ -856,8 +867,9 @@ void ata_sleepnow(void) | |||
856 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { | 867 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { |
857 | ata_state = ATA_SLEEPING; | 868 | ata_state = ATA_SLEEPING; |
858 | #ifdef HAVE_ATA_POWER_OFF | 869 | #ifdef HAVE_ATA_POWER_OFF |
859 | if (ata_disk_can_poweroff()) | 870 | if (ata_disk_can_sleep() || canflush) { |
860 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; | 871 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; |
872 | } | ||
861 | #endif | 873 | #endif |
862 | } | 874 | } |
863 | } | 875 | } |
@@ -967,6 +979,9 @@ static int perform_soft_reset(void) | |||
967 | if (set_multiple_mode(multisectors)) | 979 | if (set_multiple_mode(multisectors)) |
968 | return -3; | 980 | return -3; |
969 | 981 | ||
982 | if (identify()) | ||
983 | return -2; | ||
984 | |||
970 | if (freeze_lock()) | 985 | if (freeze_lock()) |
971 | return -4; | 986 | return -4; |
972 | 987 | ||
@@ -1017,6 +1032,9 @@ static int ata_power_on(void) | |||
1017 | if (set_multiple_mode(multisectors)) | 1032 | if (set_multiple_mode(multisectors)) |
1018 | return -3; | 1033 | return -3; |
1019 | 1034 | ||
1035 | if (identify()) | ||
1036 | return -2; | ||
1037 | |||
1020 | if (freeze_lock()) | 1038 | if (freeze_lock()) |
1021 | return -4; | 1039 | return -4; |
1022 | 1040 | ||
@@ -1255,7 +1273,6 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1255 | } | 1273 | } |
1256 | 1274 | ||
1257 | rc = identify(); | 1275 | rc = identify(); |
1258 | |||
1259 | if (rc) { | 1276 | if (rc) { |
1260 | rc = -40 + rc; | 1277 | rc = -40 + rc; |
1261 | goto error; | 1278 | goto error; |
@@ -1280,13 +1297,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1280 | #endif /* HAVE_LBA48 */ | 1297 | #endif /* HAVE_LBA48 */ |
1281 | 1298 | ||
1282 | rc = freeze_lock(); | 1299 | rc = freeze_lock(); |
1283 | |||
1284 | if (rc) { | 1300 | if (rc) { |
1285 | rc = -50 + rc; | 1301 | rc = -50 + rc; |
1286 | goto error; | 1302 | goto error; |
1287 | } | 1303 | } |
1288 | 1304 | ||
1289 | rc = set_features(); // rror codes are between -1 and -49 | 1305 | rc = set_features(); // error codes are between -1 and -49 |
1290 | if (rc) { | 1306 | if (rc) { |
1291 | rc = -60 + rc; | 1307 | rc = -60 + rc; |
1292 | goto error; | 1308 | goto error; |
@@ -1325,6 +1341,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1325 | if (rc) | 1341 | if (rc) |
1326 | rc = -100 + rc; | 1342 | rc = -100 + rc; |
1327 | 1343 | ||
1344 | rc = identify(); | ||
1345 | if (rc) { | ||
1346 | rc = -40 + rc; | ||
1347 | goto error; | ||
1348 | } | ||
1349 | |||
1328 | error: | 1350 | error: |
1329 | mutex_unlock(&ata_mtx); | 1351 | mutex_unlock(&ata_mtx); |
1330 | return rc; | 1352 | return rc; |
@@ -1440,7 +1462,7 @@ int ata_event(long id, intptr_t data) | |||
1440 | ata_sleepnow(); | 1462 | ata_sleepnow(); |
1441 | } | 1463 | } |
1442 | else if (id == Q_STORAGE_SLEEP) { | 1464 | else if (id == Q_STORAGE_SLEEP) { |
1443 | schedule_ata_sleep(HZ/5); | 1465 | last_disk_activity = current_tick - sleep_timeout + HZ / 5; |
1444 | } | 1466 | } |
1445 | #ifndef USB_NONE | 1467 | #ifndef USB_NONE |
1446 | else if (id == SYS_USB_CONNECTED) { | 1468 | else if (id == SYS_USB_CONNECTED) { |