3 * - Modularize copy-pasta'd code such as:
4 * * The "if you value your data" warning
5 * * ATAPI packet commands
6 * * EVERYTHING---This code basically works on test hardware, now it's time to clean it up
7 * modularize and refactor.
8 * - Add menu item where the user can ask this code to test whether or not the IDE controller
9 * supports 32-bit PIO properly.
10 * - Start using this code for reference and implementation of IDE emulation within DOSBox-X
11 * - Add menu items to allow the user to play with SET FEATURES command
12 * - Add submenu where the user can play with the S.M.A.R.T. ATA commands
13 * - **TEST THIS CODE ON AS MANY MACHINES AS POSSIBLE** The IDE interface is one of those
14 * hardware standards that is conceptually simple yet so manu manufacturers managed to fuck
15 * up their implementation in some way or another.
16 * - Cleanup this code, move library into idelib.c+idelib.h
17 * - Fix corner cases where we're IDE busy waiting and user commands to break free (ESC or spacebar
18 * do not break out of read/write loop, forcing the user to CTRL+ALT+DEL or press reset.
21 * - Test programs for specific IDE chipsets (like Intel PIIX3) to demonstrate IDE DMA READ/WRITE commands
24 * - Toshiba Satellite Pro 465CDX/2.1
25 * - Putting the hard drive to sleep seems to put the IDE controller to sleep too. IDE controller
26 * "busy" bit is stuck on when hard drive asleep. Only way out seems to be doing a "host reset"
27 * on that IDE controller. Note that NORMAL behavior is that the IDE controller remains not-busy
28 * but the device is not ready.
30 * - The CD-ROM drive (or secondary IDE?) appears to ignore 32-bit I/O to port 0x170 (base_io+0).
31 * If you attempt to read a sector or identify command results using 32-bit PIO, you get only
32 * 0xFFFFFFFF. Reading data only works when PIO is done as 16-bit. NORMAL behavior suggests
33 * either 32-bit PIO gets 32 bits at a time (PCI based IDE) or 32-bit PIO gets 16 bits of IDE
34 * data and 16 bits of the adjacent 16-bit I/O register due to 386/486-era ISA subdivision of
35 * 32-bit I/O into two 16-bit I/O reads. Supposedly, on pre-PCI controllers, 32-bit PIO could
36 * be made to work if you tell the card in advance using the "VLB keying sequence", but I have
37 * yet to find such a card.
39 * Known hardware this code has trouble with (so far):
41 * - Ancient (1999-2002-ish) DVD-ROM drives. They generally work with this code but there seem to be a lot
42 * of edge cases. One DVD-ROM drive I own will not raise "drive ready" after receipt of a command it doesn't
46 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
55 #include <hw/vga/vga.h>
56 #include <hw/pci/pci.h>
57 #include <hw/dos/dos.h>
58 #include <hw/8254/8254.h> /* 8254 timer */
59 #include <hw/8259/8259.h> /* 8259 PIC interrupts */
60 #include <hw/vga/vgagui.h>
61 #include <hw/vga/vgatty.h>
62 #include <hw/ide/idelib.h>
84 #include <hw/isapnp/isapnp.h>
85 #include <hw/sndsb/sndsbpnp.h>
88 unsigned char opt_ignore_smartdrv = 0;
89 unsigned char opt_no_irq = 0;
90 unsigned char opt_no_pci = 0;
91 unsigned char opt_no_isapnp = 0;
92 unsigned char opt_no_isa_probe = 0;
93 unsigned char opt_irq_chain = 1;
95 unsigned char cdrom_read_mode = 12;
96 unsigned char pio_width_warning = 1;
97 unsigned char big_scary_write_test_warning = 1;
100 uint16_t ide_info[256];
102 static unsigned char far devnode_raw[4096];
105 #if TARGET_MSDOS == 32
106 unsigned char cdrom_sector[512U*256U];/* ~128KB, enough for 64 CD-ROM sector or 256 512-byte sectors */
108 # if defined(__LARGE__) || defined(__COMPACT__)
109 unsigned char cdrom_sector[512U*16U]; /* ~8KB, enough for 4 CD-ROM sector or 16 512-byte sectors */
111 unsigned char cdrom_sector[512U*8U]; /* ~4KB, enough for 2 CD-ROM sector or 8 512-byte sectors */
115 /*-----------------------------------------------------------------*/
117 static const char *drive_main_menustrings[] = {
118 "Show IDE register taskfile", /* 0 */
120 "Identify packet (ATAPI)",
122 "PIO mode >>", /* 4 */ /* rewritten */
124 "Tweaks and adjustments >>",
125 "CD-ROM eject/load >>",
128 "Read/Write tests >>", /* 10 */
132 void do_ide_controller_drive(struct ide_controller *ide,unsigned char which) {
133 struct menuboxbounds mbox;
141 /* UI element vars */
142 menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
143 menuboxbounds_set_item_strings_arraylen(&mbox,drive_main_menustrings);
145 /* most of the commands assume a ready controller. if it's stuck,
146 * we'd rather the user have a visual indication that it's stuck that way */
147 c = do_ide_controller_user_wait_busy_controller(ide);
150 /* select the drive we want */
151 idelib_controller_drive_select(ide,which,/*head*/0,IDELIB_DRIVE_SELECT_MODE_CHS);
153 /* in case the IDE controller is busy for that time */
154 c = do_ide_controller_user_wait_busy_controller(ide);
157 /* read back: did the drive select take effect? if not, it might not be there. another common sign is the head/drive select reads back 0xFF */
158 c = do_ide_controller_drive_check_select(ide,which);
161 /* it might be a CD-ROM drive, which in some cases might not raise the Drive Ready bit */
162 do_ide_controller_atapi_device_check_post_host_reset(ide);
164 /* wait for the drive to indicate readiness */
165 /* NTS: If the drive never becomes ready even despite our reset hacks, there's a strong
166 * possibility that the device doesn't exist. This can happen for example if there
167 * is a master attached but no slave. */
168 c = do_ide_controller_user_wait_drive_ready(ide);
171 /* for completeness, clear pending IRQ */
172 idelib_controller_ack_irq(ide);
180 for (y=0;y < vga_height;y++) {
181 for (x=0;x < vga_width;x++) {
182 *vga++ = 0x1E00 + 177;
188 vga_write_color(0x1F);
189 vga_write(" IDE controller ");
190 sprintf(tmp,"@%X",ide->base_io);
192 if (ide->alt_io != 0) {
193 sprintf(tmp," alt %X",ide->alt_io);
197 sprintf(tmp," IRQ %d",ide->irq);
200 vga_write(which ? " Slave" : " Master");
201 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
203 vga_write_color(0xC);
204 vga_write("WARNING: This code talks directly to your hard disk controller.");
205 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
206 vga_write_color(0xC);
207 vga_write(" If you value the data on your hard drive do not run this program.");
208 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
214 /* update a string or two: PIO mode */
215 if (ide->pio_width == 33)
216 drive_main_menustrings[4] = "PIO mode (currently: 32-bit VLB) >>";
217 else if (ide->pio_width == 32)
218 drive_main_menustrings[4] = "PIO mode (currently: 32-bit) >>";
220 drive_main_menustrings[4] = "PIO mode (currently: 16-bit) >>";
222 vga_moveto(mbox.ofsx,mbox.ofsy - 2);
223 vga_write_color((select == -1) ? 0x70 : 0x0F);
224 vga_write("Back to IDE controller main menu");
225 while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
227 menuboxbound_redraw(&mbox,select);
231 if (c == 0) c = getch() << 8;
241 case 0: /* show IDE register taskfile */
242 do_common_show_ide_taskfile(ide,which);
243 redraw = backredraw = 1;
246 case 2: /*Identify packet*/
247 do_drive_identify_device_test(ide,which,select == 2 ? 0xA1/*Identify packet*/ : 0xEC/*Identify*/);
248 redraw = backredraw = 1;
250 case 3: /* power states */
252 do_drive_power_states_test(ide,which);
253 redraw = backredraw = 1;
256 case 4: /* PIO mode */
258 do_drive_pio_mode(ide,which);
259 redraw = backredraw = 1;
264 do_ide_controller_drive_nop_test(ide,which);
267 case 6: /* Tweaks and adjustments */
269 do_drive_tweaks_and_adjustments(ide,which);
270 redraw = backredraw = 1;
273 case 7: /* CD-ROM start/stop/eject/load */
274 do_drive_cdrom_startstop_test(ide,which);
275 redraw = backredraw = 1;
277 case 8: /* CD-ROM reading */
278 do_drive_cdrom_reading(ide,which);
279 redraw = backredraw = 1;
281 case 9: /* multiple mode */
282 #ifdef MULTIPLE_MODE_MENU
283 do_drive_multiple_mode(ide,which);
284 redraw = backredraw = 1;
287 case 10: /* read/write tests */
288 do_drive_readwrite_tests(ide,which);
289 redraw = backredraw = 1;
293 do_drive_misc_tests(ide,which);
294 redraw = backredraw = 1;
299 else if (c == 0x4800) {
301 select = mbox.item_max;
305 else if (c == 0x4B00) { /* left */
308 else if (c == 0x4D00) { /* right */
311 else if (c == 0x5000) {
312 if (++select > mbox.item_max)
320 static void (interrupt *my_ide_old_irq)() = NULL;
321 static struct ide_controller *my_ide_irq_ide = NULL;
322 static unsigned long ide_irq_counter = 0;
323 static int my_ide_irq_number = -1;
325 static void interrupt my_ide_irq() {
330 /* we CANNOT use sprintf() here. sprintf() doesn't work to well from within an interrupt handler,
331 * and can cause crashes in 16-bit realmode builds. */
332 i = vga_width*(vga_height-1);
333 vga_alpha_ram[i++] = 0x1F00 | 'I';
334 vga_alpha_ram[i++] = 0x1F00 | 'R';
335 vga_alpha_ram[i++] = 0x1F00 | 'Q';
336 vga_alpha_ram[i++] = 0x1F00 | ':';
337 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 100000UL) % 10UL));
338 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 10000UL) % 10UL));
339 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 1000UL) % 10UL));
340 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 100UL) % 10UL));
341 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 10UL) % 10UL));
342 vga_alpha_ram[i++] = 0x1F00 | ('0' + ((ide_irq_counter / 1L) % 10UL));
343 vga_alpha_ram[i++] = 0x1F00 | ' ';
346 if (my_ide_irq_ide != NULL) {
347 my_ide_irq_ide->irq_fired++;
349 /* NTS: This code requires some explanation: On an Intel Core i3 mini-itx motherboard I recently
350 * bought, the SATA controller (in IDE mode) has a problem with IDE interrupts where for reasons
351 * beyond my understanding, once the IRQ fires, the IRQ continues to fire and will not stop no
352 * matter what registers we read or ports we poke. It fires rapidly enough that our busy wait
353 * code cannot proceed and the program "hangs" while the IRQ counter on the screen counts upward
354 * very fast. It is only when exiting back to DOS that the BIOS somehow makes it stop.
356 * That motherboard is the reason this code was implemented. should any other SATA/IDE controller
357 * have this problem, this code will eventually stop the IRQ flood by masking off the IRQ and
358 * switching the IDE controller struct into polling mode so that the user can continue to use
359 * this program without having to hit the reset button!
361 * Another Intel Core i3 system (2010) has the same problem, with SATA ports and one IDE port.
362 * This happens even when talking to the IDE port and not the SATA-IDE emulation.
364 * It seems to be a problem with Intel-based motherboards, 2010 or later.
366 * Apparently the fix is to chain to the BIOS IRQ handler, which knows how to cleanup the IRQ signal. */
368 /* ack IRQ on IDE controller */
369 idelib_controller_ack_irq(my_ide_irq_ide);
372 if (!opt_irq_chain || my_ide_old_irq == NULL) {
374 if (my_ide_irq_ide->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
375 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
378 /* chain to previous */
382 /* If too many IRQs fired, then stop the IRQ and use polling from now on. */
383 if (my_ide_irq_ide != NULL) {
384 if (my_ide_irq_ide->irq_fired >= 0xFFFEU) {
385 do_ide_controller_emergency_halt_irq(my_ide_irq_ide);
386 vga_alpha_ram[i+12] = 0x1C00 | '!';
387 my_ide_irq_ide->irq_fired = ~0; /* make sure the IRQ counter is as large as possible */
392 void do_ide_controller_hook_irq(struct ide_controller *ide) {
393 if (my_ide_irq_number >= 0 || ide->irq < 0)
396 /* let the IRQ know what IDE controller */
397 my_ide_irq_ide = ide;
399 /* enable on IDE controller */
400 p8259_mask(ide->irq);
401 idelib_otr_enable_interrupt(ide,1);
402 idelib_controller_ack_irq(ide);
405 my_ide_old_irq = _dos_getvect(irq2int(ide->irq));
406 _dos_setvect(irq2int(ide->irq),my_ide_irq);
407 my_ide_irq_number = ide->irq;
410 p8259_unmask(ide->irq);
413 void do_ide_controller_unhook_irq(struct ide_controller *ide) {
414 if (my_ide_irq_number < 0 || ide->irq < 0)
417 /* disable on IDE controller, then mask at PIC */
418 p8259_mask(ide->irq);
419 idelib_controller_ack_irq(ide);
420 idelib_otr_enable_interrupt(ide,0);
422 /* restore the original vector */
423 _dos_setvect(irq2int(ide->irq),my_ide_old_irq);
424 my_ide_irq_number = -1;
425 my_ide_old_irq = NULL;
428 void do_ide_controller_emergency_halt_irq(struct ide_controller *ide) {
429 /* disable on IDE controller, then mask at PIC */
430 if (ide->irq >= 0) p8259_mask(ide->irq);
431 idelib_controller_ack_irq(ide);
432 idelib_otr_enable_interrupt(ide,0);
435 void do_ide_controller_enable_irq(struct ide_controller *ide,unsigned char en) {
436 if (!en || ide->irq < 0 || ide->irq != my_ide_irq_number)
437 do_ide_controller_unhook_irq(ide);
438 if (en && ide->irq >= 0)
439 do_ide_controller_hook_irq(ide);
442 void do_ide_controller(struct ide_controller *ide) {
443 struct vga_msg_box vgabox;
451 /* we're taking a drive, possibly out from MS-DOS.
452 * make sure SMARTDRV flushes the cache so that it does not attempt to
453 * write to the disk while we're controlling the IDE controller */
454 if (smartdrv_version != 0) {
455 for (c=0;c < 4;c++) smartdrv_flush();
458 /* most of the commands assume a ready controller. if it's stuck,
459 * we'd rather the user have a visual indication that it's stuck that way */
460 c = do_ide_controller_user_wait_busy_controller(ide);
463 /* if the IDE struct says to use interrupts, then do it */
464 do_ide_controller_enable_irq(ide,ide->flags.io_irq_enable);
472 for (y=0;y < vga_height;y++) {
473 for (x=0;x < vga_width;x++) {
474 *vga++ = 0x1E00 + 177;
480 vga_write_color(0x1F);
481 vga_write(" IDE controller ");
482 sprintf(tmp,"@%X",ide->base_io);
484 if (ide->alt_io != 0) {
485 sprintf(tmp," alt %X",ide->alt_io);
489 sprintf(tmp," IRQ %d",ide->irq);
492 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
494 vga_write_color(0xC);
495 vga_write("WARNING: This code talks directly to your hard disk controller.");
496 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
497 vga_write_color(0xC);
498 vga_write(" If you value the data on your hard drive do not run this program.");
499 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
507 vga_write_color((select == -1) ? 0x70 : 0x0F);
508 vga_write("Main menu");
509 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
513 vga_write_color((select == 0) ? 0x70 : 0x0F);
514 vga_write("Host Reset");
515 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
518 vga_write_color((select == 1) ? 0x70 : 0x0F);
519 vga_write("Tinker with Master device");
520 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
523 vga_write_color((select == 2) ? 0x70 : 0x0F);
524 vga_write("Tinker with Slave device");
525 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
528 vga_write_color((select == 3) ? 0x70 : 0x0F);
529 vga_write("Currently using ");
530 vga_write(ide->flags.io_irq_enable ? "IRQ" : "polling");
531 vga_write(", switch to ");
532 vga_write((!ide->flags.io_irq_enable) ? "IRQ" : "polling");
533 while (vga_pos_x < (vga_width-8) && vga_pos_x != 0) vga_writec(' ');
537 if (c == 0) c = getch() << 8;
546 else if (select == 0) { /* host reset */
547 if (ide->alt_io != 0) {
548 vga_msg_box_create(&vgabox,"Host reset in progress",0,0);
550 idelib_device_control_set_reset(ide,1);
551 t8254_wait(t8254_us2ticks(1000000));
552 idelib_device_control_set_reset(ide,0);
554 vga_msg_box_destroy(&vgabox);
556 /* now wait for not busy */
557 do_ide_controller_user_wait_busy_controller(ide);
560 else if (select == 1) {
561 do_ide_controller_drive(ide,0/*master*/);
562 redraw = backredraw = 1;
564 else if (select == 2) {
565 do_ide_controller_drive(ide,1/*slave*/);
566 redraw = backredraw = 1;
568 else if (select == 3) {
570 ide->flags.io_irq_enable = !ide->flags.io_irq_enable;
572 ide->flags.io_irq_enable = 0;
574 do_ide_controller_enable_irq(ide,ide->flags.io_irq_enable);
575 redraw = backredraw = 1;
578 else if (c == 0x4800) {
584 else if (c == 0x5000) {
592 do_ide_controller_enable_irq(ide,0);
593 idelib_otr_enable_interrupt(ide,1); /* NTS: Most BIOSes know to unmask the IRQ at the PIC, but there might be some
594 idiot BIOSes who don't clear the nIEN bit in the device control when
595 executing INT 13h, so it's probably best to do it for them. */
598 void do_main_menu() {
602 struct ide_controller *ide;
613 for (y=0;y < vga_height;y++) {
614 for (x=0;x < vga_width;x++) {
615 *vga++ = 0x1E00 + 177;
621 vga_write_color(0x1F);
622 vga_write(" IDE controller test program");
623 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
625 vga_write_color(0xC);
626 vga_write("WARNING: This code talks directly to your hard disk controller.");
627 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
628 vga_write_color(0xC);
629 vga_write(" If you value the data on your hard drive do not run this program.");
630 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
638 vga_write_color((select == -1) ? 0x70 : 0x0F);
639 vga_write("Exit program");
642 for (i=0;i < MAX_IDE_CONTROLLER;i++) {
643 ide = idelib_get_controller(i);
646 vga_write_color((select == (int)i) ? 0x70 : 0x0F);
648 sprintf(tmp,"Controller @ %04X",ide->base_io);
651 if (ide->alt_io != 0) {
652 sprintf(tmp," alt %04X",ide->alt_io);
657 sprintf(tmp," IRQ %2d",ide->irq);
665 if (c == 0) c = getch() << 8;
674 else if (select >= 0 && select < MAX_IDE_CONTROLLER) {
675 ide = idelib_get_controller(select);
676 if (ide != NULL) do_ide_controller(ide);
677 backredraw = redraw = 1;
680 else if (c == 0x4800) {
682 select = MAX_IDE_CONTROLLER - 1;
686 while (select >= 0 && idelib_get_controller(select) == NULL)
691 else if (c == 0x5000) {
693 while (select >= 0 && select < MAX_IDE_CONTROLLER && idelib_get_controller(select) == NULL)
695 if (select >= MAX_IDE_CONTROLLER)
704 printf("test [options]\n");
706 printf("IDE ATA/ATAPI test program\n");
707 printf("(C) 2012-2015 Jonathan Campbell, Hackipedia.org\n");
709 printf(" /NS Don't check if SMARTDRV is resident\n");
710 printf(" /NOIRQ Don't use IRQ by default\n");
712 printf(" /NOPCI Don't scan PCI bus\n");
715 printf(" /NOISAPNP Don't scan ISA Plug & Play BIOS\n");
717 printf(" /NOPROBE Don't probe ISA legacy ports\n");
718 printf(" /IRQCHAIN IRQ should chain to previous handler (default)\n");
719 printf(" /IRQNOCHAIN IRQ should NOT chain to previous handler\n");
722 int parse_argv(int argc,char **argv) {
726 for (i=1;i < argc;) {
730 do { a++; } while (*a == '/');
732 if (!strcasecmp(a,"?") || !strcasecmp(a,"h") || !strcasecmp(a,"help")) {
736 else if (!strcasecmp(a,"ns")) {
737 opt_ignore_smartdrv = 1;
739 else if (!strcasecmp(a,"irqnochain")) {
742 else if (!strcasecmp(a,"irqchain")) {
745 else if (!strcasecmp(a,"noirq")) {
748 else if (!strcasecmp(a,"nopci")) {
751 else if (!strcasecmp(a,"noisapnp")) {
754 else if (!strcasecmp(a,"noprobe")) {
755 opt_no_isa_probe = 1;
758 printf("Unknown switch %s\n",a);
771 int main(int argc,char **argv) {
772 struct ide_controller *idectrl;
773 struct ide_controller *newide;
776 if (parse_argv(argc,argv))
779 if (!opt_ignore_smartdrv) {
780 if (smartdrv_detect()) {
781 printf("WARNING: SMARTDRV %u.%02u or equivalent disk cache detected!\n",smartdrv_version>>8,smartdrv_version&0xFF);
783 printf(" Running this program with SMARTDRV enabled is NOT RECOMMENDED,\n");
784 printf(" especially when using the snapshot functions!\n");
785 printf(" If you choose to test anyway, this program will attempt to flush\n");
786 printf(" the disk cache as much as possible to avoid conflict.\n");
791 /* we take a GUI-based approach (kind of) */
793 printf("Cannot init VGA\n");
796 /* the IDE code has some timing requirements and we'll use the 8254 to do it */
797 /* I bet that by the time motherboard manufacturers stop implementing the 8254 the legacy DOS support this
798 * program requires to run will be long gone too. */
800 printf("8254 chip not detected\n");
803 /* interrupt controller */
805 printf("8259 chip not detected\n");
808 if (!init_idelib()) {
809 printf("Cannot init IDE lib\n");
814 if (pci_probe(-1/*default preference*/) != PCI_CFG_NONE) {
815 uint8_t bus,dev,func,iport;
817 printf("PCI bus detected.\n");
818 if (pci_bios_last_bus == -1) {
819 printf(" Autodetecting PCI bus count...\n");
820 pci_probe_for_last_bus();
822 printf(" Last bus: %d\n",pci_bios_last_bus);
823 printf(" Bus decode bits: %d\n",pci_bus_decode_bits);
824 for (bus=0;bus <= pci_bios_last_bus;bus++) {
825 for (dev=0;dev < 32;dev++) {
826 uint8_t functions = pci_probe_device_functions(bus,dev);
827 for (func=0;func < functions;func++) {
828 /* make sure something is there before announcing it */
829 uint16_t vendor,device,subsystem,subvendor_id;
830 struct ide_controller ide={0};
836 vendor = pci_read_cfgw(bus,dev,func,0x00); if (vendor == 0xFFFF) continue;
837 device = pci_read_cfgw(bus,dev,func,0x02); if (device == 0xFFFF) continue;
838 subvendor_id = pci_read_cfgw(bus,dev,func,0x2C);
839 subsystem = pci_read_cfgw(bus,dev,func,0x2E);
840 class_code = pci_read_cfgl(bus,dev,func,0x08);
841 revision_id = class_code & 0xFF;
844 /* must be: class 0x01 (mass storage) 0x01 (IDE controller) */
845 if ((class_code&0xFFFF00UL) != 0x010100UL)
848 /* read the command register. is the device enabled? */
849 reg = pci_read_cfgw(bus,dev,func,0x04); /* read Command register */
850 if (!(reg&1)) continue; /* if the I/O space bit is cleared, then no */
853 printf(" Found PCI IDE controller %02x:%02x:%02x class=0x%06x\n",bus,dev,func,class_code&0xFFFFFFUL);
855 /* enumerate from THAT the primary and secondary IDE */
856 for (iport=0;iport < 2;iport++) {
857 if (class_code&(0x01 << (iport*2))) { /* bit 0 is set if primary in native, bit 2 if secondary in native */
860 /* read it from the BARs */
861 reg = pci_read_cfgl(bus,dev,func,0x10+(iport*8)); /* command block */
862 if ((reg&1) && (reg&0xFFFF0000UL) == 0UL) /* copy down IF an I/O resource */
863 ide.base_io = reg & 0xFFFC;
865 reg = pci_read_cfgl(bus,dev,func,0x14+(iport*8)); /* control block */
866 if ((reg&1) && (reg&0xFFFF0000UL) == 0UL) { /* copy down IF an I/O resource */
867 /* NTS: This requires some explanation: The PCI I/O resource encoding cannot
868 * represent I/O port ranges smaller than 4 ports, nor can it represent
869 * a 4-port resource unless the base port is a multiple of the I/O port
872 * The alt I/O port on legacy systems is 0x3F6/0x376. For a PCI device to
873 * declare the same range, it must effectively declare 0x3F4/0x374 to
874 * 0x3F7/377 and then map the legacy ports from 2 ports in from the base.
876 * When a newer chipset uses a different base port, the same rule applies:
877 * the I/O resource is 4 ports large, and the last 2 ports (base+2) are
878 * the legacy IDE I/O ports that would be 0x3F6/0x376. */
879 ide.alt_io = (reg & 0xFFFC) + 2;
882 /* get IRQ number and PCI interrupt (A-D) */
883 IRQ_n = pci_read_cfgb(bus,dev,func,0x3C);
884 IRQ_pin = pci_read_cfgb(bus,dev,func,0x3D);
885 if (IRQ_n != 0 && IRQ_n < 16 && IRQ_pin != 0 && IRQ_pin <= 4)
890 if (ide.base_io != 0 && (ide.base_io&7) == 0) {
891 printf(" PCI IDE%u in native mode, IRQ=%d base=0x%3x alt=0x%3x\n",
892 iport,ide.irq,ide.base_io,ide.alt_io);
894 if ((newide = idelib_probe(&ide)) == NULL)
895 printf(" Warning: probe failed\n");
897 /* HACK: An ASUS Intel Core i3 motherboard I own has a SATA controller
898 * that has problems with IDE interrupts (when set to IDE mode).
899 * Once an IDE interrupt fires there's no way to shut it off and
900 * the controller crapfloods the PIC causing our program to "hang"
901 * running through the IRQ handler. */
902 if (vendor == 0x8086 && device == 0x8C80) { /* Intel Haswell-based motherboard (2014) */
903 idelib_enable_interrupt(newide,0); /* don't bother with interrupts */
908 /* "compatability mode".
909 * this is retarded, why didn't the PCI standards people just come out and
910 * say: guys, if you're a PCI device then frickin' show up as a proper PCI
911 * device and announce what resources you're using in the BARs and IRQ
912 * registers so OSes are not required to guess like this! */
913 ide.base_io = iport ? 0x170 : 0x1F0;
914 ide.alt_io = iport ? 0x376 : 0x3F6;
915 ide.irq = iport ? 15 : 14;
917 printf(" PCI IDE%u in compat mode, IRQ=%d base=0x%3x alt=0x%3x\n",
918 iport,ide.irq,ide.base_io,ide.alt_io);
920 if ((newide = idelib_probe(&ide)) == NULL)
921 printf(" Warning: probe failed\n");
931 if (!opt_no_isapnp) {
932 if (!init_isa_pnp_bios()) {
933 printf("Cannot init ISA PnP\n");
935 if (find_isa_pnp_bios()) {
936 unsigned int nodesize=0;
937 unsigned char node=0,numnodes=0xFF,data[192];
939 memset(data,0,sizeof(data));
940 printf("ISA PnP BIOS detected\n");
941 if (isa_pnp_bios_get_pnp_isa_cfg(data) == 0) {
942 struct isapnp_pnp_isa_cfg *nfo = (struct isapnp_pnp_isa_cfg*)data;
943 isapnp_probe_next_csn = nfo->total_csn;
944 isapnp_read_data = nfo->isa_pnp_port;
947 printf(" ISA PnP BIOS failed to return configuration info\n");
950 /* enumerate device nodes reported by the BIOS */
951 if (isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize) == 0 && numnodes != 0xFF && nodesize <= sizeof(devnode_raw)) {
952 printf("Scanning ISA PnP BIOS devices...\n");
953 for (node=0;node != 0xFF;) {
954 struct isa_pnp_device_node far *devn;
955 unsigned char far *rsc, far *rf;
956 unsigned char this_node;
957 struct isapnp_tag tag;
958 unsigned int ioport1=0;
959 unsigned int ioport2=0;
963 /* apparently, start with 0. call updates node to
964 * next node number, or 0xFF to signify end */
966 if (isa_pnp_bios_get_sysdev_node(&node,devnode_raw,ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW) != 0) break;
968 devn = (struct isa_pnp_device_node far*)devnode_raw;
969 if (devn->type_code[0] == 0x01/*system device, hard disk controller*/ &&
970 devn->type_code[1] == 0x01/*Generic ESDI/IDE/ATA controller*/ &&
971 devn->type_code[2] == 0x00/*Generic IDE*/) {
972 rsc = (unsigned char far*)devn + sizeof(*devn);
973 rf = (unsigned char far*)devn + sizeof(devnode_raw);
976 if (!isapnp_read_tag(&rsc,rf,&tag))
978 if (tag.tag == ISAPNP_TAG_END)
981 /* NTS: A Toshiba Satellite 465CDX I own lists the primary IDE controller's alt port range (0x3F6)
982 * as having length == 1 for some reason. Probably because of the floppy controller. */
985 case ISAPNP_TAG_IO_PORT: {
986 struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
987 if (ioport1 == 0 && x->length == 8)
988 ioport1 = x->min_range;
989 else if (ioport2 == 0 && (x->length == 1 || x->length == 2 || x->length == 4))
990 ioport2 = x->min_range;
992 case ISAPNP_TAG_FIXED_IO_PORT: {
993 struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
994 if (ioport1 == 0 && x->length == 8)
996 else if (ioport2 == 0 && (x->length == 1 || x->length == 2 || x->length == 4))
999 case ISAPNP_TAG_IRQ_FORMAT: {
1000 struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
1001 for (i=0;i < 16;i++) {
1002 if (x->irq_mask & (1U << (unsigned int)i)) { /* NTS: PnP devices usually support odd IRQs like IRQ 9 */
1003 if (irq < 0) irq = i;
1011 struct ide_controller n;
1013 printf(" Found PnP IDE controller: base=0x%03x alt=0x%03x IRQ=%d\n",
1014 ioport1,ioport2,irq);
1016 memset(&n,0,sizeof(n));
1017 n.base_io = ioport1;
1019 n.irq = (int8_t)irq; /* -1 is no IRQ */
1020 if ((newide = idelib_probe(&n)) == NULL) {
1021 printf(" Warning: probe failed\n");
1022 /* not filling it in leaves it open for allocation again */
1032 if (!opt_no_isa_probe) {
1033 printf("Probing standard IDE ports...\n");
1034 for (i=0;(idectrl = (struct ide_controller*)idelib_get_standard_isa_port(i)) != NULL;i++) {
1035 printf(" %3X/%3X IRQ %d: ",idectrl->base_io,idectrl->alt_io,idectrl->irq); fflush(stdout);
1037 if ((newide = idelib_probe(idectrl)) != NULL) {
1038 printf("FOUND: alt=%X irq=%d\n",newide->alt_io,newide->irq);
1041 printf("\x0D \x0D"); fflush(stdout);
1049 for (i=0;i < MAX_IDE_CONTROLLER;i++) {
1050 struct ide_controller *ide = &ide_controller[i];
1051 if (idelib_controller_allocated(ide)) idelib_enable_interrupt(ide,0); /* don't bother with interrupts */
1055 printf("Hit ENTER to continue, ESC to cancel\n");
1056 i = wait_for_enter_or_escape();
1063 if (int10_getmode() != 3) {
1065 update_state_from_vga();