diff options
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r-- | firmware/drivers/ata.c | 81 |
1 files changed, 65 insertions, 16 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 8c591253f9..f5b8810d28 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -47,7 +47,9 @@ | |||
47 | 47 | ||
48 | #define CMD_READ_SECTORS 0x20 | 48 | #define CMD_READ_SECTORS 0x20 |
49 | #define CMD_WRITE_SECTORS 0x30 | 49 | #define CMD_WRITE_SECTORS 0x30 |
50 | #define CMD_WRITE_SECTORS_EXT 0x34 | ||
50 | #define CMD_READ_MULTIPLE 0xC4 | 51 | #define CMD_READ_MULTIPLE 0xC4 |
52 | #define CMD_READ_MULTIPLE_EXT 0x29 | ||
51 | #define CMD_WRITE_MULTIPLE 0xC5 | 53 | #define CMD_WRITE_MULTIPLE 0xC5 |
52 | #define CMD_SET_MULTIPLE_MODE 0xC6 | 54 | #define CMD_SET_MULTIPLE_MODE 0xC6 |
53 | #define CMD_STANDBY_IMMEDIATE 0xE0 | 55 | #define CMD_STANDBY_IMMEDIATE 0xE0 |
@@ -76,6 +78,9 @@ static long sleep_timeout = 5*HZ; | |||
76 | #ifdef HAVE_ATA_POWER_OFF | 78 | #ifdef HAVE_ATA_POWER_OFF |
77 | static int poweroff_timeout = 2*HZ; | 79 | static int poweroff_timeout = 2*HZ; |
78 | #endif | 80 | #endif |
81 | #ifdef HAVE_BIGLBA | ||
82 | static bool biglba = false; /* set for 48 bit addressing */ | ||
83 | #endif | ||
79 | static long ata_stack[DEFAULT_STACK_SIZE/sizeof(long)]; | 84 | static long ata_stack[DEFAULT_STACK_SIZE/sizeof(long)]; |
80 | static const char ata_thread_name[] = "ata"; | 85 | static const char ata_thread_name[] = "ata"; |
81 | static struct event_queue ata_queue; | 86 | static struct event_queue ata_queue; |
@@ -252,16 +257,34 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
252 | ret = 0; | 257 | ret = 0; |
253 | last_disk_activity = current_tick; | 258 | last_disk_activity = current_tick; |
254 | 259 | ||
255 | if ( count == 256 ) | 260 | #ifdef HAVE_BIGLBA |
256 | SET_REG(ATA_NSECTOR, 0); /* 0 means 256 sectors */ | 261 | if (biglba) |
262 | { | ||
263 | SET_REG(ATA_NSECTOR, count >> 8); | ||
264 | SET_REG(ATA_NSECTOR, count & 0xff); | ||
265 | SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */ | ||
266 | SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */ | ||
267 | SET_REG(ATA_LCYL, 0); /* 39:32 */ | ||
268 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */ | ||
269 | SET_REG(ATA_HCYL, 0); /* 47:40 */ | ||
270 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | ||
271 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | ||
272 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT); | ||
273 | } | ||
257 | else | 274 | else |
258 | SET_REG(ATA_NSECTOR, (unsigned char)count); | 275 | #endif |
276 | { | ||
277 | if ( count == 256 ) | ||
278 | SET_REG(ATA_NSECTOR, 0); /* 0 means 256 sectors */ | ||
279 | else | ||
280 | SET_REG(ATA_NSECTOR, (unsigned char)count); | ||
259 | 281 | ||
260 | SET_REG(ATA_SECTOR, start & 0xff); | 282 | SET_REG(ATA_SECTOR, start & 0xff); |
261 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | 283 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); |
262 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | 284 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); |
263 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | 285 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); |
264 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); | 286 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); |
287 | } | ||
265 | 288 | ||
266 | /* wait at least 400ns between writing command and reading status */ | 289 | /* wait at least 400ns between writing command and reading status */ |
267 | __asm__ volatile ("nop"); | 290 | __asm__ volatile ("nop"); |
@@ -429,15 +452,33 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
429 | return -2; | 452 | return -2; |
430 | } | 453 | } |
431 | 454 | ||
432 | if ( count == 256 ) | 455 | #ifdef HAVE_BIGLBA |
433 | SET_REG(ATA_NSECTOR, 0); /* 0 means 256 sectors */ | 456 | if (biglba) |
457 | { | ||
458 | SET_REG(ATA_NSECTOR, count >> 8); | ||
459 | SET_REG(ATA_NSECTOR, count & 0xff); | ||
460 | SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */ | ||
461 | SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */ | ||
462 | SET_REG(ATA_LCYL, 0); /* 39:32 */ | ||
463 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */ | ||
464 | SET_REG(ATA_HCYL, 0); /* 47:40 */ | ||
465 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | ||
466 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | ||
467 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT); | ||
468 | } | ||
434 | else | 469 | else |
435 | SET_REG(ATA_NSECTOR, (unsigned char)count); | 470 | #endif |
436 | SET_REG(ATA_SECTOR, start & 0xff); | 471 | { |
437 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | 472 | if ( count == 256 ) |
438 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | 473 | SET_REG(ATA_NSECTOR, 0); /* 0 means 256 sectors */ |
439 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | 474 | else |
440 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS); | 475 | SET_REG(ATA_NSECTOR, (unsigned char)count); |
476 | SET_REG(ATA_SECTOR, start & 0xff); | ||
477 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | ||
478 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | ||
479 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | ||
480 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS); | ||
481 | } | ||
441 | 482 | ||
442 | for (i=0; i<count; i++) { | 483 | for (i=0; i<count; i++) { |
443 | 484 | ||
@@ -944,6 +985,14 @@ int ata_init(void) | |||
944 | multisectors = identify_info[47] & 0xff; | 985 | multisectors = identify_info[47] & 0xff; |
945 | DEBUGF("ata: %d sectors per ata request\n",multisectors); | 986 | DEBUGF("ata: %d sectors per ata request\n",multisectors); |
946 | 987 | ||
988 | #ifdef HAVE_BIGLBA | ||
989 | if (identify_info[83] & 0x0400 /* 48 bit address support */ | ||
990 | && identify_info[60] == 0xFFFF /* and disk size >= 128 GiB */ | ||
991 | && identify_info[61] == 0x0FFF) /* (needs BigLBA addressing) */ | ||
992 | { | ||
993 | biglba = true; /* use BigLBA */ | ||
994 | } | ||
995 | #endif | ||
947 | rc = freeze_lock(); | 996 | rc = freeze_lock(); |
948 | 997 | ||
949 | if (rc) | 998 | if (rc) |