diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/drivers/ata.c | 269 |
1 files changed, 74 insertions, 195 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 3c37077fd3..b00f67f5ec 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -71,7 +71,7 @@ | |||
71 | #define Q_SLEEP 0 | 71 | #define Q_SLEEP 0 |
72 | #define Q_CLOSE 1 | 72 | #define Q_CLOSE 1 |
73 | 73 | ||
74 | #define READ_TIMEOUT 5*HZ | 74 | #define READWRITE_TIMEOUT 5*HZ |
75 | 75 | ||
76 | #ifdef HAVE_ATA_POWER_OFF | 76 | #ifdef HAVE_ATA_POWER_OFF |
77 | #define ATA_POWER_OFF_TIMEOUT 2*HZ | 77 | #define ATA_POWER_OFF_TIMEOUT 2*HZ |
@@ -302,16 +302,47 @@ STATICIRAM ICODE_ATTR void copy_read_sectors(unsigned char* buf, int wordcount) | |||
302 | } | 302 | } |
303 | #endif /* !ATA_OPTIMIZED_READING */ | 303 | #endif /* !ATA_OPTIMIZED_READING */ |
304 | 304 | ||
305 | #ifdef MAX_PHYS_SECTOR_SIZE | 305 | #ifndef ATA_OPTIMIZED_WRITING |
306 | static int _read_sectors(unsigned long start, | 306 | STATICIRAM ICODE_ATTR void copy_write_sectors(const unsigned char* buf, |
307 | int incount, | 307 | int wordcount) |
308 | void* inbuf) | 308 | { |
309 | if ( (unsigned long)buf & 1) | ||
310 | { /* not 16-bit aligned, copy byte by byte */ | ||
311 | unsigned short tmp = 0; | ||
312 | const unsigned char* bufend = buf + wordcount*2; | ||
313 | do | ||
314 | { | ||
315 | #if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN) | ||
316 | tmp = (unsigned short) *buf++; | ||
317 | tmp |= (unsigned short) *buf++ << 8; | ||
318 | SET_16BITREG(ATA_DATA, tmp); | ||
309 | #else | 319 | #else |
310 | int ata_read_sectors(IF_MD2(int drive,) | 320 | tmp = (unsigned short) *buf++ << 8; |
311 | unsigned long start, | 321 | tmp |= (unsigned short) *buf++; |
312 | int incount, | 322 | SET_16BITREG(ATA_DATA, tmp); |
313 | void* inbuf) | ||
314 | #endif | 323 | #endif |
324 | } while (buf < bufend); /* tail loop is faster */ | ||
325 | } | ||
326 | else | ||
327 | { /* 16-bit aligned, can do faster copy */ | ||
328 | unsigned short* wbuf = (unsigned short*)buf; | ||
329 | unsigned short* wbufend = wbuf + wordcount; | ||
330 | do | ||
331 | { | ||
332 | #ifdef SWAP_WORDS | ||
333 | SET_16BITREG(ATA_DATA, swap16(*wbuf)); | ||
334 | #else | ||
335 | SET_16BITREG(ATA_DATA, *wbuf); | ||
336 | #endif | ||
337 | } while (++wbuf < wbufend); /* tail loop is faster */ | ||
338 | } | ||
339 | } | ||
340 | #endif /* !ATA_OPTIMIZED_WRITING */ | ||
341 | |||
342 | static int ata_transfer_sectors(unsigned long start, | ||
343 | int incount, | ||
344 | void* inbuf, | ||
345 | int write) | ||
315 | { | 346 | { |
316 | int ret = 0; | 347 | int ret = 0; |
317 | long timeout; | 348 | long timeout; |
@@ -323,9 +354,6 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
323 | #endif | 354 | #endif |
324 | 355 | ||
325 | #ifndef MAX_PHYS_SECTOR_SIZE | 356 | #ifndef MAX_PHYS_SECTOR_SIZE |
326 | #ifdef HAVE_MULTIDRIVE | ||
327 | (void)drive; /* unused for now */ | ||
328 | #endif | ||
329 | mutex_lock(&ata_mtx); | 357 | mutex_lock(&ata_mtx); |
330 | #endif | 358 | #endif |
331 | 359 | ||
@@ -355,7 +383,7 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
355 | } | 383 | } |
356 | } | 384 | } |
357 | 385 | ||
358 | timeout = current_tick + READ_TIMEOUT; | 386 | timeout = current_tick + READWRITE_TIMEOUT; |
359 | 387 | ||
360 | SET_REG(ATA_SELECT, ata_device); | 388 | SET_REG(ATA_SELECT, ata_device); |
361 | if (!wait_for_rdy()) | 389 | if (!wait_for_rdy()) |
@@ -373,7 +401,7 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
373 | 401 | ||
374 | #ifdef HAVE_ATA_DMA | 402 | #ifdef HAVE_ATA_DMA |
375 | /* If DMA is supported and parameters are ok for DMA, use it */ | 403 | /* If DMA is supported and parameters are ok for DMA, use it */ |
376 | if (dma_mode && ata_dma_setup(inbuf, incount * SECTOR_SIZE, false)) | 404 | if (dma_mode && ata_dma_setup(inbuf, incount * SECTOR_SIZE, write)) |
377 | usedma = true; | 405 | usedma = true; |
378 | #endif | 406 | #endif |
379 | 407 | ||
@@ -390,9 +418,12 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
390 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | 418 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ |
391 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | 419 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); |
392 | #ifdef HAVE_ATA_DMA | 420 | #ifdef HAVE_ATA_DMA |
393 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT); | 421 | if (write) |
422 | SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA_EXT : CMD_WRITE_MULTIPLE_EXT); | ||
423 | else | ||
424 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA_EXT : CMD_READ_MULTIPLE_EXT); | ||
394 | #else | 425 | #else |
395 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE_EXT); | 426 | SET_REG(ATA_COMMAND, write ? CMD_WRITE_MULTIPLE_EXT : CMD_READ_MULTIPLE_EXT); |
396 | #endif | 427 | #endif |
397 | } | 428 | } |
398 | else | 429 | else |
@@ -404,9 +435,12 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
404 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | 435 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); |
405 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | 436 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); |
406 | #ifdef HAVE_ATA_DMA | 437 | #ifdef HAVE_ATA_DMA |
407 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA : CMD_READ_MULTIPLE); | 438 | if (write) |
439 | SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA : CMD_WRITE_MULTIPLE); | ||
440 | else | ||
441 | SET_REG(ATA_COMMAND, usedma ? CMD_READ_DMA : CMD_READ_MULTIPLE); | ||
408 | #else | 442 | #else |
409 | SET_REG(ATA_COMMAND, CMD_READ_MULTIPLE); | 443 | SET_REG(ATA_COMMAND, write ? CMD_WRITE_MULTIPLE : CMD_READ_MULTIPLE); |
410 | #endif | 444 | #endif |
411 | } | 445 | } |
412 | 446 | ||
@@ -473,7 +507,10 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
473 | 507 | ||
474 | wordcount = sectors * SECTOR_SIZE / 2; | 508 | wordcount = sectors * SECTOR_SIZE / 2; |
475 | 509 | ||
476 | copy_read_sectors(buf, wordcount); | 510 | if (write) |
511 | copy_write_sectors(buf, wordcount); | ||
512 | else | ||
513 | copy_read_sectors(buf, wordcount); | ||
477 | 514 | ||
478 | /* | 515 | /* |
479 | "Device errors encountered during READ MULTIPLE commands | 516 | "Device errors encountered during READ MULTIPLE commands |
@@ -513,191 +550,33 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
513 | return ret; | 550 | return ret; |
514 | } | 551 | } |
515 | 552 | ||
516 | #ifndef ATA_OPTIMIZED_WRITING | 553 | #ifndef MAX_PHYS_SECTOR_SIZE |
517 | STATICIRAM ICODE_ATTR void copy_write_sectors(const unsigned char* buf, | 554 | int ata_read_sectors(IF_MD2(int drive,) |
518 | int wordcount) | 555 | unsigned long start, |
556 | int incount, | ||
557 | void* inbuf) | ||
519 | { | 558 | { |
520 | if ( (unsigned long)buf & 1) | 559 | #ifdef HAVE_MULTIDRIVE |
521 | { /* not 16-bit aligned, copy byte by byte */ | 560 | (void)drive; /* unused for now */ |
522 | unsigned short tmp = 0; | ||
523 | const unsigned char* bufend = buf + wordcount*2; | ||
524 | do | ||
525 | { | ||
526 | #if defined(SWAP_WORDS) || defined(ROCKBOX_LITTLE_ENDIAN) | ||
527 | tmp = (unsigned short) *buf++; | ||
528 | tmp |= (unsigned short) *buf++ << 8; | ||
529 | SET_16BITREG(ATA_DATA, tmp); | ||
530 | #else | ||
531 | tmp = (unsigned short) *buf++ << 8; | ||
532 | tmp |= (unsigned short) *buf++; | ||
533 | SET_16BITREG(ATA_DATA, tmp); | ||
534 | #endif | ||
535 | } while (buf < bufend); /* tail loop is faster */ | ||
536 | } | ||
537 | else | ||
538 | { /* 16-bit aligned, can do faster copy */ | ||
539 | unsigned short* wbuf = (unsigned short*)buf; | ||
540 | unsigned short* wbufend = wbuf + wordcount; | ||
541 | do | ||
542 | { | ||
543 | #ifdef SWAP_WORDS | ||
544 | SET_16BITREG(ATA_DATA, swap16(*wbuf)); | ||
545 | #else | ||
546 | SET_16BITREG(ATA_DATA, *wbuf); | ||
547 | #endif | 561 | #endif |
548 | } while (++wbuf < wbufend); /* tail loop is faster */ | 562 | |
549 | } | 563 | return ata_transfer_sectors(start, incount, inbuf, false); |
550 | } | 564 | } |
551 | #endif /* !ATA_OPTIMIZED_WRITING */ | 565 | #endif |
552 | 566 | ||
553 | #ifdef MAX_PHYS_SECTOR_SIZE | 567 | #ifndef MAX_PHYS_SECTOR_SIZE |
554 | static int _write_sectors(unsigned long start, | ||
555 | int count, | ||
556 | const void* buf) | ||
557 | #else | ||
558 | int ata_write_sectors(IF_MD2(int drive,) | 568 | int ata_write_sectors(IF_MD2(int drive,) |
559 | unsigned long start, | 569 | unsigned long start, |
560 | int count, | 570 | int count, |
561 | const void* buf) | 571 | const void* buf) |
562 | #endif | ||
563 | { | 572 | { |
564 | int i; | ||
565 | int ret = 0; | ||
566 | long spinup_start; | ||
567 | #ifdef HAVE_ATA_DMA | ||
568 | bool usedma = false; | ||
569 | #endif | ||
570 | |||
571 | #ifndef MAX_PHYS_SECTOR_SIZE | ||
572 | #ifdef HAVE_MULTIDRIVE | 573 | #ifdef HAVE_MULTIDRIVE |
573 | (void)drive; /* unused for now */ | 574 | (void)drive; /* unused for now */ |
574 | #endif | 575 | #endif |
575 | mutex_lock(&ata_mtx); | ||
576 | #endif | ||
577 | |||
578 | if (start + count > total_sectors) | ||
579 | panicf("Writing past end of disk"); | ||
580 | 576 | ||
581 | last_disk_activity = current_tick; | 577 | return ata_transfer_sectors(start, count, (void*)buf, true); |
582 | spinup_start = current_tick; | ||
583 | |||
584 | ata_led(true); | ||
585 | |||
586 | if ( sleeping ) { | ||
587 | spinup = true; | ||
588 | if (poweroff) { | ||
589 | if (ata_power_on()) { | ||
590 | ret = -1; | ||
591 | goto error; | ||
592 | } | ||
593 | } | ||
594 | else { | ||
595 | if (perform_soft_reset()) { | ||
596 | ret = -1; | ||
597 | goto error; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | |||
602 | SET_REG(ATA_SELECT, ata_device); | ||
603 | if (!wait_for_rdy()) | ||
604 | { | ||
605 | ret = -2; | ||
606 | goto error; | ||
607 | } | ||
608 | |||
609 | #ifdef HAVE_ATA_DMA | ||
610 | /* If DMA is supported and parameters are ok for DMA, use it */ | ||
611 | if (dma_mode && ata_dma_setup((void *)buf, count * SECTOR_SIZE, true)) | ||
612 | usedma = true; | ||
613 | #endif | ||
614 | |||
615 | #ifdef HAVE_LBA48 | ||
616 | if (lba48) | ||
617 | { | ||
618 | SET_REG(ATA_NSECTOR, count >> 8); | ||
619 | SET_REG(ATA_NSECTOR, count & 0xff); | ||
620 | SET_REG(ATA_SECTOR, (start >> 24) & 0xff); /* 31:24 */ | ||
621 | SET_REG(ATA_SECTOR, start & 0xff); /* 7:0 */ | ||
622 | SET_REG(ATA_LCYL, 0); /* 39:32 */ | ||
623 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); /* 15:8 */ | ||
624 | SET_REG(ATA_HCYL, 0); /* 47:40 */ | ||
625 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); /* 23:16 */ | ||
626 | SET_REG(ATA_SELECT, SELECT_LBA | ata_device); | ||
627 | #ifdef HAVE_ATA_DMA | ||
628 | SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA_EXT : CMD_WRITE_SECTORS_EXT); | ||
629 | #else | ||
630 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS_EXT); | ||
631 | #endif | ||
632 | } | ||
633 | else | ||
634 | #endif | ||
635 | { | ||
636 | SET_REG(ATA_NSECTOR, count & 0xff); /* 0 means 256 sectors */ | ||
637 | SET_REG(ATA_SECTOR, start & 0xff); | ||
638 | SET_REG(ATA_LCYL, (start >> 8) & 0xff); | ||
639 | SET_REG(ATA_HCYL, (start >> 16) & 0xff); | ||
640 | SET_REG(ATA_SELECT, ((start >> 24) & 0xf) | SELECT_LBA | ata_device); | ||
641 | #ifdef HAVE_ATA_DMA | ||
642 | SET_REG(ATA_COMMAND, usedma ? CMD_WRITE_DMA : CMD_WRITE_SECTORS); | ||
643 | #else | ||
644 | SET_REG(ATA_COMMAND, CMD_WRITE_SECTORS); | ||
645 | #endif | ||
646 | } | ||
647 | |||
648 | #ifdef HAVE_ATA_DMA | ||
649 | if (usedma) { | ||
650 | if (!ata_dma_finish()) | ||
651 | ret = -7; | ||
652 | else if (spinup) { | ||
653 | spinup_time = current_tick - spinup_start; | ||
654 | spinup = false; | ||
655 | sleeping = false; | ||
656 | poweroff = false; | ||
657 | } | ||
658 | } | ||
659 | else | ||
660 | #endif /* HAVE_ATA_DMA */ | ||
661 | { | ||
662 | for (i=0; i<count; i++) { | ||
663 | |||
664 | if (!wait_for_start_of_transfer()) { | ||
665 | ret = -3; | ||
666 | break; | ||
667 | } | ||
668 | |||
669 | if (spinup) { | ||
670 | spinup_time = current_tick - spinup_start; | ||
671 | spinup = false; | ||
672 | sleeping = false; | ||
673 | poweroff = false; | ||
674 | } | ||
675 | |||
676 | copy_write_sectors(buf, SECTOR_SIZE/2); | ||
677 | |||
678 | #ifdef USE_INTERRUPT | ||
679 | /* reading the status register clears the interrupt */ | ||
680 | j = ATA_STATUS; | ||
681 | #endif | ||
682 | buf += SECTOR_SIZE; | ||
683 | |||
684 | last_disk_activity = current_tick; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | if(!ret && !wait_for_end_of_transfer()) { | ||
689 | DEBUGF("End on transfer failed. -- jyp"); | ||
690 | ret = -4; | ||
691 | } | ||
692 | |||
693 | error: | ||
694 | ata_led(false); | ||
695 | #ifndef MAX_PHYS_SECTOR_SIZE | ||
696 | mutex_unlock(&ata_mtx); | ||
697 | #endif | ||
698 | |||
699 | return ret; | ||
700 | } | 578 | } |
579 | #endif | ||
701 | 580 | ||
702 | #ifdef MAX_PHYS_SECTOR_SIZE | 581 | #ifdef MAX_PHYS_SECTOR_SIZE |
703 | static int cache_sector(unsigned long sector) | 582 | static int cache_sector(unsigned long sector) |
@@ -713,7 +592,7 @@ static int cache_sector(unsigned long sector) | |||
713 | 592 | ||
714 | /* not found: read the sector */ | 593 | /* not found: read the sector */ |
715 | sector_cache.inuse = false; | 594 | sector_cache.inuse = false; |
716 | rc = _read_sectors(sector, phys_sector_mult, sector_cache.data); | 595 | rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false); |
717 | if (!rc) | 596 | if (!rc) |
718 | { | 597 | { |
719 | sector_cache.sectornum = sector; | 598 | sector_cache.sectornum = sector; |
@@ -724,8 +603,8 @@ static int cache_sector(unsigned long sector) | |||
724 | 603 | ||
725 | static inline int flush_current_sector(void) | 604 | static inline int flush_current_sector(void) |
726 | { | 605 | { |
727 | return _write_sectors(sector_cache.sectornum, phys_sector_mult, | 606 | return ata_transfer_sectors(sector_cache.sectornum, phys_sector_mult, |
728 | sector_cache.data); | 607 | sector_cache.data, true); |
729 | } | 608 | } |
730 | 609 | ||
731 | int ata_read_sectors(IF_MD2(int drive,) | 610 | int ata_read_sectors(IF_MD2(int drive,) |
@@ -767,7 +646,7 @@ int ata_read_sectors(IF_MD2(int drive,) | |||
767 | 646 | ||
768 | if (incount) | 647 | if (incount) |
769 | { | 648 | { |
770 | rc = _read_sectors(start, incount, inbuf); | 649 | rc = ata_transfer_sectors(start, incount, inbuf, false); |
771 | if (rc) | 650 | if (rc) |
772 | { | 651 | { |
773 | rc = rc * 10 - 2; | 652 | rc = rc * 10 - 2; |
@@ -838,7 +717,7 @@ int ata_write_sectors(IF_MD2(int drive,) | |||
838 | 717 | ||
839 | if (count) | 718 | if (count) |
840 | { | 719 | { |
841 | rc = _write_sectors(start, count, buf); | 720 | rc = ata_transfer_sectors(start, count, (void*)buf, true); |
842 | if (rc) | 721 | if (rc) |
843 | { | 722 | { |
844 | rc = rc * 10 - 3; | 723 | rc = rc * 10 - 3; |