1 // 16bit code to access hard drives.
3 // Copyright (C) 2008 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 GPLv3 license.
8 #include "disk.h" // floppy_13
9 #include "biosvar.h" // struct bregs
10 #include "config.h" // CONFIG_*
11 #include "cmos.h" // inb_cmos
12 #include "util.h" // debug_enter
13 #include "ata.h" // ATA_*
16 // ---------------------------------------------------------------------------
17 // ATA/ATAPI driver : device detection
18 // ---------------------------------------------------------------------------
23 u8 hdcount, cdcount, device, type;
26 #if CONFIG_MAX_ATA_INTERFACES > 0
27 SET_EBDA(ata.channels[0].iface,ATA_IFACE_ISA);
28 SET_EBDA(ata.channels[0].iobase1,0x1f0);
29 SET_EBDA(ata.channels[0].iobase2,0x3f0);
30 SET_EBDA(ata.channels[0].irq,14);
32 #if CONFIG_MAX_ATA_INTERFACES > 1
33 SET_EBDA(ata.channels[1].iface,ATA_IFACE_ISA);
34 SET_EBDA(ata.channels[1].iobase1,0x170);
35 SET_EBDA(ata.channels[1].iobase2,0x370);
36 SET_EBDA(ata.channels[1].irq,15);
38 #if CONFIG_MAX_ATA_INTERFACES > 2
39 SET_EBDA(ata.channels[2].iface,ATA_IFACE_ISA);
40 SET_EBDA(ata.channels[2].iobase1,0x1e8);
41 SET_EBDA(ata.channels[2].iobase2,0x3e0);
42 SET_EBDA(ata.channels[2].irq,12);
44 #if CONFIG_MAX_ATA_INTERFACES > 3
45 SET_EBDA(ata.channels[3].iface,ATA_IFACE_ISA);
46 SET_EBDA(ata.channels[3].iobase1,0x168);
47 SET_EBDA(ata.channels[3].iobase2,0x360);
48 SET_EBDA(ata.channels[3].irq,11);
50 #if CONFIG_MAX_ATA_INTERFACES > 4
51 #error Please fill the ATA interface informations
57 for(device=0; device<CONFIG_MAX_ATA_DEVICES; device++) {
59 u8 channel, slave, shift;
60 u8 sc, sn, cl, ch, st;
65 iobase1 =GET_EBDA(ata.channels[channel].iobase1);
66 iobase2 =GET_EBDA(ata.channels[channel].iobase2);
69 outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2+ATA_CB_DC);
72 outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
73 outb(0x55, iobase1+ATA_CB_SC);
74 outb(0xaa, iobase1+ATA_CB_SN);
75 outb(0xaa, iobase1+ATA_CB_SC);
76 outb(0x55, iobase1+ATA_CB_SN);
77 outb(0x55, iobase1+ATA_CB_SC);
78 outb(0xaa, iobase1+ATA_CB_SN);
80 // If we found something
81 sc = inb(iobase1+ATA_CB_SC);
82 sn = inb(iobase1+ATA_CB_SN);
84 if ( (sc == 0x55) && (sn == 0xaa) ) {
85 SET_EBDA(ata.devices[device].type,ATA_TYPE_UNKNOWN);
90 // check for ATA or ATAPI
91 outb(slave ? ATA_CB_DH_DEV1 : ATA_CB_DH_DEV0, iobase1+ATA_CB_DH);
92 sc = inb(iobase1+ATA_CB_SC);
93 sn = inb(iobase1+ATA_CB_SN);
94 if ((sc==0x01) && (sn==0x01)) {
95 cl = inb(iobase1+ATA_CB_CL);
96 ch = inb(iobase1+ATA_CB_CH);
97 st = inb(iobase1+ATA_CB_STAT);
99 if ((cl==0x14) && (ch==0xeb)) {
100 SET_EBDA(ata.devices[device].type,ATA_TYPE_ATAPI);
101 } else if ((cl==0x00) && (ch==0x00) && (st!=0x00)) {
102 SET_EBDA(ata.devices[device].type,ATA_TYPE_ATA);
103 } else if ((cl==0xff) && (ch==0xff)) {
104 SET_EBDA(ata.devices[device].type,ATA_TYPE_NONE);
109 type=GET_EBDA(ata.devices[device].type);
111 // Now we send a IDENTIFY command to ATA device
112 if(type == ATA_TYPE_ATA) {
114 u16 cylinders, heads, spt, blksize;
115 u8 translation, removable, mode;
117 //Temporary values to do the transfer
118 SET_EBDA(ata.devices[device].device,ATA_DEVICE_HD);
119 SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16);
121 u16 ret = ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE
123 , GET_SEG(SS), (u32)buffer);
125 BX_PANIC("ata-detect: Failed to detect ATA device\n");
127 removable = (buffer[0] & 0x80) ? 1 : 0;
128 mode = buffer[96] ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
129 blksize = *(u16*)&buffer[10];
131 cylinders = *(u16*)&buffer[1*2]; // word 1
132 heads = *(u16*)&buffer[3*2]; // word 3
133 spt = *(u16*)&buffer[6*2]; // word 6
135 sectors = *(u32*)&buffer[60*2]; // word 60 and word 61
137 SET_EBDA(ata.devices[device].device,ATA_DEVICE_HD);
138 SET_EBDA(ata.devices[device].removable, removable);
139 SET_EBDA(ata.devices[device].mode, mode);
140 SET_EBDA(ata.devices[device].blksize, blksize);
141 SET_EBDA(ata.devices[device].pchs.heads, heads);
142 SET_EBDA(ata.devices[device].pchs.cylinders, cylinders);
143 SET_EBDA(ata.devices[device].pchs.spt, spt);
144 SET_EBDA(ata.devices[device].sectors, sectors);
145 BX_INFO("ata%d-%d: PCHS=%u/%d/%d translation=", channel, slave,cylinders, heads, spt);
147 translation = inb_cmos(0x39 + channel/2);
148 for (shift=device%4; shift>0; shift--)
152 SET_EBDA(ata.devices[device].translation, translation);
154 switch (translation) {
155 case ATA_TRANSLATION_NONE:
158 case ATA_TRANSLATION_LBA:
161 case ATA_TRANSLATION_LARGE:
164 case ATA_TRANSLATION_RECHS:
168 switch (translation) {
169 case ATA_TRANSLATION_NONE:
171 case ATA_TRANSLATION_LBA:
174 heads = sectors / 1024;
175 if (heads>128) heads = 255;
176 else if (heads>64) heads = 128;
177 else if (heads>32) heads = 64;
178 else if (heads>16) heads = 32;
180 cylinders = sectors / heads;
182 case ATA_TRANSLATION_RECHS:
183 // Take care not to overflow
185 if(cylinders>61439) cylinders=61439;
187 cylinders = (u16)((u32)(cylinders)*16/15);
189 // then go through the large bitshift process
190 case ATA_TRANSLATION_LARGE:
191 while(cylinders > 1024) {
195 // If we max out the head count
196 if (heads > 127) break;
200 // clip to 1024 cylinders in lchs
201 if (cylinders > 1024) cylinders=1024;
202 BX_INFO(" LCHS=%d/%d/%d\n", cylinders, heads, spt);
204 SET_EBDA(ata.devices[device].lchs.heads, heads);
205 SET_EBDA(ata.devices[device].lchs.cylinders, cylinders);
206 SET_EBDA(ata.devices[device].lchs.spt, spt);
209 SET_EBDA(ata.hdidmap[hdcount], device);
213 // Now we send a IDENTIFY command to ATAPI device
214 if(type == ATA_TYPE_ATAPI) {
216 u8 type, removable, mode;
219 //Temporary values to do the transfer
220 SET_EBDA(ata.devices[device].device,ATA_DEVICE_CDROM);
221 SET_EBDA(ata.devices[device].mode, ATA_MODE_PIO16);
223 u16 ret = ata_cmd_data_in(device,ATA_CMD_IDENTIFY_DEVICE_PACKET
225 , GET_SEG(SS), (u32)buffer);
227 BX_PANIC("ata-detect: Failed to detect ATAPI device\n");
229 type = buffer[1] & 0x1f;
230 removable = (buffer[0] & 0x80) ? 1 : 0;
231 mode = buffer[96] ? ATA_MODE_PIO32 : ATA_MODE_PIO16;
234 SET_EBDA(ata.devices[device].device, type);
235 SET_EBDA(ata.devices[device].removable, removable);
236 SET_EBDA(ata.devices[device].mode, mode);
237 SET_EBDA(ata.devices[device].blksize, blksize);
240 SET_EBDA(ata.cdidmap[cdcount], device);
246 u8 c, i, version=0, model[41];
250 sizeinmb = GET_EBDA(ata.devices[device].sectors);
253 // Read ATA/ATAPI version
254 ataversion=((u16)(buffer[161])<<8) | buffer[160];
255 for(version=15;version>0;version--) {
256 if ((ataversion&(1<<version))!=0)
262 model[i*2] = buffer[(i*2)+54+1];
263 model[(i*2)+1] = buffer[(i*2)+54];
279 printf("ata%d %s: ",channel,slave?" slave":"master");
281 while ((c=model[i++]))
283 if (sizeinmb < (1UL<<16))
284 printf(" ATA-%d Hard-Disk (%4u MBytes)\n", version, (u16)sizeinmb);
286 printf(" ATA-%d Hard-Disk (%4u GBytes)\n", version, (u16)(sizeinmb>>10));
289 printf("ata%d %s: ",channel,slave?" slave":"master");
291 while ((c=model[i++]))
293 if (GET_EBDA(ata.devices[device].device)==ATA_DEVICE_CDROM)
294 printf(" ATAPI-%d CD-Rom/DVD-Rom\n",version);
296 printf(" ATAPI-%d Device\n",version);
298 case ATA_TYPE_UNKNOWN:
299 printf("ata%d %s: Unknown device\n",channel,slave?" slave":"master");
304 // Store the devices counts
305 SET_EBDA(ata.hdcount, hdcount);
306 SET_EBDA(ata.cdcount, cdcount);
307 SET_BDA(disk_count, hdcount);
311 // FIXME : should use bios=cmos|auto|disable bits
312 // FIXME : should know about translation bits
313 // FIXME : move hard_drive_post here
319 disk_ret(struct bregs *regs, u8 code)
322 SET_BDA(disk_last_status, code);
326 // disk controller reset
328 disk_1300(struct bregs *regs, u8 device)
335 disk_1301(struct bregs *regs, u8 device)
337 regs->ah = GET_BDA(disk_last_status);
338 disk_ret(regs, DISK_RET_SUCCESS);
342 check_params(struct bregs *regs, u8 device)
346 u16 count = regs->al;
347 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
348 u16 sector = regs->cl & 0x3f;
351 if ((count > 128) || (count == 0) || (sector == 0)) {
352 BX_INFO("int13_harddisk: function %02x, parameter out of range!\n"
354 disk_ret(regs, DISK_RET_EPARAM);
358 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
359 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
360 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
362 bprintf(0, "dev=%d c=%d h=%d s=%d nc=%d nh=%d ns=%d\n"
363 , device, cylinder, head, sector
366 // sanity check on cyl heads, sec
367 if ( (cylinder >= nlc) || (head >= nlh) || (sector > nlspt )) {
368 BX_INFO("int13_harddisk: function %02x, parameters out of"
369 " range %04x/%04x/%04x!\n"
370 , regs->ah, cylinder, head, sector);
371 disk_ret(regs, DISK_RET_EPARAM);
378 disk_1302(struct bregs *regs, u8 device)
381 int ret = check_params(regs, device);
384 u16 count = regs->al;
385 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
386 u16 sector = regs->cl & 0x3f;
388 u16 nph = GET_EBDA(ata.devices[device].pchs.heads);
389 u16 npspt = GET_EBDA(ata.devices[device].pchs.spt);
391 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
392 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
395 // if needed, translate lchs to lba, and execute command
396 if ( (nph != nlh) || (npspt != nlspt)) {
397 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
399 sector = 0; // this forces the command to be lba
402 u16 segment = regs->es;
403 u16 offset = regs->bx;
405 u8 status = ata_cmd_data_in(device, ATA_CMD_READ_SECTORS
406 , count, cylinder, head, sector
407 , lba, segment, offset);
409 // Set nb of sector transferred
410 regs->al = GET_EBDA(ata.trsfsectors);
413 BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
414 disk_ret(regs, DISK_RET_EBADTRACK);
416 disk_ret(regs, DISK_RET_SUCCESS);
420 disk_1303(struct bregs *regs, u8 device)
423 int ret = check_params(regs, device);
426 u16 count = regs->al;
427 u16 cylinder = regs->ch | ((((u16) regs->cl) << 2) & 0x300);
428 u16 sector = regs->cl & 0x3f;
430 u16 nph = GET_EBDA(ata.devices[device].pchs.heads);
431 u16 npspt = GET_EBDA(ata.devices[device].pchs.spt);
433 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
434 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
437 // if needed, translate lchs to lba, and execute command
438 if ( (nph != nlh) || (npspt != nlspt)) {
439 lba = (((((u32)cylinder * (u32)nlh) + (u32)head) * (u32)nlspt)
441 sector = 0; // this forces the command to be lba
444 u16 segment = regs->es;
445 u16 offset = regs->bx;
447 u8 status = ata_cmd_data_out(device, ATA_CMD_READ_SECTORS
448 , count, cylinder, head, sector
449 , lba, segment, offset);
451 // Set nb of sector transferred
452 regs->al = GET_EBDA(ata.trsfsectors);
455 BX_INFO("int13_harddisk: function %02x, error %02x !\n",regs->ah,status);
456 disk_ret(regs, DISK_RET_EBADTRACK);
458 disk_ret(regs, DISK_RET_SUCCESS);
462 disk_1304(struct bregs *regs, u8 device)
464 int ret = check_params(regs, device);
468 disk_ret(regs, DISK_RET_SUCCESS);
471 #define DISK_STUB(regs) do { \
472 struct bregs *__regs = (regs); \
473 debug_stub(__regs); \
474 disk_ret(__regs, DISK_RET_SUCCESS); \
479 disk_1305(struct bregs *regs, u8 device)
484 // read disk drive parameters
486 disk_1308(struct bregs *regs, u8 device)
488 // Get logical geometry from table
489 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
490 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
491 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
492 u16 count = GET_EBDA(ata.hdcount);
494 nlc = nlc - 2; /* 0 based , last sector not used */
496 regs->ch = nlc & 0xff;
497 regs->cl = ((nlc >> 2) & 0xc0) | (nlspt & 0x3f);
499 regs->dl = count; /* FIXME returns 0, 1, or n hard drives */
501 // FIXME should set ES & DI
502 disk_ret(regs, DISK_RET_SUCCESS);
509 disk_1310(struct bregs *regs, u8 device)
511 // should look at 40:8E also???
513 // Read the status from controller
514 u8 status = inb(GET_EBDA(ata.channels[device/2].iobase1) + ATA_CB_STAT);
515 if ( (status & ( ATA_CB_STAT_BSY | ATA_CB_STAT_RDY )) == ATA_CB_STAT_RDY )
516 disk_ret(regs, DISK_RET_SUCCESS);
518 disk_ret(regs, DISK_RET_ENOTREADY);
521 // read disk drive size
523 disk_1315(struct bregs *regs, u8 device)
525 // Get logical geometry from table
526 u16 nlc = GET_EBDA(ata.devices[device].lchs.cylinders);
527 u16 nlh = GET_EBDA(ata.devices[device].lchs.heads);
528 u16 nlspt = GET_EBDA(ata.devices[device].lchs.spt);
530 // Compute sector count seen by int13
531 u32 lba = (u32)(nlc - 1) * (u32)nlh * (u32)nlspt;
532 regs->cx = lba >> 16;
533 regs->dx = lba & 0xffff;
536 regs->ah = 3; // hard disk accessible
540 disk_13XX(struct bregs *regs, u8 device)
542 BX_INFO("int13_harddisk: function %02xh unsupported, returns fail\n", regs->ah);
543 disk_ret(regs, DISK_RET_EPARAM);
547 disk_13(struct bregs *regs, u8 drive)
550 disk_13XX(regs, drive);
556 // clear completion flag
557 SET_BDA(disk_interrupt_flag, 0);
559 // basic check : device has to be defined
560 if (drive < 0x80 || drive >= 0x80 + CONFIG_MAX_ATA_DEVICES) {
561 disk_13XX(regs, drive);
565 // Get the ata channel
566 u8 device = GET_EBDA(ata.hdidmap[drive-0x80]);
568 // basic check : device has to be valid
569 if (device >= CONFIG_MAX_ATA_DEVICES) {
570 disk_13XX(regs, drive);
575 case 0x00: disk_1300(regs, device); break;
576 case 0x01: disk_1301(regs, device); break;
577 case 0x02: disk_1302(regs, device); break;
578 case 0x03: disk_1303(regs, device); break;
579 case 0x04: disk_1304(regs, device); break;
580 case 0x05: disk_1305(regs, device); break;
581 case 0x08: disk_1308(regs, device); break;
582 case 0x10: disk_1310(regs, device); break;
583 case 0x15: disk_1315(regs, device); break;
584 // XXX - several others defined
585 default: disk_13XX(regs, device); break;
590 handle_legacy_disk(struct bregs *regs, u8 drive)
593 floppy_13(regs, drive);
598 int13_cdrom(regs); // xxx
603 disk_13(regs, drive);
607 handle_40(struct bregs *regs)
610 handle_legacy_disk(regs, regs->dl);
614 // INT 13h Fixed Disk Services Entry Point
616 handle_13(struct bregs *regs)
622 if (regs->ah >= 0x4a || regs->ah <= 0x4d) {
623 int13_eltorito(regs);
624 } else if (cdemu_isactive() && cdrom_emulated_drive()) {
628 handle_legacy_disk(regs, drive);
632 // record completion in BIOS task complete flag
634 handle_76(struct bregs *regs)
637 SET_BDA(floppy_harddisk_info, 0xff);