3 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
12 #include <hw/vga/vga.h>
13 #include <hw/pci/pci.h>
14 #include <hw/dos/dos.h>
15 #include <hw/8254/8254.h> /* 8254 timer */
16 #include <hw/8259/8259.h> /* 8259 PIC interrupts */
17 #include <hw/vga/vgagui.h>
18 #include <hw/vga/vgatty.h>
19 #include <hw/ide/idelib.h>
42 const char *drive_readwrite_test_modes[] = {
44 "Mode: C/H/S MULTIPLE",
48 "Mode: LBA48 MULTIPLE"
51 struct drive_rw_test_info drive_rw_test_nfo;
53 char drive_readwrite_test_geo[128];
54 char drive_readwrite_test_chs[128];
55 char drive_readwrite_test_numsec[128];
56 char drive_readwrite_test_mult[128];
58 int drive_rw_test_mode_supported(struct drive_rw_test_info *nfo) {
59 if (!drive_rw_test_nfo.can_do_multiple &&
60 (nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE ||
61 nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
62 nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
65 if (!drive_rw_test_nfo.can_do_lba &&
66 (nfo->mode == DRIVE_RW_MODE_LBA ||
67 nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE ||
68 nfo->mode == DRIVE_RW_MODE_LBA48 ||
69 nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
72 if (!drive_rw_test_nfo.can_do_lba48 &&
73 (nfo->mode == DRIVE_RW_MODE_LBA48 ||
74 nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE))
80 void do_drive_readwrite_edit_chslba(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo,unsigned char editgeo) {
83 struct vga_msg_box box;
84 unsigned char redraw=1;
91 cyl = nfo->num_cylinder;
92 sect = nfo->num_sector;
103 vga_msg_box_create(&box,editgeo ?
104 "Edit disk geometry: " :
114 vga_moveto(box.x+2,box.y+2+1 + 0);
115 vga_write_color(0x1E);
116 vga_write("Cylinder: ");
117 vga_write_color(select == 0 ? 0x70 : 0x1E);
118 i=sprintf(temp_str,"%u",cyl);
119 while (i < (box.w-4-11)) temp_str[i++] = ' ';
123 vga_moveto(box.x+2,box.y+2+1 + 1);
124 vga_write_color(0x1E);
126 vga_write_color(select == 1 ? 0x70 : 0x1E);
127 i=sprintf(temp_str,"%u",head);
128 while (i < (box.w-4-11)) temp_str[i++] = ' ';
132 vga_moveto(box.x+2,box.y+2+1 + 2);
133 vga_write_color(0x1E);
134 vga_write("Sector: ");
135 vga_write_color(select == 2 ? 0x70 : 0x1E);
136 i=sprintf(temp_str,"%u",sect);
137 while (i < (box.w-4-11)) temp_str[i++] = ' ';
141 vga_moveto(box.x+2,box.y+2+1 + 3);
142 vga_write_color(0x1E);
144 vga_write_color(select == 3 ? 0x70 : 0x1E);
145 i=sprintf(temp_str,"%llu",lba);
146 while (i < (box.w-4-11)) temp_str[i++] = ' ';
152 if (c == 0) c = getch() << 8;
154 nextkey: if (c == 27) {
162 else if (c == 0x4800) {
163 if (--select < 0) select = 3;
166 else if (c == 0x5000 || c == 9/*tab*/) {
167 if (++select > 3) select = 0;
171 else if (c == 0x4B00) { /* left */
174 if (cyl == 0) cyl = editgeo ? 16383 : (nfo->num_cylinder - 1);
178 if (head == 0) head = editgeo ? 16 : (nfo->num_head - 1);
182 if (sect <= 1) sect = editgeo ? 256 : nfo->num_sector;
186 if (lba > 0ULL) lba--;
193 else if (c == 0x4D00) { /* right */
196 if ((++cyl) >= (editgeo ? 16384 : nfo->num_cylinder)) cyl = 0;
199 if ((++head) >= (editgeo ? 17 : nfo->num_head)) head = 0;
202 if ((++sect) >= (editgeo ? 257 : (nfo->num_sector+1))) sect = 1;
213 else if (c == 8 || isdigit(c)) {
214 unsigned int sy = box.y+2+1 + select;
215 unsigned int sx = box.x+2+11;
218 case 0: sprintf(temp_str,"%u",cyl); break;
219 case 1: sprintf(temp_str,"%u",head); break;
220 case 2: sprintf(temp_str,"%u",sect); break;
221 case 3: sprintf(temp_str,"%llu",lba); break;
225 i = strlen(temp_str) - 1;
230 i = strlen(temp_str);
231 if (i == 1 && temp_str[0] == '0') i--;
232 if ((i+2) < sizeof(temp_str)) {
233 temp_str[i++] = (char)c;
243 vga_write_color(0x70);
245 while (vga_pos_x < (box.x+box.w-4) && vga_pos_x != 0) vga_writec(' ');
249 if (c == 0) c = getch() << 8;
257 else if (isdigit(c)) {
258 if ((i+2) < sizeof(temp_str)) {
259 temp_str[i++] = (char)c;
270 case 0: tmp=strtoull(temp_str,NULL,0); cyl=(tmp > 16383ULL ? 16383ULL : tmp); break;
271 case 1: tmp=strtoull(temp_str,NULL,0); head=(tmp > 16ULL ? 16ULL : tmp); break;
272 case 2: tmp=strtoull(temp_str,NULL,0); sect=(tmp > 256ULL ? 256ULL : tmp); break;
273 case 3: lba=strtoull(temp_str,NULL,0); break;
282 if (sect == 0) sect = 1;
283 if (cyl > 16383) cyl = 16383;
286 if (cyl < 1) cyl = 1;
287 if (head < 1) head = 1;
288 if (head > 16) head = 16;
289 if (sect > 256) sect = 256;
292 if (lba >= (16383ULL * 16ULL * 63ULL)) {
298 cyl = (int)(lba / (unsigned long long)sect / (unsigned long long)head);
299 if (cyl < 0) cyl = 1;
300 if (cyl > 16383) cyl = 16383;
303 else if (cyl < 16383) {
304 lba = (unsigned long long)cyl * (unsigned long long)head * (unsigned long long)sect;
308 if (cyl < 0) cyl = 0;
309 if (head < 0) head = 0;
310 if (head > 15) head = 15;
311 if (sect > 255) sect = 255;
314 sect = (int)(lba % (unsigned long long)nfo->num_sector) + 1;
315 head = (int)((lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
316 if (lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
318 sect = nfo->num_sector;
319 head = nfo->num_head - 1;
322 cyl = (int)((lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
326 lba = (unsigned long long)cyl * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
327 lba += (unsigned long long)head * (unsigned long long)nfo->num_sector;
328 lba += (unsigned long long)sect - 1ULL;
340 vga_msg_box_destroy(&box);
344 nfo->num_cylinder = cyl;
345 nfo->num_sector = sect;
346 nfo->num_head = head;
358 void do_drive_readwrite_test_choose_mode(struct ide_controller *ide,unsigned char which,struct drive_rw_test_info *nfo) {
359 int select=drive_rw_test_nfo.mode;
360 struct menuboxbounds mbox;
367 /* UI element vars */
368 menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
369 menuboxbounds_set_item_strings_arraylen(&mbox,drive_readwrite_test_modes);
377 for (y=0;y < vga_height;y++) {
378 for (x=0;x < vga_width;x++) {
379 *vga++ = 0x1E00 + 177;
385 vga_write_color(0x1F);
386 vga_write(" IDE r/w test mode ");
387 sprintf(tmp,"@%X",ide->base_io);
389 if (ide->alt_io != 0) {
390 sprintf(tmp," alt %X",ide->alt_io);
394 sprintf(tmp," IRQ %d",ide->irq);
397 vga_write(which ? " Slave" : " Master");
399 sprintf(tmp," lba=%u lba48=%u multiple=%u",
400 drive_rw_test_nfo.can_do_lba?1:0,
401 drive_rw_test_nfo.can_do_lba48?1:0,
402 drive_rw_test_nfo.can_do_multiple?1:0);
405 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
407 vga_write_color(0xC);
408 vga_write("WARNING: This code talks directly to your hard disk controller.");
409 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
410 vga_write_color(0xC);
411 vga_write(" If you value the data on your hard drive do not run this program.");
412 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
418 vga_moveto(mbox.ofsx,mbox.ofsy - 2);
419 vga_write_color((select == -1) ? 0x70 : 0x0F);
421 while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
423 menuboxbound_redraw(&mbox,select);
427 if (c == 0) c = getch() << 8;
433 struct vga_msg_box vgabox;
435 if (!drive_rw_test_nfo.can_do_multiple &&
436 (select == DRIVE_RW_MODE_CHSMULTIPLE ||
437 select == DRIVE_RW_MODE_LBAMULTIPLE ||
438 select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
440 vga_msg_box_create(&vgabox,
441 "The IDE device doesn't seem to support SET MULTIPLE/READ MULTIPLE.\n"
442 "Are you sure you want to choose this mode?\n"
444 "Hit ENTER to proceed, ESC to cancel"
448 if (c == 0) c = getch() << 8;
449 } while (!(c == 13 || c == 27));
450 vga_msg_box_destroy(&vgabox);
451 if (c == 27) continue;
454 if (!drive_rw_test_nfo.can_do_lba &&
455 (select == DRIVE_RW_MODE_LBA ||
456 select == DRIVE_RW_MODE_LBAMULTIPLE ||
457 select == DRIVE_RW_MODE_LBA48 ||
458 select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
460 vga_msg_box_create(&vgabox,
461 "The IDE device doesn't seem to support LBA mode.\n"
462 "Are you sure you want to choose this mode?\n"
464 "Hit ENTER to proceed, ESC to cancel"
468 if (c == 0) c = getch() << 8;
469 } while (!(c == 13 || c == 27));
470 vga_msg_box_destroy(&vgabox);
471 if (c == 27) continue;
474 if (!drive_rw_test_nfo.can_do_lba48 &&
475 (select == DRIVE_RW_MODE_LBA48 ||
476 select == DRIVE_RW_MODE_LBA48_MULTIPLE)) {
478 vga_msg_box_create(&vgabox,
479 "The IDE device doesn't seem to support 48-bit LBA.\n"
480 "Are you sure you want to choose this mode?\n"
482 "Hit ENTER to proceed, ESC to cancel"
486 if (c == 0) c = getch() << 8;
487 } while (!(c == 13 || c == 27));
488 vga_msg_box_destroy(&vgabox);
489 if (c == 27) continue;
493 drive_rw_test_nfo.mode = select;
497 else if (c == 0x4800) {
499 select = mbox.item_max;
503 else if (c == 0x5000) {
504 if (++select > mbox.item_max)
512 /*-----------------------------------------------------------------*/
514 const char *drive_readwrite_tests_menustrings[] = {
515 "Show IDE register taskfile", /* 0 */
521 void do_drive_readwrite_tests(struct ide_controller *ide,unsigned char which) {
522 struct menuboxbounds mbox;
530 /* get geometry and max sector count *NOW* then the user can tweak them later */
531 memset(&drive_rw_test_nfo,0,sizeof(drive_rw_test_nfo));
535 c = do_ide_identify((unsigned char*)info,sizeof(info),ide,which,0xEC/*ATA IDENTIFY DEVICE*/);
538 drive_rw_test_nfo.can_do_lba = (info[49] & 0x200) ? 1 : 0;
539 drive_rw_test_nfo.can_do_multiple = ((info[47] & 0xFF) != 0) ? 1 : 0;
540 drive_rw_test_nfo.can_do_lba48 = drive_rw_test_nfo.can_do_lba && ((info[83] & 0x400) ? 1 : 0);
542 /* NTS: Never mind the thousands of OSes out there still using these fields, ATA-8 marks them "obsolete".
543 * Thanks. You guys realize this is the same logic behind the infuriating number of APIs in Windows
544 * that are "obsolete" yet everything relies on them?
546 * This is why you keep OLDER copies of standards around, guys! */
547 drive_rw_test_nfo.num_cylinder = info[54]; /* number of current logical cylinders */
548 drive_rw_test_nfo.num_head = info[55]; /* number of current logical heads */
549 drive_rw_test_nfo.num_sector = info[56]; /* number of current logical sectors */
550 if (drive_rw_test_nfo.num_cylinder == 0 && drive_rw_test_nfo.num_head == 0 && drive_rw_test_nfo.num_sector == 0) {
551 drive_rw_test_nfo.num_cylinder = info[1]; /* number of logical cylinders */
552 drive_rw_test_nfo.num_head = info[3]; /* number of logical heads */
553 drive_rw_test_nfo.num_sector = info[6]; /* number of logical sectors */
556 if (drive_rw_test_nfo.can_do_lba48)
557 drive_rw_test_nfo.max_lba = ((uint64_t)info[103] << 48ULL) + ((uint64_t)info[102] << 32ULL) +
558 ((uint64_t)info[101] << 16ULL) + ((uint64_t)info[100]);
559 if (drive_rw_test_nfo.max_lba == 0)
560 drive_rw_test_nfo.max_lba = ((uint64_t)info[61] << 16ULL) + ((uint64_t)info[60]);
561 if (drive_rw_test_nfo.max_lba == 0)
562 drive_rw_test_nfo.max_lba = ((uint64_t)info[58] << 16ULL) + ((uint64_t)info[57]);
564 drive_rw_test_nfo.sector = 1;
565 drive_rw_test_nfo.read_sectors = 1;
566 drive_rw_test_nfo.mode = DRIVE_RW_MODE_CHS;
567 if (drive_rw_test_nfo.can_do_multiple && (info[59]&0x100))
568 drive_rw_test_nfo.multiple_sectors = info[59]&0xFF;
569 if (drive_rw_test_nfo.can_do_multiple && (info[47]&0xFF) != 0)
570 drive_rw_test_nfo.max_multiple_sectors = info[47]&0xFF;
573 /* UI element vars */
574 menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
575 menuboxbounds_set_item_strings_arraylen(&mbox,drive_readwrite_tests_menustrings);
583 for (y=0;y < vga_height;y++) {
584 for (x=0;x < vga_width;x++) {
585 *vga++ = 0x1E00 + 177;
591 vga_write_color(0x1F);
592 vga_write(" IDE controller read/write tests ");
593 sprintf(tmp,"@%X",ide->base_io);
595 if (ide->alt_io != 0) {
596 sprintf(tmp," alt %X",ide->alt_io);
600 sprintf(tmp," IRQ %d",ide->irq);
603 vga_write(which ? " Slave" : " Master");
604 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
606 vga_write_color(0xC);
607 vga_write("WARNING: This code talks directly to your hard disk controller.");
608 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
609 vga_write_color(0xC);
610 vga_write(" If you value the data on your hard drive do not run this program.");
611 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
617 vga_moveto(mbox.ofsx,mbox.ofsy - 2);
618 vga_write_color((select == -1) ? 0x70 : 0x0F);
619 vga_write("Back to IDE controller main menu");
620 while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
622 menuboxbound_redraw(&mbox,select);
626 if (c == 0) c = getch() << 8;
636 case 0: /* show IDE register taskfile */
637 do_common_show_ide_taskfile(ide,which);
638 redraw = backredraw = 1;
640 case 1: /* Read tests */
641 do_drive_read_test(ide,which);
642 redraw = backredraw = 1;
644 case 2: /* Write tests */
645 do_drive_write_test(ide,which);
646 redraw = backredraw = 1;
648 case 3: /* Read verify tests */
650 do_drive_read_verify_test(ide,which);
651 redraw = backredraw = 1;
656 else if (c == 0x4800) {
658 select = mbox.item_max;
662 else if (c == 0x4B00) { /* left */
665 else if (c == 0x4D00) { /* right */
668 else if (c == 0x5000) {
669 if (++select > mbox.item_max)