|
|
1.1 root 1: // Disk setup and access
2: //
3: // Copyright (C) 2008,2009 Kevin O'Connor <[email protected]>
4: // Copyright (C) 2002 MandrakeSoft S.A.
5: //
6: // This file may be distributed under the terms of the GNU LGPLv3 license.
7:
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
1.1.1.4 root 13: #include "ahci.h" // process_ahci_op
1.1.1.6 ! root 14: #include "virtio-blk.h" // process_virtio_blk_op
! 15: #include "blockcmd.h" // cdb_*
1.1 root 16:
1.1.1.4 root 17: u8 FloppyCount VAR16VISIBLE;
18: u8 CDCount;
19: struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE;
1.1.1.5 root 20: u8 *bounce_buf_fl VAR16VISIBLE;
1.1 root 21:
22: struct drive_s *
23: getDrive(u8 exttype, u8 extdriveoffset)
24: {
1.1.1.4 root 25: if (extdriveoffset >= ARRAY_SIZE(IDMap[0]))
1.1 root 26: return NULL;
1.1.1.4 root 27: struct drive_s *drive_gf = GET_GLOBAL(IDMap[exttype][extdriveoffset]);
1.1.1.3 root 28: if (!drive_gf)
1.1 root 29: return NULL;
1.1.1.3 root 30: return GLOBALFLAT2GLOBAL(drive_gf);
1.1 root 31: }
32:
1.1.1.4 root 33: int getDriveId(u8 exttype, struct drive_s *drive_g)
34: {
35: int i;
36: for (i = 0; i < ARRAY_SIZE(IDMap[0]); i++)
37: if (getDrive(exttype, i) == drive_g)
38: return i;
39: return -1;
40: }
41:
1.1.1.5 root 42: int bounce_buf_init(void)
43: {
44: if (bounce_buf_fl)
45: return 0;
46:
47: u8 *buf = malloc_low(CDROM_SECTOR_SIZE);
48: if (!buf) {
49: warn_noalloc();
50: return -1;
51: }
52: bounce_buf_fl = buf;
53: return 0;
54: }
1.1 root 55:
56: /****************************************************************
57: * Disk geometry translation
58: ****************************************************************/
59:
60: static u8
61: get_translation(struct drive_s *drive_g)
62: {
63: u8 type = GET_GLOBAL(drive_g->type);
64: if (! CONFIG_COREBOOT && type == DTYPE_ATA) {
65: // Emulators pass in the translation info via nvram.
66: u8 ataid = GET_GLOBAL(drive_g->cntl_id);
67: u8 channel = ataid / 2;
68: u8 translation = inb_cmos(CMOS_BIOS_DISKTRANSFLAG + channel/2);
69: translation >>= 2 * (ataid % 4);
70: translation &= 0x03;
71: return translation;
72: }
73:
1.1.1.3 root 74: // Otherwise use a heuristic to determine translation type.
1.1 root 75: u16 heads = GET_GLOBAL(drive_g->pchs.heads);
76: u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
77: u16 spt = GET_GLOBAL(drive_g->pchs.spt);
1.1.1.3 root 78: u64 sectors = GET_GLOBAL(drive_g->sectors);
79: u64 psectors = (u64)heads * cylinders * spt;
80: if (!heads || !cylinders || !spt || psectors > sectors)
81: // pchs doesn't look valid - use LBA.
82: return TRANSLATION_LBA;
1.1 root 83:
84: if (cylinders <= 1024 && heads <= 16 && spt <= 63)
85: return TRANSLATION_NONE;
86: if (cylinders * heads <= 131072)
87: return TRANSLATION_LARGE;
88: return TRANSLATION_LBA;
89: }
90:
1.1.1.4 root 91: static void
1.1 root 92: setup_translation(struct drive_s *drive_g)
93: {
94: u8 translation = get_translation(drive_g);
95: SET_GLOBAL(drive_g->translation, translation);
96:
97: u16 heads = GET_GLOBAL(drive_g->pchs.heads);
98: u16 cylinders = GET_GLOBAL(drive_g->pchs.cylinders);
99: u16 spt = GET_GLOBAL(drive_g->pchs.spt);
100: u64 sectors = GET_GLOBAL(drive_g->sectors);
101: const char *desc = NULL;
102:
103: switch (translation) {
104: default:
105: case TRANSLATION_NONE:
106: desc = "none";
107: break;
108: case TRANSLATION_LBA:
109: desc = "lba";
110: spt = 63;
111: if (sectors > 63*255*1024) {
112: heads = 255;
113: cylinders = 1024;
114: break;
115: }
116: u32 sect = (u32)sectors / 63;
117: heads = sect / 1024;
118: if (heads>128)
119: heads = 255;
120: else if (heads>64)
121: heads = 128;
122: else if (heads>32)
123: heads = 64;
124: else if (heads>16)
125: heads = 32;
126: else
127: heads = 16;
128: cylinders = sect / heads;
129: break;
130: case TRANSLATION_RECHS:
131: desc = "r-echs";
132: // Take care not to overflow
133: if (heads==16) {
134: if (cylinders>61439)
135: cylinders=61439;
136: heads=15;
137: cylinders = (u16)((u32)(cylinders)*16/15);
138: }
139: // then go through the large bitshift process
140: case TRANSLATION_LARGE:
141: if (translation == TRANSLATION_LARGE)
142: desc = "large";
143: while (cylinders > 1024) {
144: cylinders >>= 1;
145: heads <<= 1;
146:
147: // If we max out the head count
148: if (heads > 127)
149: break;
150: }
151: break;
152: }
153: // clip to 1024 cylinders in lchs
154: if (cylinders > 1024)
155: cylinders = 1024;
1.1.1.3 root 156: dprintf(1, "drive %p: PCHS=%u/%d/%d translation=%s LCHS=%d/%d/%d s=%d\n"
157: , drive_g
1.1 root 158: , drive_g->pchs.cylinders, drive_g->pchs.heads, drive_g->pchs.spt
159: , desc
1.1.1.3 root 160: , cylinders, heads, spt
161: , (u32)sectors);
1.1 root 162:
163: SET_GLOBAL(drive_g->lchs.heads, heads);
164: SET_GLOBAL(drive_g->lchs.cylinders, cylinders);
165: SET_GLOBAL(drive_g->lchs.spt, spt);
166: }
167:
168:
169: /****************************************************************
170: * Drive mapping
171: ****************************************************************/
172:
173: // Fill in Fixed Disk Parameter Table (located in ebda).
174: static void
175: fill_fdpt(struct drive_s *drive_g, int hdid)
176: {
177: if (hdid > 1)
178: return;
179:
180: u16 nlc = GET_GLOBAL(drive_g->lchs.cylinders);
181: u16 nlh = GET_GLOBAL(drive_g->lchs.heads);
182: u16 nlspt = GET_GLOBAL(drive_g->lchs.spt);
183:
184: u16 npc = GET_GLOBAL(drive_g->pchs.cylinders);
185: u16 nph = GET_GLOBAL(drive_g->pchs.heads);
186: u16 npspt = GET_GLOBAL(drive_g->pchs.spt);
187:
188: struct fdpt_s *fdpt = &get_ebda_ptr()->fdpt[hdid];
189: fdpt->precompensation = 0xffff;
190: fdpt->drive_control_byte = 0xc0 | ((nph > 8) << 3);
191: fdpt->landing_zone = npc;
192: fdpt->cylinders = nlc;
193: fdpt->heads = nlh;
194: fdpt->sectors = nlspt;
195:
1.1.1.2 root 196: if (nlc != npc || nlh != nph || nlspt != npspt) {
197: // Logical mapping present - use extended structure.
1.1 root 198:
1.1.1.2 root 199: // complies with Phoenix style Translated Fixed Disk Parameter
200: // Table (FDPT)
201: fdpt->phys_cylinders = npc;
202: fdpt->phys_heads = nph;
203: fdpt->phys_sectors = npspt;
204: fdpt->a0h_signature = 0xa0;
1.1 root 205:
1.1.1.2 root 206: // Checksum structure.
207: fdpt->checksum -= checksum(fdpt, sizeof(*fdpt));
208: }
1.1 root 209:
210: if (hdid == 0)
211: SET_IVT(0x41, SEGOFF(get_ebda_seg(), offsetof(
212: struct extended_bios_data_area_s, fdpt[0])));
213: else
214: SET_IVT(0x46, SEGOFF(get_ebda_seg(), offsetof(
215: struct extended_bios_data_area_s, fdpt[1])));
216: }
217:
218: // Find spot to add a drive
219: static void
1.1.1.4 root 220: add_drive(struct drive_s **idmap, u8 *count, struct drive_s *drive_g)
1.1 root 221: {
1.1.1.4 root 222: if (*count >= ARRAY_SIZE(IDMap[0])) {
1.1.1.3 root 223: warn_noalloc();
1.1 root 224: return;
225: }
1.1.1.4 root 226: idmap[*count] = drive_g;
1.1 root 227: *count = *count + 1;
1.1.1.4 root 228: }
229:
230: // Map a hard drive
231: void
232: map_hd_drive(struct drive_s *drive_g)
233: {
234: ASSERT32FLAT();
235: struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
236: int hdid = bda->hdcount;
237: dprintf(3, "Mapping hd drive %p to %d\n", drive_g, hdid);
238: add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
239:
240: // Setup disk geometry translation.
241: setup_translation(drive_g);
242:
243: // Fill "fdpt" structure.
244: fill_fdpt(drive_g, hdid);
1.1 root 245: }
246:
247: // Map a cd
248: void
249: map_cd_drive(struct drive_s *drive_g)
250: {
251: dprintf(3, "Mapping cd drive %p\n", drive_g);
1.1.1.4 root 252: add_drive(IDMap[EXTTYPE_CD], &CDCount, drive_g);
1.1 root 253: }
254:
255: // Map a floppy
256: void
257: map_floppy_drive(struct drive_s *drive_g)
258: {
259: dprintf(3, "Mapping floppy drive %p\n", drive_g);
1.1.1.4 root 260: add_drive(IDMap[EXTTYPE_FLOPPY], &FloppyCount, drive_g);
1.1 root 261:
262: // Update equipment word bits for floppy
1.1.1.4 root 263: if (FloppyCount == 1) {
1.1 root 264: // 1 drive, ready for boot
265: SETBITS_BDA(equipment_list_flags, 0x01);
266: SET_BDA(floppy_harddisk_info, 0x07);
1.1.1.4 root 267: } else if (FloppyCount >= 2) {
1.1 root 268: // 2 drives, ready for boot
269: SETBITS_BDA(equipment_list_flags, 0x41);
270: SET_BDA(floppy_harddisk_info, 0x77);
271: }
272: }
273:
274:
275: /****************************************************************
276: * 16bit calling interface
277: ****************************************************************/
278:
1.1.1.6 ! root 279: static int
! 280: process_scsi_op(struct disk_op_s *op)
! 281: {
! 282: if (!CONFIG_VIRTIO_SCSI && !CONFIG_USB_MSC)
! 283: return 0;
! 284: switch (op->command) {
! 285: case CMD_READ:
! 286: return cdb_read(op);
! 287: case CMD_WRITE:
! 288: return cdb_write(op);
! 289: case CMD_FORMAT:
! 290: case CMD_RESET:
! 291: case CMD_ISREADY:
! 292: case CMD_VERIFY:
! 293: case CMD_SEEK:
! 294: return DISK_RET_SUCCESS;
! 295: default:
! 296: op->count = 0;
! 297: return DISK_RET_EPARAM;
! 298: }
! 299: }
! 300:
1.1 root 301: // Execute a disk_op request.
302: int
303: process_op(struct disk_op_s *op)
304: {
1.1.1.3 root 305: ASSERT16();
1.1 root 306: u8 type = GET_GLOBAL(op->drive_g->type);
307: switch (type) {
308: case DTYPE_FLOPPY:
309: return process_floppy_op(op);
310: case DTYPE_ATA:
311: return process_ata_op(op);
312: case DTYPE_ATAPI:
313: return process_atapi_op(op);
314: case DTYPE_RAMDISK:
315: return process_ramdisk_op(op);
316: case DTYPE_CDEMU:
317: return process_cdemu_op(op);
1.1.1.6 ! root 318: case DTYPE_VIRTIO_BLK:
! 319: return process_virtio_blk_op(op);
1.1.1.4 root 320: case DTYPE_AHCI:
1.1.1.6 ! root 321: return process_ahci_op(op);
! 322: case DTYPE_USB:
! 323: case DTYPE_VIRTIO_SCSI:
! 324: return process_scsi_op(op);
1.1 root 325: default:
326: op->count = 0;
327: return DISK_RET_EPARAM;
328: }
329: }
330:
331: // Execute a "disk_op_s" request - this runs on a stack in the ebda.
332: static int
333: __send_disk_op(struct disk_op_s *op_far, u16 op_seg)
334: {
335: struct disk_op_s dop;
336: memcpy_far(GET_SEG(SS), &dop
337: , op_seg, op_far
338: , sizeof(dop));
339:
340: dprintf(DEBUG_HDL_13, "disk_op d=%p lba=%d buf=%p count=%d cmd=%d\n"
341: , dop.drive_g, (u32)dop.lba, dop.buf_fl
342: , dop.count, dop.command);
343:
344: int status = process_op(&dop);
345:
346: // Update count with total sectors transferred.
347: SET_FARVAR(op_seg, op_far->count, dop.count);
348:
349: return status;
350: }
351:
352: // Execute a "disk_op_s" request by jumping to a stack in the ebda.
353: int
354: send_disk_op(struct disk_op_s *op)
355: {
1.1.1.3 root 356: ASSERT16();
1.1 root 357: if (! CONFIG_DRIVES)
358: return -1;
359:
1.1.1.3 root 360: return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
1.1 root 361: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.