[comp.os.minix] xt_wini.c diffs for WD autoconfig

myxm@beta.UUCP (05/08/87)

	What follows are diffs from the original xt_wini.c for the Western
Digital Controller. The diffs presented here come from a couple of sources.
Thanks to Gary Oliver for the original set of diffs which allowed the
Western Digital Controller to operate fairly well under Minix. Thanx to
Harry McGavren for the second set of diffs which made the winchester
controller a little more robust and operate on turbo clones better.

	I have also incorperated some code which will sense if the WD
controller is being used in auto-configuration mode and will retrieve
the drive parameter tables from the hard disk. This will give some
Minix users greater flexibility as to what drives Minix will now work
with. (Hopefully if you are able to talk to your drive with DOS, then
you should be able to now have Minix operate with it). These patches
were prompted by the fact that I have a Seagate 4038 on my controller
and there are no drive tables in the ROM for this particular drive.
I figured that the cleanest way to patch xt_wini.c was to force it to
query the drive for the actual parameters.

	The context diffs which follow are suitable for use with the
most recent version of patch. To make use of these diffs, place a
copy of xt_wini.c (original) and these diffs in the same directory
and use the command "patch -l xt_wini.c < xt_wini.diffs". You should
then wind up with an updated copy of xt_wini.c.

	Have fun.

#include <stddisclaimer.h>

Mike Mitchell
myxm@lanl.gov | ...!{cmcl2,ucbvax,decvax}!lanl!myxm

---/---/---/---/---/---/--- TEAR HERE ---/---/---/---/---/---/---

*** xt_wini.c	Thu May  7 23:48:28 1987
--- xt_wini.new	Thu May  7 23:50:21 1987
***************
*** 27,35 ****
--- 27,44 ----
  #include "type.h"
  #include "proc.h"
  
+ #define AUTO_BIOS      TRUE	/* TRUE: working with western autoconfig bios */
+ #define DEBUG	       FALSE	/* TRUE: enable debug messages		   */
+ #define MONITOR        TRUE	/* TRUE: monitor performance of busy loops */
+ 
  /* I/O Ports used by winchester disk task. */
  #define WIN_DATA       0x320	/* winchester disk controller data register */
  #define WIN_STATUS     0x321	/* winchester disk controller status register */
+ #define WST_REQ        0x001	/* Request bit */
+ #define WST_INPUT      0x002	/* Set if controller is writing to cpu */
+ #define WST_BUS        0x004	/* Command/status bit */
+ #define WST_BUSY       0x008	/* Busy */
+ #define WST_INTERRUPT  0x020	/* Interrupt generated ?? */
  #define WIN_SELECT     0x322	/* winchester disk controller select port */
  #define WIN_DMA	       0x323	/* winchester disk controller dma register */
  #define DMA_ADDR       0x006	/* port for low 16 bits of DMA address */
***************
*** 50,56 ****
  #define DMA_INT		   3 /* Command with dma and interrupt */
  #define INT		   2	/* Command with interrupt, no dma */
  #define NO_DMA_INT	   0	/* Command without dma and interrupt */
- #define CTRL_BYTE	   5 /* Control byte for controller */
  
  /* DMA channel commands. */
  #define DMA_READ        0x47	/* DMA read opcode */
--- 59,64 ----
***************
*** 67,85 ****
  #define MAX_ERRORS         4	/* how often to try rd/wt before quitting */
  #define MAX_RESULTS        4	/* max number of bytes controller returns */
  #define NR_DEVICES        10	/* maximum number of drives */
