*BSD News Article 24356


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!agate!howland.reston.ans.net!gatech!udel!newsserv.cs.sunysb.edu!stark.UUCP!cs.sunysb.edu!newsserv!stark!gene
From: newsserv!stark!gene@cs.sunysb.edu (Gene Stark)
Newsgroups: comp.os.386bsd.bugs
Subject: Re: FreeBSD hangs o n boot!
Date: 23 Nov 93 06:44:57
Organization: Gene Stark's home system
Lines: 678
Message-ID: <NEWSSERV!STARK!GENE.93Nov23064457@stark.uucp>
References: <matrix.753754654@noc>
NNTP-Posting-Host: stark.uucp
In-reply-to: matrix@noc.unt.edu's message of Sat, 20 Nov 1993 00:17:34 GMT

>I installed FreeBSD on a 386DX/33 with 20MB of RAM.  I have 2 hard drives. A
>Conner 205MB and a Maxtor 345MB drive.  Both of them are IDE drives.  The
>205 drive is master and the 345 is slave.  I have installed 4K partitions
>on the 205 and 8K on the 345MB.  When I boot the computer is hangs when mounting
>the root (/) partition.  It just sits there.  I can boot it in single user and
>and the type exit and let it boot into multi-user and it comes up.  Boot from
>a warmboot or cold boot it will not boot multiuser.  I need help please!  An
>ideas?  

It appears that you have exactly the same drives that I have, except that I
was unable to get anything to work unless the Conner was the slave drive.
Perhaps you could tell me if you did anything special to the Conner drive.
Mine is a CP30204.

I found after installing that hanging occurs in the wd driver when one of
the disks is initially opened and it does the first read, which is a
one sector read.  For me, this occured during the fsck.  My solution was
to hack the wd driver to get rid of the loops.  I posted these patches a
month ago, but here they are again.  Give 'em a try!

							- Gene Stark

*** /usr/src/sys/i386/isa/wd.c	Tue Nov  2 21:25:51 1993
--- /sys/i386/isa/wd.c	Thu Nov  4 07:40:01 1993
***************
*** 38,43 ****
--- 38,44 ----
   */
  
  /* TODO:peel out buffer at low ipl, speed improvement */
+ /*      make dk_copenpart and dk_bopenpart do something useful */
  
  
  #include "wd.h"
***************
*** 54,59 ****
--- 55,61 ----
  #include "buf.h"
  #include "uio.h"
  #include "malloc.h"
+ #include "kernel.h"
  #include "machine/cpu.h"
  #include "i386/isa/isa.h"
  #include "i386/isa/isa_device.h"
***************
*** 68,73 ****
--- 70,92 ----
  #define WDCTIMEOUT	10000000  /* arbitrary timeout for drive ready waits */
  #endif
  
+ #define WAITWHILE(cond,tout)  { \
+ 				int tymeout = WDCTIMEOUT; \
+ 				while(cond) { \
+ 				  if(--tymeout < 0) { tout } \
+ 				} \
+ 			      }
+ 
+ #define WDCRESET(wdc)  { \
+ 		         /* reset the device */ \
+ 		         outb((wdc)+wd_ctlr, (WDCTL_RST|WDCTL_IDS)); \
+ 		         DELAY(1000); \
+ 		         outb((wdc)+wd_ctlr, WDCTL_IDS); \
+ 		         DELAY(1000); \
+ 		         (void) inb((wdc)+wd_error);	/* XXX! */ \
+ 		         outb((wdc)+wd_ctlr, WDCTL_4BIT); \
+ 		        }
+ 
  #define	RETRIES		5	/* number of retries before giving up */
  #define	MAXTRANSFER	32	/* max size of transfer in page clusters */
  
***************
*** 136,145 ****
--- 155,166 ----
  
  static void wdustart(struct disk *);
  static void wdstart();
+ static void wdrestart(struct buf *bp);
  static int wdcommand(struct disk *, int);
  static int wdcontrol(struct buf *);
  static int wdsetctlr(dev_t, struct disk *);
  static int wdgetctlr(int, struct disk *);
