diff options
-rw-r--r-- | apps/debug_menu.c | 2 | ||||
-rw-r--r-- | firmware/drivers/ata.c | 52 | ||||
-rw-r--r-- | firmware/export/ata.h | 6 | ||||
-rw-r--r-- | firmware/export/storage.h | 2 | ||||
-rw-r--r-- | firmware/storage.c | 2 | ||||
-rw-r--r-- | firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | 103 | ||||
-rw-r--r-- | manual/getting_started/installation.tex | 9 |
7 files changed, 110 insertions, 66 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 57c51e7b54..6f30d00d49 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -1481,6 +1481,8 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
1481 | i = identify_info[83] & (1<<9); | 1481 | i = identify_info[83] & (1<<9); |
1482 | simplelist_addline( | 1482 | simplelist_addline( |
1483 | "Noise mgmt: %s", i ? "enabled" : "unsupported"); | 1483 | "Noise mgmt: %s", i ? "enabled" : "unsupported"); |
1484 | simplelist_addline( | ||
1485 | "Flush cache: %s", identify_info[83] & (1<<13) ? "extended" : identify_info[83] & (1<<12) ? "standard" : identify_info[80] >= (1<<5) ? "ATA-5" : "unsupported"); | ||
1484 | i = identify_info[82] & (1<<6); | 1486 | i = identify_info[82] & (1<<6); |
1485 | simplelist_addline( | 1487 | simplelist_addline( |
1486 | "Read-ahead: %s", i ? "enabled" : "unsupported"); | 1488 | "Read-ahead: %s", i ? "enabled" : "unsupported"); |
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index c995f6de85..8df9acb9da 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -103,6 +103,7 @@ static long sleep_timeout = 5*HZ; | |||
103 | #ifdef HAVE_LBA48 | 103 | #ifdef HAVE_LBA48 |
104 | static bool lba48 = false; /* set for 48 bit addressing */ | 104 | static bool lba48 = false; /* set for 48 bit addressing */ |
105 | #endif | 105 | #endif |
106 | static bool canflush = true; | ||
106 | 107 | ||
107 | static long last_disk_activity = -1; | 108 | static long last_disk_activity = -1; |
108 | #ifdef HAVE_ATA_POWER_OFF | 109 | #ifdef HAVE_ATA_POWER_OFF |
@@ -141,11 +142,6 @@ static inline void keep_ata_active(void) | |||
141 | last_disk_activity = current_tick; | 142 | last_disk_activity = current_tick; |
142 | } | 143 | } |
143 | 144 | ||
144 | static inline void schedule_ata_sleep(long from_now) | ||
145 | { | ||
146 | last_disk_activity = current_tick - sleep_timeout + from_now; | ||
147 | } | ||
148 | |||
149 | static inline bool ata_sleep_timed_out(void) | 145 | static inline bool ata_sleep_timed_out(void) |
150 | { | 146 | { |
151 | return sleep_timeout && | 147 | return sleep_timeout && |
@@ -223,7 +219,7 @@ static int ata_perform_wakeup(int state) | |||
223 | static int ata_perform_sleep(void) | 219 | static int ata_perform_sleep(void) |
224 | { | 220 | { |
225 | /* If device doesn't support PM features, don't try to sleep. */ | 221 | /* If device doesn't support PM features, don't try to sleep. */ |
226 | if (!ata_disk_can_poweroff()) | 222 | if (!ata_disk_can_sleep()) |
227 | return 0; // XXX or return a failure? | 223 | return 0; // XXX or return a failure? |
228 | 224 | ||
229 | logf("ata SLEEP %ld", current_tick); | 225 | logf("ata SLEEP %ld", current_tick); |
@@ -257,13 +253,18 @@ static int ata_perform_flush_cache(void) | |||
257 | { | 253 | { |
258 | uint8_t cmd; | 254 | uint8_t cmd; |
259 | 255 | ||
260 | if (identify_info[83] & (1 << 13)) { | 256 | if (!canflush) { |
261 | cmd = CMD_FLUSH_CACHE_EXT; | 257 | return 0; |
258 | } else if (lba48 && identify_info[83] & (1 << 13)) { | ||
259 | cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices */ | ||
262 | } else if (identify_info[83] & (1 << 12)) { | 260 | } else if (identify_info[83] & (1 << 12)) { |
263 | cmd = CMD_FLUSH_CACHE; | 261 | cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ |
262 | } else if (identify_info[80] >= (1 << 5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ | ||
263 | cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ | ||
264 | } else { | 264 | } else { |
265 | /* If neither (mandatory!) command is supported | 265 | /* If neither (mandatory!) command is supported |
266 | then don't issue it. */ | 266 | then don't issue it. */ |
267 | canflush = 0; | ||
267 | return 0; | 268 | return 0; |
268 | } | 269 | } |
269 | 270 | ||
@@ -286,6 +287,16 @@ static int ata_perform_flush_cache(void) | |||
286 | return 0; | 287 | return 0; |
287 | } | 288 | } |
288 | 289 | ||
290 | int ata_flush(void) | ||
291 | { | ||
292 | if (ata_state >= ATA_SPINUP) { | ||
293 | mutex_lock(&ata_mtx); | ||
294 | ata_perform_flush_cache(); | ||
295 | mutex_unlock(&ata_mtx); | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
289 | static ICODE_ATTR int wait_for_start_of_transfer(void) | 300 | static ICODE_ATTR int wait_for_start_of_transfer(void) |
290 | { | 301 | { |
291 | if (!wait_for_bsy()) | 302 | if (!wait_for_bsy()) |
@@ -844,7 +855,7 @@ void ata_spindown(int seconds) | |||
844 | 855 | ||
845 | bool ata_disk_is_active(void) | 856 | bool ata_disk_is_active(void) |
846 | { | 857 | { |
847 | return ata_disk_can_poweroff() ? (ata_state >= ATA_SPINUP) : 0; | 858 | return (ata_state >= ATA_SPINUP); |
848 | } | 859 | } |
849 | 860 | ||
850 | void ata_sleepnow(void) | 861 | void ata_sleepnow(void) |
@@ -856,8 +867,9 @@ void ata_sleepnow(void) | |||
856 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { | 867 | if (!ata_perform_flush_cache() && !ata_perform_sleep()) { |
857 | ata_state = ATA_SLEEPING; | 868 | ata_state = ATA_SLEEPING; |
858 | #ifdef HAVE_ATA_POWER_OFF | 869 | #ifdef HAVE_ATA_POWER_OFF |
859 | if (ata_disk_can_poweroff()) | 870 | if (ata_disk_can_sleep() || canflush) { |
860 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; | 871 | power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; |
872 | } | ||
861 | #endif | 873 | #endif |
862 | } | 874 | } |
863 | } | 875 | } |
@@ -967,6 +979,9 @@ static int perform_soft_reset(void) | |||
967 | if (set_multiple_mode(multisectors)) | 979 | if (set_multiple_mode(multisectors)) |
968 | return -3; | 980 | return -3; |
969 | 981 | ||
982 | if (identify()) | ||
983 | return -2; | ||
984 | |||
970 | if (freeze_lock()) | 985 | if (freeze_lock()) |
971 | return -4; | 986 | return -4; |
972 | 987 | ||
@@ -1017,6 +1032,9 @@ static int ata_power_on(void) | |||
1017 | if (set_multiple_mode(multisectors)) | 1032 | if (set_multiple_mode(multisectors)) |
1018 | return -3; | 1033 | return -3; |
1019 | 1034 | ||
1035 | if (identify()) | ||
1036 | return -2; | ||
1037 | |||
1020 | if (freeze_lock()) | 1038 | if (freeze_lock()) |
1021 | return -4; | 1039 | return -4; |
1022 | 1040 | ||
@@ -1255,7 +1273,6 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1255 | } | 1273 | } |
1256 | 1274 | ||
1257 | rc = identify(); | 1275 | rc = identify(); |
1258 | |||
1259 | if (rc) { | 1276 | if (rc) { |
1260 | rc = -40 + rc; | 1277 | rc = -40 + rc; |
1261 | goto error; | 1278 | goto error; |
@@ -1280,13 +1297,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1280 | #endif /* HAVE_LBA48 */ | 1297 | #endif /* HAVE_LBA48 */ |
1281 | 1298 | ||
1282 | rc = freeze_lock(); | 1299 | rc = freeze_lock(); |
1283 | |||
1284 | if (rc) { | 1300 | if (rc) { |
1285 | rc = -50 + rc; | 1301 | rc = -50 + rc; |
1286 | goto error; | 1302 | goto error; |
1287 | } | 1303 | } |
1288 | 1304 | ||
1289 | rc = set_features(); // rror codes are between -1 and -49 | 1305 | rc = set_features(); // error codes are between -1 and -49 |
1290 | if (rc) { | 1306 | if (rc) { |
1291 | rc = -60 + rc; | 1307 | rc = -60 + rc; |
1292 | goto error; | 1308 | goto error; |
@@ -1325,6 +1341,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1325 | if (rc) | 1341 | if (rc) |
1326 | rc = -100 + rc; | 1342 | rc = -100 + rc; |
1327 | 1343 | ||
1344 | rc = identify(); | ||
1345 | if (rc) { | ||
1346 | rc = -40 + rc; | ||
1347 | goto error; | ||
1348 | } | ||
1349 | |||
1328 | error: | 1350 | error: |
1329 | mutex_unlock(&ata_mtx); | 1351 | mutex_unlock(&ata_mtx); |
1330 | return rc; | 1352 | return rc; |
@@ -1440,7 +1462,7 @@ int ata_event(long id, intptr_t data) | |||
1440 | ata_sleepnow(); | 1462 | ata_sleepnow(); |
1441 | } | 1463 | } |
1442 | else if (id == Q_STORAGE_SLEEP) { | 1464 | else if (id == Q_STORAGE_SLEEP) { |
1443 | schedule_ata_sleep(HZ/5); | 1465 | last_disk_activity = current_tick - sleep_timeout + HZ / 5; |
1444 | } | 1466 | } |
1445 | #ifndef USB_NONE | 1467 | #ifndef USB_NONE |
1446 | else if (id == SYS_USB_CONNECTED) { | 1468 | else if (id == SYS_USB_CONNECTED) { |
diff --git a/firmware/export/ata.h b/firmware/export/ata.h index 0d84a91524..dfa73eebf5 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h | |||
@@ -208,8 +208,8 @@ static inline int ata_disk_isssd(void) | |||
208 | ); | 208 | ); |
209 | } | 209 | } |
210 | 210 | ||
211 | /* Returns 1 if the drive can be powered off safely */ | 211 | /* Returns 1 if the drive supports power management commands */ |
212 | static inline int ata_disk_can_poweroff(void) | 212 | static inline int ata_disk_can_sleep(void) |
213 | { | 213 | { |
214 | unsigned short *identify_info = ata_get_identify(); | 214 | unsigned short *identify_info = ata_get_identify(); |
215 | /* Only devices that claim to support PM can be safely powered off. | 215 | /* Only devices that claim to support PM can be safely powered off. |
@@ -217,6 +217,8 @@ static inline int ata_disk_can_poweroff(void) | |||
217 | return (identify_info[82] & (1<<3) && identify_info[85] & (1<<3)); | 217 | return (identify_info[82] & (1<<3) && identify_info[85] & (1<<3)); |
218 | } | 218 | } |
219 | 219 | ||
220 | int ata_flush(void); | ||
221 | |||
220 | #ifdef HAVE_ATA_DMA | 222 | #ifdef HAVE_ATA_DMA |
221 | /* Returns current DMA mode */ | 223 | /* Returns current DMA mode */ |
222 | int ata_get_dma_mode(void); | 224 | int ata_get_dma_mode(void); |
diff --git a/firmware/export/storage.h b/firmware/export/storage.h index e2ae4056be..f97cbf34d5 100644 --- a/firmware/export/storage.h +++ b/firmware/export/storage.h | |||
@@ -174,7 +174,7 @@ static inline void storage_sleep(void) {}; | |||
174 | #define storage_disk_is_active() ata_disk_is_active() | 174 | #define storage_disk_is_active() ata_disk_is_active() |
175 | #define storage_soft_reset() ata_soft_reset() | 175 | #define storage_soft_reset() ata_soft_reset() |
176 | #ifdef HAVE_STORAGE_FLUSH | 176 | #ifdef HAVE_STORAGE_FLUSH |
177 | #define storage_flush() (void)0 | 177 | #define storage_flush() ata_flush() |
178 | #endif | 178 | #endif |
179 | #define storage_last_disk_activity() ata_last_disk_activity() | 179 | #define storage_last_disk_activity() ata_last_disk_activity() |
180 | #define storage_spinup_time() ata_spinup_time() | 180 | #define storage_spinup_time() ata_spinup_time() |
diff --git a/firmware/storage.c b/firmware/storage.c index da3e06146d..2d4490369e 100644 --- a/firmware/storage.c +++ b/firmware/storage.c | |||
@@ -555,7 +555,7 @@ int storage_flush(void) | |||
555 | int rc=0; | 555 | int rc=0; |
556 | 556 | ||
557 | #if (CONFIG_STORAGE & STORAGE_ATA) | 557 | #if (CONFIG_STORAGE & STORAGE_ATA) |
558 | //if ((rc=ata_flush())) return rc; | 558 | if ((rc=ata_flush())) return rc; |
559 | #endif | 559 | #endif |
560 | 560 | ||
561 | #if (CONFIG_STORAGE & STORAGE_MMC) | 561 | #if (CONFIG_STORAGE & STORAGE_MMC) |
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c index 87450aca73..21c6f3f7c0 100644 --- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c +++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-6g.c | |||
@@ -83,6 +83,7 @@ static uint32_t ata_dma_flags; | |||
83 | static long ata_last_activity_value = -1; | 83 | static long ata_last_activity_value = -1; |
84 | static long ata_sleep_timeout = 7 * HZ; | 84 | static long ata_sleep_timeout = 7 * HZ; |
85 | static bool ata_powered; | 85 | static bool ata_powered; |
86 | static bool canflush = true; | ||
86 | static struct semaphore mmc_wakeup; | 87 | static struct semaphore mmc_wakeup; |
87 | static struct semaphore mmc_comp_wakeup; | 88 | static struct semaphore mmc_comp_wakeup; |
88 | static int spinup_time = 0; | 89 | static int spinup_time = 0; |
@@ -578,7 +579,7 @@ static void ata_set_active(void) | |||
578 | 579 | ||
579 | bool ata_disk_is_active(void) | 580 | bool ata_disk_is_active(void) |
580 | { | 581 | { |
581 | return ata_disk_can_poweroff() ? ata_powered : 0; | 582 | return ata_powered; |
582 | } | 583 | } |
583 | 584 | ||
584 | static int ata_set_feature(uint32_t feature, uint32_t param) | 585 | static int ata_set_feature(uint32_t feature, uint32_t param) |
@@ -745,6 +746,8 @@ static int ata_power_up(void) | |||
745 | ata_dma = param ? true : false; | 746 | ata_dma = param ? true : false; |
746 | dma_mode = param; | 747 | dma_mode = param; |
747 | PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ | 748 | PASS_RC(ata_set_feature(0x03, param), 3, 4); /* Transfer mode */ |
749 | |||
750 | /* SET_FEATURE only supported on PATA, not CE-ATA */ | ||
748 | if (ata_identify_data[82] & BIT(5)) | 751 | if (ata_identify_data[82] & BIT(5)) |
749 | PASS_RC(ata_set_feature(0x02, 0), 3, 5); /* Enable volatile write cache */ | 752 | PASS_RC(ata_set_feature(0x02, 0), 3, 5); /* Enable volatile write cache */ |
750 | if (ata_identify_data[82] & BIT(6)) | 753 | if (ata_identify_data[82] & BIT(6)) |
@@ -753,7 +756,10 @@ static int ata_power_up(void) | |||
753 | PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ | 756 | PASS_RC(ata_set_feature(0x05, 0x80), 3, 7); /* Enable lowest power mode w/o standby */ |
754 | if (ata_identify_data[83] & BIT(9)) | 757 | if (ata_identify_data[83] & BIT(9)) |
755 | PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ | 758 | PASS_RC(ata_set_feature(0x42, 0x80), 3, 8); /* Enable lowest noise mode */ |
759 | |||
760 | PASS_RC(ata_identify(ata_identify_data), 3, 9); /* Finally, re-read identify info */ | ||
756 | } | 761 | } |
762 | |||
757 | spinup_time = current_tick - spinup_start; | 763 | spinup_time = current_tick - spinup_start; |
758 | 764 | ||
759 | ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60]; | 765 | ata_total_sectors = (ata_identify_data[61] << 16) | ata_identify_data[60]; |
@@ -778,28 +784,6 @@ static void ata_power_down(void) | |||
778 | { | 784 | { |
779 | if (!ata_powered) | 785 | if (!ata_powered) |
780 | return; | 786 | return; |
781 | if (ceata) | ||
782 | { | ||
783 | memset(ceata_taskfile, 0, 16); | ||
784 | ceata_taskfile[0xf] = CMD_STANDBY_IMMEDIATE; | ||
785 | ceata_wait_idle(); | ||
786 | ceata_write_multiple_register(0, ceata_taskfile, 16); | ||
787 | ceata_wait_idle(); | ||
788 | sleep(HZ); | ||
789 | PWRCON(0) |= (1 << 9); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | ata_wait_for_rdy(1000000); | ||
794 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
795 | ata_write_cbr(&ATA_PIO_CSD, CMD_STANDBY_IMMEDIATE); | ||
796 | ata_wait_for_rdy(1000000); | ||
797 | sleep(HZ / 30); | ||
798 | ATA_CONTROL = 0; | ||
799 | while (!(ATA_CONTROL & BIT(1))) | ||
800 | yield(); | ||
801 | PWRCON(0) |= (1 << 5); | ||
802 | } | ||
803 | PCON(7) = 0; | 787 | PCON(7) = 0; |
804 | PCON(8) = 0; | 788 | PCON(8) = 0; |
805 | PCON(9) = 0; | 789 | PCON(9) = 0; |
@@ -1080,26 +1064,27 @@ static void ata_flush_cache(void) | |||
1080 | { | 1064 | { |
1081 | uint8_t cmd; | 1065 | uint8_t cmd; |
1082 | 1066 | ||
1083 | if (ata_identify_data[83] & BIT(13)) { | 1067 | if (ceata) { |
1084 | cmd = CMD_FLUSH_CACHE_EXT; | ||
1085 | } else if (ata_identify_data[83] & BIT(12)) { | ||
1086 | cmd = CMD_FLUSH_CACHE; | ||
1087 | } else { | ||
1088 | /* If neither (mandatory!) command is supported | ||
1089 | then don't issue it. */ | ||
1090 | return; | ||
1091 | } | ||
1092 | |||
1093 | if (ceata) | ||
1094 | { | ||
1095 | memset(ceata_taskfile, 0, 16); | 1068 | memset(ceata_taskfile, 0, 16); |
1096 | ceata_taskfile[0xf] = cmd; | 1069 | ceata_taskfile[0xf] = CMD_FLUSH_CACHE_EXT; /* CE-ATA only supports EXT */ |
1097 | ceata_wait_idle(); | 1070 | ceata_wait_idle(); |
1098 | ceata_write_multiple_register(0, ceata_taskfile, 16); | 1071 | ceata_write_multiple_register(0, ceata_taskfile, 16); |
1099 | ceata_wait_idle(); | 1072 | ceata_wait_idle(); |
1100 | } | 1073 | } else { |
1101 | else | 1074 | if (!canflush) { |
1102 | { | 1075 | return; |
1076 | } else if (ata_lba48 && ata_identify_data[83] & BIT(13)) { | ||
1077 | cmd = CMD_FLUSH_CACHE_EXT; /* Flag, optional, ATA-6 and up, for use with LBA48 devices. Mandatory for CE-ATA */ | ||
1078 | } else if (ata_identify_data[83] & BIT(12)) { | ||
1079 | cmd = CMD_FLUSH_CACHE; /* Flag, mandatory, ATA-6 and up */ | ||
1080 | } else if (ata_identify_data[80] >= BIT(5)) { /* Use >= instead of '&' because bits lower than the latest standard we support don't have to be set */ | ||
1081 | cmd = CMD_FLUSH_CACHE; /* No flag, mandatory, ATA-5 (Optional for ATA-4) */ | ||
1082 | } else { | ||
1083 | /* If neither command is supported then don't issue it. */ | ||
1084 | canflush = 0; | ||
1085 | return; | ||
1086 | } | ||
1087 | |||
1103 | ata_wait_for_rdy(1000000); | 1088 | ata_wait_for_rdy(1000000); |
1104 | ata_write_cbr(&ATA_PIO_DVR, 0); | 1089 | ata_write_cbr(&ATA_PIO_DVR, 0); |
1105 | ata_write_cbr(&ATA_PIO_CSD, cmd); | 1090 | ata_write_cbr(&ATA_PIO_CSD, cmd); |
@@ -1107,14 +1092,46 @@ static void ata_flush_cache(void) | |||
1107 | } | 1092 | } |
1108 | } | 1093 | } |
1109 | 1094 | ||
1095 | int ata_flush(void) | ||
1096 | { | ||
1097 | if (ata_powered) { | ||
1098 | mutex_lock(&ata_mutex); | ||
1099 | ata_flush_cache(); | ||
1100 | mutex_unlock(&ata_mutex); | ||
1101 | } | ||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1110 | void ata_sleepnow(void) | 1105 | void ata_sleepnow(void) |
1111 | { | 1106 | { |
1112 | mutex_lock(&ata_mutex); | 1107 | mutex_lock(&ata_mutex); |
1113 | 1108 | ||
1114 | if (ata_disk_can_poweroff()) | 1109 | ata_flush_cache(); |
1115 | ata_power_down(); | 1110 | |
1116 | else | 1111 | if (ata_disk_can_sleep()) { |
1117 | ata_flush_cache(); | 1112 | if (ceata) { |
1113 | memset(ceata_taskfile, 0, 16); | ||
1114 | ceata_taskfile[0xf] = CMD_STANDBY_IMMEDIATE; | ||
1115 | ceata_wait_idle(); | ||
1116 | ceata_write_multiple_register(0, ceata_taskfile, 16); | ||
1117 | ceata_wait_idle(); | ||
1118 | sleep(HZ); | ||
1119 | PWRCON(0) |= (1 << 9); | ||
1120 | } else { | ||
1121 | ata_wait_for_rdy(1000000); | ||
1122 | ata_write_cbr(&ATA_PIO_DVR, 0); | ||
1123 | ata_write_cbr(&ATA_PIO_CSD, CMD_STANDBY_IMMEDIATE); | ||
1124 | ata_wait_for_rdy(1000000); | ||
1125 | sleep(HZ / 30); | ||
1126 | ATA_CONTROL = 0; | ||
1127 | while (!(ATA_CONTROL & BIT(1))) | ||
1128 | yield(); | ||
1129 | PWRCON(0) |= (1 << 5); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | if (ata_disk_can_sleep() || canflush) | ||
1134 | ata_power_down(); // XXX add a powerdown delay similar to main ATA driver? | ||
1118 | 1135 | ||
1119 | mutex_unlock(&ata_mutex); | 1136 | mutex_unlock(&ata_mutex); |
1120 | } | 1137 | } |
diff --git a/manual/getting_started/installation.tex b/manual/getting_started/installation.tex index 1b09ce1f22..b42fcc47e6 100644 --- a/manual/getting_started/installation.tex +++ b/manual/getting_started/installation.tex | |||
@@ -305,14 +305,15 @@ For example, the stock Apple firmware on earlier 6th generation iPod Classic mod | |||
305 | robust, but tend to be expensive and not available in larger sizes. | 305 | robust, but tend to be expensive and not available in larger sizes. |
306 | \item[SATA.] These are fast, reliable, and available in high capacities, but are typically optimized for high performance | 306 | \item[SATA.] These are fast, reliable, and available in high capacities, but are typically optimized for high performance |
307 | at the expense of power consumption.. However, as they implement the full ATA command set, we are able | 307 | at the expense of power consumption.. However, as they implement the full ATA command set, we are able |
308 | to aggressively power them down when not being actively used. | 308 | to minimize their power consumption and power them down when not being actively used. |
309 | \item[Single Secure Digital (SD).] While these adapters come in different form factors from multiple vendors, | 309 | \item[Single Secure Digital (SD).] While these adapters come in different form factors from multiple vendors, |
310 | they are all based on the same basic design. The ATA command set is incompletely emulated, notably lacking | 310 | they are all based on the same basic design. The ATA command set is incompletely emulated, notably lacking |
311 | support for the \emph{mandatory} ATA power management commands that Rockbox uses to flush caches and safely | 311 | support for \emph{mandatory} ATA power management commands that Rockbox uses to safely |
312 | transition the device in and out of low power states. Additionally, SD cards vary widely in quality | 312 | transition the device in and out of low power states. Additionally, SD cards vary widely in quality |
313 | and power consumption with the resultant effects on data longevity and battery life. Finally, these SD adapters do not support 2TiB or larger SDUC cards. | 313 | and power consumption with the resultant effects on data longevity and battery life. Finally, these SD adapters |
314 | do not support 2TiB or larger SDUC cards. | ||
314 | \item[Dual/Quad SD.] These are similar to the above, only allowing use of mulitiple SD cards to | 315 | \item[Dual/Quad SD.] These are similar to the above, only allowing use of mulitiple SD cards to |
315 | increase the overall storage capacity. While typically described as JBOD\footnote{Just a Bunch Of Disks}, this is not accurate as each card is not individually accessable. Instead, the adapter claims to be to be a single logical drive of the combined capacity of the individual cards in a RAID0-like manner. Consquently, if any one card fails, all data on all other cards is most likely permenantly lost. Given the quality and power management concerns mentioned earlier, this means use of multiple SD cards in one of these adapters is the least reliable/robust and the most power hungry of the various SSD mods. Finally, in another violation of the ATA specification, these ATA-SD adapters fail to properly support LBA48 addressing, meaning that no matter which combination of cards is used, they simply will not work if their combined capacity exceeds 2TiB. | 316 | increase the overall storage capacity. While typically described as JBOD\footnote{Just a Bunch Of Disks}, this is not accurate as each card is not individually accessable. Instead, the adapter claims to be to be a single logical drive of the combined capacity of the individual cards in a RAID0-like manner. Consquently, if any one card fails, all data on all other cards may be rendered inacessible. Given the quality concerns mentioned earlier, this means use of multiple SD cards in one of these adapters is the least reliable/robust of the various SSD mods. Finally, in another violation of the ATA specification, these ATA-SD adapters fail to properly support LBA48 addressing, meaning that no matter what combination of cards is used, if their combined capacity exceeds 2TiB, the extra capacity will not be usable, and the device may even present as having (considerably) less space. |
316 | \end{description} | 317 | \end{description} |
317 | 318 | ||
318 | \note{All of these flash/SSD mods take up less physical space in the device enclosure than the original hard drive, so care must be taken to ensure they are securely mounted and resistant to the vibration and impacts that typically occur in portable devices. Ribbon cables are particularly vulnerable.} | 319 | \note{All of these flash/SSD mods take up less physical space in the device enclosure than the original hard drive, so care must be taken to ensure they are securely mounted and resistant to the vibration and impacts that typically occur in portable devices. Ribbon cables are particularly vulnerable.} |