diff options
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/ata.c | 493 | ||||
-rw-r--r-- | firmware/drivers/ramdisk.c | 5 |
2 files changed, 217 insertions, 281 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index b574117620..373078d8f9 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -20,18 +20,13 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
22 | #include <inttypes.h> | 22 | #include <inttypes.h> |
23 | #include "ata.h" | ||
24 | #include "kernel.h" | ||
25 | #include "thread.h" | ||
26 | #include "led.h" | 23 | #include "led.h" |
27 | #include "cpu.h" | 24 | #include "cpu.h" |
28 | #include "system.h" | 25 | #include "system.h" |
29 | #include "debug.h" | 26 | #include "debug.h" |
30 | #include "panic.h" | 27 | #include "panic.h" |
31 | #include "usb.h" | ||
32 | #include "power.h" | 28 | #include "power.h" |
33 | #include "string.h" | 29 | #include "string.h" |
34 | #include "ata_idle_notify.h" | ||
35 | #include "ata-driver.h" | 30 | #include "ata-driver.h" |
36 | #include "ata-defines.h" | 31 | #include "ata-defines.h" |
37 | #include "fs_defines.h" | 32 | #include "fs_defines.h" |
@@ -64,24 +59,28 @@ | |||
64 | #define CMD_WRITE_DMA_EXT 0x35 | 59 | #define CMD_WRITE_DMA_EXT 0x35 |
65 | #endif | 60 | #endif |
66 | 61 | ||
67 | /* Should all be < 0x100 (which are reserved for control messages) */ | ||
68 | #define Q_SLEEP 0 | ||
69 | #define Q_CLOSE 1 | ||
70 | |||
71 | #define READWRITE_TIMEOUT 5*HZ | 62 | #define READWRITE_TIMEOUT 5*HZ |
72 | 63 | ||
73 | #ifdef HAVE_ATA_POWER_OFF | 64 | #ifdef HAVE_ATA_POWER_OFF |
74 | #define ATA_POWER_OFF_TIMEOUT 2*HZ | 65 | #define ATA_POWER_OFF_TIMEOUT 2*HZ |
75 | #endif | 66 | #endif |
76 | 67 | ||
77 | #ifdef ATA_DRIVER_CLOSE | ||
78 | static unsigned int ata_thread_id = 0; | ||
79 | #endif | ||
80 | |||
81 | #if defined(HAVE_USBSTACK) | 68 | #if defined(HAVE_USBSTACK) |
82 | #define ALLOW_USB_SPINDOWN | 69 | #define ATA_ACTIVE_IN_USB 1 |
70 | #else | ||
71 | #define ATA_ACTIVE_IN_USB 0 | ||
83 | #endif | 72 | #endif |
84 | 73 | ||
74 | enum { | ||
75 | ATA_BOOT = -1, | ||
76 | ATA_OFF, | ||
77 | ATA_SLEEPING, | ||
78 | ATA_SPINUP, | ||
79 | ATA_ON, | ||
80 | }; | ||
81 | |||
82 | static int ata_state = ATA_BOOT; | ||
83 | |||
85 | static struct mutex ata_mtx SHAREDBSS_ATTR; | 84 | static struct mutex ata_mtx SHAREDBSS_ATTR; |
86 | static int ata_device; /* device 0 (master) or 1 (slave) */ | 85 | static int ata_device; /* device 0 (master) or 1 (slave) */ |
87 | 86 | ||
@@ -90,22 +89,16 @@ static int spinup_time = 0; | |||
90 | static bool ata_led_enabled = true; | 89 | static bool ata_led_enabled = true; |
91 | static bool ata_led_on = false; | 90 | static bool ata_led_on = false; |
92 | #endif | 91 | #endif |
93 | static bool spinup = false; | 92 | |
94 | static bool sleeping = true; | ||
95 | #ifdef HAVE_ATA_POWER_OFF | ||
96 | static bool poweroff = false; | ||
97 | #endif | ||
98 | static long sleep_timeout = 5*HZ; | 93 | static long sleep_timeout = 5*HZ; |
99 | #ifdef HAVE_LBA48 | 94 | #ifdef HAVE_LBA48 |
100 | static bool lba48 = false; /* set for 48 bit addressing */ | 95 | static bool lba48 = false; /* set for 48 bit addressing */ |
101 | #endif | 96 | #endif |
102 | static long ata_stack[(DEFAULT_STACK_SIZE*3)/sizeof(long)]; | ||
103 | static const char ata_thread_name[] = "ata"; | ||
104 | static struct event_queue ata_queue SHAREDBSS_ATTR; | ||
105 | static bool initialized = false; | ||
106 | 97 | ||
107 | static long last_user_activity = -1; | ||
108 | static long last_disk_activity = -1; | 98 | static long last_disk_activity = -1; |
99 | #ifdef HAVE_ATA_POWER_OFF | ||
100 | static long power_off_tick; | ||
101 | #endif | ||
109 | 102 | ||
110 | static unsigned long total_sectors; | 103 | static unsigned long total_sectors; |
111 | static int multisectors; /* number of supported multisectors */ | 104 | static int multisectors; /* number of supported multisectors */ |
@@ -135,6 +128,38 @@ static int perform_soft_reset(void); | |||
135 | static int set_multiple_mode(int sectors); | 128 | static int set_multiple_mode(int sectors); |
136 | static int set_features(void); | 129 | static int set_features(void); |
137 | 130 | ||
131 | static inline void keep_ata_active(void) | ||
132 | { | ||
133 | last_disk_activity = current_tick; | ||
134 | } | ||
135 | |||
136 | static inline void schedule_ata_sleep(long from_now) | ||
137 | { | ||
138 | last_disk_activity = current_tick - sleep_timeout + from_now; | ||
139 | } | ||
140 | |||
141 | static inline bool ata_sleep_timed_out(void) | ||
142 | { | ||
143 | return sleep_timeout && | ||
144 | TIME_AFTER(current_tick, last_disk_activity + sleep_timeout); | ||
145 | } | ||
146 | |||
147 | static inline void schedule_ata_power_off(void) | ||
148 | { | ||
149 | #ifdef HAVE_ATA_POWER_OFF | ||
150 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | static inline bool ata_power_off_timed_out(void) | ||
155 | { | ||
156 | #ifdef HAVE_ATA_POWER_OFF | ||
157 | return TIME_AFTER(current_tick, power_off_tick); | ||
158 | #else | ||
159 | return false; | ||
160 | #endif | ||
161 | } | ||
162 | |||
138 | #ifndef ATA_TARGET_POLLING | 163 | #ifndef ATA_TARGET_POLLING |
139 | static ICODE_ATTR int wait_for_bsy(void) | 164 | static ICODE_ATTR int wait_for_bsy(void) |
140 | { | 165 | { |
@@ -144,7 +169,7 @@ static ICODE_ATTR int wait_for_bsy(void) | |||
144 | { | 169 | { |
145 | if (!(ATA_IN8(ATA_STATUS) & STATUS_BSY)) | 170 | if (!(ATA_IN8(ATA_STATUS) & STATUS_BSY)) |
146 | return 1; | 171 | return 1; |
147 | last_disk_activity = current_tick; | 172 | keep_ata_active(); |
148 | yield(); | 173 | yield(); |
149 | } while (TIME_BEFORE(current_tick, timeout)); | 174 | } while (TIME_BEFORE(current_tick, timeout)); |
150 | 175 | ||
@@ -164,7 +189,7 @@ static ICODE_ATTR int wait_for_rdy(void) | |||
164 | { | 189 | { |
165 | if (ATA_IN8(ATA_ALT_STATUS) & STATUS_RDY) | 190 | if (ATA_IN8(ATA_ALT_STATUS) & STATUS_RDY) |
166 | return 1; | 191 | return 1; |
167 | last_disk_activity = current_tick; | 192 | keep_ata_active(); |
168 | yield(); | 193 | yield(); |
169 | } while (TIME_BEFORE(current_tick, timeout)); | 194 | } while (TIME_BEFORE(current_tick, timeout)); |
170 | 195 | ||
@@ -175,6 +200,44 @@ static ICODE_ATTR int wait_for_rdy(void) | |||
175 | #define wait_for_rdy ata_wait_for_rdy | 200 | #define wait_for_rdy ata_wait_for_rdy |
176 | #endif | 201 | #endif |
177 | 202 | ||
203 | static int ata_perform_wakeup(int state) | ||
204 | { | ||
205 | if (state > ATA_OFF) { | ||
206 | if (perform_soft_reset()) { | ||
207 | return -1; | ||
208 | } | ||
209 | } | ||
210 | #ifdef HAVE_ATA_POWER_OFF | ||
211 | else { | ||
212 | if (ata_power_on()) { | ||
213 | return -2; | ||
214 | } | ||
215 | } | ||
216 | #endif | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int ata_perform_sleep(void) | ||
222 | { | ||
223 | ATA_OUT8(ATA_SELECT, ata_device); | ||
224 | |||
225 | if(!wait_for_rdy()) { | ||
226 | DEBUGF("ata_perform_sleep() - not RDY\n"); | ||
227 | return -1; | ||
228 | } | ||
229 | |||
230 | ATA_OUT8(ATA_COMMAND, CMD_SLEEP); | ||
231 | |||
232 | if (!wait_for_rdy()) | ||
233 | { | ||
234 | DEBUGF("ata_perform_sleep() - CMD failed\n"); | ||
235 | return -2; | ||
236 | } | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
178 | static ICODE_ATTR int wait_for_start_of_transfer(void) | 241 | static ICODE_ATTR int wait_for_start_of_transfer(void) |
179 | { | 242 | { |
180 | if (!wait_for_bsy()) | 243 | if (!wait_for_bsy()) |
@@ -278,42 +341,27 @@ static int ata_transfer_sectors(unsigned long start, | |||
278 | long timeout; | 341 | long timeout; |
279 | int count; | 342 | int count; |
280 | void* buf; | 343 | void* buf; |
281 | long spinup_start; | 344 | long spinup_start = spinup_start; |
282 | #ifdef HAVE_ATA_DMA | 345 | #ifdef HAVE_ATA_DMA |
283 | bool usedma = false; | 346 | bool usedma = false; |
284 | #endif | 347 | #endif |
285 | 348 | ||
286 | #ifndef MAX_PHYS_SECTOR_SIZE | ||
287 | mutex_lock(&ata_mtx); | ||
288 | #endif | ||
289 | |||
290 | if (start + incount > total_sectors) { | 349 | if (start + incount > total_sectors) { |
291 | ret = -1; | 350 | ret = -1; |
292 | goto error; | 351 | goto error; |
293 | } | 352 | } |
294 | 353 | ||
295 | last_disk_activity = current_tick; | 354 | keep_ata_active(); |
296 | spinup_start = current_tick; | ||
297 | 355 | ||
298 | ata_led(true); | 356 | ata_led(true); |
299 | 357 | ||
300 | if ( sleeping ) { | 358 | if (ata_state < ATA_ON) { |
301 | sleeping = false; /* set this now since it'll be on */ | 359 | spinup_start = current_tick; |
302 | spinup = true; | 360 | int state = ata_state; |
303 | #ifdef HAVE_ATA_POWER_OFF | 361 | ata_state = ATA_SPINUP; |
304 | if (poweroff) { | 362 | if (ata_perform_wakeup(state)) { |
305 | if (ata_power_on()) { | 363 | ret = -2; |
306 | ret = -2; | 364 | goto error; |
307 | goto error; | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | #endif | ||
312 | { | ||
313 | if (perform_soft_reset()) { | ||
314 | ret = -2; | ||
315 | goto error; | ||
316 | } | ||
317 | } | 365 | } |
318 | } | 366 | } |
319 | 367 | ||
@@ -331,7 +379,7 @@ static int ata_transfer_sectors(unsigned long start, | |||
331 | count = incount; | 379 | count = incount; |
332 | while (TIME_BEFORE(current_tick, timeout)) { | 380 | while (TIME_BEFORE(current_tick, timeout)) { |
333 | ret = 0; | 381 | ret = 0; |
334 | last_disk_activity = current_tick; | 382 | keep_ata_active(); |
335 | 383 | ||
336 | #ifdef HAVE_ATA_DMA | 384 | #ifdef HAVE_ATA_DMA |
337 | /* If DMA is supported and parameters are ok for DMA, use it */ | 385 | /* If DMA is supported and parameters are ok for DMA, use it */ |
@@ -395,12 +443,9 @@ static int ata_transfer_sectors(unsigned long start, | |||
395 | goto retry; | 443 | goto retry; |
396 | } | 444 | } |
397 | 445 | ||
398 | if (spinup) { | 446 | if (ata_state == ATA_SPINUP) { |
447 | ata_state = ATA_ON; | ||
399 | spinup_time = current_tick - spinup_start; | 448 | spinup_time = current_tick - spinup_start; |
400 | spinup = false; | ||
401 | #ifdef HAVE_ATA_POWER_OFF | ||
402 | poweroff = false; | ||
403 | #endif | ||
404 | } | 449 | } |
405 | } | 450 | } |
406 | else | 451 | else |
@@ -426,12 +471,9 @@ static int ata_transfer_sectors(unsigned long start, | |||
426 | goto retry; | 471 | goto retry; |
427 | } | 472 | } |
428 | 473 | ||
429 | if (spinup) { | 474 | if (ata_state == ATA_SPINUP) { |
475 | ata_state = ATA_ON; | ||
430 | spinup_time = current_tick - spinup_start; | 476 | spinup_time = current_tick - spinup_start; |
431 | spinup = false; | ||
432 | #ifdef HAVE_ATA_POWER_OFF | ||
433 | poweroff = false; | ||
434 | #endif | ||
435 | } | 477 | } |
436 | 478 | ||
437 | /* read the status register exactly once per loop */ | 479 | /* read the status register exactly once per loop */ |
@@ -470,7 +512,7 @@ static int ata_transfer_sectors(unsigned long start, | |||
470 | buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */ | 512 | buf += sectors * SECTOR_SIZE; /* Advance one chunk of sectors */ |
471 | count -= sectors; | 513 | count -= sectors; |
472 | 514 | ||
473 | last_disk_activity = current_tick; | 515 | keep_ata_active(); |
474 | } | 516 | } |
475 | } | 517 | } |
476 | 518 | ||
@@ -490,9 +532,11 @@ static int ata_transfer_sectors(unsigned long start, | |||
490 | 532 | ||
491 | error: | 533 | error: |
492 | ata_led(false); | 534 | ata_led(false); |
493 | #ifndef MAX_PHYS_SECTOR_SIZE | 535 | |
494 | mutex_unlock(&ata_mtx); | 536 | if (ret < 0 && ata_state == ATA_SPINUP) { |
495 | #endif | 537 | /* bailed out before updating */ |
538 | ata_state = ATA_ON; | ||
539 | } | ||
496 | 540 | ||
497 | return ret; | 541 | return ret; |
498 | } | 542 | } |
@@ -507,11 +551,12 @@ int ata_read_sectors(IF_MD(int drive,) | |||
507 | (void)drive; /* unused for now */ | 551 | (void)drive; /* unused for now */ |
508 | #endif | 552 | #endif |
509 | 553 | ||
510 | return ata_transfer_sectors(start, incount, inbuf, false); | 554 | mutex_lock(&ata_mtx); |
555 | int rc = ata_transfer_sectors(start, incount, inbuf, false); | ||
556 | mutex_unlock(&ata_mtx); | ||
557 | return rc; | ||
511 | } | 558 | } |
512 | #endif | ||
513 | 559 | ||
514 | #ifndef MAX_PHYS_SECTOR_SIZE | ||
515 | int ata_write_sectors(IF_MD(int drive,) | 560 | int ata_write_sectors(IF_MD(int drive,) |
516 | unsigned long start, | 561 | unsigned long start, |
517 | int count, | 562 | int count, |
@@ -521,9 +566,12 @@ int ata_write_sectors(IF_MD(int drive,) | |||
521 | (void)drive; /* unused for now */ | 566 | (void)drive; /* unused for now */ |
522 | #endif | 567 | #endif |
523 | 568 | ||
524 | return ata_transfer_sectors(start, count, (void*)buf, true); | 569 | mutex_lock(&ata_mtx); |
570 | int rc = ata_transfer_sectors(start, count, (void*)buf, true); | ||
571 | mutex_unlock(&ata_mtx); | ||
572 | return rc; | ||
525 | } | 573 | } |
526 | #endif | 574 | #endif /* ndef MAX_PHYS_SECTOR_SIZE */ |
527 | 575 | ||
528 | #ifdef MAX_PHYS_SECTOR_SIZE | 576 | #ifdef MAX_PHYS_SECTOR_SIZE |
529 | static int cache_sector(unsigned long sector) | 577 | static int cache_sector(unsigned long sector) |
@@ -748,178 +796,26 @@ void ata_spindown(int seconds) | |||
748 | 796 | ||
749 | bool ata_disk_is_active(void) | 797 | bool ata_disk_is_active(void) |
750 | { | 798 | { |
751 | return !sleeping; | 799 | return ata_state >= ATA_SPINUP; |
752 | } | ||
753 | |||
754 | static int ata_perform_sleep(void) | ||
755 | { | ||
756 | /* guard against calls made with checks of these variables outside | ||
757 | the mutex that may not be on the ata thread; status may have changed. */ | ||
758 | if (spinup || sleeping) { | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | ATA_OUT8(ATA_SELECT, ata_device); | ||
763 | |||
764 | if(!wait_for_rdy()) { | ||
765 | DEBUGF("ata_perform_sleep() - not RDY\n"); | ||
766 | return -1; | ||
767 | } | ||
768 | |||
769 | ATA_OUT8(ATA_COMMAND, CMD_SLEEP); | ||
770 | |||
771 | if (!wait_for_rdy()) | ||
772 | { | ||
773 | DEBUGF("ata_perform_sleep() - CMD failed\n"); | ||
774 | return -2; | ||
775 | } | ||
776 | |||
777 | sleeping = true; | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | void ata_sleep(void) | ||
782 | { | ||
783 | queue_post(&ata_queue, Q_SLEEP, 0); | ||
784 | } | 800 | } |
785 | 801 | ||
786 | void ata_sleepnow(void) | 802 | void ata_sleepnow(void) |
787 | { | 803 | { |
788 | if (!spinup && !sleeping && initialized) | 804 | if (ata_state >= ATA_SPINUP) { |
789 | { | ||
790 | call_storage_idle_notifys(false); | ||
791 | mutex_lock(&ata_mtx); | 805 | mutex_lock(&ata_mtx); |
792 | ata_perform_sleep(); | 806 | if (ata_state == ATA_ON) { |
807 | if (!ata_perform_sleep()) { | ||
808 | ata_state = ATA_SLEEPING; | ||
809 | schedule_ata_power_off(); | ||
810 | } | ||
811 | } | ||
793 | mutex_unlock(&ata_mtx); | 812 | mutex_unlock(&ata_mtx); |
794 | } | 813 | } |
795 | } | 814 | } |
796 | 815 | ||
797 | void ata_spin(void) | 816 | void ata_spin(void) |
798 | { | 817 | { |
799 | last_user_activity = current_tick; | 818 | keep_ata_active(); |
800 | } | ||
801 | |||
802 | static void ata_thread(void) | ||
803 | { | ||
804 | #ifdef HAVE_ATA_POWER_OFF | ||
805 | static long last_sleep = 0; | ||
806 | #endif | ||
807 | struct queue_event ev; | ||
808 | #ifdef ALLOW_USB_SPINDOWN | ||
809 | static bool usb_mode = false; | ||
810 | #endif | ||
811 | |||
812 | while (1) { | ||
813 | queue_wait_w_tmo(&ata_queue, &ev, HZ/2); | ||
814 | |||
815 | switch ( ev.id ) { | ||
816 | case SYS_TIMEOUT: | ||
817 | if (!spinup && !sleeping) | ||
818 | { | ||
819 | if (TIME_AFTER( current_tick, | ||
820 | last_disk_activity + (HZ*2) ) ) | ||
821 | { | ||
822 | #ifdef ALLOW_USB_SPINDOWN | ||
823 | if(!usb_mode) | ||
824 | #endif | ||
825 | { | ||
826 | call_storage_idle_notifys(false); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | if ( sleep_timeout && | ||
831 | TIME_AFTER( current_tick, | ||
832 | last_user_activity + sleep_timeout ) && | ||
833 | TIME_AFTER( current_tick, | ||
834 | last_disk_activity + sleep_timeout ) ) | ||
835 | { | ||
836 | #ifdef ALLOW_USB_SPINDOWN | ||
837 | if(!usb_mode) | ||
838 | #endif | ||
839 | { | ||
840 | call_storage_idle_notifys(true); | ||
841 | } | ||
842 | mutex_lock(&ata_mtx); | ||
843 | ata_perform_sleep(); | ||
844 | #ifdef HAVE_ATA_POWER_OFF | ||
845 | last_sleep = current_tick; | ||
846 | #endif | ||
847 | mutex_unlock(&ata_mtx); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | #ifdef HAVE_ATA_POWER_OFF | ||
852 | if ( !spinup && sleeping && !poweroff && | ||
853 | TIME_AFTER( current_tick, last_sleep + ATA_POWER_OFF_TIMEOUT )) | ||
854 | { | ||
855 | mutex_lock(&ata_mtx); | ||
856 | ide_power_enable(false); | ||
857 | poweroff = true; | ||
858 | mutex_unlock(&ata_mtx); | ||
859 | } | ||
860 | #endif | ||
861 | break; | ||
862 | |||
863 | #ifndef USB_NONE | ||
864 | case SYS_USB_CONNECTED: | ||
865 | /* Tell the USB thread that we are safe */ | ||
866 | DEBUGF("ata_thread got SYS_USB_CONNECTED\n"); | ||
867 | #ifdef ALLOW_USB_SPINDOWN | ||
868 | usb_mode = true; | ||
869 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
870 | /* There is no need to force ATA power on */ | ||
871 | #else | ||
872 | mutex_lock(&ata_mtx); | ||
873 | if (sleeping) { | ||
874 | ata_led(true); | ||
875 | sleeping = false; /* set this now since it'll be on */ | ||
876 | |||
877 | #ifdef HAVE_ATA_POWER_OFF | ||
878 | if (poweroff) { | ||
879 | ata_power_on(); | ||
880 | poweroff = false; | ||
881 | } | ||
882 | else | ||
883 | #endif | ||
884 | { | ||
885 | perform_soft_reset(); | ||
886 | } | ||
887 | |||
888 | ata_led(false); | ||
889 | } | ||
890 | mutex_unlock(&ata_mtx); | ||
891 | |||
892 | /* Wait until the USB cable is extracted again */ | ||
893 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
894 | usb_wait_for_disconnect(&ata_queue); | ||
895 | #endif | ||
896 | break; | ||
897 | |||
898 | #ifdef ALLOW_USB_SPINDOWN | ||
899 | case SYS_USB_DISCONNECTED: | ||
900 | /* Tell the USB thread that we are ready again */ | ||
901 | DEBUGF("ata_thread got SYS_USB_DISCONNECTED\n"); | ||
902 | usb_mode = false; | ||
903 | break; | ||
904 | #endif | ||
905 | #endif /* USB_NONE */ | ||
906 | |||
907 | case Q_SLEEP: | ||
908 | #ifdef ALLOW_USB_SPINDOWN | ||
909 | if(!usb_mode) | ||
910 | #endif | ||
911 | { | ||
912 | call_storage_idle_notifys(false); | ||
913 | } | ||
914 | last_disk_activity = current_tick - sleep_timeout + (HZ/2); | ||
915 | break; | ||
916 | |||
917 | #ifdef ATA_DRIVER_CLOSE | ||
918 | case Q_CLOSE: | ||
919 | return; | ||
920 | #endif | ||
921 | } | ||
922 | } | ||
923 | } | 819 | } |
924 | 820 | ||
925 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ | 821 | /* Hardware reset protocol as specified in chapter 9.1, ATA spec draft v5 */ |
@@ -1025,11 +921,13 @@ static int perform_soft_reset(void) | |||
1025 | 921 | ||
1026 | int ata_soft_reset(void) | 922 | int ata_soft_reset(void) |
1027 | { | 923 | { |
1028 | int ret; | 924 | int ret = -6; |
1029 | 925 | ||
1030 | mutex_lock(&ata_mtx); | 926 | mutex_lock(&ata_mtx); |
1031 | 927 | ||
1032 | ret = perform_soft_reset(); | 928 | if (ata_state > ATA_OFF) { |
929 | ret = perform_soft_reset(); | ||
930 | } | ||
1033 | 931 | ||
1034 | mutex_unlock(&ata_mtx); | 932 | mutex_unlock(&ata_mtx); |
1035 | return ret; | 933 | return ret; |
@@ -1068,7 +966,7 @@ static int ata_power_on(void) | |||
1068 | 966 | ||
1069 | return 0; | 967 | return 0; |
1070 | } | 968 | } |
1071 | #endif | 969 | #endif /* HAVE_ATA_POWER_OFF */ |
1072 | 970 | ||
1073 | static int STORAGE_INIT_ATTR master_slave_detect(void) | 971 | static int STORAGE_INIT_ATTR master_slave_detect(void) |
1074 | { | 972 | { |
@@ -1250,9 +1148,8 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1250 | int rc = 0; | 1148 | int rc = 0; |
1251 | bool coldstart; | 1149 | bool coldstart; |
1252 | 1150 | ||
1253 | if ( !initialized ) { | 1151 | if (ata_state == ATA_BOOT) { |
1254 | mutex_init(&ata_mtx); | 1152 | mutex_init(&ata_mtx); |
1255 | queue_init(&ata_queue, true); | ||
1256 | } | 1153 | } |
1257 | 1154 | ||
1258 | mutex_lock(&ata_mtx); | 1155 | mutex_lock(&ata_mtx); |
@@ -1261,16 +1158,13 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1261 | coldstart = ata_is_coldstart(); | 1158 | coldstart = ata_is_coldstart(); |
1262 | ata_led(false); | 1159 | ata_led(false); |
1263 | ata_device_init(); | 1160 | ata_device_init(); |
1264 | sleeping = false; | ||
1265 | ata_enable(true); | 1161 | ata_enable(true); |
1266 | #ifdef MAX_PHYS_SECTOR_SIZE | 1162 | #ifdef MAX_PHYS_SECTOR_SIZE |
1267 | memset(§or_cache, 0, sizeof(sector_cache)); | 1163 | memset(§or_cache, 0, sizeof(sector_cache)); |
1268 | #endif | 1164 | #endif |
1269 | 1165 | ||
1270 | if ( !initialized ) { | 1166 | if (ata_state == ATA_BOOT) { |
1271 | /* First call won't have multiple thread contention - this | 1167 | ata_state = ATA_OFF; |
1272 | * may return at any point without having to unlock */ | ||
1273 | mutex_unlock(&ata_mtx); | ||
1274 | 1168 | ||
1275 | if (!ide_powered()) /* somebody has switched it off */ | 1169 | if (!ide_powered()) /* somebody has switched it off */ |
1276 | { | 1170 | { |
@@ -1290,14 +1184,17 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1290 | { /* failed? -> second try, always with hard reset */ | 1184 | { /* failed? -> second try, always with hard reset */ |
1291 | DEBUGF("ata: init failed, retrying...\n"); | 1185 | DEBUGF("ata: init failed, retrying...\n"); |
1292 | rc = init_and_check(true); | 1186 | rc = init_and_check(true); |
1293 | if (rc) | 1187 | if (rc) { |
1294 | return rc; | 1188 | goto error; |
1189 | } | ||
1295 | } | 1190 | } |
1296 | 1191 | ||
1297 | rc = identify(); | 1192 | rc = identify(); |
1298 | 1193 | ||
1299 | if (rc) | 1194 | if (rc) { |
1300 | return -40 + rc; | 1195 | rc = -40 + rc; |
1196 | goto error; | ||
1197 | } | ||
1301 | 1198 | ||
1302 | multisectors = identify_info[47] & 0xff; | 1199 | multisectors = identify_info[47] & 0xff; |
1303 | if (multisectors == 0) /* Invalid multisector info, try with 16 */ | 1200 | if (multisectors == 0) /* Invalid multisector info, try with 16 */ |
@@ -1317,15 +1214,20 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1317 | total_sectors = identify_info[100] | (identify_info[101] << 16); | 1214 | total_sectors = identify_info[100] | (identify_info[101] << 16); |
1318 | lba48 = true; /* use BigLBA */ | 1215 | lba48 = true; /* use BigLBA */ |
1319 | } | 1216 | } |
1320 | #endif | 1217 | #endif /* HAVE_LBA48 */ |
1218 | |||
1321 | rc = freeze_lock(); | 1219 | rc = freeze_lock(); |
1322 | 1220 | ||
1323 | if (rc) | 1221 | if (rc) { |
1324 | return -50 + rc; | 1222 | rc = -50 + rc; |
1223 | goto error; | ||
1224 | } | ||
1325 | 1225 | ||
1326 | rc = set_features(); | 1226 | rc = set_features(); |
1327 | if (rc) | 1227 | if (rc) { |
1328 | return -60 + rc; | 1228 | rc = -60 + rc; |
1229 | goto error; | ||
1230 | } | ||
1329 | 1231 | ||
1330 | #ifdef MAX_PHYS_SECTOR_SIZE | 1232 | #ifdef MAX_PHYS_SECTOR_SIZE |
1331 | /* Find out the physical sector size */ | 1233 | /* Find out the physical sector size */ |
@@ -1351,44 +1253,20 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1351 | if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE)) | 1253 | if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE)) |
1352 | panicf("Unsupported physical sector size: %d", | 1254 | panicf("Unsupported physical sector size: %d", |
1353 | phys_sector_mult * SECTOR_SIZE); | 1255 | phys_sector_mult * SECTOR_SIZE); |
1354 | #endif | 1256 | #endif /* MAX_PHYS_SECTOR_SIZE */ |
1355 | |||
1356 | mutex_lock(&ata_mtx); /* Balance unlock below */ | ||
1357 | |||
1358 | last_disk_activity = current_tick; | ||
1359 | #ifdef ATA_DRIVER_CLOSE | ||
1360 | ata_thread_id = | ||
1361 | #endif | ||
1362 | create_thread(ata_thread, ata_stack, | ||
1363 | sizeof(ata_stack), 0, ata_thread_name | ||
1364 | IF_PRIO(, PRIORITY_USER_INTERFACE) | ||
1365 | IF_COP(, CPU)); | ||
1366 | initialized = true; | ||
1367 | 1257 | ||
1258 | ata_state = ATA_ON; | ||
1259 | keep_ata_active(); | ||
1368 | } | 1260 | } |
1369 | rc = set_multiple_mode(multisectors); | 1261 | rc = set_multiple_mode(multisectors); |
1370 | if (rc) | 1262 | if (rc) |
1371 | rc = -70 + rc; | 1263 | rc = -70 + rc; |
1372 | 1264 | ||
1265 | error: | ||
1373 | mutex_unlock(&ata_mtx); | 1266 | mutex_unlock(&ata_mtx); |
1374 | return rc; | 1267 | return rc; |
1375 | } | 1268 | } |
1376 | 1269 | ||
1377 | #ifdef ATA_DRIVER_CLOSE | ||
1378 | void ata_close(void) | ||
1379 | { | ||
1380 | unsigned int thread_id = ata_thread_id; | ||
1381 | |||
1382 | if (thread_id == 0) | ||
1383 | return; | ||
1384 | |||
1385 | ata_thread_id = 0; | ||
1386 | |||
1387 | queue_post(&ata_queue, Q_CLOSE, 0); | ||
1388 | thread_wait(thread_id); | ||
1389 | } | ||
1390 | #endif /* ATA_DRIVER_CLOSE */ | ||
1391 | |||
1392 | #if (CONFIG_LED == LED_REAL) | 1270 | #if (CONFIG_LED == LED_REAL) |
1393 | void ata_set_led_enabled(bool enabled) | 1271 | void ata_set_led_enabled(bool enabled) |
1394 | { | 1272 | { |
@@ -1453,9 +1331,7 @@ int ata_get_dma_mode(void) | |||
1453 | 1331 | ||
1454 | /* Needed to allow updating while waiting for DMA to complete */ | 1332 | /* Needed to allow updating while waiting for DMA to complete */ |
1455 | void ata_keep_active(void) | 1333 | void ata_keep_active(void) |
1456 | { | 1334 | __attribute__((alias("ata_spin"))); |
1457 | last_disk_activity = current_tick; | ||
1458 | } | ||
1459 | #endif | 1335 | #endif |
1460 | 1336 | ||
1461 | #ifdef CONFIG_STORAGE_MULTI | 1337 | #ifdef CONFIG_STORAGE_MULTI |
@@ -1467,3 +1343,58 @@ int ata_num_drives(int first_drive) | |||
1467 | return 1; | 1343 | return 1; |
1468 | } | 1344 | } |
1469 | #endif | 1345 | #endif |
1346 | |||
1347 | int ata_event(long id, intptr_t data) | ||
1348 | { | ||
1349 | int rc = 0; | ||
1350 | |||
1351 | /* GCC does a lousy job culling unreachable cases in the default handler | ||
1352 | if statements are in a switch statement, so we'll do it this way. Only | ||
1353 | the first case is frequently hit anyway. */ | ||
1354 | if (LIKELY(id == Q_STORAGE_TICK)) { | ||
1355 | /* won't see ATA_BOOT in here */ | ||
1356 | int state = ata_state; | ||
1357 | if (state != ATA_ON || !ata_sleep_timed_out()) { | ||
1358 | if (state == ATA_SLEEPING && ata_power_off_timed_out()) { | ||
1359 | mutex_lock(&ata_mtx); | ||
1360 | if (ata_state == ATA_SLEEPING) { | ||
1361 | ide_power_enable(false); | ||
1362 | ata_state = ATA_OFF; | ||
1363 | } | ||
1364 | mutex_unlock(&ata_mtx); | ||
1365 | } | ||
1366 | STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); | ||
1367 | } | ||
1368 | } | ||
1369 | else if (id == Q_STORAGE_SLEEPNOW) { | ||
1370 | ata_sleepnow(); | ||
1371 | } | ||
1372 | else if (id == Q_STORAGE_SLEEP) { | ||
1373 | schedule_ata_sleep(HZ/5); | ||
1374 | } | ||
1375 | #ifndef USB_NONE | ||
1376 | else if (id == SYS_USB_CONNECTED) { | ||
1377 | if (ATA_ACTIVE_IN_USB) { | ||
1378 | /* There is no need to force ATA power on */ | ||
1379 | STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); | ||
1380 | } | ||
1381 | else { | ||
1382 | mutex_lock(&ata_mtx); | ||
1383 | if (ata_state < ATA_ON) { | ||
1384 | ata_led(true); | ||
1385 | if (!(rc = ata_perform_wakeup(ata_state))) { | ||
1386 | ata_state = ATA_ON; | ||
1387 | } | ||
1388 | ata_led(false); | ||
1389 | } | ||
1390 | mutex_unlock(&ata_mtx); | ||
1391 | } | ||
1392 | } | ||
1393 | #endif /* ndef USB_NONE */ | ||
1394 | else { | ||
1395 | rc = storage_event_default_handler(id, data, last_disk_activity, | ||
1396 | STORAGE_ATA); | ||
1397 | } | ||
1398 | |||
1399 | return rc; | ||
1400 | } | ||
diff --git a/firmware/drivers/ramdisk.c b/firmware/drivers/ramdisk.c index 44235c4575..9f73b6b5c3 100644 --- a/firmware/drivers/ramdisk.c +++ b/firmware/drivers/ramdisk.c | |||
@@ -159,3 +159,8 @@ bool ramdisk_present(IF_MD(int drive)) | |||
159 | } | 159 | } |
160 | #endif | 160 | #endif |
161 | 161 | ||
162 | int ramdisk_event(long id, intptr_t data) | ||
163 | { | ||
164 | return storage_event_default_handler(id, data, last_disk_activity, | ||
165 | STORAGE_RAMDISK); | ||
166 | } | ||