+ static int wdctimeout(struct buf *);
  
  /*
   * Probe for controller.
***************
*** 194,201 ****
  int
  wdattach(struct isa_device *dvp)
  {
! 	int unit;
! /*	int unit = dvp->id_unit;*/
  
  	for (unit=0; unit< _NWD; unit++) {
  		struct disk *du;
--- 215,221 ----
  int
  wdattach(struct isa_device *dvp)
  {
! 	int unit, x;
  
  	for (unit=0; unit< _NWD; unit++) {
  		struct disk *du;
***************
*** 208,216 ****
--- 228,238 ----
  		}
  
  		/* print out description of drive, suppressing multiple blanks*/
+ 		x = splbio();
  		if(wdgetctlr(unit, du) == 0)  {
  			int i, blank;
  			char c;
+ 			splx(x);
  			printf("wd%d: unit %d type ", unit, unit);
  			for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) {
  				char c = du->dk_params.wdp_model[i];
***************
*** 229,234 ****
--- 251,257 ----
  			printf("\n");
  			du->dk_unit = unit;
  		}
+ 		splx(x);
  	}
  	return(1);
  }
***************
*** 276,282 ****
  		/* otherwise, process transfer request */
  	}
  
- q:
  	/* queue transfer on drive, activate drive and controller if idle */
  	dp = &wdutab[unit];
  	s = splbio();
--- 299,304 ----
***************
*** 284,290 ****
  	if (dp->b_active == 0)
  		wdustart(du);		/* start drive */
  	if (wdtab.b_active == 0)
! 		wdstart(s);		/* start controller */
  	splx(s);
  	return;
  
--- 306,312 ----
  	if (dp->b_active == 0)
  		wdustart(du);		/* start drive */
  	if (wdtab.b_active == 0)
! 		wdstart();		/* start controller */
  	splx(s);
  	return;
  
***************
*** 341,362 ****
  	struct buf *dp;
  	register struct bt_bad *bt_ptr;
  	long	blknum, pagcnt, cylin, head, sector;
! 	long	secpertrk, secpercyl, addr, i, timeout;
  	int	unit, s, wdc;
  
! loop:
! 	/* is there a drive for the controller to do a transfer with? */
! 	dp = wdtab.b_actf;
! 	if (dp == NULL)
! 		return;
! 
! 	/* is there a transfer to this drive ? if so, link it on
! 	   the controller's queue */
! 	bp = dp->b_actf;
! 	if (bp == NULL) {
! 		wdtab.b_actf = dp->b_forw;
! 		goto loop;
! 	}
  
  	/* obtain controller and drive information */
  	unit = wdunit(bp->b_dev);
--- 363,383 ----
  	struct buf *dp;
  	register struct bt_bad *bt_ptr;
  	long	blknum, pagcnt, cylin, head, sector;
! 	long	secpertrk, secpercyl, addr, i;
  	int	unit, s, wdc;
  
! 	do {
! 	  /* is there a drive for the controller to do a transfer with? */
! 	  dp = wdtab.b_actf;
! 	  if (dp == NULL)
! 	    return;
! 
! 	  /* is there a transfer to this drive ? if so, link it on
! 	     the controller's queue */
! 	  bp = dp->b_actf;
! 	  if (bp == NULL)
! 	    wdtab.b_actf = dp->b_forw;
! 	} while(bp == NULL);
  
  	/* obtain controller and drive information */
  	unit = wdunit(bp->b_dev);
***************
*** 445,466 ****
  			du->dk_bc += DEV_BSIZE;
  
  		/* controller idle? */
! 		timeout = 0;
! 		while (inb(wdc+wd_status) & WDCS_BUSY)
! 		{
! 			if (++timeout > WDCTIMEOUT)
! 			{
! 				printf("wd.c: Controller busy too long!\n");
! 				/* reset the device */
! 				outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
! 				DELAY(1000);
! 				outb(wdc+wd_ctlr, WDCTL_IDS);
! 				DELAY(1000);
! 				(void) inb(wdc+wd_error);	/* XXX! */
! 				outb(wdc+wd_ctlr, WDCTL_4BIT);
! 				break;
! 			}
! 		}
  
  		/* stuff the task file */
  		outb(wdc+wd_precomp, lp->d_precompcyl / 4);
--- 466,475 ----
  			du->dk_bc += DEV_BSIZE;
  
  		/* controller idle? */
