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);
--