diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/ata.c | 84 |
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) | |||
164 | static ICODE_ATTR int wait_for_bsy(void) | 164 | static 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 | ||
221 | static int ata_perform_sleep(void) | 221 | static 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 */ |
261 | static void ata_led(bool on) | 270 | static 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 | ||
810 | bool ata_disk_is_active(void) | 819 | bool 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 | ||
829 | void ata_sleepnow(void) | 824 | void 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) | |||
954 | int ata_soft_reset(void) | 944 | int 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) | |||
969 | static int ata_power_on(void) | 959 | static 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) |
1304 | void ata_set_led_enabled(bool enabled) | 1294 | void 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 |