[comp.os.minix] Diffs to fix xt_wini bugs

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, &param0) != OK)
>>>	return (ERR);
>>>
>>>#if	DEBUG
>>>  printf("\nw_reset: drive 0 specified");
>>>#endif	/* DEBUG */
>>>
>>>  if ((nr_drives > 1) && (win_specify(1, &param1) != 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]), &param0);
<<<  copy_param((&buf[type_1 * 16]), &param1);
<<<
<<<  /* Get the nummer of drives from the bios */
>>> **** Line  682 of 'wini.c' ****
>>>  copy_param(&buf[type_0 * 16], &param0);
>>>  copy_param(&buf[type_1 * 16], &param1);
>>>
>>>  /* 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)