go@orstcs.cs.ORST.EDU (04/21/87)
Well, here goes... Several folks have asked me for the mods to the xt_wini driver I mentioned in an earlier response. The following (though rather long) is what I am currently running on my no-name clone with a WD1002S-WX2 (does that sound right?) controller. Anyway, it's a Western Digital controller of some earlier vintage -- only one hyper-dense chip and it's about 18 to 20 cm. long. These mods include fixes for: 1) Incorrect bits polled in w_reset. 2) win_results called without param in win_init (blew my system up at boot time occasionally. 3) General clean-up to use manifest constants (where I understood what was going on.) 4) Restructured some routines to share some common code - initialization stuff mostly. 5) Added some conditional debug stuff and left it in to help me make sure things were working. I hope you have success with this. I have been unable to test this with non-WD controllers, though I have tried to maintain compatibility with the SCSI-type command packet controller interfaces. This driver now looks alot like some SCSI drivers I have written... Timing has been changed to anticipate worst-case communication with controller. I haven't relied on the beast being faster then the cpu. It appears from docs I have read, that the IBM controller was somewhat spiffier at taking commands and as such, polling the request bit (WST_REQ) during data transfer of packets was unnecessary. My mods assume the worst. After installing this code, my error rate went from about 100 per nite (3 to 4 hours) to none since (about 1.5 weeks.) I do wish someone would post a "sed" to make this easier -- hint hint.. -----------here it goes (xt_wini.c is original) ---------- <<< **** Line 30 of 'xt_wini.c' **** >>> **** Line 30 of 'wini.c' **** >>>#define DEBUG FALSE /* TRUE: enable debug messages */ >>>#define MONITOR TRUE /* TRUE: monitor performance of busy loops */ >>> <<< **** Line 33 of 'xt_wini.c' **** >>> **** Line 36 of 'wini.c' **** >>>#define WST_REQ 0x01 /* Request bit */ >>>#define WST_INPUT 0x02 /* Set if controller is writing to cpu */ >>>#define WST_BUS 0x04 /* Command/status bit */ >>>#define WST_BUSY 0x08 /* Busy */ >>>#define WST_INTERRUPT 0x20 /* Interrupt generated ?? */ <<< **** Line 53 of 'xt_wini.c' **** <<<#define CTRL_BYTE 5 /* Control byte for controller */ >>> **** Line 61 of 'wini.c' **** <<< **** Line 78 of 'xt_wini.c' **** <<< int wn_drive; /* drive number addressed */ >>> **** Line 85 of 'wini.c' **** >>> int wn_drive; /* drive number addressed (<< 5) */ <<< **** Line 83 of 'xt_wini.c' **** >>> **** Line 90 of 'wini.c' **** >>> int wn_ctrl_byte; /* Control byte for COMMANDS (10-Apr-87 GO) */ <<< **** Line 105 of 'xt_wini.c' **** >>> **** Line 113 of 'wini.c' **** >>> int ctrl_byte; /* Copied control-byte from bios tables */ <<< **** Line 107 of 'xt_wini.c' **** >>> **** Line 116 of 'wini.c' **** >>>#if DEBUG >>>#define port_out(port, val) xport_out(port, val) >>>#endif /* DEBUG */ <<< **** Line 117 of 'xt_wini.c' **** <<< init_param(); >>> **** Line 129 of 'wini.c' **** >>> init_params(); <<< **** Line 168 of 'xt_wini.c' **** <<< wn->wn_drive = device/DEV_PER_DRIVE; /* save drive number */ <<< if (wn->wn_drive >= nr_drives) <<< return(EIO); >>> **** Line 180 of 'wini.c' **** >>> <<< **** Line 267 of 'xt_wini.c' **** <<< command[1] = (wn->wn_head | (wn->wn_drive << 5)); >>> **** Line 277 of 'wini.c' **** >>> command[1] = wn->wn_head | wn->wn_drive; <<< **** Line 271 of 'xt_wini.c' **** <<< command[5] = CTRL_BYTE; >>> **** Line 281 of 'wini.c' **** >>> command[5] = wn->wn_ctrl_byte; >>> <<< **** Line 277 of 'xt_wini.c' **** <<< receive(HARDWARE, &w_mess); >>> **** Line 288 of 'wini.c' **** >>> w_wait_int(); <<< **** Line 303 of 'xt_wini.c' **** <<< if (!(status & 2)) >>> **** Line 314 of 'wini.c' **** >>> if (!(status & 2)) /* Test "error" bit */ <<< **** Line 306 of 'xt_wini.c' **** <<< command[1] = (wn->wn_drive << 5); >>> **** Line 317 of 'wini.c' **** >>> command[1] = wn->wn_drive; <<< **** Line 312 of 'xt_wini.c' **** <<< if (hd_wait(1) != OK) >>> **** Line 323 of 'wini.c' **** >>> if (hd_wait(WST_REQ) != OK) <<< **** Line 317 of 'xt_wini.c' **** <<< if (wn->wn_results[0] & 63) <<< return(ERR); <<< else >>> **** Line 328 of 'wini.c' **** >>> if(hd_wait(WST_REQ) != OK) /* Missing from */ >>> return (ERR); /* Original. 11-Apr-87 G.O. */ >>> >>> port_in(WIN_DATA, &status); /* Read "error" flag */ >>> >>> if(((status & 2) != 0) || (wn->wn_results[0] & 0x3F)) { >>>#if DEBUG >>> printf("\nwin_results: results[0] = %x", wn->wn_results[0]); >>>#endif /* DEBUG */ >>> return(ERR); >>> } else <<< **** Line 334 of 'xt_wini.c' **** >>> **** Line 353 of 'wini.c' **** >>> int r; <<< **** Line 336 of 'xt_wini.c' **** <<< if (hd_wait(1) == OK) <<< port_out(WIN_DATA, val); >>> **** Line 356 of 'wini.c' **** >>> >>> do { >>> port_in(WIN_STATUS, &r); >>> } while((r & (WST_REQ | WST_BUSY)) == WST_BUSY); >>> >>> port_out(WIN_DATA, val); <<< **** Line 349 of 'xt_wini.c' **** <<< int r = 1, i; >>> **** Line 373 of 'wini.c' **** >>> int r, i; <<< **** Line 352 of 'xt_wini.c' **** <<< port_out(WIN_STATUS, r); <<< for (i = 0; i < 10000; i++) { <<< port_in(WIN_STATUS, &r); <<< if ( (r&01) == 0)break; <<< } <<< if (r & 2) { <<< printf("Hard disk won't reset\n"); <<< return(ERR); >>> **** Line 376 of 'wini.c' **** >>> port_out(WIN_STATUS, 0); >>> >>> for(i = 1000; i; --i) >>> ; /* Spin loop for a while */ >>> >>> for (i = 0; i < MAX_WIN_RETRY; i++) { >>> port_out(WIN_SELECT, 0); /* Issue select pulse */ >>> port_in(WIN_STATUS, &r); >>> if(r & 0x30) /* What is 10? 20 = INTERRUPT */ >>> return (ERR); >>> >>> if((r & (WST_BUSY | WST_BUS | WST_REQ)) == >>> (WST_BUSY | WST_BUS | WST_REQ)) >>> break; <<< **** Line 362 of 'xt_wini.c' **** >>> **** Line 392 of 'wini.c' **** >>> if (i == MAX_WIN_RETRY) { >>> printf("Hard disk won't reset\n"); >>> return(ERR); >>> } >>> <<< **** Line 365 of 'xt_wini.c' **** <<< return(win_init()); >>> **** Line 400 of 'wini.c' **** >>> if(win_specify(0, ¶m0) != OK) >>> return (ERR); >>> >>>#if DEBUG >>> printf("\nw_reset: drive 0 specified"); >>>#endif /* DEBUG */ >>> >>> if ((nr_drives > 1) && (win_specify(1, ¶m1) != OK)) >>> return (ERR); >>> >>>#if DEBUG >>> printf("\nw_reset: drive 1 specified"); >>>#endif /* DEBUG */ >>> >>> for (i=0; i<nr_drives; i++) { >>> command[0] = WIN_RECALIBRATE; >>> command[1] = i << 5; >>> command[5] = wini[i * DEV_PER_DRIVE].wn_ctrl_byte; >>> >>>#if DEBUG >>> printf("\nw_reset: recal %d, ctrl_byte = %x", i, command[5]); >>>#endif /* DEBUG */ >>> >>> if (com_out(INT) != OK) >>> return(ERR); >>> >>> w_wait_int(); >>> >>> if (win_results(&wini[i * DEV_PER_DRIVE]) != OK) { >>> w_need_reset = TRUE; >>>#if DEBUG >>> printf("\nw_reset: Recal error"); >>>#endif /* DEBUG */ >>> return(ERR); >>> } >>> } >>> return(OK); <<< **** Line 368 of 'xt_wini.c' **** <<</*===========================================================================* <<< * win_init * <<< *===========================================================================*/ <<<PRIVATE win_init() <<<{ <<</* Routine to initialize the drive parameters after boot or reset */ <<< <<< register int i; <<< <<< command[0] = WIN_SPECIFY; /* Specify some parameters */ <<< command[1] = 0; /* Drive 0 */ >>> **** Line 439 of 'wini.c' **** >>> >>>/*=====================================================================================================* >>> * w_wait_int * >>> *======================================================================================================*/ >>>PRIVATE w_wait_int() >>>{ >>> /*DEBUG: loop looking for 0x20 in status (I don't know what that is!!) */ >>> /* 10-Apr-87. G. Oliver */ >>> int r, i; /* Some local storage */ >>> >>> receive(HARDWARE, &w_mess); >>> >>> port_out(DMA_INIT, 0x07); /* Disable int from DMA */ >>> >>> for(i=0; i<MAX_WIN_RETRY; ++i) { >>> port_in(WIN_STATUS, &r); >>> if(r & WST_INTERRUPT) >>> break; /* Exit if end of int */ >>> } >>> >>>#if MONITOR >>> if(i > 10) { /* Some arbitrary limit below which we don't really care */ >>> if(i == MAX_WIN_RETRY) >>> printf("wini: timeout waiting for INTERRUPT status\n"); >>> else >>> printf("wini: %d loops waiting for INTERRUPT status\n", i); >>> } >>>#endif /* MONITOR */ >>>} >>> >>> >>>/*=====================================================================================================* >>> * win_specify * >>> *======================================================================================================*/ >>>PRIVATE win_specify(drive, paramp) >>>int drive; >>>struct param *paramp; >>>{ >>> command[0] = WIN_SPECIFY; /* Specify some parameters */ >>> command[1] = drive << 5; /* Drive number */ >>> <<< **** Line 384 of 'xt_wini.c' **** <<< win_out(param0.nr_cyl >> 8); >>> **** Line 485 of 'wini.c' **** >>> win_out(paramp->nr_cyl >> 8); <<< **** Line 387 of 'xt_wini.c' **** <<< win_out(param0.nr_cyl & 0xFF); >>> **** Line 488 of 'wini.c' **** >>> win_out(paramp->nr_cyl); <<< **** Line 390 of 'xt_wini.c' **** <<< win_out(param0.nr_heads); >>> **** Line 491 of 'wini.c' **** >>> win_out(paramp->nr_heads); <<< **** Line 393 of 'xt_wini.c' **** <<< win_out(param0.reduced_wr >> 8); >>> **** Line 494 of 'wini.c' **** >>> win_out(paramp->reduced_wr >> 8); <<< **** Line 396 of 'xt_wini.c' **** <<< win_out(param0.reduced_wr & 0xFF); >>> **** Line 497 of 'wini.c' **** >>> win_out(paramp->reduced_wr); <<< **** Line 399 of 'xt_wini.c' **** <<< win_out(param0.wr_precomp >> 8); >>> **** Line 500 of 'wini.c' **** >>> win_out(paramp->wr_precomp >> 8); <<< **** Line 402 of 'xt_wini.c' **** <<< win_out(param0.wr_precomp & 0xFF); >>> **** Line 503 of 'wini.c' **** >>> win_out(paramp->wr_precomp); <<< **** Line 405 of 'xt_wini.c' **** <<< win_out(param0.max_ecc); >>> **** Line 506 of 'wini.c' **** >>> win_out(paramp->max_ecc); <<< **** Line 412 of 'xt_wini.c' **** <<< <<< if (nr_drives > 1) { <<< command[1] = (1 << 5); /* Drive 1 */ <<< if (com_out(NO_DMA_INT) != OK) /* Output command block */ <<< return(ERR); <<< lock(); <<< <<< /* No. of cylinders (high byte) */ <<< win_out(param1.nr_cyl >> 8); <<< <<< /* No. of cylinders (low byte) */ <<< win_out(param1.nr_cyl & 0xFF); <<< <<< /* No. of heads */ <<< win_out(param1.nr_heads); <<< <<< /* Start reduced write (high byte) */ <<< win_out(param1.reduced_wr >> 8); <<< <<< /* Start reduced write (low byte) */ <<< win_out(param1.reduced_wr & 0xFF); <<< <<< /* Start write precompensation (high byte) */ <<< win_out(param1.wr_precomp >> 8); <<< <<< /* Start write precompensation (low byte) */ <<< win_out(param1.wr_precomp & 0xFF); <<< <<< /* Ecc burst length */ <<< win_out(param1.max_ecc); <<< unlock(); <<< if (check_init() != OK) { /* See if controller accepted parameters */ <<< w_need_reset = TRUE; <<< return(ERR); <<< } <<< } <<< for (i=0; i<nr_drives; i++) { <<< command[0] = WIN_RECALIBRATE; <<< command[1] = i << 5; <<< command[5] = CTRL_BYTE; <<< if (com_out(INT) != OK) <<< return(ERR); <<< receive(HARDWARE, &w_mess); <<< if (win_results() != OK) { <<< w_need_reset = TRUE; <<< return(ERR); <<< } <<< } <<< return(OK); >>> **** Line 513 of 'wini.c' **** >>> else >>> return(OK); <<< **** Line 469 of 'xt_wini.c' **** <<< int r; <<< <<< if (hd_wait(2) == OK) { <<< port_in(WIN_DATA, &r); <<< if (r & 2) <<< return(ERR); >>> **** Line 523 of 'wini.c' **** >>> int r, s; >>> >>> if (hd_wait(WST_REQ | WST_REQ |WST_INPUT) == OK) { >>> port_in(WIN_DATA, &r); >>> >>> do { >>> port_in(WIN_STATUS, &s); >>> } while(s & WST_BUSY); /* Loop while still busy */ >>> >>> if (r & 2) /* Test error bit */ >>> { >>>#if DEBUG >>> printf("\ncheck_init: error bit set in %x", r); >>>#endif /* DEBUG */ >>> return(ERR); >>> } <<< **** Line 477 of 'xt_wini.c' **** <<< } >>> **** Line 541 of 'wini.c' **** >>> } else >>> { >>>#if DEBUG >>> printf("\ncheck_init: INPUT not active"); >>>#endif /* DEBUG */ >>> return (ERR); /* Missing from original: 11-Apr-87 G.O. */ >>> } <<< **** Line 490 of 'xt_wini.c' **** <<< if (com_out(NO_DMA_INT) == OK && hd_wait(1) == OK) { <<< port_in(WIN_DATA, &r); <<< if (hd_wait(1) == OK) { >>> **** Line 560 of 'wini.c' **** >>> if (com_out(NO_DMA_INT) == OK && hd_wait(WST_REQ) == OK) { >>> port_in(WIN_DATA, &r); >>> if (hd_wait(WST_REQ) == OK) { <<< **** Line 504 of 'xt_wini.c' **** <<<PRIVATE hd_wait(bit) <<<register int bit; >>> **** Line 574 of 'wini.c' **** >>>PRIVATE hd_wait(bits) >>>register int bits; <<< **** Line 514 of 'xt_wini.c' **** <<< r &= bit; <<< } while ((i++ < MAX_WIN_RETRY) && !r); >>> **** Line 584 of 'wini.c' **** >>> r &= bits; >>> } while ((i++ < MAX_WIN_RETRY) && r != bits); /* Wait for ALL bits */ <<< **** Line 519 of 'xt_wini.c' **** >>> **** Line 589 of 'wini.c' **** >>>#if DEBUG >>> printf("\nhd_wait: timeout waiting for %x (%x)", bits, r); >>>#endif /* DEBUG */ <<< **** Line 532 of 'xt_wini.c' **** <<< register int i = 0; >>> **** Line 605 of 'wini.c' **** >>> register int i; <<< **** Line 535 of 'xt_wini.c' **** <<< port_out(WIN_SELECT, mode); <<< port_out(WIN_DMA, mode); >>> **** Line 608 of 'wini.c' **** >>> port_out(WIN_DMA, mode); >>> port_out(WIN_SELECT, mode); <<< **** Line 539 of 'xt_wini.c' **** <<< if ((r & 0x0F) == 0x0D) >>> **** Line 612 of 'wini.c' **** >>> if (r & WST_BUSY) <<< **** Line 542 of 'xt_wini.c' **** >>> **** Line 615 of 'wini.c' **** >>> <<< **** Line 544 of 'xt_wini.c' **** >>> **** Line 618 of 'wini.c' **** >>>#if DEBUG >>> printf("\ncom_out: retry exceeded, status = %x", r); >>>#endif /* DEBUG */ <<< **** Line 546 of 'xt_wini.c' **** <<< lock(); <<< for (i=0; i<6; i++) <<< port_out(WIN_DATA, command[i]); <<< unlock(); <<< port_in(WIN_STATUS, &r); <<< if (r & 1) { <<< w_need_reset = TRUE; <<< return(ERR); <<< } else >>> **** Line 623 of 'wini.c' **** >>> >>> >>> lock(); >>> >>> for (i=0; i<6; i++) { >>> if(hd_wait(WST_REQ) != OK) >>> break; /* No data request pending */ >>> >>> port_in(WIN_STATUS, &r); >>> >>> if((r & (WST_BUSY | WST_BUS | WST_INPUT)) != >>> (WST_BUSY | WST_BUS)) >>> break; >>> >>> port_out(WIN_DATA, command[i]); >>> } >>> >>> unlock(); >>> >>> if(i != 6) { >>>#if DEBUG >>> printf("\ncom_out: packet write aborted, status=%x", r); >>>#endif /* DEBUG */ >>> return (ERR); >>> } >>> else <<< **** Line 565 of 'xt_wini.c' **** <<<*/ >>> **** Line 659 of 'wini.c' **** >>> */ <<< **** Line 584 of 'xt_wini.c' **** <<< address = ((long)segment << 4) + offset; >>> **** Line 678 of 'wini.c' **** >>> address = ((phys_bytes)segment << 4) + offset; <<< **** Line 588 of 'xt_wini.c' **** <<< copy_param((&buf[type_0 * 16]), ¶m0); <<< copy_param((&buf[type_1 * 16]), ¶m1); <<< <<< /* Get the nummer of drives from the bios */ >>> **** Line 682 of 'wini.c' **** >>> copy_param(&buf[type_0 * 16], ¶m0); >>> copy_param(&buf[type_1 * 16], ¶m1); >>> >>> /* Get the number of drives from the bios */ <<< **** Line 596 of 'xt_wini.c' **** <<< for (i=0; i<5; i++) <<< wini[i].wn_heads = param0.nr_heads; <<< wini[0].wn_low = wini[5].wn_low = 0L; <<< wini[0].wn_size = (long)((long)param0.nr_cyl * (long)param0.nr_heads * (long)NR_SECTORS); <<< for (i=5; i<10; i++) <<< wini[i].wn_heads = param1.nr_heads; <<< wini[5].wn_size = (long)((long)param1.nr_cyl * (long)param1.nr_heads * (long)NR_SECTORS); >>> **** Line 690 of 'wini.c' **** >>> for (i = 0; i < DEV_PER_DRIVE; i++) { >>> wini[i].wn_heads = param0.nr_heads; >>> wini[i].wn_ctrl_byte = param0.ctrl_byte; >>> wini[i].wn_drive = 0 << 5; /* Set drive number */ >>> } >>> >>> wini[0].wn_low = wini[DEV_PER_DRIVE].wn_low = 0L; >>> wini[0].wn_size = (long)((long)param0.nr_cyl * (long)param0.nr_heads * (long)NR_SECTORS); >>> >>> for (i = DEV_PER_DRIVE; i < (2*DEV_PER_DRIVE); i++) { >>> wini[i].wn_heads = param1.nr_heads; >>> wini[i].wn_ctrl_byte = param1.ctrl_byte; >>> wini[i].wn_drive = 1 << 5; /* Set drive number */ >>> } >>> wini[DEV_PER_DRIVE].wn_size = >>> (long)((long)param1.nr_cyl * (long)param1.nr_heads * (long)NR_SECTORS); <<< **** Line 606 of 'xt_wini.c' **** <<< if ((nr_drives > 0) && (win_init() != OK)) >>> **** Line 709 of 'wini.c' **** >>> if ((nr_drives > 0) && (w_reset() != OK)) <<< **** Line 611 of 'xt_wini.c' **** <<< w_mess.DEVICE = i * 5; >>> **** Line 714 of 'wini.c' **** >>> w_mess.DEVICE = i * DEV_PER_DRIVE; <<< **** Line 619 of 'xt_wini.c' **** <<< copy_prt(i * 5); >>> **** Line 722 of 'wini.c' **** >>> copy_prt(i * DEV_PER_DRIVE); >>>#if DEBUG >>> printf("\ninit_params: drive %d processed", i); >>>#endif /* DEBUG */ <<< **** Line 631 of 'xt_wini.c' **** <<< * and sets the parameters for partition 0 and 5 >>> **** Line 737 of 'wini.c' **** >>> * and sets the parameters for partition 0 and DEV_PER_DRIVE <<< **** Line 639 of 'xt_wini.c' **** >>> **** Line 745 of 'wini.c' **** >>> dest->ctrl_byte = (int)src[8]; <<< **** Line 32765 of 'xt_wini.c' **** >>> **** Line 799 of 'wini.c' **** >>> >>>#if DEBUG >>>#undef port_out >>>/* Write values written to ports with debugging version of port_out */ >>>xport_out(port, val) >>> int port, val; >>> { >>> static int __ctr = 0; >>> >>> printf(" (%x)=%x", port, val); >>> if(++__ctr > 4) >>> { >>> printf("\n"); >>> __ctr = 0; >>> } >>> port_out(port, val); >>> } >>>#endif /* DEBUG */ ---------- Th th that's all, folks ----------- Gary Oliver ...!hplabs!hp-pcd!orstcs!go (Until the pull my plug)