Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ll-xn!ames!hc!beta!hgm From: hgm@beta.UUCP (Harry McGavran) Newsgroups: comp.os.minix Subject: harddisk driver fixes 1 of 2 Message-ID: <5123@beta.UUCP> Date: Wed, 6-May-87 16:31:11 EDT Article-I.D.: beta.5123 Posted: Wed May 6 16:31:11 1987 Date-Received: Sat, 9-May-87 01:19:12 EDT Organization: Los Alamos Natl Lab, Los Alamos, N.M. Lines: 513 Here is part one of two. I have a WD 1002A-WX1 hard disk controller on one PC and a BASIC TIME (same chip set as WD) controller in another. The BASIC TIME is in an XT with a 6 Mhz 80286 board in it, the WX1 is in a regular IBM PC-2. I picked up the changes to xt_wini.c posted by Gary Oliver for the WX2 and got the manual for WD. It turns out that the WX1 and the WX2 should be the same for the purposes of MINIX. But the BASIC TIME on the faster board would not work with Gary's mods installed. The WX1 did. I discovered that the faster CPU would not wait long enough with maximum retries set to 10000 for all the status bits to come up properly during the reset. The solution was to change to 32000. I also moved the select command out of the status loop in the reset function and put it just in front of the status loop. It didn't seem that one should select over and over. I might be wrong about this, but both systems now work great. The higher maximum doesn't seem to hurt the performance of the slower systems, so I just use the higher number everywhere. I also increased the time for the spin loop before the status loop, by changing the limit from 1000, to the maximum retries divided by 10. In pursuing this, I learned alot about the WD controller and the code. I fixed a couple typos in Gary's changes and in the original code. The disk table pointers (type_0 and type_1) are reversed according to my documentation (in both the original and in Gary's changes), so I fixed that. I also produced a diff of the old and the new, suitable for using the latest version of "patch". Move a copy of the original xt_wini.c to a system with the latest "patch". Cut out the patch below and call it "wini.fixes". Then type "patch -l xt_wini.c COUNT != BLOCK_SIZE) return(EINVAL); wn = &wini[device]; /* 'wn' points to entry for this drive */ ! wn->wn_drive = device/DEV_PER_DRIVE; /* save drive number */ ! if (wn->wn_drive >= nr_drives) ! return(EIO); wn->wn_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */ if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL); --- 177,183 ---- if (m_ptr->COUNT != BLOCK_SIZE) return(EINVAL); wn = &wini[device]; /* 'wn' points to entry for this drive */ ! wn->wn_opcode = m_ptr->m_type; /* DISK_READ or DISK_WRITE */ if (m_ptr->POSITION % BLOCK_SIZE != 0) return(EINVAL); *************** *** 264,280 **** /* The command is issued by outputing 6 bytes to the controller chip. */ command[0] = (wn->wn_opcode == DISK_READ ? WIN_READ : WIN_WRITE); ! command[1] = (wn->wn_head | (wn->wn_drive << 5)); command[2] = (((wn->wn_cylinder & 0x0300) >> 2) | wn->wn_sector); command[3] = (wn->wn_cylinder & 0xFF); command[4] = BLOCK_SIZE/SECTOR_SIZE; ! command[5] = CTRL_BYTE; if (com_out(DMA_INT) != OK) return(ERR); port_out(DMA_INIT, 3); /* initialize DMA */ /* Block, waiting for disk interrupt. */ ! receive(HARDWARE, &w_mess); /* Get controller status and check for errors. */ if (win_results(wn) == OK) --- 274,291 ---- /* The command is issued by outputing 6 bytes to the controller chip. */ command[0] = (wn->wn_opcode == DISK_READ ? WIN_READ : WIN_WRITE); ! command[1] = wn->wn_head | wn->wn_drive; command[2] = (((wn->wn_cylinder & 0x0300) >> 2) | wn->wn_sector); command[3] = (wn->wn_cylinder & 0xFF); command[4] = BLOCK_SIZE/SECTOR_SIZE; ! command[5] = wn->wn_ctrl_byte; ! if (com_out(DMA_INT) != OK) return(ERR); port_out(DMA_INIT, 3); /* initialize DMA */ /* Block, waiting for disk interrupt. */ ! w_wait_int(); /* Get controller status and check for errors. */ if (win_results(wn) == OK) *************** *** 300,322 **** port_in(WIN_DATA, &status); port_out(WIN_DMA, 0); ! if (!(status & 2)) return(OK); command[0] = WIN_SENSE; ! command[1] = (wn->wn_drive << 5); if (com_out(NO_DMA_INT) != OK) return(ERR); /* Loop, extracting bytes from WIN */ for (i = 0; i < MAX_RESULTS; i++) { ! if (hd_wait(1) != OK) return(ERR); port_in(WIN_DATA, &status); wn->wn_results[i] = status & BYTE; } ! if (wn->wn_results[0] & 63) return(ERR); ! else return(OK); } --- 311,341 ---- port_in(WIN_DATA, &status); port_out(WIN_DMA, 0); ! if (!(status & 2)) /* Test "error" bit */ return(OK); command[0] = WIN_SENSE; ! command[1] = wn->wn_drive; if (com_out(NO_DMA_INT) != OK) return(ERR); /* Loop, extracting bytes from WIN */ for (i = 0; i < MAX_RESULTS; i++) { ! if (hd_wait(WST_REQ) != OK) return(ERR); port_in(WIN_DATA, &status); wn->wn_results[i] = status & BYTE; } ! 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 return(OK); } *************** *** 331,339 **** * can only write to it when it is listening, and it decides when to listen. * If the controller refuses to listen, the WIN chip is given a hard reset. */ if (w_need_reset) return; /* if controller is not listening, return */ ! if (hd_wait(1) == OK) port_out(WIN_DATA, val); } --- 350,363 ---- * can only write to it when it is listening, and it decides when to listen. * If the controller refuses to listen, the WIN chip is given a hard reset. */ + int r; if (w_need_reset) return; /* if controller is not listening, return */ ! ! do { ! port_in(WIN_STATUS, &r); ! } while((r & (WST_REQ | WST_BUSY)) == WST_BUSY); ! port_out(WIN_DATA, val); } *************** *** 346,361 **** * like the controller refusing to respond. */ ! int r = 1, i; /* Strobe reset bit low. */ ! 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); } --- 370,396 ---- * like the controller refusing to respond. */ ! int r = 0, i; /* Strobe reset bit low. */ ! port_out(WIN_STATUS, 0); ! ! for(i = MAX_WIN_RETRY/10; i; --i) ! ; /* Spin loop for a while */ ! ! port_out(WIN_SELECT, 0); /* Issue select pulse */ ! for (i = 0; i < MAX_WIN_RETRY; i++) { 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; } ! ! if (i == MAX_WIN_RETRY) { ! printf("Hard disk won't reset, status = %x\n", r); return(ERR); } *************** *** 362,462 **** /* Reset succeeded. Tell WIN drive parameters. */ w_need_reset = FALSE; ! return(win_init()); ! } ! /*===========================================================================* ! * 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 */ ! if (com_out(NO_DMA_INT) != OK) /* Output command block */ return(ERR); - lock(); ! /* No. of cylinders (high byte) */ ! win_out(param0.nr_cyl >> 8); ! /* No. of cylinders (low byte) */ ! win_out(param0.nr_cyl & 0xFF); ! /* No. of heads */ ! win_out(param0.nr_heads); ! /* Start reduced write (high byte) */ ! win_out(param0.reduced_wr >> 8); ! /* Start reduced write (low byte) */ ! win_out(param0.reduced_wr & 0xFF); ! /* Start write precompensation (high byte) */ ! win_out(param0.wr_precomp >> 8); - /* Start write precompensation (low byte) */ - win_out(param0.wr_precomp & 0xFF); ! /* Ecc burst length */ ! win_out(param0.max_ecc); ! unlock(); ! if (check_init() != OK) { /* See if controller accepted parameters */ ! w_need_reset = TRUE; ! return(ERR); } ! 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 1) && (win_specify(1, ¶m1) != OK)) return (ERR); ! #if DEBUG ! printf("\nw_reset: drive 1 specified"); ! #endif /* DEBUG */ ! for (i=0; i