! 		WAITWHILE((inb(wdc+wd_status) & WDCS_BUSY),
! 			  {printf("wd.c: Controller busy too long!\n");
! 			   WDCRESET(wdc)
! 			   break;})
  
  		/* stuff the task file */
  		outb(wdc+wd_precomp, lp->d_precompcyl / 4);
***************
*** 487,508 ****
  		outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
  
  		/* wait for drive to become ready */
! 		timeout = 0;
! 		while ((inb(wdc+wd_status) & WDCS_READY) == 0)
! 		{
! 			if (++timeout > WDCTIMEOUT)
! 			{
! 				printf("wd.c: Drive busy too long!\n");
! 				/* reset the device */
! 				outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
! 				DELAY(1000);
! 				outb(wdc+wd_ctlr, WDCTL_IDS);
! 				DELAY(1000);
! 				(void) inb(wdc+wd_error);	/* XXX! */
! 				outb(wdc+wd_ctlr, WDCTL_4BIT);
! 				goto RETRY;
! 			}
! 		}
  
  		/* initiate command! */
  #ifdef	B_FORMAT
--- 496,505 ----
  		outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
  
  		/* wait for drive to become ready */
! 		WAITWHILE(((inb(wdc+wd_status) & WDCS_READY) == 0),
! 			  {printf("wd.c: Drive busy too long!\n");
! 			   WDCRESET(wdc)
! 			   goto RETRY;})
  
  		/* initiate command! */
  #ifdef	B_FORMAT
***************
*** 518,543 ****
  #endif
  	}
  
  	/* if this is a read operation, just go away until it's done.	*/
  	if (bp->b_flags & B_READ) return;
  
  	/* ready to send data?	*/
! 	timeout = 0;
! 	while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
! 	{
! 		if (++timeout > WDCTIMEOUT)
! 		{
! 			printf("wd.c: Drive not ready for too long!\n");
! 			/* reset the device */
! 			outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
! 			DELAY(1000);
! 			outb(wdc+wd_ctlr, WDCTL_IDS);
! 			DELAY(1000);
! 			(void) inb(wdc+wd_error);	/* XXX! */
! 			outb(wdc+wd_ctlr, WDCTL_4BIT);
! 			goto RETRY;
! 		}
! 	}
  
  	/* then send it! */
  	outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
--- 515,531 ----
  #endif
  	}
  
+ 	/* set alarm clock in case we never get an interrupt */
+ 	timeout(wdctimeout, bp, 2*hz);
+ 
  	/* if this is a read operation, just go away until it's done.	*/
  	if (bp->b_flags & B_READ) return;
  
  	/* ready to send data?	*/
! 	WAITWHILE(((inb(wdc+wd_status) & WDCS_DRQ) == 0),
! 		  {printf("wd.c: Drive not ready for too long!\n");
! 		   WDCRESET(wdc)
! 		   goto RETRY;})
  
  	/* then send it! */
  	outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
***************
*** 574,580 ****
  	printf("I ");
  #endif
  
! 	while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
  
  	/* is it not a transfer, but a control operation? */
  	if (du->dk_state < OPEN) {
--- 562,571 ----
  	printf("I ");
  #endif
  
! 	WAITWHILE(((status = inb(wdc+wd_status)) & WDCS_BUSY),
! 		  {printf("wd.c: Controller not ready after interrupt!\n");
! 		   wdrestart(bp);
! 		   return;})
  
  	/* is it not a transfer, but a control operation? */
  	if (du->dk_state < OPEN) {
***************
*** 634,641 ****
  		chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
  
  		/* ready to receive data? */
! 		while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
! 			;
  
  		/* suck in data */
  		insw (wdc+wd_data,
--- 625,634 ----
  		chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
  
  		/* ready to receive data? */
! 		WAITWHILE(((inb(wdc+wd_status) & WDCS_DRQ) == 0),
! 			  {printf("wd.c: not ready to receive data!\n");
! 			   wdrestart(bp);
! 			   return;})
  
  		/* suck in data */
  		insw (wdc+wd_data,
***************
*** 657,662 ****
--- 650,656 ----
  
  			/* see if more to transfer */
  			if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
+ 			        untimeout(wdctimeout, bp);
  				wdstart();
  				return;		/* next chunk is started */
  			} else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR))
***************
*** 664,669 ****
--- 658,664 ----
  				du->dk_skip = 0;
  				du->dk_flags &= ~DKFL_ERROR;
  				du->dk_flags |=  DKFL_SINGLE;
+ 				untimeout(wdctimeout, bp);
  				wdstart();
  				return;		/* redo xfer sector by sector */
  			}
