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 static const char *drive_read_verify_test_menustrings[] = {
43 "Show IDE register taskfile", /* 0 */
44 "*mode*", /* 1 */ /* rewritten (CHS, LBA, CHS MULTI, etc) */
45 drive_readwrite_test_geo,
46 drive_readwrite_test_chs,
47 drive_readwrite_test_numsec,
48 "Read verify sectors",
49 "Read verify sectors continuously"
52 static void do_hdd_drive_read_verify_test(struct ide_controller *ide,unsigned char which,unsigned char continuous,struct drive_rw_test_info *nfo) {
53 unsigned char user_esc = 0;
54 struct ide_taskfile *tsk;
55 unsigned long tlen_sect;
56 unsigned int cleared=0;
59 if (nfo->read_sectors == 0) return;
60 if (nfo->multiple_sectors == 0) return;
62 idelib_controller_reset_irq_counter(ide); /* IRQ will fire after command completion */
63 tsk = idelib_controller_get_taskfile(ide,-1/*selected drive*/);
65 again: /* jump point: send execution back here for another sector */
66 if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
68 idelib_controller_ack_irq(ide); /* <- make sure to ack IRQ */
70 tlen_sect = nfo->read_sectors;
71 /* C/H/S continuous: limit reads to within track, don't cross. we can't assume the drive will do that. */
72 if (continuous && (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE)) {
73 if ((nfo->sector + tlen_sect) > nfo->num_sector)
74 tlen_sect = (nfo->num_sector + 1 - nfo->sector);
77 if (nfo->mode == DRIVE_RW_MODE_LBA48 || nfo->mode == DRIVE_RW_MODE_LBA48_MULTIPLE) {
78 tsk->sector_count = tlen_sect;
79 tsk->lba0_3 = nfo->lba & 0xFF;
80 tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
81 tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
82 tsk->lba0_3 |= ((nfo->lba >> 24) & 0xFF) << 8;
83 tsk->lba1_4 |= ((nfo->lba >> 32) & 0xFF) << 8;
84 tsk->lba2_5 |= ((nfo->lba >> 40) & 0xFF) << 8;
85 tsk->head_select = (which << 4) | 0x40;
87 tsk->command = 0x42; /* READ VERIFY EXT */
88 if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE|IDELIB_TASKFILE_LBA48/*set LBA48*/) < 0)
92 if (tsk->sector_count > 256) return;
93 tsk->sector_count = (tlen_sect&0xFF);
94 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
95 tsk->chs_sector = nfo->sector;
96 tsk->chs_cylinder_low = nfo->cylinder & 0xFF;
97 tsk->chs_cylinder_high = (nfo->cylinder >> 8) & 0xFF;
98 tsk->head_select = (nfo->head & 0xF) | (which << 4) | 0xA0;
100 else if (nfo->mode == DRIVE_RW_MODE_LBA || nfo->mode == DRIVE_RW_MODE_LBAMULTIPLE) {
101 tsk->lba0_3 = nfo->lba & 0xFF;
102 tsk->lba1_4 = (nfo->lba >> 8) & 0xFF;
103 tsk->lba2_5 = (nfo->lba >> 16) & 0xFF;
104 tsk->head_select = ((nfo->lba >> 24) & 0xF) | (which << 4) | 0xE0;
107 tsk->command = 0x40; /* READ VERIFY */
108 if (idelib_controller_apply_taskfile(ide,0xFC/*base_io+2-7*/,IDELIB_TASKFILE_LBA48_UPDATE/*clear LBA48*/) < 0)
112 if (ide->flags.io_irq_enable) { /* NOW we wait for the IRQ */
113 if (do_ide_controller_user_wait_irq(ide,1) < 0)
115 idelib_controller_ack_irq(ide); /* <- or else it won't fire again */
118 if (do_ide_controller_user_wait_busy_controller(ide) != 0 || do_ide_controller_user_wait_drive_ready(ide) < 0)
121 /* ---- draw contents on the screen ---- */
122 vga_write_color(0x0E);
129 vga_write("Sector verification:\n");
130 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
131 sprintf(tmp,"CHS %u/%u/%u ",nfo->cylinder,nfo->head,nfo->sector); vga_write(tmp);
134 sprintf(tmp,"%llu-%llu",nfo->lba,nfo->lba+(unsigned long long)tlen_sect-1ULL); vga_write(tmp);
137 if (!idelib_controller_is_error(ide)) { /* OK. success. now read the data */
138 vga_write_color(0x0A);
139 vga_write(" PASSED\n");
142 vga_write_color(0x0C);
143 vga_write(" FAILED\n");
146 if (continuous && !user_esc) {
149 if (c == 0) c = getch() << 8;
156 if ((c=wait_for_enter_or_escape()) == 27)
157 return; /* allow user to exit early by hitting ESC */
160 if (c != 27 && !user_esc) {
161 /* if the user hit ENTER, then read another sector and display that too */
162 if (nfo->mode == DRIVE_RW_MODE_CHS || nfo->mode == DRIVE_RW_MODE_CHSMULTIPLE) {
163 nfo->sector += (unsigned long long)tlen_sect;
164 while (nfo->sector > nfo->num_sector) {
165 nfo->sector -= nfo->num_sector;
168 while (nfo->head >= nfo->num_head) {
169 nfo->head -= nfo->num_head;
173 if (nfo->cylinder >= 16384) {
174 nfo->cylinder = 16383;
175 nfo->sector = nfo->num_sector;
176 nfo->head = nfo->num_head - 1;
179 nfo->lba = (unsigned long long)nfo->cylinder * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head;
180 nfo->lba += (unsigned long long)nfo->head * (unsigned long long)nfo->num_sector;
181 nfo->lba += (unsigned long long)nfo->sector - 1ULL;
184 nfo->lba += (unsigned long long)tlen_sect;
186 nfo->sector = (int)(nfo->lba % (unsigned long long)nfo->num_sector) + 1;
187 nfo->head = (int)((nfo->lba / (unsigned long long)nfo->num_sector) % (unsigned long long)nfo->num_head);
188 if (nfo->lba >= (16384ULL * (unsigned long long)nfo->num_sector * (unsigned long long)nfo->num_head)) {
189 nfo->cylinder = 16383;
190 nfo->sector = nfo->num_sector;
191 nfo->head = nfo->num_head - 1;
194 nfo->cylinder = (int)((nfo->lba / (unsigned long long)nfo->num_sector) / (unsigned long long)nfo->num_head);
204 void do_drive_read_verify_test(struct ide_controller *ide,unsigned char which) {
205 struct menuboxbounds mbox;
213 /* UI element vars */
214 menuboxbounds_set_def_list(&mbox,/*ofsx=*/4,/*ofsy=*/7,/*cols=*/1);
215 menuboxbounds_set_item_strings_arraylen(&mbox,drive_read_verify_test_menustrings);
223 for (y=0;y < vga_height;y++) {
224 for (x=0;x < vga_width;x++) {
225 *vga++ = 0x1E00 + 177;
231 vga_write_color(0x1F);
232 vga_write(" IDE r/w tests ");
233 sprintf(tmp,"@%X",ide->base_io);
235 if (ide->alt_io != 0) {
236 sprintf(tmp," alt %X",ide->alt_io);
240 sprintf(tmp," IRQ %d",ide->irq);
243 vga_write(which ? " Slave" : " Master");
245 sprintf(tmp," lba=%u lba48=%u multiple=%u",
246 drive_rw_test_nfo.can_do_lba?1:0,
247 drive_rw_test_nfo.can_do_lba48?1:0,
248 drive_rw_test_nfo.can_do_multiple?1:0);
251 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
253 vga_write_color(0xC);
254 vga_write("WARNING: This code talks directly to your hard disk controller.");
255 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
256 vga_write_color(0xC);
257 vga_write(" If you value the data on your hard drive do not run this program.");
258 while (vga_pos_x < vga_width && vga_pos_x != 0) vga_writec(' ');
264 drive_read_verify_test_menustrings[1] = drive_readwrite_test_modes[drive_rw_test_nfo.mode];
266 sprintf(drive_readwrite_test_geo,"Geometry: C/H/S %u/%u/%u LBA %llu",
267 drive_rw_test_nfo.num_cylinder,
268 drive_rw_test_nfo.num_head,
269 drive_rw_test_nfo.num_sector,
270 drive_rw_test_nfo.max_lba);
272 sprintf(drive_readwrite_test_chs,"Position: C/H/S %u/%u/%u LBA %llu",
273 drive_rw_test_nfo.cylinder,
274 drive_rw_test_nfo.head,
275 drive_rw_test_nfo.sector,
276 drive_rw_test_nfo.lba);
278 sprintf(drive_readwrite_test_numsec,"Number of sectors per read: %u",
279 drive_rw_test_nfo.read_sectors);
281 sprintf(drive_readwrite_test_mult,"Multiple mode: %u sectors (max=%u)",
282 drive_rw_test_nfo.multiple_sectors,
283 drive_rw_test_nfo.max_multiple_sectors);
285 vga_moveto(mbox.ofsx,mbox.ofsy - 2);
286 vga_write_color((select == -1) ? 0x70 : 0x0F);
287 vga_write("Back to IDE controller main menu");
288 while (vga_pos_x < (mbox.width+mbox.ofsx) && vga_pos_x != 0) vga_writec(' ');
290 menuboxbound_redraw(&mbox,select);
294 if (c == 0) c = getch() << 8;
304 case 0: /* show IDE register taskfile */
305 do_common_show_ide_taskfile(ide,which);
306 redraw = backredraw = 1;
309 do_drive_readwrite_test_choose_mode(ide,which,&drive_rw_test_nfo);
310 redraw = backredraw = 1;
312 case 2: /* Edit geometry/max LBA */
313 do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/1);
316 case 3: /* Edit position */
317 do_drive_readwrite_edit_chslba(ide,which,&drive_rw_test_nfo,/*editgeo*/0);
320 case 4: /* Number of sectors */
321 c = prompt_sector_count();
322 if (c >= 1 && c <= 256) {
323 drive_rw_test_nfo.read_sectors = c;
327 case 5: /*Read sectors*/
328 case 6: /*Read sectors continuously*/
329 do_hdd_drive_read_verify_test(ide,which,/*continuous=*/(select==6),&drive_rw_test_nfo);
330 redraw = backredraw = 1;
334 else if (c == 0x4800) {
336 select = mbox.item_max;
340 else if (c == 0x4B00) { /* left */
344 if (drive_rw_test_nfo.mode == 0)
345 drive_rw_test_nfo.mode = DRIVE_RW_MODE_MAX-1;
347 drive_rw_test_nfo.mode--;
348 } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
350 case 4: /* Number of sectors */
351 if (drive_rw_test_nfo.read_sectors > 1)
352 drive_rw_test_nfo.read_sectors--;
358 else if (c == 0x4D00) { /* right */
362 if (++drive_rw_test_nfo.mode >= DRIVE_RW_MODE_MAX)
363 drive_rw_test_nfo.mode = 0;
364 } while (!drive_rw_test_mode_supported(&drive_rw_test_nfo));
366 case 4: /* Number of sectors */
367 if (drive_rw_test_nfo.read_sectors < 256)
368 drive_rw_test_nfo.read_sectors++;
374 else if (c == 0x5000) {
375 if (++select > mbox.item_max)
382 #endif /*READ_VERIFY*/