summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/ata-common.c238
-rw-r--r--firmware/drivers/ata.c218
2 files changed, 245 insertions, 211 deletions
diff --git a/firmware/drivers/ata-common.c b/firmware/drivers/ata-common.c
new file mode 100644
index 0000000000..53a7780262
--- /dev/null
+++ b/firmware/drivers/ata-common.c
@@ -0,0 +1,238 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2024 Solomon Peachy
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ****************************************************************************/
20
21/* This is intended to be #included into the ATA driver */
22
23#ifdef MAX_PHYS_SECTOR_SIZE
24
25struct sector_cache_entry {
26 unsigned char data[MAX_PHYS_SECTOR_SIZE];
27 sector_t sectornum; /* logical sector */
28 bool inuse;
29};
30/* buffer for reading and writing large physical sectors */
31static struct sector_cache_entry sector_cache STORAGE_ALIGN_ATTR;
32static int phys_sector_mult = 1;
33
34static int cache_sector(sector_t sector)
35{
36 int rc;
37
38 /* round down to physical sector boundary */
39 sector &= ~(phys_sector_mult - 1);
40
41 /* check whether the sector is already cached */
42 if (sector_cache.inuse && (sector_cache.sectornum == sector))
43 return 0;
44
45 /* not found: read the sector */
46 sector_cache.inuse = false;
47 rc = ata_transfer_sectors(sector, phys_sector_mult, sector_cache.data, false);
48 if (!rc)
49 {
50 sector_cache.sectornum = sector;
51 sector_cache.inuse = true;
52 }
53 return rc;
54}
55
56static inline int flush_current_sector(void)
57{
58 return ata_transfer_sectors(sector_cache.sectornum, phys_sector_mult,
59 sector_cache.data, true);
60}
61
62int ata_read_sectors(IF_MD(int drive,)
63 sector_t start,
64 int incount,
65 void* inbuf)
66{
67 int rc = 0;
68 int offset;
69
70#ifdef HAVE_MULTIDRIVE
71 (void)drive; /* unused for now */
72#endif
73 mutex_lock(&ata_mutex);
74
75 offset = start & (phys_sector_mult - 1);
76
77 if (offset) /* first partial sector */
78 {
79 int partcount = MIN(incount, phys_sector_mult - offset);
80
81 rc = cache_sector(start);
82 if (rc)
83 {
84 rc = rc * 10 - 1;
85 goto error;
86 }
87 memcpy(inbuf, sector_cache.data + offset * SECTOR_SIZE,
88 partcount * SECTOR_SIZE);
89
90 start += partcount;
91 inbuf += partcount * SECTOR_SIZE;
92 incount -= partcount;
93 }
94 if (incount)
95 {
96 offset = incount & (phys_sector_mult - 1);
97 incount -= offset;
98
99 if (incount)
100 {
101 rc = ata_transfer_sectors(start, incount, inbuf, false);
102 if (rc)
103 {
104 rc = rc * 10 - 2;
105 goto error;
106 }
107 start += incount;
108 inbuf += incount * SECTOR_SIZE;
109 }
110 if (offset)
111 {
112 rc = cache_sector(start);
113 if (rc)
114 {
115 rc = rc * 10 - 3;
116 goto error;
117 }
118 memcpy(inbuf, sector_cache.data, offset * SECTOR_SIZE);
119 }
120 }
121
122 error:
123 mutex_unlock(&ata_mutex);
124
125 return rc;
126}
127
128int ata_write_sectors(IF_MD(int drive,)
129 sector_t start,
130 int count,
131 const void* buf)
132{
133 int rc = 0;
134 int offset;
135
136#ifdef HAVE_MULTIDRIVE
137 (void)drive; /* unused for now */
138#endif
139 mutex_lock(&ata_mutex);
140
141 offset = start & (phys_sector_mult - 1);
142
143 if (offset) /* first partial sector */
144 {
145 int partcount = MIN(count, phys_sector_mult - offset);
146
147 rc = cache_sector(start);
148 if (rc)
149 {
150 rc = rc * 10 - 1;
151 goto error;
152 }
153 memcpy(sector_cache.data + offset * SECTOR_SIZE, buf,
154 partcount * SECTOR_SIZE);
155 rc = flush_current_sector();
156 if (rc)
157 {
158 rc = rc * 10 - 2;
159 goto error;
160 }
161 start += partcount;
162 buf += partcount * SECTOR_SIZE;
163 count -= partcount;
164 }
165 if (count)
166 {
167 offset = count & (phys_sector_mult - 1);
168 count -= offset;
169
170 if (count)
171 {
172 rc = ata_transfer_sectors(start, count, (void*)buf, true);
173 if (rc)
174 {
175 rc = rc * 10 - 3;
176 goto error;
177 }
178 start += count;
179 buf += count * SECTOR_SIZE;
180 }
181 if (offset)
182 {
183 rc = cache_sector(start);
184 if (rc)
185 {
186 rc = rc * 10 - 4;
187 goto error;
188 }
189 memcpy(sector_cache.data, buf, offset * SECTOR_SIZE);
190 rc = flush_current_sector();
191 if (rc)
192 {
193 rc = rc * 10 - 5;
194 goto error;
195 }
196 }
197 }
198
199 error:
200 mutex_unlock(&ata_mutex);
201
202 return rc;
203}
204
205static int ata_get_phys_sector_mult(void)
206{
207 int rc = 0;
208
209 /* Find out the physical sector size */
210 if((identify_info[106] & 0xe000) == 0x6000) /* B14, B13 */
211 phys_sector_mult = BIT_N(identify_info[106] & 0x000f);
212 else
213 phys_sector_mult = 1;
214
215 DEBUGF("ata: %d logical sectors per phys sector", phys_sector_mult);
216
217 if (phys_sector_mult > 1)
218 {
219 /* Check if drive really needs emulation - if we can access
220 sector 1 then assume the drive supports "512e" and will handle
221 it better than us, so ignore the large physical sectors.
222 */
223 char throwaway[SECTOR_SIZE];
224 rc = ata_transfer_sectors(1, 1, &throwaway, false);
225 if (rc == 0)
226 phys_sector_mult = 1;
227 }
228
229 if (phys_sector_mult > (MAX_PHYS_SECTOR_SIZE/SECTOR_SIZE))
230 panicf("Unsupported physical sector size: %d",
231 phys_sector_mult * SECTOR_SIZE);
232
233 memset(&sector_cache, 0, sizeof(sector_cache));
234
235 return 0;
236}
237
238#endif /* MAX_PHYS_SECTOR_SIZE */
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 }