summaryrefslogtreecommitdiff
path: root/firmware/drivers/ata.c
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2021-03-04 17:47:01 -0500
committerSolomon Peachy <pizza@shaftnet.org>2021-03-11 19:28:52 +0000
commitbd507fc7b4e3c6145e3d4e17747f6d77a34427f4 (patch)
tree33f3b30792b01912b2b017a02ae7c50e8f59df15 /firmware/drivers/ata.c
parenteb9f05f835dab48f8d5de4ac364c6a46670cc61c (diff)
downloadrockbox-bd507fc7b4e3c6145e3d4e17747f6d77a34427f4.tar.gz
rockbox-bd507fc7b4e3c6145e3d4e17747f6d77a34427f4.zip
ATA: When device doesn't support powermgmt, only gate ata sleep command.
The FC1307A ATA->SD chipset (used by the common iFlash adapters) doesn't support mandatory ATA power management commands, leading to massive data corruption if they were issued. A workaround was identified (54629073ae) that basically disabled all of rockbox's power management code for these adapters, which extends well beyond the specific ATA commands issued. This patch moves the gating test to the issuance of the actual SLEEP, so that the rest of rockbox's PM code can function as intended. This allows the device to get powered down when idle, yielding potentially significant improvements in battery life. Change-Id: Ia13e2405243fe5efe6f68c3a549ab4933567790b
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r--firmware/drivers/ata.c84
1 files changed, 37 insertions, 47 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 7d306084e4..d2e1ad4a22 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -164,8 +164,8 @@ static inline bool ata_power_off_timed_out(void)
164static ICODE_ATTR int wait_for_bsy(void) 164static ICODE_ATTR int wait_for_bsy(void)
165{ 165{
166 long timeout = current_tick + HZ*30; 166 long timeout = current_tick + HZ*30;
167 167
168 do 168 do
169 { 169 {
170 if (!(ATA_IN8(ATA_STATUS) & STATUS_BSY)) 170 if (!(ATA_IN8(ATA_STATUS) & STATUS_BSY))
171 return 1; 171 return 1;
@@ -184,8 +184,8 @@ static ICODE_ATTR int wait_for_rdy(void)
184 return 0; 184 return 0;
185 185
186 timeout = current_tick + HZ*10; 186 timeout = current_tick + HZ*10;
187 187
188 do 188 do
189 { 189 {
190 if (ATA_IN8(ATA_ALT_STATUS) & STATUS_RDY) 190 if (ATA_IN8(ATA_ALT_STATUS) & STATUS_RDY)
191 return 1; 191 return 1;
@@ -220,6 +220,15 @@ static int ata_perform_wakeup(int state)
220 220
221static int ata_perform_sleep(void) 221static int ata_perform_sleep(void)
222{ 222{
223 /* Don't issue the sleep command if the device
224 doesn't support (mandatory!) ATA power management commands!
225
226 The FC1307A ATA->SD chipset (used by the common iFlash adapters)
227 is the only known offender, and will eat your data if told to sleep.
228 */
229 if (!(identify_info[82] & (1 << 3)))
230 return 0;
231
223 ATA_OUT8(ATA_SELECT, ata_device); 232 ATA_OUT8(ATA_SELECT, ata_device);
224 233
225 if(!wait_for_rdy()) { 234 if(!wait_for_rdy()) {
@@ -250,15 +259,15 @@ static ICODE_ATTR int wait_for_end_of_transfer(void)
250{ 259{
251 if (!wait_for_bsy()) 260 if (!wait_for_bsy())
252 return 0; 261 return 0;
253 return (ATA_IN8(ATA_ALT_STATUS) & 262 return (ATA_IN8(ATA_ALT_STATUS) &
254 (STATUS_BSY|STATUS_RDY|STATUS_DF|STATUS_DRQ|STATUS_ERR)) 263 (STATUS_BSY|STATUS_RDY|STATUS_DF|STATUS_DRQ|STATUS_ERR))
255 == STATUS_RDY; 264 == STATUS_RDY;
256} 265}
257 266
258#if (CONFIG_LED == LED_REAL) 267#if (CONFIG_LED == LED_REAL)
259/* Conditionally block LED access for the ATA driver, so the LED can be 268/* Conditionally block LED access for the ATA driver, so the LED can be
260 * (mis)used for other purposes */ 269 * (mis)used for other purposes */
261static void ata_led(bool on) 270static void ata_led(bool on)
262{ 271{
263 ata_led_on = on; 272 ata_led_on = on;
264 if (ata_led_enabled) 273 if (ata_led_enabled)
@@ -591,7 +600,7 @@ static int cache_sector(unsigned long sector)
591{ 600{
592 int rc; 601 int rc;
593 602
594 sector &= ~(phys_sector_mult - 1); 603 sector &= ~(phys_sector_mult - 1);
595 /* round down to physical sector boundary */ 604 /* round down to physical sector boundary */
596 605
597 /* check whether the sector is already cached */ 606 /* check whether the sector is already cached */
@@ -602,7 +611,7 @@ static int cache_sector(unsigned long sector)
602 sector_cache.inuse = false; 611 sector_cache.inuse = false;
603 rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false); 612 rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false);
604 if (!rc) 613 if (!rc)
605 { 614 {
606 sector_cache.sectornum = sector; 615 sector_cache.sectornum = sector;
607 sector_cache.inuse = true; 616 sector_cache.inuse = true;
608 } 617 }
@@ -627,19 +636,19 @@ int ata_read_sectors(IF_MD(int drive,)
627 (void)drive; /* unused for now */ 636 (void)drive; /* unused for now */
628#endif 637#endif
629 mutex_lock(&ata_mtx); 638 mutex_lock(&ata_mtx);
630 639
631 offset = start & (phys_sector_mult - 1); 640 offset = start & (phys_sector_mult - 1);
632 641
633 if (offset) /* first partial sector */ 642 if (offset) /* first partial sector */
634 { 643 {
635 int partcount = MIN(incount, phys_sector_mult - offset); 644 int partcount = MIN(incount, phys_sector_mult - offset);
636 645
637 rc = cache_sector(start); 646 rc = cache_sector(start);
638 if (rc) 647 if (rc)
639 { 648 {
640 rc = rc * 10 - 1; 649 rc = rc * 10 - 1;
641 goto error; 650 goto error;
642 } 651 }
643 memcpy(inbuf, sector_cache.data + offset * SECTOR_SIZE, 652 memcpy(inbuf, sector_cache.data + offset * SECTOR_SIZE,
644 partcount * SECTOR_SIZE); 653 partcount * SECTOR_SIZE);
645 654
@@ -651,7 +660,7 @@ int ata_read_sectors(IF_MD(int drive,)
651 { 660 {
652 offset = incount & (phys_sector_mult - 1); 661 offset = incount & (phys_sector_mult - 1);
653 incount -= offset; 662 incount -= offset;
654 663
655 if (incount) 664 if (incount)
656 { 665 {
657 rc = ata_transfer_sectors(start, incount, inbuf, false); 666 rc = ata_transfer_sectors(start, incount, inbuf, false);
@@ -693,9 +702,9 @@ int ata_write_sectors(IF_MD(int drive,)
693 (void)drive; /* unused for now */ 702 (void)drive; /* unused for now */
694#endif 703#endif
695 mutex_lock(&ata_mtx); 704 mutex_lock(&ata_mtx);
696 705
697 offset = start & (phys_sector_mult - 1); 706 offset = start & (phys_sector_mult - 1);
698 707
699 if (offset) /* first partial sector */ 708 if (offset) /* first partial sector */
700 { 709 {
701 int partcount = MIN(count, phys_sector_mult - offset); 710 int partcount = MIN(count, phys_sector_mult - offset);
@@ -705,7 +714,7 @@ int ata_write_sectors(IF_MD(int drive,)
705 { 714 {
706 rc = rc * 10 - 1; 715 rc = rc * 10 - 1;
707 goto error; 716 goto error;
708 } 717 }
709 memcpy(sector_cache.data + offset * SECTOR_SIZE, buf, 718 memcpy(sector_cache.data + offset * SECTOR_SIZE, buf,
710 partcount * SECTOR_SIZE); 719 partcount * SECTOR_SIZE);
711 rc = flush_current_sector(); 720 rc = flush_current_sector();
@@ -713,7 +722,7 @@ int ata_write_sectors(IF_MD(int drive,)
713 { 722 {
714 rc = rc * 10 - 2; 723 rc = rc * 10 - 2;
715 goto error; 724 goto error;
716 } 725 }
717 start += partcount; 726 start += partcount;
718 buf += partcount * SECTOR_SIZE; 727 buf += partcount * SECTOR_SIZE;
719 count -= partcount; 728 count -= partcount;
@@ -722,7 +731,7 @@ int ata_write_sectors(IF_MD(int drive,)
722 { 731 {
723 offset = count & (phys_sector_mult - 1); 732 offset = count & (phys_sector_mult - 1);
724 count -= offset; 733 count -= offset;
725 734
726 if (count) 735 if (count)
727 { 736 {
728 rc = ata_transfer_sectors(start, count, (void*)buf, true); 737 rc = ata_transfer_sectors(start, count, (void*)buf, true);
@@ -742,7 +751,7 @@ int ata_write_sectors(IF_MD(int drive,)
742 rc = rc * 10 - 4; 751 rc = rc * 10 - 4;
743 goto error; 752 goto error;
744 } 753 }
745 memcpy(sector_cache.data, buf, offset * SECTOR_SIZE); 754 memcpy(sector_cache.data, buf, offset * SECTOR_SIZE);
746 rc = flush_current_sector(); 755 rc = flush_current_sector();
747 if (rc) 756 if (rc)
748 { 757 {
@@ -809,30 +818,11 @@ void ata_spindown(int seconds)
809 818
810bool ata_disk_is_active(void) 819bool ata_disk_is_active(void)
811{ 820{
812 /* "active" here means "spinning / not sleeping"
813 we normally leave active state by putting the device to
814 sleep (using ATA powersave commands) which flushes all writes
815 and puts the device into an inactive/quiescent state.
816
817 Unfortuantely the CF->SD chipset used by the common iFlash
818 adapters does not support ATA powersave, which makes the
819 "active/not" distinction irrelevant, so insead we just mirror
820 the sd/mmc/flash storage drivers and claim that we're always
821 inactive.
822 */
823 if (!(identify_info[82] & (1 << 3)))
824 return false;
825
826 return ata_state >= ATA_SPINUP; 821 return ata_state >= ATA_SPINUP;
827} 822}
828 823
829void ata_sleepnow(void) 824void ata_sleepnow(void)
830{ 825{
831 /* Don't enter sleep if the device doesn't support
832 power management. See comment in ata_disk_is_active() */
833 if (!(identify_info[82] & (1 << 3)))
834 return;
835
836 if (ata_state >= ATA_SPINUP) { 826 if (ata_state >= ATA_SPINUP) {
837 mutex_lock(&ata_mtx); 827 mutex_lock(&ata_mtx);
838 if (ata_state == ATA_ON) { 828 if (ata_state == ATA_ON) {
@@ -954,7 +944,7 @@ static int perform_soft_reset(void)
954int ata_soft_reset(void) 944int ata_soft_reset(void)
955{ 945{
956 int ret = -6; 946 int ret = -6;
957 947
958 mutex_lock(&ata_mtx); 948 mutex_lock(&ata_mtx);
959 949
960 if (ata_state > ATA_OFF) { 950 if (ata_state > ATA_OFF) {
@@ -969,7 +959,7 @@ int ata_soft_reset(void)
969static int ata_power_on(void) 959static int ata_power_on(void)
970{ 960{
971 int rc; 961 int rc;
972 962
973 ide_power_enable(true); 963 ide_power_enable(true);
974 sleep(HZ/4); /* allow voltage to build up */ 964 sleep(HZ/4); /* allow voltage to build up */
975 965
@@ -1100,7 +1090,7 @@ static int set_features(void)
1100 } 1090 }
1101 else 1091 else
1102 features[4].id_word = 88; 1092 features[4].id_word = 88;
1103 1093
1104 features[4].id_bit = dma_mode & 7; 1094 features[4].id_bit = dma_mode & 7;
1105 features[4].parameter = dma_mode; 1095 features[4].parameter = dma_mode;
1106#endif /* HAVE_ATA_DMA */ 1096#endif /* HAVE_ATA_DMA */
@@ -1172,7 +1162,7 @@ static int STORAGE_INIT_ATTR init_and_check(bool hard_reset)
1172 rc = check_registers(); 1162 rc = check_registers();
1173 if (rc) 1163 if (rc)
1174 return -30 + rc; 1164 return -30 + rc;
1175 1165
1176 return 0; 1166 return 0;
1177} 1167}
1178 1168
@@ -1243,7 +1233,7 @@ int STORAGE_INIT_ATTR ata_init(void)
1243 { /* (needs BigLBA addressing) */ 1233 { /* (needs BigLBA addressing) */
1244 if (identify_info[102] || identify_info[103]) 1234 if (identify_info[102] || identify_info[103])
1245 panicf("Unsupported disk size: >= 2^32 sectors"); 1235 panicf("Unsupported disk size: >= 2^32 sectors");
1246 1236
1247 total_sectors = identify_info[100] | (identify_info[101] << 16); 1237 total_sectors = identify_info[100] | (identify_info[101] << 16);
1248 lba48 = true; /* use BigLBA */ 1238 lba48 = true; /* use BigLBA */
1249 } 1239 }
@@ -1282,7 +1272,7 @@ int STORAGE_INIT_ATTR ata_init(void)
1282 if (rc == 0) 1272 if (rc == 0)
1283 phys_sector_mult = 1; 1273 phys_sector_mult = 1;
1284 } 1274 }
1285 1275
1286 if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE)) 1276 if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE))
1287 panicf("Unsupported physical sector size: %d", 1277 panicf("Unsupported physical sector size: %d",
1288 phys_sector_mult * SECTOR_SIZE); 1278 phys_sector_mult * SECTOR_SIZE);
@@ -1301,7 +1291,7 @@ error:
1301} 1291}
1302 1292
1303#if (CONFIG_LED == LED_REAL) 1293#if (CONFIG_LED == LED_REAL)
1304void ata_set_led_enabled(bool enabled) 1294void ata_set_led_enabled(bool enabled)
1305{ 1295{
1306 ata_led_enabled = enabled; 1296 ata_led_enabled = enabled;
1307 if (ata_led_enabled) 1297 if (ata_led_enabled)
@@ -1372,7 +1362,7 @@ int ata_num_drives(int first_drive)
1372{ 1362{
1373 /* We don't care which logical drive number(s) we have been assigned */ 1363 /* We don't care which logical drive number(s) we have been assigned */
1374 (void)first_drive; 1364 (void)first_drive;
1375 1365
1376 return 1; 1366 return 1;
1377} 1367}
1378#endif 1368#endif