***************
*** 671,676 ****
--- 666,672 ----
  
  done:
  		/* done with this transfer, with or without error */
+ 		untimeout(wdctimeout, bp);
  		du->dk_flags &= ~DKFL_SINGLE;
  		wdtab.b_actf = dp->b_forw;
  		wdtab.b_errcnt = 0;
***************
*** 694,699 ****
--- 690,729 ----
  }
  
  /*
+  * Timeout routine in case no interrupt is forthcoming for
+  * the current transfer.  Reset the device, and start over.
+  */
+ 
+ int
+ wdctimeout(struct buf *bp)
+ {
+   printf("wd.c: Transfer is taking too long -- restarting\n");
+   wdrestart(bp);
+ }
+ 
+ /*
+  * Reset the controller and restart the current transfer in case the
+  * controller doesn't do something when it seems like it should.
+  */
+ 
+ void
+ wdrestart(struct buf *bp)
+ {
+   register struct disk *du;
+   int i;
+ 
+   i = splbio();
+   untimeout(wdctimeout, bp);
+   du = wddrives[wdunit(bp->b_dev)];
+   WDCRESET(du->dk_port)
+   wdtab.b_active = 0;
+   du->dk_skip = 0;
+   du->dk_flags &= ~DKFL_ERROR;
+   wdstart();
+   splx(i);
+ }
+ 
+ /*
   * Initialize a drive.
   */
  int
***************
*** 722,728 ****
  		 * or longer if there isn't one there.
  		 */
  		bzero(&du->dk_dd, sizeof(du->dk_dd));
- #undef d_type /* fix goddamn segments.h! XXX */
  		du->dk_dd.d_type = DTYPE_ST506;
  		du->dk_dd.d_ncylinders = 1024;
  		du->dk_dd.d_secsize = DEV_BSIZE;
--- 752,757 ----
***************
*** 760,766 ****
           * that overlaps another partition which is open
           * unless one is the "raw" partition (whole disk).
           */
!         if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
  		int	start, end;
  
                  pp = &du->dk_dd.d_partitions[part];
--- 789,795 ----
           * that overlaps another partition which is open
           * unless one is the "raw" partition (whole disk).
           */
!         if ((du->dk_openpart & mask) == 0 && part != WDRAW) {
  		int	start, end;
  
                  pp = &du->dk_dd.d_partitions[part];
***************
*** 772,779 ****
                          if (pp->p_offset + pp->p_size <= start ||
                              pp->p_offset >= end)
                                  continue;
-                         /*if (pp - du->dk_dd.d_partitions == RAWPART)
-                                 continue; */
                          if (pp - du->dk_dd.d_partitions == WDRAW)
                                  continue;
                          if (du->dk_openpart & (1 << (pp -
--- 801,806 ----
***************
*** 835,843 ****
  		wdtab.b_active = 1;
  
  		/* wait for drive and controller to become ready */
! 		for (i = WDCTIMEOUT; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY))
! 				  != WDCS_READY && i-- != 0; )
! 			;
  		outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
  		du->dk_state++;
  		splx(s);
--- 862,870 ----
  		wdtab.b_active = 1;
  
  		/* wait for drive and controller to become ready */
! 		WAITWHILE(((inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY))
! 			    != WDCS_READY),{break;})
! 
  		outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
  		du->dk_state++;
  		splx(s);
***************
*** 853,859 ****
  				goto tryagainrecal;
  			}
  			bp->b_error = ENXIO;	/* XXX needs translation */
! 			goto badopen;
  		}
  
  		/* some controllers require this ... */
--- 880,889 ----
  				goto tryagainrecal;
  			}
  			bp->b_error = ENXIO;	/* XXX needs translation */
! 			printf(": status %b error %b\n", stat, WDCS_BITS,
! 			       inb(wdc + wd_error), WDERR_BITS);
! 			bp->b_flags |= B_ERROR;
! 			return(1);
  		}
  
  		/* some controllers require this ... */
***************
*** 871,882 ****
  		panic("wdcontrol");
  	}
  	/* NOTREACHED */
