summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/ata.c493
-rw-r--r--firmware/drivers/ramdisk.c5
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
78static 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
74enum {
75 ATA_BOOT = -1,
76 ATA_OFF,
77 ATA_SLEEPING,
78 ATA_SPINUP,
79 ATA_ON,
80};
81
82static int ata_state = ATA_BOOT;
83
85static struct mutex ata_mtx SHAREDBSS_ATTR; 84static struct mutex ata_mtx SHAREDBSS_ATTR;
86static int ata_device; /* device 0 (master) or 1 (slave) */ 85static int ata_device; /* device 0 (master) or 1 (slave) */
87 86
@@ -90,22 +89,16 @@ static int spinup_time = 0;
90static bool ata_led_enabled = true; 89static bool ata_led_enabled = true;
91static bool ata_led_on = false; 90static bool ata_led_on = false;
92#endif 91#endif
93static bool spinup = false; 92
94static bool sleeping = true;
95#ifdef HAVE_ATA_POWER_OFF
96static bool poweroff = false;
97#endif
98static long sleep_timeout = 5*HZ; 93static long sleep_timeout = 5*HZ;
99#ifdef HAVE_LBA48 94#ifdef HAVE_LBA48
100static bool lba48 = false; /* set for 48 bit addressing */ 95static bool lba48 = false; /* set for 48 bit addressing */
101#endif 96#endif
102static long ata_stack[(DEFAULT_STACK_SIZE*3)/sizeof(long)];
103static const char ata_thread_name[] = "ata";
104static struct event_queue ata_queue SHAREDBSS_ATTR;
105static bool initialized = false;
106 97
107static long last_user_activity = -1;
108static long last_disk_activity = -1; 98static long last_disk_activity = -1;
99#ifdef HAVE_ATA_POWER_OFF
100static long power_off_tick;
101#endif
109 102
110static unsigned long total_sectors; 103static unsigned long total_sectors;
111static int multisectors; /* number of supported multisectors */ 104static int multisectors; /* number of supported multisectors */
@@ -135,6 +128,38 @@ static int perform_soft_reset(void);
135static int set_multiple_mode(int sectors); 128static int set_multiple_mode(int sectors);
136static int set_features(void); 129static int set_features(void);
137 130
131static inline void keep_ata_active(void)
132{
133 last_disk_activity = current_tick;
134}
135
136static inline void schedule_ata_sleep(long from_now)
137{
138 last_disk_activity = current_tick - sleep_timeout + from_now;
139}
140
141static inline bool ata_sleep_timed_out(void)
142{
143 return sleep_timeout &&
144 TIME_AFTER(current_tick, last_disk_activity + sleep_timeout);
145}
146
147static 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
154static 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
139static ICODE_ATTR int wait_for_bsy(void) 164static 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
203static 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
221static 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
178static ICODE_ATTR int wait_for_start_of_transfer(void) 241static 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
515int ata_write_sectors(IF_MD(int drive,) 560int 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
529static int cache_sector(unsigned long sector) 577static int cache_sector(unsigned long sector)
@@ -748,178 +796,26 @@ void ata_spindown(int seconds)
748 796
749bool ata_disk_is_active(void) 797bool ata_disk_is_active(void)
750{ 798{
751 return !sleeping; 799 return ata_state >= ATA_SPINUP;
752}
753
754static 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
781void ata_sleep(void)
782{
783 queue_post(&ata_queue, Q_SLEEP, 0);
784} 800}
785 801
786void ata_sleepnow(void) 802void 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
797void ata_spin(void) 816void ata_spin(void)
798{ 817{
799 last_user_activity = current_tick; 818 keep_ata_active();
800}
801
802static 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
1026int ata_soft_reset(void) 922int 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
1073static int STORAGE_INIT_ATTR master_slave_detect(void) 971static 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(&sector_cache, 0, sizeof(sector_cache)); 1163 memset(&sector_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
1265error:
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
1378void 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)
1393void ata_set_led_enabled(bool enabled) 1271void 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 */
1455void ata_keep_active(void) 1333void 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
1347int 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
162int ramdisk_event(long id, intptr_t data)
163{
164 return storage_event_default_handler(id, data, last_disk_activity,
165 STORAGE_RAMDISK);
166}