| Index: emcore/trunk/target/ipodclassic/usbtarget.c |
| — | — | @@ -69,6 +69,20 @@ |
| 70 | 70 | size = 16;
|
| 71 | 71 | break;
|
| 72 | 72 | }
|
| | 73 | + case 0xffff0003: // ATA_BBT_RELOAD
|
| | 74 | + {
|
| | 75 | + ata_bbt_reload();
|
| | 76 | + buffer[0] = 1;
|
| | 77 | + size = 16;
|
| | 78 | + break;
|
| | 79 | + }
|
| | 80 | + case 0xffff0004: // ATA_BBT_DISABLE
|
| | 81 | + {
|
| | 82 | + ata_bbt_disable();
|
| | 83 | + buffer[0] = 1;
|
| | 84 | + size = 16;
|
| | 85 | + break;
|
| | 86 | + }
|
| 73 | 87 | default:
|
| 74 | 88 | buffer[0] = 2;
|
| 75 | 89 | size = 16;
|
| Index: emcore/trunk/target/ipodclassic/storage_ata-target.h |
| — | — | @@ -24,9 +24,18 @@ |
| 25 | 25 | #ifndef __STORAGE_ATA_TARGET_H__
|
| 26 | 26 | #define __STORAGE_ATA_TARGET_H__
|
| 27 | 27 |
|
| 28 | | -#include "global.h"
|
| | 28 | +#include "../global.h"
|
| 29 | 29 |
|
| 30 | 30 |
|
| | 31 | +struct ata_target_driverinfo
|
| | 32 | +{
|
| | 33 | + int (*soft_reset)();
|
| | 34 | + int (*bbt_translate)(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t* physcount);
|
| | 35 | + void (*bbt_reload)();
|
| | 36 | + void (*bbt_disable)();
|
| | 37 | +};
|
| | 38 | +
|
| | 39 | +
|
| 31 | 40 | extern uint16_t ata_identify_data[0x100];
|
| 32 | 41 | extern uint64_t ata_total_sectors;
|
| 33 | 42 | extern struct mutex ata_mutex;
|
| — | — | @@ -35,6 +44,9 @@ |
| 36 | 45 | extern uint16_t (*ata_bbt)[0x20];
|
| 37 | 46 | extern uint64_t ata_virtual_sectors;
|
| 38 | 47 |
|
| | 48 | +int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t* physcount);
|
| | 49 | +void ata_bbt_reload();
|
| | 50 | +void ata_bbt_disable();
|
| 39 | 51 | int ata_rw_sectors_internal(uint64_t sector, uint32_t count, void* buffer, bool write);
|
| 40 | 52 | #endif
|
| 41 | 53 |
|
| Index: emcore/trunk/target/ipodclassic/storage_ata.c |
| — | — | @@ -26,6 +26,12 @@ |
| 27 | 27 | #include "timer.h"
|
| 28 | 28 | #include "../ipodnano3g/s5l8702.h"
|
| 29 | 29 |
|
| | 30 | +
|
| | 31 | +#ifndef ATA_RETRIES
|
| | 32 | +#define ATA_RETRIES 3
|
| | 33 | +#endif
|
| | 34 | +
|
| | 35 | +
|
| 30 | 36 | /** static, private data **/
|
| 31 | 37 | uint16_t ata_identify_data[0x100];
|
| 32 | 38 | bool ata_lba48;
|
| — | — | @@ -56,7 +62,17 @@ |
| 57 | 63 | }
|
| 58 | 64 | #endif
|
| 59 | 65 |
|
| | 66 | +static struct ata_target_driverinfo drvinfo =
|
| | 67 | +{
|
| | 68 | + .soft_reset = ata_soft_reset,
|
| | 69 | +#ifdef ATA_HAVE_BBT
|
| | 70 | + .bbt_translate = ata_bbt_translate,
|
| | 71 | + .bbt_reload = ata_bbt_reload,
|
| | 72 | + .bbt_disable = ata_bbt_disable
|
| | 73 | +#endif
|
| | 74 | +};
|
| 60 | 75 |
|
| | 76 | +
|
| 61 | 77 | static uint16_t ata_read_cbr(uint32_t volatile* reg)
|
| 62 | 78 | {
|
| 63 | 79 | while (!(ATA_PIO_READY & 2)) yield();
|
| — | — | @@ -333,6 +349,59 @@ |
| 334 | 350 | return 0;
|
| 335 | 351 | }
|
| 336 | 352 |
|
| | 353 | +#ifdef ATA_HAVE_BBT
|
| | 354 | +int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t* physcount)
|
| | 355 | +{
|
| | 356 | + if (sector + count > ata_virtual_sectors) RET_ERR(0);
|
| | 357 | + if (!ata_bbt)
|
| | 358 | + {
|
| | 359 | + *phys = sector;
|
| | 360 | + *physcount = count;
|
| | 361 | + return 0;
|
| | 362 | + }
|
| | 363 | + if (!count)
|
| | 364 | + {
|
| | 365 | + *phys = 0;
|
| | 366 | + *physcount = 0;
|
| | 367 | + return 0;
|
| | 368 | + }
|
| | 369 | + uint32_t offset;
|
| | 370 | + uint32_t l0idx = sector >> 15;
|
| | 371 | + uint32_t l0offs = sector & 0x7fff;
|
| | 372 | + *physcount = MIN(count, 0x8000 - l0offs);
|
| | 373 | + uint32_t l0data = ata_bbt[0][l0idx << 1];
|
| | 374 | + uint32_t base = ata_bbt[0][(l0idx << 1) | 1] << 12;
|
| | 375 | + if (l0data < 0x8000) offset = l0data + base;
|
| | 376 | + else
|
| | 377 | + {
|
| | 378 | + uint32_t l1idx = (sector >> 10) & 0x1f;
|
| | 379 | + uint32_t l1offs = sector & 0x3ff;
|
| | 380 | + *physcount = MIN(count, 0x400 - l1offs);
|
| | 381 | + uint32_t l1data = ata_bbt[l0data & 0x7fff][l1idx];
|
| | 382 | + if (l1data < 0x8000) offset = l1data + base;
|
| | 383 | + else
|
| | 384 | + {
|
| | 385 | + uint32_t l2idx = (sector >> 5) & 0x1f;
|
| | 386 | + uint32_t l2offs = sector & 0x1f;
|
| | 387 | + *physcount = MIN(count, 0x20 - l2offs);
|
| | 388 | + uint32_t l2data = ata_bbt[l1data & 0x7fff][l2idx];
|
| | 389 | + if (l2data < 0x8000) offset = l2data + base;
|
| | 390 | + else
|
| | 391 | + {
|
| | 392 | + uint32_t l3idx = sector & 0x1f;
|
| | 393 | + uint32_t l3data = ata_bbt[l2data & 0x7fff][l3idx];
|
| | 394 | + for (*physcount = 1; *physcount < count && l3idx + *physcount < 0x20; *physcount++)
|
| | 395 | + if (ata_bbt[l2data & 0x7fff][l3idx + *physcount] != l3data)
|
| | 396 | + break;
|
| | 397 | + offset = l3data + base;
|
| | 398 | + }
|
| | 399 | + }
|
| | 400 | + }
|
| | 401 | + *phys = sector + offset;
|
| | 402 | + return 0;
|
| | 403 | +}
|
| | 404 | +#endif
|
| | 405 | +
|
| 337 | 406 | int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
|
| 338 | 407 | {
|
| 339 | 408 | #ifdef ATA_HAVE_BBT
|
| — | — | @@ -340,39 +409,10 @@ |
| 341 | 410 | if (ata_bbt)
|
| 342 | 411 | while (count)
|
| 343 | 412 | {
|
| 344 | | - uint32_t offset;
|
| 345 | | - uint32_t l0idx = sector >> 15;
|
| 346 | | - uint32_t l0offs = sector & 0x7fff;
|
| 347 | | - uint32_t cnt = MIN(count, 0x8000 - l0offs);
|
| 348 | | - uint32_t l0data = ata_bbt[0][l0idx << 1];
|
| 349 | | - uint32_t base = ata_bbt[0][(l0idx << 1) | 1] << 12;
|
| 350 | | - if (l0data < 0x8000) offset = l0data + base;
|
| 351 | | - else
|
| 352 | | - {
|
| 353 | | - uint32_t l1idx = (sector >> 10) & 0x1f;
|
| 354 | | - uint32_t l1offs = sector & 0x3ff;
|
| 355 | | - cnt = MIN(count, 0x400 - l1offs);
|
| 356 | | - uint32_t l1data = ata_bbt[l0data & 0x7fff][l1idx];
|
| 357 | | - if (l1data < 0x8000) offset = l1data + base;
|
| 358 | | - else
|
| 359 | | - {
|
| 360 | | - uint32_t l2idx = (sector >> 5) & 0x1f;
|
| 361 | | - uint32_t l2offs = sector & 0x1f;
|
| 362 | | - cnt = MIN(count, 0x20 - l2offs);
|
| 363 | | - uint32_t l2data = ata_bbt[l1data & 0x7fff][l2idx];
|
| 364 | | - if (l2data < 0x8000) offset = l2data + base;
|
| 365 | | - else
|
| 366 | | - {
|
| 367 | | - uint32_t l3idx = sector & 0x1f;
|
| 368 | | - uint32_t l3data = ata_bbt[l2data & 0x7fff][l3idx];
|
| 369 | | - for (cnt = 1; cnt < count && l3idx + cnt < 0x20; cnt++)
|
| 370 | | - if (ata_bbt[l2data & 0x7fff][l3idx + cnt] != l3data)
|
| 371 | | - break;
|
| 372 | | - offset = l3data + base;
|
| 373 | | - }
|
| 374 | | - }
|
| 375 | | - }
|
| 376 | | - uint64_t phys = sector + offset;
|
| | 413 | + uint64_t phys;
|
| | 414 | + uint32_t cnt;
|
| | 415 | + PASS_RC(ata_bbt_translate(sector, count, &phys, &cnt), 0, 0);
|
| | 416 | + uint32_t offset = phys - sector;
|
| 377 | 417 | if (offset != ata_last_offset && phys - ata_last_phys < 64) ata_soft_reset();
|
| 378 | 418 | ata_last_offset = offset;
|
| 379 | 419 | ata_last_phys = phys + cnt;
|
| — | — | @@ -398,20 +438,16 @@ |
| 399 | 439 | {
|
| 400 | 440 | uint32_t cnt = MIN(ata_lba48 ? 8192 : 32, count);
|
| 401 | 441 | int rc = -1;
|
| 402 | | - int tries = 3;
|
| 403 | | - while (tries-- && rc)
|
| | 442 | + rc = ata_rw_chunk(sector, cnt, buffer, write);
|
| | 443 | + if (rc) ata_soft_reset();
|
| | 444 | + if (rc && ATA_RETRIES)
|
| 404 | 445 | {
|
| 405 | | - rc = ata_rw_chunk(sector, cnt, buffer, write);
|
| 406 | | - if (rc) ata_soft_reset();
|
| 407 | | - }
|
| 408 | | - if (rc)
|
| 409 | | - {
|
| 410 | 446 | void* buf = buffer;
|
| 411 | 447 | uint64_t sect;
|
| 412 | 448 | for (sect = sector; sect < sector + cnt; sect++)
|
| 413 | 449 | {
|
| 414 | 450 | rc = -1;
|
| 415 | | - tries = 3;
|
| | 451 | + tries = ATA_RETRIES;
|
| 416 | 452 | while (tries-- && rc)
|
| 417 | 453 | {
|
| 418 | 454 | rc = ata_rw_chunk(sect, 1, buf, write);
|
| — | — | @@ -451,7 +487,13 @@ |
| 452 | 488 | ata_write_cbr(&ATA_PIO_DAD, BIT(1) | BIT(2));
|
| 453 | 489 | sleep(10);
|
| 454 | 490 | ata_write_cbr(&ATA_PIO_DAD, 0);
|
| 455 | | - PASS_RC_MTX(ata_wait_for_rdy(60000000), 0, 0, &ata_mutex);
|
| | 491 | + int rc = ata_wait_for_rdy(20000000);
|
| | 492 | + if (IS_ERR(rc))
|
| | 493 | + {
|
| | 494 | + ata_power_down();
|
| | 495 | + sleep(3000000);
|
| | 496 | + ata_power_up();
|
| | 497 | + }
|
| 456 | 498 | ata_set_active();
|
| 457 | 499 | mutex_unlock(&ata_mutex);
|
| 458 | 500 | }
|
| — | — | @@ -512,6 +554,7 @@ |
| 513 | 555 | (*info).vendor = "Apple";
|
| 514 | 556 | (*info).product = "iPod Classic";
|
| 515 | 557 | (*info).revision = "1.0";
|
| | 558 | + (*info).driverinfo = &drvinfo;
|
| 516 | 559 | }
|
| 517 | 560 |
|
| 518 | 561 | long ata_last_disk_activity(void)
|
| — | — | @@ -519,19 +562,20 @@ |
| 520 | 563 | return ata_last_activity_value;
|
| 521 | 564 | }
|
| 522 | 565 |
|
| 523 | | -int ata_init(void)
|
| | 566 | +#ifdef ATA_HAVE_BBT
|
| | 567 | +void ata_bbt_disable()
|
| 524 | 568 | {
|
| 525 | | - mutex_init(&ata_mutex);
|
| 526 | | - wakeup_init(&ata_wakeup);
|
| 527 | | - PCON(7) = 0x44444444;
|
| 528 | | - PCON(8) = 0x44444444;
|
| 529 | | - PCON(9) = 0x44444444;
|
| 530 | | - PCON(10) = (PCON(10) & ~0xffff) | 0x4444;
|
| 531 | | - ata_powered = false;
|
| 532 | | - ata_total_sectors = 0;
|
| 533 | | -#ifdef ATA_HAVE_BBT
|
| 534 | 569 | mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 570 | + if (ata_bbt) free(ata_bbt);
|
| 535 | 571 | ata_bbt = NULL;
|
| | 572 | + ata_virtual_sectors = ata_total_sectors;
|
| | 573 | + mutex_unlock(&ata_mutex);
|
| | 574 | +}
|
| | 575 | +
|
| | 576 | +void ata_bbt_reload()
|
| | 577 | +{
|
| | 578 | + mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
|
| | 579 | + ata_bbt_disable();
|
| 536 | 580 | ata_power_up();
|
| 537 | 581 | uint32_t* buf = (uint32_t*)memalign(0x10, 0x1000);
|
| 538 | 582 | if (buf)
|
| — | — | @@ -559,7 +603,22 @@ |
| 560 | 604 | }
|
| 561 | 605 | else ata_virtual_sectors = ata_total_sectors;
|
| 562 | 606 | mutex_unlock(&ata_mutex);
|
| | 607 | +}
|
| 563 | 608 | #endif
|
| | 609 | +
|
| | 610 | +int ata_init(void)
|
| | 611 | +{
|
| | 612 | + mutex_init(&ata_mutex);
|
| | 613 | + wakeup_init(&ata_wakeup);
|
| | 614 | + PCON(7) = 0x44444444;
|
| | 615 | + PCON(8) = 0x44444444;
|
| | 616 | + PCON(9) = 0x44444444;
|
| | 617 | + PCON(10) = (PCON(10) & ~0xffff) | 0x4444;
|
| | 618 | + ata_powered = false;
|
| | 619 | + ata_total_sectors = 0;
|
| | 620 | +#ifdef ATA_HAVE_BBT
|
| | 621 | + ata_bbt_reload();
|
| | 622 | +#endif
|
| 564 | 623 | thread_create(&ata_thread_handle, "ATA idle monitor", ata_thread, ata_stack,
|
| 565 | 624 | sizeof(ata_stack), OS_THREAD, 1, true);
|
| 566 | 625 | return 0;
|