- 
- badopen:
- 	printf(": status %b error %b\n", stat, WDCS_BITS,
- 		inb(wdc + wd_error), WDERR_BITS);
- 	bp->b_flags |= B_ERROR;
- 	return(1);
  }
  
  /*
--- 901,906 ----
***************
*** 887,917 ****
   */
  static int
  wdcommand(struct disk *du, int cmd) {
! 	int timeout = WDCTIMEOUT, stat, wdc;
  
  	/* controller ready for command? */
  	wdc = du->dk_port;
! 	while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
! 		timeout--;
! 	if (timeout <= 0)
! 		return(-1);
  
  	/* send command, await results */
  	outb(wdc+wd_command, cmd);
! 	while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
! 		timeout--;
! 	if (timeout <= 0)
! 		return(-1);
  	if (cmd != WDCC_READP)
  		return (stat);
  
  	/* is controller ready to return data? */
! 	while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
! 		timeout > 0)
! 		timeout--;
! 	if (timeout <= 0)
! 		return(-1);
! 
  	return (stat);
  }
  
--- 911,931 ----
   */
  static int
  wdcommand(struct disk *du, int cmd) {
! 	int stat, wdc;
  
  	/* controller ready for command? */
  	wdc = du->dk_port;
! 	WAITWHILE(((stat = inb(wdc + wd_status)) & WDCS_BUSY), return(-1);)
  
  	/* send command, await results */
  	outb(wdc+wd_command, cmd);
! 	WAITWHILE(((stat = inb(wdc+wd_status)) & WDCS_BUSY), return(-1);)
  	if (cmd != WDCC_READP)
  		return (stat);
  
  	/* is controller ready to return data? */
! 	WAITWHILE((((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0),
! 	          return(-1);)
  	return (stat);
  }
  
***************
*** 946,965 ****
  
  /*
   * issue READP to drive to ask it what it is.
   */
  static int
  wdgetctlr(int u, struct disk *du) {
! 	int stat, x, i, wdc;
  	char tb[DEV_BSIZE];
  	struct wdparams *wp;
  
- 	x = splbio();		/* not called from intr level ... */
  	wdc = du->dk_port;
  	outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
  	stat = wdcommand(du, WDCC_READP);
  
  	if (stat < 0) {
- 		splx(x);
  		return(stat);
  	}
  	/*
--- 960,979 ----
  
  /*
   * issue READP to drive to ask it what it is.
+  * EWS: call at splbio()
   */
  static int
  wdgetctlr(int u, struct disk *du) {
! 	int stat, i, wdc;
  	char tb[DEV_BSIZE];
  	struct wdparams *wp;
  
  	wdc = du->dk_port;
+ 	WDCRESET(wdc)  /* EWS: seems to help sometimes */
  	outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
  	stat = wdcommand(du, WDCC_READP);
  
  	if (stat < 0) {
  		return(stat);
  	}
  	/*
***************
*** 971,977 ****
  		stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
  		if (stat & WDCS_ERR) {
  	  		stat = inb(wdc+wd_error);
- 			splx(x);
  			return(stat);
  		}
  
--- 985,990 ----
***************
*** 980,986 ****
  		strncpy(du->dk_params.wdp_model, "Unknown Type",
  			sizeof du->dk_params.wdp_model);
  		du->dk_dd.d_type = DTYPE_ST506;
- 		splx(x);
  		return(0);
  	}
  
--- 993,998 ----
***************
*** 1201,1207 ****
  	addr = (char *) 0;		/* starting address */
  
  	/* toss any characters present prior to dump */
! 	while (sgetc(1))
  		;
  
  	/* size of memory to dump */
--- 1213,1219 ----
  	addr = (char *) 0;		/* starting address */
  
  	/* toss any characters present prior to dump */
! 	while (sgetc(1) & 0xff)  /* EWS: A hack to work with syscons */
  		;
  
  	/* size of memory to dump */
***************
*** 1333,1339 ****
  		(int) addr += 512;
  
  		/* operator aborting dump? */
! 		if (sgetc(1))
  			return(EINTR);
  	}
  	return(0);
--- 1345,1351 ----
  		(int) addr += 512;
  
  		/* operator aborting dump? */
! 		if (sgetc(1) & 0xff)  /* EWS: A hack to work with syscons */
  			return(EINTR);
  	}
  	return(0);

--