! #define MAX_WIN_RETRY  10000	/* max # times to try to output to WIN */
  #define PART_TABLE     0x1C6	/* IBM partition table starts here in sect 0 */
  #define DEV_PER_DRIVE      5	/* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */
  
  /* Variables. */
  PRIVATE struct wini {		/* main drive struct, one entry per drive */
    int wn_opcode;		/* DISK_READ or DISK_WRITE */
    int wn_procnr;		/* which proc wanted this operation? */
!   int wn_drive;			/* drive number addressed */
    int wn_cylinder;		/* cylinder number addressed */
    int wn_sector;		/* sector addressed */
    int wn_head;			/* head number addressed */
    int wn_heads;			/* maximum number of heads */
    long wn_low;			/* lowest cylinder of partition */
    long wn_size;			/* size of partition in blocks */
    int wn_count;			/* byte count */
--- 75,106 ----
  #define MAX_ERRORS         4	/* how often to try rd/wt before quitting */
  #define MAX_RESULTS        4	/* max number of bytes controller returns */
  #define NR_DEVICES        10	/* maximum number of drives */
! #define MAX_WIN_RETRY  32000	/* max # times to try to output to WIN */
  #define PART_TABLE     0x1C6	/* IBM partition table starts here in sect 0 */
  #define DEV_PER_DRIVE      5	/* hd0 + hd1 + hd2 + hd3 + hd4 = 5 */
+ #if AUTO_BIOS
+ #define AUTO_PARAM     0x1AD	/* drive parameter table starts here in sect 0 */
+ #define AUTO_ENABLE	0x10	/* auto bios enabled bit from status reg */
+ /* some start up parameters in order to extract the drive parameter table */
+ /* from the winchester. these should not need changed. */
+ #define AUTO_CYLS	 306	/* default number of cylinders */
+ #define AUTO_HEADS	   4	/* default number of heads */
+ #define AUTO_RWC	 307	/* default reduced write cylinder */
+ #define AUTO_WPC	 307	/* default write precomp cylinder */
+ #define AUTO_ECC	  11	/* default ecc burst */
+ #define AUTO_CTRL	   5	/* default winchester stepping speed byte */
+ #endif
  
  /* Variables. */
  PRIVATE struct wini {		/* main drive struct, one entry per drive */
    int wn_opcode;		/* DISK_READ or DISK_WRITE */
    int wn_procnr;		/* which proc wanted this operation? */
!   int wn_drive; 		/* drive number addressed (<< 5) */
    int wn_cylinder;		/* cylinder number addressed */
    int wn_sector;		/* sector addressed */
    int wn_head;			/* head number addressed */
    int wn_heads;			/* maximum number of heads */
+   int wn_ctrl_byte;		/* Control byte for COMMANDS (10-Apr-87 GO) */
    long wn_low;			/* lowest cylinder of partition */
    long wn_size;			/* size of partition in blocks */
    int wn_count;			/* byte count */
***************
*** 102,109 ****
--- 123,134 ----
  	int reduced_wr;		/* First cylinder with reduced write current */
  	int wr_precomp;		/* First cylinder with write precompensation */
  	int max_ecc;		/* Maximum ECC burst length */
+ 	int ctrl_byte;		/* Copied control-byte from bios tables */
  } param0, param1;
  
+ #if	DEBUG
+ #define 	port_out(port, val)	xport_out(port, val)
+ #endif	/* DEBUG */
  /*===========================================================================*
   *				winchester_task				     * 
   *===========================================================================*/
***************
*** 114,120 ****
    int r, caller, proc_nr;
  
    /* First initialize the controller */
!   init_param();
  
    /* Here is the main loop of the disk task.  It waits for a message, carries
     * it out, and sends a reply.
--- 139,145 ----
    int r, caller, proc_nr;
  
    /* First initialize the controller */
!   init_params();
  
    /* Here is the main loop of the disk task.  It waits for a message, carries
     * it out, and sends a reply.
***************
*** 165,173 ****
    if (m_ptr->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);
--- 190,196 ----
    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)
--- 287,304 ----
  
    /* 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);
  }
  
--- 324,354 ----
  
    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);
  }
  
--- 363,376 ----
   * 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);
    }
  
--- 383,409 ----
   * 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<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);
  }
  
--- 410,529 ----
    /* Reset succeeded.  Tell WIN drive parameters. */
    w_need_reset = FALSE;
  
!   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);
! }
  
  
! /*===========================================================================*
!  *				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 */
! 
  	if (com_out(NO_DMA_INT) != OK)		/* Output command block */
  		return(ERR);
  	lock();
  
  	/* No. of cylinders (high byte) */
