summaryrefslogtreecommitdiff
path: root/firmware/drivers/ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r--firmware/drivers/ata.c111
1 files changed, 34 insertions, 77 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 1c85b7bd5f..9896fa87e0 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -58,6 +58,7 @@
58#define CMD_IDENTIFY 0xEC 58#define CMD_IDENTIFY 0xEC
59#define CMD_SLEEP 0xE6 59#define CMD_SLEEP 0xE6
60#define CMD_FLUSH_CACHE 0xE7 60#define CMD_FLUSH_CACHE 0xE7
61#define CMD_FLUSH_CACHE_EXT 0xEA
61#define CMD_SET_FEATURES 0xEF 62#define CMD_SET_FEATURES 0xEF
62#define CMD_SECURITY_FREEZE_LOCK 0xF5 63#define CMD_SECURITY_FREEZE_LOCK 0xF5
63#ifdef HAVE_ATA_DMA 64#ifdef HAVE_ATA_DMA
@@ -105,7 +106,7 @@ static bool lba48 = false; /* set for 48 bit addressing */
105 106
106static long last_disk_activity = -1; 107static long last_disk_activity = -1;
107#ifdef HAVE_ATA_POWER_OFF 108#ifdef HAVE_ATA_POWER_OFF
108static long power_off_tick; 109static long power_off_tick = 0;
109#endif 110#endif
110 111
111static unsigned long total_sectors; 112static unsigned long total_sectors;
@@ -152,18 +153,10 @@ static inline bool ata_sleep_timed_out(void)
152 TIME_AFTER(current_tick, last_disk_activity + sleep_timeout); 153 TIME_AFTER(current_tick, last_disk_activity + sleep_timeout);
153} 154}
154 155
155static inline void schedule_ata_power_off(void)
156{
157#ifdef HAVE_ATA_POWER_OFF
158 if (!ata_disk_can_poweroff())
159 power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT;
160#endif
161}
162
163static inline bool ata_power_off_timed_out(void) 156static inline bool ata_power_off_timed_out(void)
164{ 157{
165#ifdef HAVE_ATA_POWER_OFF 158#ifdef HAVE_ATA_POWER_OFF
166 return TIME_AFTER(current_tick, power_off_tick); 159 return power_off_tick && TIME_AFTER(current_tick, power_off_tick);
167#else 160#else
168 return false; 161 return false;
169#endif 162#endif
@@ -230,6 +223,10 @@ static int ata_perform_wakeup(int state)
230 223
231static int ata_perform_sleep(void) 224static int ata_perform_sleep(void)
232{ 225{
226 /* If device doesn't support PM features, don't try to sleep. */
227 if (!ata_disk_can_poweroff())
228 return 0; // XXX or return a failure?
229
233 logf("ata SLEEP %ld", current_tick); 230 logf("ata SLEEP %ld", current_tick);
234 231
235 ATA_OUT8(ATA_SELECT, ata_device); 232 ATA_OUT8(ATA_SELECT, ata_device);
@@ -244,18 +241,10 @@ static int ata_perform_sleep(void)
244 - transitions to PM2:Standby 241 - transitions to PM2:Standby
245 - enters Standby_z power condition 242 - enters Standby_z power condition
246 243
247 This places the device into a state where power-off is safe, but 244 This places the device into a state where power-off is safe. We
248 it is not the lowest-theoretical power state -- that is SLEEP, but 245 will cut power at a later time.
249 that is bugged on some SSDs (FC1307A-based).
250
251 TODO: Is there a practical downside to using STANDBY_IMMEDIATE instead
252 of SLEEP, assuming the former spins down the drive?
253 */ 246 */
254 if (ata_disk_isssd()) { 247 ATA_OUT8(ATA_COMMAND, CMD_STANDBY_IMMEDIATE);
255 ATA_OUT8(ATA_COMMAND, CMD_STANDBY_IMMEDIATE);
256 } else {
257 ATA_OUT8(ATA_COMMAND, CMD_SLEEP);
258 }
259 248
260 if (!wait_for_rdy()) { 249 if (!wait_for_rdy()) {
261 DEBUGF("ata_perform_sleep() - CMD failed\n"); 250 DEBUGF("ata_perform_sleep() - CMD failed\n");
@@ -267,11 +256,17 @@ static int ata_perform_sleep(void)
267 256
268static int ata_perform_flush_cache(void) 257static int ata_perform_flush_cache(void)
269{ 258{
270 /* Don't issue the flush cache command if the device 259 uint8_t cmd;
271 doesn't support it, even though it's mandatory. 260
272 */ 261 if (identify_info[83] & (1 << 13)) {
273 if (!(identify_info[83] & (1 << 12))) 262 cmd = CMD_FLUSH_CACHE_EXT;
263 } else if (identify_info[83] & (1 << 12)) {
264 cmd = CMD_FLUSH_CACHE;
265 } else {
266 /* If neither (mandatory!) command is supported
267 then don't issue it. */
274 return 0; 268 return 0;
269 }
275 270
276 logf("ata FLUSH CACHE %ld", current_tick); 271 logf("ata FLUSH CACHE %ld", current_tick);
277 272
@@ -282,7 +277,7 @@ static int ata_perform_flush_cache(void)
282 return -1; 277 return -1;
283 } 278 }
284 279
285 ATA_OUT8(ATA_COMMAND, CMD_FLUSH_CACHE); 280 ATA_OUT8(ATA_COMMAND, cmd);
286 281
287 if (!wait_for_rdy()) { 282 if (!wait_for_rdy()) {
288 DEBUGF("ata_perform_flush_cache() - CMD failed\n"); 283 DEBUGF("ata_perform_flush_cache() - CMD failed\n");
@@ -387,47 +382,6 @@ static ICODE_ATTR void copy_write_sectors(const unsigned char* buf,
387} 382}
388#endif /* !ATA_OPTIMIZED_WRITING */ 383#endif /* !ATA_OPTIMIZED_WRITING */
389 384
390int ata_disk_isssd(void)
391{
392 /*
393 Offset 217 is "Nominal Rotation rate"
394 0x0000 == Not reported
395 0x0001 == Solid State
396 0x0401 -> 0xffe == RPM
397 All others reserved
398
399 Some CF cards return 0x0100 (ie byteswapped 0x0001) so accept either.
400 However, this is a relatively recent change, and we can't rely on it,
401 especially for the FC1307A CF->SD adapters!
402
403 Offset 168 is "Nominal Form Factor"
404 all values >= 0x06 are guaranteed to be Solid State (mSATA, m.2, etc)
405
406 Offset 83 b2 and/or 86 b2 is set to show device implementes CFA commands
407
408 Offset 169 b0 is set to show device implements TRIM.
409
410 Offset 0 is 0x848a for CF, but that's not guaranteed, because reasons.
411 */
412 return (identify_info[83] & (1<<2) || identify_info[86] & (1<<2) ||
413 (identify_info[168] & 0x0f) >= 0x06 ||
414 identify_info[169] & (1<<0) ||
415 identify_info[217] == 0x0001 || identify_info[217] == 0x0100);
416}
417
418int ata_disk_can_poweroff(void)
419{
420 /* Some SSDs don't like getting powered off, presumably because
421 in the real world they're not in removable form factors and
422 don't expect to have power removed.
423
424 In particular, mSATA, m.2, and MicroSSD are suspect.
425 */
426
427 return ((identify_info[168] & 0x0f) < 0x06 ||
428 (identify_info[168] & 0x0f) > 0x08);
429}
430
431static int ata_transfer_sectors(unsigned long start, 385static int ata_transfer_sectors(unsigned long start,
432 int incount, 386 int incount,
433 void* inbuf, 387 void* inbuf,
@@ -903,7 +857,10 @@ void ata_sleepnow(void)
903 if (ata_state == ATA_ON) { 857 if (ata_state == ATA_ON) {
904 if (!ata_perform_flush_cache() && !ata_perform_sleep()) { 858 if (!ata_perform_flush_cache() && !ata_perform_sleep()) {
905 ata_state = ATA_SLEEPING; 859 ata_state = ATA_SLEEPING;
906 schedule_ata_power_off(); 860#ifdef HAVE_ATA_POWER_OFF
861 if (ata_disk_can_poweroff())
862 power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT;
863#endif
907 } 864 }
908 } 865 }
909 mutex_unlock(&ata_mtx); 866 mutex_unlock(&ata_mtx);
@@ -1136,7 +1093,7 @@ static int set_features(void)
1136 unsigned char parameter; 1093 unsigned char parameter;
1137 } features[] = { 1094 } features[] = {
1138 { 83, 14, 0x03, 0 }, /* force PIO mode */ 1095 { 83, 14, 0x03, 0 }, /* force PIO mode */
1139 { 83, 3, 0x05, 0x80 }, /* adv. power management: lowest w/o standby */ // TODO: What about FC1307A that doesn't advertise this properly? 1096 { 83, 3, 0x05, 0x80 }, /* adv. power management: lowest w/o standby */
1140 { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */ 1097 { 83, 9, 0x42, 0x80 }, /* acoustic management: lowest noise */
1141 { 82, 6, 0xaa, 0 }, /* enable read look-ahead */ 1098 { 82, 6, 0xaa, 0 }, /* enable read look-ahead */
1142#ifdef HAVE_ATA_DMA 1099#ifdef HAVE_ATA_DMA
@@ -1455,17 +1412,17 @@ int ata_event(long id, intptr_t data)
1455 the first case is frequently hit anyway. */ 1412 the first case is frequently hit anyway. */
1456 if (LIKELY(id == Q_STORAGE_TICK)) { 1413 if (LIKELY(id == Q_STORAGE_TICK)) {
1457 /* won't see ATA_BOOT in here */ 1414 /* won't see ATA_BOOT in here */
1458 int state = ata_state; 1415 if (ata_state != ATA_ON || !ata_sleep_timed_out()) {
1459 if (state != ATA_ON || !ata_sleep_timed_out()) { 1416#ifdef HAVE_ATA_POWER_OFF
1460 if (state == ATA_SLEEPING && ata_power_off_timed_out()) { 1417 if (ata_state == ATA_SLEEPING && ata_power_off_timed_out()) {
1418 power_off_tick = 0;
1461 mutex_lock(&ata_mtx); 1419 mutex_lock(&ata_mtx);
1462 if (ata_state == ATA_SLEEPING) { 1420 logf("ata OFF %ld", current_tick);
1463 logf("ata OFF %ld", current_tick); 1421 ide_power_enable(false);
1464 ide_power_enable(false); 1422 ata_state = ATA_OFF;
1465 ata_state = ATA_OFF;
1466 }
1467 mutex_unlock(&ata_mtx); 1423 mutex_unlock(&ata_mtx);
1468 } 1424 }
1425#endif
1469 STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); 1426 STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA);
1470 } 1427 }
1471 } 1428 }