diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-11-01 19:58:22 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-11-04 07:33:26 -0500 |
commit | 2824bd5f1644a6b9129a0c0fcfe2bafab91a7225 (patch) | |
tree | c50259c7efcd751ed4666e4e538609097f43ce80 /firmware/drivers/ata.c | |
parent | d60dee6188ee134ddd3019a219c41e39df1ae5ff (diff) | |
download | rockbox-2824bd5f1644a6b9129a0c0fcfe2bafab91a7225.tar.gz rockbox-2824bd5f1644a6b9129a0c0fcfe2bafab91a7225.zip |
ipod6g: Support MAX_PHYS_SECTOR_SIZE of 4K
This lets us *natively* handle varying physical sector sizes
without playing games and lying about the logical sector size.
(The original drives use 4K _physical_ sectors with 512B logical
sectors, but you have to access everything in 4K blocks...)
Achieve this by splitting the MAX_PHYS_SECTOR_SIZE code out
of the main ATA driver and re-using it.
Change-Id: I0bc615ab4562f1e3e83171a8633c74fb60c7da1f
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r-- | firmware/drivers/ata.c | 218 |
1 files changed, 7 insertions, 211 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 119297ff02..7b43d3c536 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -115,17 +115,6 @@ static int multisectors; /* number of supported multisectors */ | |||
115 | 115 | ||
116 | static unsigned short identify_info[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; | 116 | static unsigned short identify_info[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; |
117 | 117 | ||
118 | #ifdef MAX_PHYS_SECTOR_SIZE | ||
119 | struct sector_cache_entry { | ||
120 | unsigned char data[MAX_PHYS_SECTOR_SIZE]; | ||
121 | sector_t sectornum; /* logical sector */ | ||
122 | bool inuse; | ||
123 | }; | ||
124 | /* buffer for reading and writing large physical sectors */ | ||
125 | static struct sector_cache_entry sector_cache STORAGE_ALIGN_ATTR; | ||
126 | static int phys_sector_mult = 1; | ||
127 | #endif | ||
128 | |||
129 | #ifdef HAVE_ATA_DMA | 118 | #ifdef HAVE_ATA_DMA |
130 | static int dma_mode = 0; | 119 | static int dma_mode = 0; |
131 | #endif | 120 | #endif |
@@ -600,6 +589,8 @@ static int ata_transfer_sectors(uint64_t start, | |||
600 | return ret; | 589 | return ret; |
601 | } | 590 | } |
602 | 591 | ||
592 | #include "ata-common.c" | ||
593 | |||
603 | #ifndef MAX_PHYS_SECTOR_SIZE | 594 | #ifndef MAX_PHYS_SECTOR_SIZE |
604 | int ata_read_sectors(IF_MD(int drive,) | 595 | int ata_read_sectors(IF_MD(int drive,) |
605 | sector_t start, | 596 | sector_t start, |
@@ -632,179 +623,6 @@ int ata_write_sectors(IF_MD(int drive,) | |||
632 | } | 623 | } |
633 | #endif /* ndef MAX_PHYS_SECTOR_SIZE */ | 624 | #endif /* ndef MAX_PHYS_SECTOR_SIZE */ |
634 | 625 | ||
635 | #ifdef MAX_PHYS_SECTOR_SIZE | ||
636 | static int cache_sector(sector_t sector) | ||
637 | { | ||
638 | int rc; | ||
639 | |||
640 | /* round down to physical sector boundary */ | ||
641 | sector &= ~(phys_sector_mult - 1); | ||
642 | |||
643 | /* check whether the sector is already cached */ | ||
644 | if (sector_cache.inuse && (sector_cache.sectornum == sector)) | ||
645 | return 0; | ||
646 | |||
647 | /* not found: read the sector */ | ||
648 | sector_cache.inuse = false; | ||
649 | rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false); | ||
650 | if (!rc) | ||
651 | { | ||
652 | sector_cache.sectornum = sector; | ||
653 | sector_cache.inuse = true; | ||
654 | } | ||
655 | return rc; | ||
656 | } | ||
657 | |||
658 | static inline int flush_current_sector(void) | ||
659 | { | ||
660 | return ata_transfer_sectors(sector_cache.sectornum, phys_sector_mult, | ||
661 | sector_cache.data, true); | ||
662 | } | ||
663 | |||
664 | int ata_read_sectors(IF_MD(int drive,) | ||
665 | sector_t start, | ||
666 | int incount, | ||
667 | void* inbuf) | ||
668 | { | ||
669 | int rc = 0; | ||
670 | int offset; | ||
671 | |||
672 | #ifdef HAVE_MULTIDRIVE | ||
673 | (void)drive; /* unused for now */ | ||
674 | #endif | ||
675 | mutex_lock(&ata_mutex); | ||
676 | |||
677 | offset = start & (phys_sector_mult - 1); | ||
678 | |||
679 | if (offset) /* first partial sector */ | ||
680 | { | ||
681 | int partcount = MIN(incount, phys_sector_mult - offset); | ||
682 | |||
683 | rc = cache_sector(start); | ||
684 | if (rc) | ||
685 | { | ||
686 | rc = rc * 10 - 1; | ||
687 | goto error; | ||
688 | } | ||
689 | memcpy(inbuf, sector_cache.data + offset * SECTOR_SIZE, | ||
690 | partcount * SECTOR_SIZE); | ||
691 | |||
692 | start += partcount; | ||
693 | inbuf += partcount * SECTOR_SIZE; | ||
694 | incount -= partcount; | ||
695 | } | ||
696 | if (incount) | ||
697 | { | ||
698 | offset = incount & (phys_sector_mult - 1); | ||
699 | incount -= offset; | ||
700 | |||
701 | if (incount) | ||
702 | { | ||
703 | rc = ata_transfer_sectors(start, incount, inbuf, false); | ||
704 | if (rc) | ||
705 | { | ||
706 | rc = rc * 10 - 2; | ||
707 | goto error; | ||
708 | } | ||
709 | start += incount; | ||
710 | inbuf += incount * SECTOR_SIZE; | ||
711 | } | ||
712 | if (offset) | ||
713 | { | ||
714 | rc = cache_sector(start); | ||
715 | if (rc) | ||
716 | { | ||
717 | rc = rc * 10 - 3; | ||
718 | goto error; | ||
719 | } | ||
720 | memcpy(inbuf, sector_cache.data, offset * SECTOR_SIZE); | ||
721 | } | ||
722 | } | ||
723 | |||
724 | error: | ||
725 | mutex_unlock(&ata_mutex); | ||
726 | |||
727 | return rc; | ||
728 | } | ||
729 | |||
730 | int ata_write_sectors(IF_MD(int drive,) | ||
731 | sector_t start, | ||
732 | int count, | ||
733 | const void* buf) | ||
734 | { | ||
735 | int rc = 0; | ||
736 | int offset; | ||
737 | |||
738 | #ifdef HAVE_MULTIDRIVE | ||
739 | (void)drive; /* unused for now */ | ||
740 | #endif | ||
741 | mutex_lock(&ata_mutex); | ||
742 | |||
743 | offset = start & (phys_sector_mult - 1); | ||
744 | |||
745 | if (offset) /* first partial sector */ | ||
746 | { | ||
747 | int partcount = MIN(count, phys_sector_mult - offset); | ||
748 | |||
749 | rc = cache_sector(start); | ||
750 | if (rc) | ||
751 | { | ||
752 | rc = rc * 10 - 1; | ||
753 | goto error; | ||
754 | } | ||
755 | memcpy(sector_cache.data + offset * SECTOR_SIZE, buf, | ||
756 | partcount * SECTOR_SIZE); | ||
757 | rc = flush_current_sector(); | ||
758 | if (rc) | ||
759 | { | ||
760 | rc = rc * 10 - 2; | ||
761 | goto error; | ||
762 | } | ||
763 | start += partcount; | ||
764 | buf += partcount * SECTOR_SIZE; | ||
765 | count -= partcount; | ||
766 | } | ||
767 | if (count) | ||
768 | { | ||
769 | offset = count & (phys_sector_mult - 1); | ||
770 | count -= offset; | ||
771 | |||
772 | if (count) | ||
773 | { | ||
774 | rc = ata_transfer_sectors(start, count, (void*)buf, true); | ||
775 | if (rc) | ||
776 | { | ||
777 | rc = rc * 10 - 3; | ||
778 | goto error; | ||
779 | } | ||
780 | start += count; | ||
781 | buf += count * SECTOR_SIZE; | ||
782 | } | ||
783 | if (offset) | ||
784 | { | ||
785 | rc = cache_sector(start); | ||
786 | if (rc) | ||
787 | { | ||
788 | rc = rc * 10 - 4; | ||
789 | goto error; | ||
790 | } | ||
791 | memcpy(sector_cache.data, buf, offset * SECTOR_SIZE); | ||
792 | rc = flush_current_sector(); | ||
793 | if (rc) | ||
794 | { | ||
795 | rc = rc * 10 - 5; | ||
796 | goto error; | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
801 | error: | ||
802 | mutex_unlock(&ata_mutex); | ||
803 | |||
804 | return rc; | ||
805 | } | ||
806 | #endif /* MAX_PHYS_SECTOR_SIZE */ | ||
807 | |||
808 | static int STORAGE_INIT_ATTR check_registers(void) | 626 | static int STORAGE_INIT_ATTR check_registers(void) |
809 | { | 627 | { |
810 | int i; | 628 | int i; |
@@ -1242,9 +1060,6 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1242 | ata_led(false); | 1060 | ata_led(false); |
1243 | ata_device_init(); | 1061 | ata_device_init(); |
1244 | ata_enable(true); | 1062 | ata_enable(true); |
1245 | #ifdef MAX_PHYS_SECTOR_SIZE | ||
1246 | memset(§or_cache, 0, sizeof(sector_cache)); | ||
1247 | #endif | ||
1248 | 1063 | ||
1249 | if (ata_state == ATA_BOOT) { | 1064 | if (ata_state == ATA_BOOT) { |
1250 | ata_state = ATA_OFF; | 1065 | ata_state = ATA_OFF; |
@@ -1309,31 +1124,12 @@ int STORAGE_INIT_ATTR ata_init(void) | |||
1309 | } | 1124 | } |
1310 | 1125 | ||
1311 | #ifdef MAX_PHYS_SECTOR_SIZE | 1126 | #ifdef MAX_PHYS_SECTOR_SIZE |
1312 | /* Find out the physical sector size */ | 1127 | rc = ata_get_phys_sector_mult(); |
1313 | if((identify_info[106] & 0xe000) == 0x6000) /* B14, B13 */ | 1128 | if (rc) { |
1314 | phys_sector_mult = BIT_N(identify_info[106] & 0x000f); | 1129 | rc = -70 + rc; |
1315 | else | 1130 | goto error; |
1316 | phys_sector_mult = 1; | ||
1317 | |||
1318 | DEBUGF("ata: %d logical sectors per phys sector", phys_sector_mult); | ||
1319 | |||
1320 | if (phys_sector_mult > 1) | ||
1321 | { | ||
1322 | /* Check if drive really needs emulation - if we can access | ||
1323 | sector 1 then assume the drive supports "512e" and will handle | ||
1324 | it better than us, so ignore the large physical sectors. | ||
1325 | */ | ||
1326 | char throwaway[SECTOR_SIZE]; | ||
1327 | rc = ata_transfer_sectors(1, 1, &throwaway, false); | ||
1328 | if (rc == 0) | ||
1329 | phys_sector_mult = 1; | ||
1330 | } | 1131 | } |
1331 | 1132 | #endif | |
1332 | if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE)) | ||
1333 | panicf("Unsupported physical sector size: %d", | ||
1334 | phys_sector_mult * SECTOR_SIZE); | ||
1335 | #endif /* MAX_PHYS_SECTOR_SIZE */ | ||
1336 | |||
1337 | ata_state = ATA_ON; | 1133 | ata_state = ATA_ON; |
1338 | keep_ata_active(); | 1134 | keep_ata_active(); |
1339 | } | 1135 | } |