1 // Disk setup and access
3 // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
4 // Copyright (C) 2002 MandrakeSoft S.A.
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
8 #include "disk.h" // struct ata_s
9 #include "biosvar.h" // GET_GLOBAL
10 #include "cmos.h" // inb_cmos
11 #include "util.h" // dprintf
12 #include "ata.h" // process_ata_op
14 struct drives_s Drives VAR16VISIBLE;
17 /****************************************************************
18 * Disk geometry translation
19 ****************************************************************/
22 get_translation(int driveid)
24 u8 type = GET_GLOBAL(Drives.drives[driveid].type);
25 if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
26 // Emulators pass in the translation info via nvram.
27 u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
28 u8 channel = ataid / 2;
29 u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
30 translation >>= 2 * (ataid % 4);
35 // On COREBOOT, use a heuristic to determine translation type.
36 u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
37 u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
38 u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
40 if (cylinders <= 1024 && heads <= 16 && spt <= 63)
41 return TRANSLATION_NONE;
42 if (cylinders * heads <= 131072)
43 return TRANSLATION_LARGE;
44 return TRANSLATION_LBA;
48 setup_translation(int driveid)
50 u8 translation = get_translation(driveid);
51 SET_GLOBAL(Drives.drives[driveid].translation, translation);
53 u8 ataid = GET_GLOBAL(Drives.drives[driveid].cntl_id);
54 u8 channel = ataid / 2;
56 u16 heads = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
57 u16 cylinders = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
58 u16 spt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
59 u64 sectors = GET_GLOBAL(Drives.drives[driveid].sectors);
61 dprintf(1, "ata%d-%d: PCHS=%u/%d/%d translation="
62 , channel, slave, cylinders, heads, spt);
63 switch (translation) {
64 case TRANSLATION_NONE:
70 if (sectors > 63*255*1024) {
75 u32 sect = (u32)sectors / 63;
87 cylinders = sect / heads;
89 case TRANSLATION_RECHS:
91 // Take care not to overflow
96 cylinders = (u16)((u32)(cylinders)*16/15);
98 // then go through the large bitshift process
99 case TRANSLATION_LARGE:
100 if (translation == TRANSLATION_LARGE)
102 while (cylinders > 1024) {
106 // If we max out the head count
112 // clip to 1024 cylinders in lchs
113 if (cylinders > 1024)
115 dprintf(1, " LCHS=%d/%d/%d\n", cylinders, heads, spt);
117 SET_GLOBAL(Drives.drives[driveid].lchs.heads, heads);
118 SET_GLOBAL(Drives.drives[driveid].lchs.cylinders, cylinders);
119 SET_GLOBAL(Drives.drives[driveid].lchs.spt, spt);
123 /****************************************************************
125 ****************************************************************/
127 // Fill in Fixed Disk Parameter Table (located in ebda).
129 fill_fdpt(int driveid, int hdid)
134 u16 nlc = GET_GLOBAL(Drives.drives[driveid].lchs.cylinders);
135 u16 nlh = GET_GLOBAL(Drives.drives[driveid].lchs.heads);
136 u16 nlspt = GET_GLOBAL(Drives.drives[driveid].lchs.spt);
138 u16 npc = GET_GLOBAL(Drives.drives[driveid].pchs.cylinders);
139 u16 nph = GET_GLOBAL(Drives.drives[driveid].pchs.heads);
140 u16 npspt = GET_GLOBAL(Drives.drives[driveid].pchs.spt);
142 struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
143 fdpt->precompensation = 0xffff;
144 fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
145 fdpt->landing_zone = npc;
146 fdpt->cylinders = nlc;
148 fdpt->sectors = nlspt;
150 if (nlc == npc && nlh == nph && nlspt == npspt)
151 // no logical CHS mapping used, just physical CHS
152 // use Standard Fixed Disk Parameter Table (FDPT)
155 // complies with Phoenix style Translated Fixed Disk Parameter
157 fdpt->phys_cylinders = npc;
158 fdpt->phys_heads = nph;
159 fdpt->phys_sectors = npspt;
160 fdpt->a0h_signature = 0xa0;
162 // Checksum structure.
163 fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
166 SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
167 struct extended_bios_data_area_s, fdpt[0])));
169 SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
170 struct extended_bios_data_area_s, fdpt[1])));
173 // Map a drive (that was registered via add_bcv_hd)
175 map_hd_drive(int driveid)
178 u8 hdcount = GET_BDA(hdcount);
179 if (hdcount >= ARRAY_SIZE(Drives.idmap[0]))
181 dprintf(3, "Mapping hd driveid %d to %d\n", driveid, hdcount);
182 SET_GLOBAL(Drives.idmap[EXTTYPE_HD][hdcount], driveid);
183 SET_BDA(hdcount, hdcount + 1);
185 // Fill "fdpt" structure.
186 fill_fdpt(driveid, hdcount);
191 map_cd_drive(int driveid)
194 u8 cdcount = GET_GLOBAL(Drives.cdcount);
195 if (cdcount >= ARRAY_SIZE(Drives.idmap[0]))
197 dprintf(3, "Mapping cd driveid %d to %d\n", driveid, cdcount);
198 SET_GLOBAL(Drives.idmap[EXTTYPE_CD][cdcount], driveid);
199 SET_GLOBAL(Drives.cdcount, cdcount+1);
204 map_floppy_drive(int driveid)
207 u8 floppycount = GET_GLOBAL(Drives.floppycount);
208 if (floppycount >= ARRAY_SIZE(Drives.idmap[0]))
210 dprintf(3, "Mapping floppy driveid %d to %d\n", driveid, floppycount);
211 SET_GLOBAL(Drives.idmap[EXTTYPE_FLOPPY][floppycount], driveid);
213 SET_GLOBAL(Drives.floppycount, floppycount);
215 // Update equipment word bits for floppy
216 if (floppycount == 1) {
217 // 1 drive, ready for boot
218 SETBITS_BDA(equipment_list_flags, 0x01);
219 SET_BDA(floppy_harddisk_info, 0x07);
221 // 2 drives, ready for boot
222 SETBITS_BDA(equipment_list_flags, 0x41);
223 SET_BDA(floppy_harddisk_info, 0x77);
227 // Show a one line description (without trailing newline) of a drive.
229 describe_drive(int driveid)
232 u8 type = GET_GLOBAL(Drives.drives[driveid].type);
235 describe_floppy(driveid);
238 describe_ata(driveid);
241 describe_atapi(driveid);
244 describe_ramdisk(driveid);
253 /****************************************************************
254 * 16bit calling interface
255 ****************************************************************/
257 // Execute a disk_op request.
259 process_op(struct disk_op_s *op)
261 u8 type = GET_GLOBAL(Drives.drives[op->driveid].type);
264 return process_floppy_op(op);
266 return process_ata_op(op);
268 return process_atapi_op(op);
270 return process_ramdisk_op(op);
272 return process_cdemu_op(op);
275 return DISK_RET_EPARAM;
279 // Execute a "disk_op_s" request - this runs on a stack in the ebda.
281 __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
283 struct disk_op_s dop;
284 memcpy_far(GET_SEG(SS), &dop
288 dprintf(DEBUG_HDL_13, "disk_op d=%d lba=%d buf=%p count=%d cmd=%d\n"
289 , dop.driveid, (u32)dop.lba, dop.buf_fl
290 , dop.count, dop.command);
294 int status = process_op(&dop);
298 // Update count with total sectors transferred.
299 SET_FARVAR(op_seg, op_far->count, dop.count);
304 // Execute a "disk_op_s" request by jumping to a stack in the ebda.
306 send_disk_op(struct disk_op_s *op)
312 return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
316 /****************************************************************
318 ****************************************************************/
323 memset(&Drives, 0, sizeof(Drives));
324 memset(&Drives.idmap, 0xff, sizeof(Drives.idmap));