!   win_out(paramp->nr_cyl >> 8);
  
  	/* No. of cylinders (low byte) */
!   win_out(paramp->nr_cyl);
  
  	/* No. of heads */
!   win_out(paramp->nr_heads);
  
  	/* Start reduced write (high byte) */
!   win_out(paramp->reduced_wr >> 8);
  
  	/* Start reduced write (low byte) */
!   win_out(paramp->reduced_wr);
  
  	/* Start write precompensation (high byte) */
!   win_out(paramp->wr_precomp >> 8);
  
  	/* Start write precompensation (low byte) */
!   win_out(paramp->wr_precomp);
  
  	/* Ecc burst length */
!   win_out(paramp->max_ecc);
  	unlock();
+ 
  	if (check_init() != OK) {  /* See if controller accepted parameters */
  		w_need_reset = TRUE;
  		return(ERR);
  	}
!   else
    return(OK);
  }
  
***************
*** 466,479 ****
  PRIVATE check_init()
  {
  /* Routine to check if controller accepted the parameters */
!   int r;
  
!   if (hd_wait(2) == OK) {
  	  port_in(WIN_DATA, &r);
! 	  if (r & 2)
  		return(ERR);
  	  else
  		return(OK);
    }
  }
  
--- 533,562 ----
  PRIVATE check_init()
  {
  /* Routine to check if controller accepted the parameters */
!   int r, s;
  
!   if (hd_wait(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);
+ 		}
  	  else
  		return(OK);
+   } else
+ 	{
+ #if	DEBUG
+ 	printf("\ncheck_init: INPUT not active");
+ #endif	/* DEBUG */
+ 	return (ERR);	/* Missing from original: 11-Apr-87 G.O. */
    }
  }
  
***************
*** 487,495 ****
    int r;
  
    command[0] = WIN_ECC_READ;
