summaryrefslogtreecommitdiff
path: root/firmware/drivers/ata.c
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2024-11-01 19:58:22 -0400
committerSolomon Peachy <pizza@shaftnet.org>2024-11-04 07:33:26 -0500
commit2824bd5f1644a6b9129a0c0fcfe2bafab91a7225 (patch)
treec50259c7efcd751ed4666e4e538609097f43ce80 /firmware/drivers/ata.c
parentd60dee6188ee134ddd3019a219c41e39df1ae5ff (diff)
downloadrockbox-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.c218
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
116static unsigned short identify_info[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR; 116static unsigned short identify_info[ATA_IDENTIFY_WORDS] STORAGE_ALIGN_ATTR;
117 117
118#ifdef MAX_PHYS_SECTOR_SIZE
119struct 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 */
125static struct sector_cache_entry sector_cache STORAGE_ALIGN_ATTR;
126static int phys_sector_mult = 1;
127#endif
128
129#ifdef HAVE_ATA_DMA 118#ifdef HAVE_ATA_DMA
130static int dma_mode = 0; 119static 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
604int ata_read_sectors(IF_MD(int drive,) 595int 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
636static 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
658static 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
664int 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
730int 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
808static int STORAGE_INIT_ATTR check_registers(void) 626static 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(&sector_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 }