summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/ata.c52
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
104static bool lba48 = false; /* set for 48 bit addressing */ 104static bool lba48 = false; /* set for 48 bit addressing */
105#endif 105#endif
106static bool canflush = true;
106 107
107static long last_disk_activity = -1; 108static 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
144static inline void schedule_ata_sleep(long from_now)
145{
146 last_disk_activity = current_tick - sleep_timeout + from_now;
147}
148
149static inline bool ata_sleep_timed_out(void) 145static 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)
223static int ata_perform_sleep(void) 219static 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
290int 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
289static ICODE_ATTR int wait_for_start_of_transfer(void) 300static 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
845bool ata_disk_is_active(void) 856bool 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
850void ata_sleepnow(void) 861void 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
1328error: 1350error:
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) {