!   if (com_out(NO_DMA_INT) == OK && hd_wait(1) == OK) {
  	port_in(WIN_DATA, &r);
! 	if (hd_wait(1) == OK) {
  		port_in(WIN_DATA, &r);
  		if (r & 1)
  			w_need_reset = TRUE;
--- 570,578 ----
    int r;
  
    command[0] = WIN_ECC_READ;
!   if (com_out(NO_DMA_INT) == OK && hd_wait(WST_REQ) == OK) {
  	port_in(WIN_DATA, &r);
! 	if (hd_wait(WST_REQ) == OK) {
  		port_in(WIN_DATA, &r);
  		if (r & 1)
  			w_need_reset = TRUE;
***************
*** 501,508 ****
  /*============================================================================*
   *				hd_wait					      *
   *============================================================================*/
! PRIVATE hd_wait(bit)
! register int bit;
  {
  /* Wait until the controller is ready to receive a command or send status */
  
--- 584,591 ----
  /*============================================================================*
   *				hd_wait					      *
   *============================================================================*/
! PRIVATE hd_wait(bits)
! register int bits;
  {
  /* Wait until the controller is ready to receive a command or send status */
  
***************
*** 511,521 ****
  
    do {
  	port_in(WIN_STATUS, &r);
! 	r &= bit;
!   } while ((i++ < MAX_WIN_RETRY) && !r);
  
    if (i >= MAX_WIN_RETRY) {
  	w_need_reset = TRUE;
  	return(ERR);
    } else
  	return(OK);
--- 594,607 ----
  
    do {
  	port_in(WIN_STATUS, &r);
! 	r &= bits;
!   } while ((i++ < MAX_WIN_RETRY) && r != bits); 	/* Wait for ALL bits */
  
    if (i >= MAX_WIN_RETRY) {
  	w_need_reset = TRUE;
+ #if	DEBUG
+ 	printf("\nhd_wait: timeout waiting for %x (%x)", bits, r);
+ #endif	/* DEBUG */
  	return(ERR);
    } else
  	return(OK);
***************
*** 529,557 ****
  {
  /* Output the command block to the winchester controller and return status */
  
! 	register int i = 0;
  	int r;
  
- 	port_out(WIN_SELECT, mode);
  	port_out(WIN_DMA, mode);
  	for (i=0; i<MAX_WIN_RETRY; i++) {
  		port_in(WIN_STATUS, &r);
! 		if ((r & 0x0F) == 0x0D)
  			break;
  	}
  	if (i == MAX_WIN_RETRY) {
  		w_need_reset = TRUE;
  		return(ERR);
  	}
  	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
  		return(OK);
  }
  
--- 615,664 ----
  {
  /* Output the command block to the winchester controller and return status */
  
! 	register int i;
  	int r;
  
  	port_out(WIN_DMA, mode);
+ 	port_out(WIN_SELECT, mode);
  	for (i=0; i<MAX_WIN_RETRY; i++) {
  		port_in(WIN_STATUS, &r);
! 		if (r & WST_BUSY)
  			break;
  	}
+ 
  	if (i == MAX_WIN_RETRY) {
  		w_need_reset = TRUE;
+ #if	DEBUG
+ 		printf("\ncom_out: retry exceeded, status = %x", r);
+ #endif	/* DEBUG */
  		return(ERR);
  	}
+ 
+ 
  	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
  		return(OK);
  }
  
***************
*** 572,580 ****
    /* Read the switches from the controller */
    port_in(WIN_SELECT, &i);
  
    /* Calculate the drive types */
!   type_0 = (i >> 2) & 3;
!   type_1 = i & 3;
  
    /* Copy the parameter vector from the saved vector table */
    offset = vec_table[2 * 0x41];
--- 679,728 ----
    /* Read the switches from the controller */
    port_in(WIN_SELECT, &i);
  
+ #if AUTO_BIOS
+   /* Get the drive parameters from sector zero of the drive if the */
+   /* autoconfig mode of the controller has been selected */
+   if(i & AUTO_ENABLE) {
+ 
+     /* set up some phoney parameters so that we can read the first sector */
+     /* from the winchester. all drives will have one cylinder and one head */
+     /* but set up initially to the mini scribe drives from ibm */
+     nr_drives = 1;
+     param0.nr_cyl = AUTO_CYLS;
+     param0.nr_heads = AUTO_HEADS;
+     param0.reduced_wr = AUTO_RWC;
+     param0.wr_precomp = AUTO_WPC;
+     param0.max_ecc = AUTO_ECC;
+     param0.ctrl_byte = AUTO_CTRL;
+     wini[0].wn_heads = param0.nr_heads;
+     wini[0].wn_low = 0L;
+     wini[0].wn_size = (long)AUTO_CYLS * (long)AUTO_HEADS * (long)NR_SECTORS;
+     if(w_reset() != OK)
+       panic("cannot setup for reading winchester parameter table",0);
+ 
+     /* generate the request to read the first sector from the winchester */
+     w_mess.DEVICE = 0;
+     w_mess.POSITION = 0L;
+     w_mess.COUNT = BLOCK_SIZE;
+     w_mess.ADDRESS = (char *) buf;
+     w_mess.PROC_NR = WINCHESTER;
+     w_mess.m_type = DISK_READ;
+     if(w_do_rdwt(&w_mess) != BLOCK_SIZE)
+       panic("cannot read drive parameters from winchester", 0);
+ 
+     /* copy the parameter tables into the structures for later use */
+     copy_param(&buf[AUTO_PARAM], &param0);
+     copy_param(&buf[AUTO_PARAM + 16], &param1);
+ 
+   /* whoever compiled the kernel wanted the auto bios code included. if it
+    * turns out that the tables should be read from the rom, then handle
+    * this case the regular way */
+   } else {
+ #endif
+ 
    /* Calculate the drive types */
!   type_0 = i & 3;
!   type_1 = (i >> 2) & 3;
  
    /* Copy the parameter vector from the saved vector table */
    offset = vec_table[2 * 0x41];
***************
*** 581,614 ****
    segment = vec_table[2 * 0x41 + 1];
  
    /* Calculate the address off the parameters and copy them to buf */
!   address = ((long)segment << 4) + offset;
    phys_copy(address, umap(proc_addr(WINCHESTER), D, buf, 64), 64L);
  
    /* Copy the parameters to the structures */
!   copy_param((&buf[type_0 * 16]), &param0);
!   copy_param((&buf[type_1 * 16]), &param1);
  
!   /* Get the nummer of drives from the bios */
    phys_copy(0x475L, umap(proc_addr(WINCHESTER), D, buf, 1), 1L);
    nr_drives = (int) *buf;
  
    /* Set the parameters in the drive structure */
!   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);
  
  
    /* Initialize the controller */
!   if ((nr_drives > 0) && (win_init() != OK))
  		nr_drives = 0;
  
    /* Read the partition table for each drive and save them */
    for (i = 0; i < nr_drives; i++) {
! 	w_mess.DEVICE = i * 5;
  	w_mess.POSITION = 0L;
  	w_mess.COUNT = BLOCK_SIZE;
  	w_mess.ADDRESS = (char *) buf;
--- 729,777 ----
    segment = vec_table[2 * 0x41 + 1];
  
    /* Calculate the address off the parameters and copy them to buf */
!   address = ((phys_bytes)segment << 4) + offset;
    phys_copy(address, umap(proc_addr(WINCHESTER), D, buf, 64), 64L);
  
    /* Copy the parameters to the structures */
!   copy_param(&buf[type_0 * 16], &param0);
!   copy_param(&buf[type_1 * 16], &param1);
  
! #if AUTO_BIOS
!   /* close up the code to be executed when the controller has not been
!    * set up to for auto configuration */
!   }
! #endif
! 
!   /* Get the number of drives from the bios */
    phys_copy(0x475L, umap(proc_addr(WINCHESTER), D, buf, 1), 1L);
    nr_drives = (int) *buf;
  
    /* Set the parameters in the drive structure */
!   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);
  
  
    /* Initialize the controller */
!   if ((nr_drives > 0) && (w_reset() != OK))
  		nr_drives = 0;
  
    /* Read the partition table for each drive and save them */
    for (i = 0; i < nr_drives; i++) {
! 	w_mess.DEVICE = i * DEV_PER_DRIVE;
  	w_mess.POSITION = 0L;
  	w_mess.COUNT = BLOCK_SIZE;
  	w_mess.ADDRESS = (char *) buf;
***************
*** 616,622 ****
  	w_mess.m_type = DISK_READ;
  	if (w_do_rdwt(&w_mess) != BLOCK_SIZE)
  		panic("Can't read partition table of winchester ", i);
! 	copy_prt(i * 5);
    }
  }
  
--- 779,788 ----
  	w_mess.m_type = DISK_READ;
  	if (w_do_rdwt(&w_mess) != BLOCK_SIZE)
  		panic("Can't read partition table of winchester ", i);
! 	copy_prt(i * DEV_PER_DRIVE);
! #if	DEBUG
! 	printf("\ninit_params: drive %d processed", i);
! #endif	/* DEBUG */
    }
  }
  
***************
*** 628,634 ****
  register struct param *dest;
  {
  /* This routine copies the parameters from src to dest
!  * and sets the parameters for partition 0 and 5
  */
  
    dest->nr_cyl = *(int *)src;
--- 794,800 ----
  register struct param *dest;
  {
  /* This routine copies the parameters from src to dest
!  * and sets the parameters for partition 0 and DEV_PER_DRIVE
  */
  
    dest->nr_cyl = *(int *)src;
***************
*** 636,641 ****
--- 802,808 ----
    dest->reduced_wr = *(int *)&src[3];
    dest->wr_precomp = *(int *)&src[5];
    dest->max_ecc = (int)src[7];
+   dest->ctrl_byte = (int)src[8];
  }
  
  /*============================================================================*
***************
*** 689,691 ****
--- 856,876 ----
    *first = *second;
    *second = tmp;
  }
+ 
+ #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 */