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