diff options
| author | mycroft <mycroft@NetBSD.org> | 1994-03-10 05:18:33 +0000 |
|---|---|---|
| committer | mycroft <mycroft@NetBSD.org> | 1994-03-10 05:18:33 +0000 |
| commit | e4102b8797beaa9f12c36ecf9947d0e3bc5dc19c (patch) | |
| tree | f8cbca4f0c1ca70a27c6a2b73c3721946898d7e6 /sys/dev | |
| parent | 90812e91d855669a98a090c4d10f35575bb3bb49 (diff) | |
Cleanup to fit standard coding conventions, and *many* bugs fixed.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/ata/wd.c | 1348 | ||||
| -rw-r--r-- | sys/dev/ic/wdcreg.h | 17 | ||||
| -rw-r--r-- | sys/dev/isa/wd.c | 1348 | ||||
| -rw-r--r-- | sys/dev/isa/wdreg.h | 17 |
4 files changed, 1390 insertions, 1340 deletions
diff --git a/sys/dev/ata/wd.c b/sys/dev/ata/wd.c index 50068924530..4cccda603b2 100644 --- a/sys/dev/ata/wd.c +++ b/sys/dev/ata/wd.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.63 1994/03/07 05:54:44 mycroft Exp $ + * $Id: wd.c,v 1.64 1994/03/10 05:18:33 mycroft Exp $ */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */ @@ -55,6 +55,7 @@ #include <sys/buf.h> #include <sys/uio.h> #include <sys/malloc.h> +#include <sys/device.h> #include <sys/syslog.h> #ifdef INSTRUMENT #include <sys/dkstat.h> @@ -73,10 +74,11 @@ #define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */ #define WDCDELAY 100 +#define RECOVERYTIME hz/2 /* time to recover from an error */ #if 0 -/* if you enable this, it will report any delays more than 100us * N long */ -#define WDCNDELAY_DEBUG 100 +/* If you enable this, it will report any delays more than 100us * N long. */ +#define WDCNDELAY_DEBUG 50 #endif #define WDIORETRIES 5 /* number of retries before giving up */ @@ -92,7 +94,7 @@ /* * Drive states. Used to initialize drive. */ -#define CLOSED 0 /* disk is closed. */ +#define CLOSED 0 /* disk is closed */ #define WANTOPEN 1 /* open requested, not started */ #define RECAL 2 /* doing restore */ #define OPEN 3 /* done with open */ @@ -100,68 +102,68 @@ /* * Drive status. */ -struct disk { - long dk_bc; /* byte count left */ - long dk_bct; /* total byte count left */ - short dk_skip; /* blocks already transferred */ - short dk_skipm; /* blocks already transferred for multi */ - char dk_ctrlr; /* physical controller number */ - char dk_unit; /* physical unit number */ - char dk_lunit; /* logical unit number */ - char dk_state; /* control state */ - int dk_timeout; /* timeout counter */ - u_char dk_status; /* copy of status reg. */ - u_char dk_error; /* copy of error reg. */ - u_short dk_port; /* i/o port base */ +struct wd_softc { + struct device sc_dev; + + long sc_bcount; /* byte count left */ + long sc_mbcount; /* total byte count left */ + short sc_skip; /* blocks already transferred */ + short sc_mskip; /* blocks already transferred for multi */ + char sc_unit; /* physical unit number */ + char sc_lunit; /* logical unit number */ + char sc_state; /* control state */ - u_long dk_copenpart; /* character units open on this drive */ - u_long dk_bopenpart; /* block units open on this drive */ - u_long dk_openpart; /* all units open on this drive */ - short dk_wlabel; /* label writable? */ - short dk_flags; /* drive characteistics found */ -#define DKFL_SINGLE 0x00004 /* sector at a time mode */ -#define DKFL_ERROR 0x00008 /* processing a disk error */ -#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */ -#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */ -#define DKFL_WRITEPROT 0x00040 /* manual unit write protect */ - struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */ - struct disklabel dk_dd; /* device configuration data */ - struct cpu_disklabel dk_cpd; - long dk_badsect[127]; /* 126 plus trailing -1 marker */ -}; - -struct board { - short dkc_port; -}; - -struct board wdcontroller[NWDC]; -struct disk *wddrives[NWD]; /* table of units */ -struct buf wdtab[NWDC]; /* various per-controller info */ -struct buf wdutab[NWD]; /* head of queue per drive */ -struct buf rwdbuf[NWD]; /* buffers for raw IO */ -long wdxfer[NWD]; /* count of transfers */ - -int wdprobe(), wdattach(); + u_long sc_copenpart; /* character units open on this drive */ + u_long sc_bopenpart; /* block units open on this drive */ + u_long sc_openpart; /* all units open on this drive */ + short sc_wlabel; /* label writable? */ + short sc_flags; /* drive characteistics found */ +#define WDF_SINGLE 0x00004 /* sector at a time mode */ +#define WDF_ERROR 0x00008 /* processing a disk error */ +#define WDF_BSDLABEL 0x00010 /* has a BSD disk label */ +#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */ +#define WDF_WRITEPROT 0x00040 /* manual unit write protect */ + struct buf sc_q; + struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ + struct disklabel sc_label; /* device configuration data */ + struct cpu_disklabel sc_cpulabel; + long sc_badsect[127]; /* 126 plus trailing -1 marker */ +} *wd_softc[NWD]; + +struct wdc_softc { + struct device sc_dev; + + struct buf sc_q; + u_char sc_status; /* copy of status register */ + u_char sc_error; /* copy of error register */ + u_short sc_iobase; /* i/o port base */ + int sc_timeout; /* timeout counter */ +} wdc_softc[NWDC]; + +int wdprobe(), wdattach(), wdintr(); struct isa_driver wdcdriver = { wdprobe, wdattach, "wdc", }; -static void wdustart __P((struct disk *)); -static void wdstart __P((int)); -static int wdcommand __P((struct disk *, int, int, int, int, int)); +void wdfinish __P((struct wd_softc *, struct buf *)); +static void wdstart __P((struct wd_softc *)); +static void wdcstart __P((struct wdc_softc *)); +static int wdcommand __P((struct wd_softc *, int, int, int, int, int)); static int wdcontrol __P((struct buf *)); -static int wdsetctlr __P((struct disk *)); -static int wdgetctlr __P((struct disk *)); -static void bad144intern __P((struct disk *)); -static int wdreset __P((struct disk *, int)); -static void wdtimeout __P((caddr_t)); +static int wdsetctlr __P((struct wd_softc *)); +static int wdgetctlr __P((struct wd_softc *)); +static void bad144intern __P((struct wd_softc *)); +static int wdcreset __P((struct wdc_softc *)); +static void wdcrestart __P((struct wdc_softc *)); +static void wdcunwedge __P((struct wdc_softc *)); +static void wdctimeout __P((struct wdc_softc *)); void wddisksort __P((struct buf *, struct buf *)); -static void wderror __P((struct disk *, struct buf *, char *)); -int wdwait __P((struct disk *, int)); -#define wait_for_drq(d) wdwait(d, WDCS_DRQ) -#define wait_for_ready(d) wdwait(d, WDCS_READY | WDCS_SEEKCMPLT) -#define wait_for_unbusy(d) wdwait(d, 0) +static void wderror __P((void *, struct buf *, char *)); +int wdcwait __P((struct wdc_softc *, int)); +#define wait_for_drq(d) wdcwait(d, WDCS_DRQ) +#define wait_for_ready(d) wdcwait(d, WDCS_READY | WDCS_SEEKCMPLT) +#define wait_for_unbusy(d) wdcwait(d, 0) /* * Probe for controller. @@ -170,52 +172,66 @@ int wdprobe(isa_dev) struct isa_device *isa_dev; { - struct disk *du; - u_short wdc; + struct wd_softc *wd; + struct wdc_softc *wdc; + u_short iobase; if (isa_dev->id_unit >= NWDC) return 0; + wdc = &wdc_softc[isa_dev->id_unit]; - du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); - bzero(du, sizeof(struct disk)); + /* XXX HACK */ + sprintf(wdc->sc_dev.dv_xname, "%s%d", "wdc", isa_dev->id_unit); + wdc->sc_dev.dv_unit = isa_dev->id_unit; - du->dk_ctrlr = isa_dev->id_unit; - du->dk_unit = 0; - du->dk_lunit = 0; - wdcontroller[isa_dev->id_unit].dkc_port = isa_dev->id_iobase; + wdc->sc_iobase = iobase = isa_dev->id_iobase; - wdc = du->dk_port = isa_dev->id_iobase; + /* Check if we have registers that work. */ + outb(iobase+wd_error, 0x5a); /* Error register not writable. */ + outb(iobase+wd_cyl_lo, 0xa5); /* But all of cyllo are implemented. */ + if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5) + return 0; - /* check if we have registers that work */ - outb(wdc+wd_error, 0x5a); /* error register not writable */ - outb(wdc+wd_cyl_lo, 0xa5); /* but all of cyllo are implemented */ - if (inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5) - goto nodevice; + if (wdcreset(wdc) != 0) { + delay(500000); + if (wdcreset(wdc) != 0) + return 0; + } - wdreset(du, 0); + /* + * XXX wdcommand() accepts a wd_softc, so we have to make it one. + */ + wd = (void *)malloc(sizeof(struct wd_softc), M_TEMP, M_NOWAIT); + bzero(wd, sizeof(struct wd_softc)); + wd->sc_unit = 0; + wd->sc_lunit = 0; + wd->sc_dev.dv_parent = (void *)wdc; - /* execute a controller only command */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0) - goto nodevice; + /* Execute a controller only command. */ + if (wdcommand(wd, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0 || + wait_for_unbusy(wdc) != 0) + goto lose; - free(du, M_TEMP); + wdctimeout(wdc); + + free(wd, M_TEMP); return 8; -nodevice: - free(du, M_TEMP); +lose: + free(wd, M_TEMP); return 0; } /* - * Called for the controller too - * Attach each drive if possible. + * Called for the controller too. Attach each drive if possible. */ int wdattach(isa_dev) struct isa_device *isa_dev; { - int unit, lunit; - struct disk *du; + int lunit; + struct wd_softc *wd; + struct wdc_softc *wdc; int i, blank; if (isa_dev->id_masunit == -1) @@ -225,44 +241,40 @@ wdattach(isa_dev) lunit = isa_dev->id_unit; if (lunit == -1) { - printf("wdc%d: cannot support unit ?\n", isa_dev->id_masunit); + printf("%s: cannot support unit ?\n", wdc->sc_dev.dv_xname); return 0; } if (lunit >= NWD) return 0; - unit = isa_dev->id_physid; - du = wddrives[lunit] = - (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); - bzero(du, sizeof(struct disk)); - bzero(&wdutab[lunit], sizeof(struct buf)); - bzero(&rwdbuf[lunit], sizeof(struct buf)); - wdxfer[lunit] = 0; - du->dk_ctrlr = isa_dev->id_masunit; - du->dk_unit = unit; - du->dk_lunit = lunit; - du->dk_port = wdcontroller[isa_dev->id_masunit].dkc_port; - - if (wdgetctlr(du) != 0) { - /*printf("wd%d at wdc%d slave %d -- error\n", lunit, - isa_dev->id_masunit, unit);*/ - wddrives[lunit] = 0; - free(du, M_TEMP); + wdc = &wdc_softc[isa_dev->id_masunit]; + + wd_softc[lunit] = wd = + (void *)malloc(sizeof(struct wd_softc), M_TEMP, M_NOWAIT); + bzero(wd, sizeof(struct wd_softc)); + wd->sc_unit = isa_dev->id_physid; + wd->sc_lunit = lunit; + + /* XXX HACK */ + sprintf(wd->sc_dev.dv_xname, "%s%d", "wd", isa_dev->id_unit); + wd->sc_dev.dv_unit = isa_dev->id_unit; + wd->sc_dev.dv_parent = (void *)wdc; + + if (wdgetctlr(wd) != 0) return 0; - } - printf("wd%d at wdc%d targ %d: ", isa_dev->id_unit, - isa_dev->id_masunit, isa_dev->id_physid); - if (du->dk_params.wdp_heads == 0) + printf("%s at %s targ %d: ", wd->sc_dev.dv_xname, wdc->sc_dev.dv_xname, + isa_dev->id_physid); + if (wd->sc_params.wdp_heads == 0) printf("(unknown size) <"); else printf("%dMB %d cyl, %d head, %d sec <", - du->dk_dd.d_ncylinders * du->dk_dd.d_secpercyl / + wd->sc_label.d_ncylinders * wd->sc_label.d_secpercyl / (1048576 / DEV_BSIZE), - du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, - du->dk_dd.d_nsectors); - for (i = blank = 0; i < sizeof(du->dk_params.wdp_model); i++) { - char c = du->dk_params.wdp_model[i]; + wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks, + wd->sc_label.d_nsectors); + for (i = blank = 0; i < sizeof(wd->sc_params.wdp_model); i++) { + char c = wd->sc_params.wdp_model[i]; if (c == '\0') break; if (c != ' ') { @@ -276,68 +288,70 @@ wdattach(isa_dev) } printf(">\n"); - wdtimeout((caddr_t)du); - return 1; } -/* Read/write routine for a buffer. Finds the proper unit, range checks - * arguments, and schedules the transfer. Does not wait for the transfer - * to complete. Multi-page transfers are supported. All I/O requests must - * be a multiple of a sector in length. +/* + * Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer to + * complete. Multi-page transfers are supported. All I/O requests must be a + * multiple of a sector in length. */ -int +void wdstrategy(bp) struct buf *bp; { struct buf *dp; - struct disk *du; /* Disk unit to do the IO. */ + struct wd_softc *wd; /* disk unit to do the IO */ + struct wdc_softc *wdc; int lunit = WDUNIT(bp->b_dev); int s; - /* valid unit, controller, and request? */ + /* Valid unit, controller, and request? */ if (lunit >= NWD || bp->b_blkno < 0 || howmany(bp->b_bcount, DEV_BSIZE) >= (1 << NBBY) || - (du = wddrives[lunit]) == 0) { + (wd = wd_softc[lunit]) == 0) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; goto done; } - /* "soft" write protect check */ - if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) { + /* "Soft" write protect check. */ + if ((wd->sc_flags & WDF_WRITEPROT) && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; bp->b_flags |= B_ERROR; goto done; } - /* have partitions and want to use them? */ - if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) { + /* Have partitions and want to use them? */ + if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) { /* - * do bounds checking, adjust transfer. if error, process. - * if end of partition, just return + * Do bounds checking, adjust transfer. if error, process. + * If end of partition, just return. */ - if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0) + if (bounds_check_with_label(bp, &wd->sc_label, + wd->sc_wlabel) <= 0) goto done; - /* otherwise, process transfer request */ + /* Otherwise, process transfer request. */ } - /* don't bother */ + /* Don't bother doing rotational optimization. */ bp->b_cylin = 0; - /* queue transfer on drive, activate drive and controller if idle */ - dp = &wdutab[lunit]; + /* Queue transfer on drive, activate drive and controller if idle. */ + dp = &wd->sc_q; s = splbio(); wddisksort(dp, bp); if (dp->b_active == 0) - wdustart(du); /* start drive */ - if (wdtab[du->dk_ctrlr].b_active == 0) - wdstart(du->dk_ctrlr); /* start controller */ + wdstart(wd); /* Start drive. */ + wdc = (void *)wd->sc_dev.dv_parent; + if (wdc->sc_q.b_active == 0) + wdcstart(wdc); /* Start controller. */ splx(s); - return 0; + return; done: - /* toss transfer, we're done early */ + /* Toss transfer; we're done early. */ biodone(bp); } @@ -356,192 +370,245 @@ wddisksort(dp, bp) } /* - * Routine to queue a command to the controller. The unit's - * request is linked into the active list for the controller. - * If the controller is idle, the transfer is started. + * Routine to queue a command to the controller. The unit's request is linked + * into the active list for the controller. If the controller is idle, the + * transfer is started. */ static void -wdustart(du) - struct disk *du; +wdstart(wd) + struct wd_softc *wd; { - struct buf *dp = &wdutab[du->dk_lunit]; - int ctrlr = du->dk_ctrlr; + struct buf *dp; + struct wdc_softc *wdc; + + dp = &wd->sc_q; - /* unit already active? */ + /* Unit already active? */ if (dp->b_active) return; - - /* anything to start? */ + /* Anything to start? */ if (dp->b_actf == NULL) return; - /* link onto controller queue */ + /* Link onto controller queue. */ dp->b_forw = NULL; - if (wdtab[ctrlr].b_forw == NULL) - wdtab[ctrlr].b_forw = dp; + wdc = (void *)wd->sc_dev.dv_parent; + if (wdc->sc_q.b_forw == NULL) + wdc->sc_q.b_forw = dp; else - wdtab[ctrlr].b_actl->b_forw = dp; - wdtab[ctrlr].b_actl = dp; + wdc->sc_q.b_actl->b_forw = dp; + wdc->sc_q.b_actl = dp; - /* mark the drive unit as busy */ + /* Mark the drive unit as busy. */ dp->b_active = 1; } +void +wdfinish(wd, bp) + struct wd_softc *wd; + struct buf *bp; +{ + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; + +#ifdef INSTRUMENT + dk_busy &= ~(1 << wd->sc_unit); +#endif + wd->sc_flags &= ~(WDF_SINGLE | WDF_ERROR); + wdc->sc_q.b_errcnt = 0; + /* + * If this is the only buf or the last buf in the transfer (taking into + * account any residual, in case we erred)... + */ + wd->sc_mbcount -= wd->sc_bcount; + if (wd->sc_mbcount == 0) { + /* + * ...then move this drive to the end of the queue to give + * others a `fair' chance. + */ + wdc->sc_q.b_forw = wd->sc_q.b_forw; + wd->sc_mskip = 0; + wd->sc_q.b_active = 0; + if (wd->sc_q.b_actf) + wdstart(wd); + } + bp->b_resid = wd->sc_bcount; + bp->b_flags &= ~B_XXX; + wd->sc_skip = 0; + wd->sc_q.b_actf = bp->b_actf; + biodone(bp); +} + /* - * Controller startup routine. This does the calculation, and starts - * a single-sector read or write operation. Called to start a transfer, - * or from the interrupt routine to continue a multi-sector transfer. + * Controller startup routine. This does the calculation, and starts a + * single-sector read or write operation. Called to start a transfer, or from + * the interrupt routine to continue a multi-sector transfer. * RESTRICTIONS: * 1. The transfer length must be an exact multiple of the sector size. */ static void -wdstart(ctrlr) - int ctrlr; +wdcstart(wdc) + struct wdc_softc *wdc; { - register struct disk *du; /* disk unit for IO */ - register struct buf *bp; + struct wd_softc *wd; /* disk unit for IO */ + struct buf *bp; struct disklabel *lp; struct buf *dp; long blknum, cylin, head, sector; long secpertrk, secpercyl; int xfrblknum; int lunit; - + loop: - /* is there a drive for the controller to do a transfer with? */ - dp = wdtab[ctrlr].b_forw; + /* Is there a drive for the controller to do a transfer with? */ + dp = wdc->sc_q.b_forw; if (dp == NULL) { - wdtab[ctrlr].b_active = 0; + wdc->sc_q.b_active = 0; return; } - /* is there a transfer to this drive ? if so, link it on - the controller's queue */ + /* Is there a transfer to this drive? If not, deactivate drive. */ bp = dp->b_actf; if (bp == NULL) { dp->b_active = 0; - wdtab[ctrlr].b_forw = dp->b_forw; + wdc->sc_q.b_forw = dp->b_forw; goto loop; } - /* obtain controller and drive information */ + /* Obtain controller and drive information */ lunit = WDUNIT(bp->b_dev); - du = wddrives[lunit]; + wd = wd_softc[lunit]; - /* clear any pending timeout, just in case */ - du->dk_timeout = 0; + if (wdc->sc_q.b_errcnt >= WDIORETRIES) { + wderror(wd, bp, "hard error"); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + wdfinish(wd, bp); + goto loop; + } - /* if not really a transfer, do control operations specially */ - if (du->dk_state < OPEN) { + /* Clear any pending timeout, just in case. */ + wdc->sc_timeout = 0; + + /* If not really a transfer, do control operations specially. */ + if (wd->sc_state < OPEN) { (void) wdcontrol(bp); return; } - - /* calculate transfer details */ - blknum = bp->b_blkno + du->dk_skip; + + /* + * WDF_ERROR is set by wdcunwedge() and wdintr() when an error is + * encountered *only* in multi-sector mode. We switch to single-sector + * mode and retry the operation from the start. + */ + if (wd->sc_flags & WDF_ERROR) { + /* Switch to single-sector mode. */ + wd->sc_flags &= ~WDF_ERROR; + wd->sc_flags |= WDF_SINGLE; + wd->sc_skip = 0; + wd->sc_mskip = 0; + } + + /* Calculate transfer details. */ + blknum = bp->b_blkno + wd->sc_skip; #ifdef WDDEBUG - if (du->dk_skip == 0) - printf("\nwdstart %d: %s %d@%d; map ", lunit, + if (wd->sc_skip == 0) + printf("\nwdcstart %d: %s %d@%d; map ", lunit, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else - printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts)); + printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts)); #endif - if (du->dk_skip == 0) - du->dk_bc = bp->b_bcount; - if (du->dk_skipm == 0) { + if (wd->sc_skip == 0) + wd->sc_bcount = bp->b_bcount; + if (wd->sc_mskip == 0) { struct buf *oldbp, *nextbp; oldbp = bp; nextbp = bp->b_actf; - du->dk_bct = du->dk_bc; + wd->sc_mbcount = wd->sc_bcount; oldbp->b_flags |= B_XXX; - while (nextbp && (oldbp->b_flags & DKFL_SINGLE) == 0 && + while (nextbp && (oldbp->b_flags & WDF_SINGLE) == 0 && oldbp->b_dev == nextbp->b_dev && nextbp->b_blkno == (oldbp->b_blkno + (oldbp->b_bcount / DEV_BSIZE)) && (oldbp->b_flags & B_READ) == (nextbp->b_flags & B_READ)) { - if ((du->dk_bct + nextbp->b_bcount) / DEV_BSIZE >= 240) + if ((wd->sc_mbcount + nextbp->b_bcount) / DEV_BSIZE >= 240) break; - du->dk_bct += nextbp->b_bcount; + wd->sc_mbcount += nextbp->b_bcount; nextbp->b_flags |= B_XXX; oldbp = nextbp; nextbp = nextbp->b_actf; } } - lp = &du->dk_dd; + lp = &wd->sc_label; secpertrk = lp->d_nsectors; secpercyl = lp->d_secpercyl; - if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) + if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - /* Check for bad sectors if we have them, and not formatting */ - /* Only do this in single-sector mode, or when starting a */ - /* multiple-sector transfer. */ - if ((du->dk_flags & DKFL_BADSECT) && + /* + * Check for bad sectors if we have them, and not formatting. Only do + * this in single-sector mode, or when starting a multiple-sector + * transfer. + */ + if ((wd->sc_flags & WDF_BADSECT) && #ifdef B_FORMAT (bp->b_flags & B_FORMAT) == 0 && #endif - (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE))) { + (wd->sc_mskip == 0 || (wd->sc_flags & WDF_SINGLE))) { long blkchk, blkend, blknew; int i; - blkend = blknum + howmany(du->dk_bct, DEV_BSIZE) - 1; - for (i = 0; (blkchk = du->dk_badsect[i]) != -1; i++) { + blkend = blknum + howmany(wd->sc_mbcount, DEV_BSIZE) - 1; + for (i = 0; (blkchk = wd->sc_badsect[i]) != -1; i++) { if (blkchk > blkend) - break; /* transfer is completely OK; done */ + break; /* Transfer is completely OK; done. */ if (blkchk == blknum) { blknew = lp->d_secperunit - lp->d_nsectors - i - 1; cylin = blknew / secpercyl; head = (blknew % secpercyl) / secpertrk; sector = blknew % secpertrk; - du->dk_flags |= DKFL_SINGLE; - /* found and replaced first blk of transfer; done */ + wd->sc_flags |= WDF_SINGLE; + /* Found and replaced first blk of transfer; done. */ break; } else if (blkchk > blknum) { - du->dk_flags |= DKFL_SINGLE; - break; /* bad block inside transfer; done */ + wd->sc_flags |= WDF_SINGLE; + break; /* Bad block inside transfer; done. */ } } } - if (du->dk_flags & DKFL_SINGLE) { - du->dk_bct = du->dk_bc; - du->dk_skipm = du->dk_skip; + if (wd->sc_flags & WDF_SINGLE) { + wd->sc_mbcount = wd->sc_bcount; + wd->sc_mskip = wd->sc_skip; } #ifdef WDDEBUG printf("c%d h%d s%d ", cylin, head, sector); #endif - sector++; /* sectors begin with 1, not 0 */ + sector++; /* Sectors begin with 1, not 0. */ - wdtab[ctrlr].b_active = 1; /* mark controller active */ + wdc->sc_q.b_active = 1; /* Mark controller active. */ #ifdef INSTRUMENT - /* instrumentation */ - if (du->dk_unit >= 0 && du->dk_skip == 0) { - dk_busy |= 1 << du->dk_lunit; - dk_wds[du->dk_lunit] += bp->b_bcount >> 6; - } - if (du->dk_unit >= 0 && du->dk_skipm == 0) { - ++dk_seek[du->dk_lunit]; - ++dk_xfer[du->dk_lunit]; + if (wd->sc_skip == 0) { + dk_busy |= 1 << wd->sc_lunit; + dk_wds[wd->sc_lunit] += bp->b_bcount >> 6; } #endif -retry: - /* if starting a multisector transfer, or doing single transfers */ - if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) { + /* If starting a multisector transfer, or doing single transfers. */ + if (wd->sc_mskip == 0 || (wd->sc_flags & WDF_SINGLE)) { int command, count; - if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) { - du->dk_bc += DEV_BSIZE; - du->dk_bct += DEV_BSIZE; - } +#ifdef INSTRUMENT + ++dk_seek[wd->sc_lunit]; + ++dk_xfer[wd->sc_lunit]; +#endif #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { @@ -549,109 +616,103 @@ retry: count = lp->d_nsectors; command = WDCC_FORMAT; } else { - if (du->dk_flags & DKFL_SINGLE) + if (wd->sc_flags & WDF_SINGLE) count = 1; else - count = howmany(du->dk_bct, DEV_BSIZE); + count = howmany(wd->sc_mbcount, DEV_BSIZE); command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE; } #else - if (du->dk_flags & DKFL_SINGLE) + if (wd->sc_flags & WDF_SINGLE) count = 1; else - count = howmany(du->dk_bct, DEV_BSIZE); + count = howmany(wd->sc_mbcount, DEV_BSIZE); command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE; #endif - /* initiate command! */ - while (wdcommand(du, cylin, head, sector, count, command) < 0) { - wderror(du, NULL, - "wdstart: timeout waiting for unbusy"); - wdreset(du, 1); + /* Initiate command! */ + if (wdcommand(wd, cylin, head, sector, count, command) != 0) { + wderror(wd, NULL, + "wdcstart: timeout waiting for unbusy"); + wdcunwedge(wdc); + return; } #ifdef WDDEBUG printf("sector %d cylin %d head %d addr %x sts %x\n", sector, - cylin, head, bp->b_un.b_addr, inb(du->dk_port+wd_altsts)); + cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts)); #endif } - du->dk_timeout = 2; + wdc->sc_timeout = 4; - /* if this is a read operation, just go away until it's done. */ + /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; - if (wait_for_drq(du) < 0) { - /* XXX seems wrong */ - wdreset(du, 1); - goto retry; + if (wait_for_drq(wdc) < 0) { + wderror(wd, NULL, "wdcstart: timeout waiting for drq"); + wdcunwedge(wdc); + return; } - /* then send it! */ - outsw(du->dk_port+wd_data, bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, + /* Then send it! */ + outsw(wdc->sc_iobase+wd_data, bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE, DEV_BSIZE / sizeof(short)); - - du->dk_bc -= DEV_BSIZE; - du->dk_bct -= DEV_BSIZE; } -/* Interrupt routine for the controller. Acknowledge the interrupt, check for - * errors on the current operation, mark it done if necessary, and start - * the next request. Also check for a partially done transfer, and - * continue with the next chunk if so. +/* + * Interrupt routine for the controller. Acknowledge the interrupt, check for + * errors on the current operation, mark it done if necessary, and start the + * next request. Also check for a partially done transfer, and continue with + * the next chunk if so. */ -void +int wdintr(ctrlr) int ctrlr; { - register struct disk *du; - register struct buf *bp, *dp; + struct wdc_softc *wdc = &wdc_softc[ctrlr]; + struct wd_softc *wd; + struct buf *bp; - /* clear the pending interrupt */ - (void) inb(wdcontroller[ctrlr].dkc_port+wd_status); + /* Clear the pending interrupt. */ + (void) inb(wdc->sc_iobase+wd_status); - if (!wdtab[ctrlr].b_active) { - printf("wdc%d: extra interrupt\n", ctrlr); - return; + if (!wdc->sc_q.b_active) { + printf("%s: extra interrupt\n", wdc->sc_dev.dv_xname); + return 0; } - dp = wdtab[ctrlr].b_forw; - bp = dp->b_actf; - du = wddrives[WDUNIT(bp->b_dev)]; - du->dk_timeout = 0; + bp = wdc->sc_q.b_forw->b_actf; + wd = wd_softc[WDUNIT(bp->b_dev)]; + wdc->sc_timeout = 0; #ifdef WDDEBUG printf("I%d ", ctrlr); #endif - if (wait_for_unbusy(du) < 0) { - wderror(du, NULL, "wdintr: timeout waiting for unbusy"); - du->dk_status |= WDCS_ERR; /* XXX */ + if (wait_for_unbusy(wdc) < 0) { + wderror(wd, NULL, "wdintr: timeout waiting for unbusy"); + wdc->sc_status |= WDCS_ERR; /* XXX */ } - /* is it not a transfer, but a control operation? */ - if (du->dk_state < OPEN) { - wdtab[ctrlr].b_active = 0; - switch (wdcontrol(bp)) { - case -1: - goto done; - case 1: - wdstart(ctrlr); - break; - } - return; + /* Is it not a transfer, but a control operation? */ + if (wd->sc_state < OPEN) { + wdc->sc_q.b_active = 0; + if (wdcontrol(bp)) + wdcstart(wdc); + return 1; } - /* have we an error? */ - if (du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) { + /* Have we an error? */ + if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) { lose: #ifdef WDDEBUG - wderror(du, NULL, "wdintr"); + wderror(wd, NULL, "wdintr"); #endif - if ((du->dk_flags & DKFL_SINGLE) == 0) { - du->dk_flags |= DKFL_ERROR; - goto outt; + if ((wd->sc_flags & WDF_SINGLE) == 0) { + wd->sc_flags |= WDF_ERROR; + goto restart; } #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { @@ -661,102 +722,60 @@ wdintr(ctrlr) } #endif - /* error or error correction? */ - if (du->dk_status & WDCS_ERR) { - if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) - wdtab[ctrlr].b_active = 0; - else { - wderror(du, bp, "hard error"); + /* Error or error correction? */ + if (wdc->sc_status & WDCS_ERR) { + if (++wdc->sc_q.b_errcnt >= WDIORETRIES) { + wderror(wd, bp, "hard error"); bp->b_error = EIO; - bp->b_flags |= B_ERROR; /* flag the error */ - } + bp->b_flags |= B_ERROR; /* Flag the error. */ + goto done; + } else + goto restart; } else - wderror(du, bp, "soft ecc"); + wderror(wd, bp, "soft ecc"); } - /* - * If this was a successful read operation, fetch the data. - */ - if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && - wdtab[ctrlr].b_active) { - int chk; - - chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short)); - - /* ready to receive data? */ - if (wait_for_drq(du) != 0) { - wderror(du, NULL, "wdintr: read error detected late"); - goto lose; + /* If this was a read, fetch the data. */ + if (bp->b_flags & B_READ) { + /* Ready to receive data? */ + if (wait_for_drq(wdc) != 0) { + wderror(wd, NULL, "wdintr: read error detected late"); + wdcunwedge(wdc); + return 1; } - /* suck in data */ - insw(du->dk_port+wd_data, - bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk); - du->dk_bc -= chk * sizeof(short); - du->dk_bct -= chk * sizeof(short); - - /* for obselete fractional sector reads */ - while (chk++ < (DEV_BSIZE / sizeof(short))) - (void) inw(du->dk_port+wd_data); + /* Suck in data. */ + insw(wdc->sc_iobase+wd_data, + bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE, + DEV_BSIZE / sizeof(short)); } - wdxfer[du->dk_lunit]++; -outt: - if (wdtab[ctrlr].b_active) { -#ifdef INSTRUMENT - if (du->dk_unit >= 0) - dk_busy &= ~(1 << du->dk_unit); -#endif - if ((bp->b_flags & B_ERROR) == 0) { - du->dk_skip++; /* Add to succ. sect */ - du->dk_skipm++; /* Add to succ. sect for multitransfer */ - if (wdtab[ctrlr].b_errcnt) - wderror(du, bp, "soft error"); - wdtab[ctrlr].b_errcnt = 0; - - /* see if more to transfer */ - if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { - wdtab[ctrlr].b_active = 0; - wdstart(ctrlr); - return; /* next chunk is started */ - } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR)) == DKFL_ERROR) { - du->dk_skip = 0; - du->dk_skipm = 0; - du->dk_flags &= ~DKFL_ERROR; - du->dk_flags |= DKFL_SINGLE; - wdtab[ctrlr].b_active = 0; - wdstart(ctrlr); - return; /* redo xfer sector by sector */ - } - } - - done: - /* done with this transfer, with or without error */ - du->dk_flags &= ~DKFL_SINGLE; - wdtab[ctrlr].b_errcnt = 0; - if (du->dk_bct == 0) { - wdtab[ctrlr].b_forw = dp->b_forw; - du->dk_skipm = 0; - dp->b_active = 0; - } - bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE; - bp->b_flags &= ~B_XXX; - du->dk_skip = 0; - dp->b_actf = bp->b_actf; - dp->b_errcnt = 0; - biodone(bp); + /* If we encountered any abnormalities, flag it as a soft error. */ + if (wdc->sc_q.b_errcnt) { + wderror(wd, bp, "soft error"); + wdc->sc_q.b_errcnt = 0; } + + /* Ready for the next block, if any. */ + wd->sc_skip++; + wd->sc_mskip++; + wd->sc_bcount -= DEV_BSIZE; + wd->sc_mbcount -= DEV_BSIZE; - /* controller now idle */ - wdtab[ctrlr].b_active = 0; + /* See if more to transfer. */ + if (wd->sc_bcount > 0) + goto restart; - /* anything more on drive queue? */ - if (dp->b_actf && du->dk_bct == 0) - wdustart(du); +done: + /* Done with this transfer, with or without error. */ + wdfinish(wd, bp); + +restart: + /* Start the next transfer, if any. */ + wdc->sc_q.b_active = 0; + wdcstart(wdc); - /* anything more for controller to do? */ - if (wdtab[ctrlr].b_forw) - wdstart(ctrlr); + return 1; } /* @@ -770,7 +789,7 @@ wdopen(dev, flag, fmt, p) struct proc *p; { int lunit; - struct disk *du; + struct wd_softc *wd; int part = WDPART(dev), mask = 1 << part; struct partition *pp; char *msg; @@ -778,98 +797,98 @@ wdopen(dev, flag, fmt, p) lunit = WDUNIT(dev); if (lunit >= NWD) return ENXIO; - du = wddrives[lunit]; - if (du == 0) + wd = wd_softc[lunit]; + if (wd == 0) return ENXIO; - if ((du->dk_flags & DKFL_BSDLABEL) == 0) { - du->dk_flags |= DKFL_WRITEPROT; - wdutab[lunit].b_actf = NULL; + if ((wd->sc_flags & WDF_BSDLABEL) == 0) { + wd->sc_flags |= WDF_WRITEPROT; + wd->sc_q.b_actf = NULL; /* - * Use the default sizes until we've read the label, - * or longer if there isn't one there. + * Use the default sizes until we've read the label, or longer + * if there isn't one there. */ - bzero(&du->dk_dd, sizeof(du->dk_dd)); - du->dk_dd.d_type = DTYPE_ST506; - du->dk_dd.d_ncylinders = 1024; - du->dk_dd.d_secsize = DEV_BSIZE; - du->dk_dd.d_ntracks = 8; - du->dk_dd.d_nsectors = 17; - du->dk_dd.d_secpercyl = 17*8; - du->dk_dd.d_secperunit = 17*8*1024; - du->dk_state = WANTOPEN; - - /* read label using "raw" partition */ + bzero(&wd->sc_label, sizeof(wd->sc_label)); + wd->sc_label.d_type = DTYPE_ST506; + wd->sc_label.d_ncylinders = 1024; + wd->sc_label.d_secsize = DEV_BSIZE; + wd->sc_label.d_ntracks = 8; + wd->sc_label.d_nsectors = 17; + wd->sc_label.d_secpercyl = 17*8; + wd->sc_label.d_secperunit = 17*8*1024; + wd->sc_state = WANTOPEN; + + /* Read label using "raw" partition. */ #ifdef notdef - /* wdsetctlr(du); */ /* Maybe do this TIH */ + /* wdsetctlr(wd); */ /* Maybe do this TIH */ msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW), - wdstrategy, &du->dk_dd, &du->dk_cpd); - wdsetctlr(du); + wdstrategy, &wd->sc_label, &wd->sc_cpulabel); + wdsetctlr(wd); #endif if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), - WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) { - log(LOG_WARNING, "wd%d: cannot find label (%s)\n", - lunit, msg); + WDRAW), wdstrategy, &wd->sc_label, &wd->sc_cpulabel)) { + log(LOG_WARNING, "%s: cannot find label (%s)\n", + wd->sc_dev.dv_xname, msg); if (part != WDRAW) return EINVAL; /* XXX needs translation */ } else { - wdsetctlr(du); - du->dk_flags |= DKFL_BSDLABEL; - du->dk_flags &= ~DKFL_WRITEPROT; - if (du->dk_dd.d_flags & D_BADSECT) - du->dk_flags |= DKFL_BADSECT; + wdsetctlr(wd); + wd->sc_flags |= WDF_BSDLABEL; + wd->sc_flags &= ~WDF_WRITEPROT; + if (wd->sc_label.d_flags & D_BADSECT) + wd->sc_flags |= WDF_BADSECT; } } - if (du->dk_flags & DKFL_BADSECT) - bad144intern(du); + if (wd->sc_flags & WDF_BADSECT) + bad144intern(wd); /* * Warn if a partition is opened that overlaps another partition which * is open unless one is the "raw" partition (whole disk). */ - if ((du->dk_openpart & mask) == 0 && part != WDRAW) { + if ((wd->sc_openpart & mask) == 0 && part != WDRAW) { int start, end; - pp = &du->dk_dd.d_partitions[part]; + pp = &wd->sc_label.d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; - for (pp = du->dk_dd.d_partitions; - pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; + for (pp = wd->sc_label.d_partitions; + pp < &wd->sc_label.d_partitions[wd->sc_label.d_npartitions]; pp++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; - if (pp - du->dk_dd.d_partitions == WDRAW) + if (pp - wd->sc_label.d_partitions == WDRAW) continue; - if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions))) + if (wd->sc_openpart & (1 << (pp - wd->sc_label.d_partitions))) log(LOG_WARNING, - "wd%d%c: overlaps open partition (%c)\n", - lunit, part + 'a', - pp - du->dk_dd.d_partitions + 'a'); + "%s%c: overlaps open partition (%c)\n", + wd->sc_dev.dv_xname, part + 'a', + pp - wd->sc_label.d_partitions + 'a'); } } - if (part >= du->dk_dd.d_npartitions && part != WDRAW) + if (part >= wd->sc_label.d_npartitions && part != WDRAW) return ENXIO; - /* insure only one open at a time */ - du->dk_openpart |= mask; + /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: - du->dk_copenpart |= mask; + wd->sc_copenpart |= mask; break; case S_IFBLK: - du->dk_bopenpart |= mask; + wd->sc_bopenpart |= mask; break; } + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; return 0; } /* * Implement operations other than read/write. - * Called from wdstart or wdintr during opens and formats. + * Called from wdcstart or wdintr during opens and formats. * Uses finite-state-machine to track progress of operation in progress. * Returns 0 if operation still in progress, 1 if completed. */ @@ -877,39 +896,30 @@ static int wdcontrol(bp) struct buf *bp; { - struct disk *du; - int ctrlr; + struct wd_softc *wd = wd_softc[WDUNIT(bp->b_dev)]; + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; - du = wddrives[WDUNIT(bp->b_dev)]; - ctrlr = du->dk_ctrlr; - - switch (du->dk_state) { - case WANTOPEN: /* set SDH, step rate, do restore */ + switch (wd->sc_state) { + case WANTOPEN: /* Set SDH, step rate, do restore. */ tryagainrecal: - wdgetctlr(du); /* XXX Is this necessary? */ - wdtab[ctrlr].b_active = 1; - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) { - wderror(du, 0, "wdcontrol: wdcommand failed"); - goto lose; + wdgetctlr(wd); /* XXX Is this necessary? */ + wdc->sc_q.b_active = 1; + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) { + wderror(wd, NULL, "wdcontrol: wdcommand failed"); + wdcunwedge(wdc); + return 0; } - du->dk_state = RECAL; + wd->sc_state = RECAL; return 0; case RECAL: - if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) { - wderror(du, NULL, "wdcontrol: recal failed"); - lose: - if (du->dk_status & WDCS_ERR) - wdreset(du, 1); - du->dk_state = WANTOPEN; - if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) - goto tryagainrecal; - bp->b_error = ENXIO; /* XXX needs translation */ - bp->b_flags |= B_ERROR; - return -1; + if (wdc->sc_status & WDCS_ERR || wdsetctlr(wd) != 0) { + wderror(wd, NULL, "wdcontrol: recal failed"); + wdcunwedge(wdc); + return 0; } - wdtab[ctrlr].b_errcnt = 0; - du->dk_state = OPEN; + wdc->sc_q.b_errcnt = 0; + wd->sc_state = OPEN; /* * The rest of the initialization can be done by normal means. */ @@ -922,136 +932,128 @@ wdcontrol(bp) } /* - * send a command and wait uninterruptibly until controller is finished. - * return -1 if controller busy for too long, otherwise - * return status. intended for brief controller commands at critical points. - * assumes interrupts are blocked. + * Send a command and wait uninterruptibly until controller is finished. + * Return -1 if controller busy for too long, otherwise return non-zero if + * error. Intended for brief controller commands at critical points. + * Assumes interrupts are blocked. */ static int -wdcommand(du, cylin, head, sector, count, cmd) - struct disk *du; +wdcommand(wd, cylin, head, sector, count, cmd) + struct wd_softc *wd; int cylin, head, sector, count; int cmd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; int stat; - u_short wdc; + u_short iobase; - /* controller ready for command? */ - if (wait_for_unbusy(du) < 0) + /* Controller ready for command? */ + if (wait_for_unbusy(wdc) < 0) return -1; - /* select drive */ - wdc = du->dk_port; - outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head); + /* Select drive. */ + iobase = wdc->sc_iobase; + outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_unit << 4) | head); if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC) - stat = wait_for_unbusy(du); + stat = wait_for_unbusy(wdc); else - stat = wdwait(du, WDCS_READY); + stat = wdcwait(wdc, WDCS_READY); if (stat < 0) return -1; - /* load parameters */ - outb(wdc+wd_precomp, du->dk_dd.d_precompcyl / 4); - outb(wdc+wd_cyl_lo, cylin); - outb(wdc+wd_cyl_hi, cylin >> 8); - outb(wdc+wd_sector, sector); - outb(wdc+wd_seccnt, count); + /* Load parameters. */ + outb(iobase+wd_precomp, wd->sc_label.d_precompcyl / 4); + outb(iobase+wd_cyl_lo, cylin); + outb(iobase+wd_cyl_hi, cylin >> 8); + outb(iobase+wd_sector, sector); + outb(iobase+wd_seccnt, count); - /* send command, await results */ - outb(wdc+wd_command, cmd); + /* Send command, await results. */ + outb(iobase+wd_command, cmd); - switch (cmd) { - default: -#if 0 - case WDCC_FORMAT: - case WDCC_RESTORE | WD_STEP: - case WDCC_DIAGNOSE: -#endif - return wait_for_unbusy(du); - case WDCC_READ: - case WDCC_WRITE: - return 0; - case WDCC_IDC: - return wdwait(du, WDCS_READY); - case WDCC_READP: - return wait_for_drq(du); - } + return 0; } /* - * issue IDC to drive to tell it just what geometry it is to be. + * Issue IDC to drive to tell it just what geometry it is to be. */ static int -wdsetctlr(du) - struct disk *du; +wdsetctlr(wd) + struct wd_softc *wd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; #ifdef WDDEBUG - printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit, - du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors); + printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_ctrlr, wd->sc_unit, + wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks, + wd->sc_label.d_nsectors); #endif - if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0, - du->dk_dd.d_nsectors, WDCC_IDC) != 0) { - wderror(du, NULL, "wdsetctlr: failed"); + if (wdcommand(wd, wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks - 1, + 0, wd->sc_label.d_nsectors, WDCC_IDC) != 0 || + wdcwait(wdc, WDCS_READY) != 0) { + wderror(wd, NULL, "wdsetctlr: failed"); return -1; } return 0; } /* - * issue READP to drive to ask it what it is. + * Issue READP to drive to ask it what it is. */ static int -wdgetctlr(du) - struct disk *du; +wdgetctlr(wd) + struct wd_softc *wd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; int i; char tb[DEV_BSIZE]; struct wdparams *wp; - if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0) { + if (wdcommand(wd, 0, 0, 0, 0, WDCC_READP) != 0 || + wait_for_drq(wdc) != 0) { /* - * If WDCC_READP fails then we might have an old drive - * so we try a seek to 0; if that passes then the - * drive is there but it's OLD AND KRUSTY. + * If WDCC_READP fails then we might have an old drive so we + * try a seek to 0; if that passes then the drive is there but + * it's OLD AND KRUSTY. */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || + wait_for_ready(wdc) != 0) return -1; - strncpy(du->dk_dd.d_typename, "ST506", - sizeof du->dk_dd.d_typename); - strncpy(du->dk_params.wdp_model, "Unknown Type", - sizeof du->dk_params.wdp_model); - du->dk_dd.d_type = DTYPE_ST506; + strncpy(wd->sc_label.d_typename, "ST506", + sizeof wd->sc_label.d_typename); + strncpy(wd->sc_params.wdp_model, "Unknown Type", + sizeof wd->sc_params.wdp_model); + wd->sc_label.d_type = DTYPE_ST506; } else { - /* obtain parameters */ - wp = &du->dk_params; - insw(du->dk_port+wd_data, tb, sizeof(tb) / sizeof(short)); + /* Obtain parameters. */ + wp = &wd->sc_params; + insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short)); bcopy(tb, wp, sizeof(struct wdparams)); - /* shuffle string byte order */ + /* Shuffle string byte order. */ for (i = 0; i < sizeof(wp->wdp_model); i += 2) { u_short *p; p = (u_short *)(wp->wdp_model + i); *p = ntohs(*p); } - strncpy(du->dk_dd.d_typename, "ESDI/IDE", - sizeof du->dk_dd.d_typename); - du->dk_dd.d_type = DTYPE_ESDI; - bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); + strncpy(wd->sc_label.d_typename, "ESDI/IDE", + sizeof wd->sc_label.d_typename); + wd->sc_label.d_type = DTYPE_ESDI; + bcopy(wp->wdp_model+20, wd->sc_label.d_packname, 14-1); - /* update disklabel given drive information */ - du->dk_dd.d_ncylinders = + /* Update disklabel given drive information. */ + wd->sc_label.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; - du->dk_dd.d_ntracks = wp->wdp_heads; - du->dk_dd.d_nsectors = wp->wdp_sectors; - du->dk_dd.d_secpercyl = - du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; - du->dk_dd.d_partitions[1].p_size = - du->dk_dd.d_secpercyl * wp->wdp_sectors; - du->dk_dd.d_partitions[1].p_offset = 0; + wd->sc_label.d_ntracks = wp->wdp_heads; + wd->sc_label.d_nsectors = wp->wdp_sectors; + wd->sc_label.d_secpercyl = + wd->sc_label.d_ntracks * wd->sc_label.d_nsectors; + wd->sc_label.d_partitions[1].p_size = + wd->sc_label.d_secpercyl * wp->wdp_sectors; + wd->sc_label.d_partitions[1].p_offset = 0; } #if 0 @@ -1060,11 +1062,10 @@ wdgetctlr(du) wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model); #endif - /* better ... */ - du->dk_dd.d_subtype |= DSTYPE_GEOMETRY; + wd->sc_label.d_subtype |= DSTYPE_GEOMETRY; /* XXX sometimes possibly needed */ - (void) inb(du->dk_port+wd_status); + (void) inb(wdc->sc_iobase+wd_status); return 0; } @@ -1075,18 +1076,18 @@ wdclose(dev, flag, fmt) int flag; int fmt; { - struct disk *du = wddrives[WDUNIT(dev)]; + struct wd_softc *wd = wd_softc[WDUNIT(dev)]; int part = WDPART(dev), mask = 1 << part; - du->dk_openpart &= ~mask; switch (fmt) { case S_IFCHR: - du->dk_copenpart &= ~mask; + wd->sc_copenpart &= ~mask; break; case S_IFBLK: - du->dk_bopenpart &= ~mask; + wd->sc_bopenpart &= ~mask; break; } + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; return 0; } @@ -1100,75 +1101,75 @@ wdioctl(dev, cmd, addr, flag, p) struct proc *p; { int lunit = WDUNIT(dev); - struct disk *du = wddrives[lunit]; + struct wd_softc *wd = wd_softc[lunit]; int error; switch (cmd) { case DIOCSBAD: if ((flag & FWRITE) == 0) return EBADF; - du->dk_cpd.bad = *(struct dkbad *)addr; - bad144intern(du); + wd->sc_cpulabel.bad = *(struct dkbad *)addr; + bad144intern(wd); return 0; case DIOCGDINFO: - *(struct disklabel *)addr = du->dk_dd; + *(struct disklabel *)addr = wd->sc_label; return 0; case DIOCGPART: - ((struct partinfo *)addr)->disklab = &du->dk_dd; + ((struct partinfo *)addr)->disklab = &wd->sc_label; ((struct partinfo *)addr)->part = - &du->dk_dd.d_partitions[WDPART(dev)]; + &wd->sc_label.d_partitions[WDPART(dev)]; return 0; case DIOCSDINFO: if ((flag & FWRITE) == 0) return EBADF; - error = setdisklabel(&du->dk_dd, + error = setdisklabel(&wd->sc_label, (struct disklabel *)addr, - /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0, - &du->dk_cpd); + /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart : */0, + &wd->sc_cpulabel); if (error == 0) { - du->dk_flags |= DKFL_BSDLABEL; - wdsetctlr(du); + wd->sc_flags |= WDF_BSDLABEL; + wdsetctlr(wd); } return error; case DIOCWLABEL: - du->dk_flags &= ~DKFL_WRITEPROT; + wd->sc_flags &= ~WDF_WRITEPROT; if ((flag & FWRITE) == 0) return EBADF; - du->dk_wlabel = *(int *)addr; + wd->sc_wlabel = *(int *)addr; return 0; case DIOCWDINFO: - du->dk_flags &= ~DKFL_WRITEPROT; + wd->sc_flags &= ~WDF_WRITEPROT; if ((flag & FWRITE) == 0) return EBADF; - error = setdisklabel(&du->dk_dd, + error = setdisklabel(&wd->sc_label, (struct disklabel *)addr, - /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/0, - &du->dk_cpd); + /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart :*/0, + &wd->sc_cpulabel); if (error == 0) { int wlab; - du->dk_flags |= DKFL_BSDLABEL; - wdsetctlr(du); + wd->sc_flags |= WDF_BSDLABEL; + wdsetctlr(wd); - /* simulate opening partition 0 so write succeeds */ - du->dk_openpart |= (1 << 0); /* XXX */ - wlab = du->dk_wlabel; - du->dk_wlabel = 1; - error = writedisklabel(dev, wdstrategy, &du->dk_dd, - &du->dk_cpd); - du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; - du->dk_wlabel = wlab; + /* Simulate opening partition 0 so write succeeds. */ + wd->sc_openpart |= (1 << 0); /* XXX */ + wlab = wd->sc_wlabel; + wd->sc_wlabel = 1; + error = writedisklabel(dev, wdstrategy, &wd->sc_label, + &wd->sc_cpulabel); + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; + wd->sc_wlabel = wlab; } return error; #ifdef notyet case DIOCGDINFOP: - *(struct disklabel **)addr = &du->dk_dd; + *(struct disklabel **)addr = &wd->sc_label; return 0; case DIOCWFORMAT: @@ -1187,12 +1188,12 @@ wdioctl(dev, cmd, addr, flag, p) auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = - fop->df_startblk * du->dk_dd.d_secsize; - error = physio(wdformat, &rwdbuf[lunit], dev, B_WRITE, - minphys, &auio); + fop->df_startblk * wd->sc_label.d_secsize; + error = physio(wdformat, NULL, dev, B_WRITE, minphys, + &auio); fop->df_count -= auio.uio_resid; - fop->df_reg[0] = du->dk_status; - fop->df_reg[1] = du->dk_error; + fop->df_reg[0] = wdc->sc_status; + fop->df_reg[1] = wdc->sc_error; return error; } #endif @@ -1221,15 +1222,15 @@ wdsize(dev) dev_t dev; { int lunit = WDUNIT(dev), part = WDPART(dev); - struct disk *du; + struct wd_softc *wd; if (lunit >= NWD) return -1; - du = wddrives[lunit]; - if (du == 0) + wd = wd_softc[lunit]; + if (wd == 0) return -1; - if (du->dk_state < OPEN || (du->dk_flags & DKFL_BSDLABEL) == 0) { + if (wd->sc_state < OPEN || (wd->sc_flags & WDF_BSDLABEL) == 0) { int val; val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, S_IFBLK, 0); @@ -1238,20 +1239,23 @@ wdsize(dev) return -1; } - if ((du->dk_flags & (DKFL_WRITEPROT | DKFL_BSDLABEL)) != DKFL_BSDLABEL) + if ((wd->sc_flags & (WDF_WRITEPROT | WDF_BSDLABEL)) != WDF_BSDLABEL) return -1; - return (int)du->dk_dd.d_partitions[part].p_size; + return (int)wd->sc_label.d_partitions[part].p_size; } -/* dump core after a system crash */ +/* + * Dump core after a system crash. + */ int wddump(dev) dev_t dev; { - register struct disk *du; /* disk unit to do the IO */ - long num; /* number of sectors to write */ - int ctrlr, lunit, part; + struct wd_softc *wd; /* disk unit to do the IO */ + struct wdc_softc *wdc; + long num; /* number of sectors to write */ + int lunit, part; long blkoff, blknum; long cylin, head, sector; long secpertrk, secpercyl, nblocks; @@ -1260,81 +1264,74 @@ wddump(dev) extern caddr_t CADDR1; extern struct pte *CMAP1; - addr = (char *)0; /* starting address */ + addr = (char *)0; /* starting address */ #if DO_NOT_KNOW_HOW - /* toss any characters present prior to dump, ie. non-blocking getc */ + /* Toss any characters present prior to dump, ie. non-blocking getc. */ while (cngetc()) ; #endif - /* size of memory to dump */ lunit = WDUNIT(dev); - part = WDPART(dev); /* file system */ - /* check for acceptable drive number */ + /* Check for acceptable drive number. */ if (lunit >= NWD) return ENXIO; - du = wddrives[lunit]; - /* was it ever initialized ? */ - if (du == 0 || du->dk_state < OPEN || du->dk_flags & DKFL_WRITEPROT) + wd = wd_softc[lunit]; + /* Was it ever initialized? */ + if (wd == 0 || wd->sc_state < OPEN || wd->sc_flags & WDF_WRITEPROT) return ENXIO; - ctrlr = du->dk_ctrlr; - - /* Convert to disk sectors */ - num = ctob(physmem) / du->dk_dd.d_secsize; + wdc = (void *)wd->sc_dev.dv_parent; + + /* Convert to disk sectors. */ + num = ctob(physmem) / wd->sc_label.d_secsize; - secpertrk = du->dk_dd.d_nsectors; - secpercyl = du->dk_dd.d_secpercyl; - nblocks = du->dk_dd.d_partitions[part].p_size; - blkoff = du->dk_dd.d_partitions[part].p_offset; + secpertrk = wd->sc_label.d_nsectors; + secpercyl = wd->sc_label.d_secpercyl; + part = WDPART(dev); + nblocks = wd->sc_label.d_partitions[part].p_size; + blkoff = wd->sc_label.d_partitions[part].p_offset; /*printf("part %x, nblocks %d, dumplo %d, num %d\n", part, nblocks, dumplo, num);*/ - /* check transfer bounds against partition size */ + /* Check transfer bounds against partition size. */ if (dumplo < 0 || dumplo + num > nblocks) return EINVAL; - /* check if controller active */ - /*if (wdtab[ctrlr].b_active) - return EFAULT;*/ if (wddoingadump) return EFAULT; - - /* mark controller active for if we panic during the dump */ - /*wdtab[ctrlr].b_active = 1;*/ wddoingadump = 1; /* Recalibrate. */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || - wdsetctlr(du) != 0) { - wderror(du, NULL, "wddump: recal failed"); + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || + wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0) { + wderror(wd, NULL, "wddump: recal failed"); return EIO; } blknum = dumplo + blkoff; while (num > 0) { - /* compute disk address */ + /* Compute disk address. */ cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - if (du->dk_flags & DKFL_BADSECT) { + if (wd->sc_flags & WDF_BADSECT) { long newblk; int i; - for (i = 0; du->dk_badsect[i] != -1; i++) { - if (blknum < du->dk_badsect[i]) { - /* sorted list, passed our block by */ + for (i = 0; wd->sc_badsect[i] != -1; i++) { + if (blknum < wd->sc_badsect[i]) { + /* Sorted list, passed our block by. */ break; - } else if (blknum == du->dk_badsect[i]) { - newblk = du->dk_dd.d_secperunit - - du->dk_dd.d_nsectors - i - 1; + } else if (blknum == wd->sc_badsect[i]) { + newblk = wd->sc_label.d_secperunit - + wd->sc_label.d_nsectors - i - 1; cylin = newblk / secpercyl; head = (newblk % secpercyl) / secpertrk; sector = newblk % secpertrk; - /* found and replaced; done */ + /* Found and replaced; done. */ break; } } @@ -1342,49 +1339,49 @@ wddump(dev) sector++; /* origin 1 */ #ifdef notdef - /* lets just talk about this first...*/ + /* Let's just talk about this first. */ printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head, sector, addr); #endif - if (wdcommand(du, cylin, head, sector, 1, WDCC_WRITE) != 0) { - wderror(du, NULL, "wddump: wdcommand failed"); + if (wdcommand(wd, cylin, head, sector, 1, WDCC_WRITE) != 0) { + wderror(wd, NULL, "wddump: wdcommand failed"); return EIO; } - if (wait_for_drq(du) != 0) { - wderror(du, NULL, "wddump: timeout waiting for drq"); + if (wait_for_drq(wdc) != 0) { + wderror(wd, NULL, "wddump: timeout waiting for drq"); return EIO; } -#ifdef notdef /* cannot use this since this address was mapped differently */ +#ifdef notdef /* Cannot use this since this address was mapped differently. */ pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); #else *(int *)CMAP1 = PG_V | PG_KW | ctob((long)addr); tlbflush(); #endif - outsw(du->dk_port+wd_data, CADDR1 + ((int)addr & PGOFSET), + outsw(wdc->sc_iobase+wd_data, CADDR1 + ((int)addr & PGOFSET), DEV_BSIZE / sizeof(short)); /* Check data request (should be done). */ - if (wait_for_ready(du) != 0) { - wderror(du, NULL, "wddump: timeout waiting for ready"); + if (wait_for_ready(wdc) != 0) { + wderror(wd, NULL, "wddump: timeout waiting for ready"); return EIO; } - if (du->dk_status & WDCS_DRQ) { - wderror(du, NULL, "wddump: extra drq"); + if (wdc->sc_status & WDCS_DRQ) { + wderror(wd, NULL, "wddump: extra drq"); return EIO; } if ((unsigned)addr % 1048576 == 0) printf("%d ", num / (1048576 / DEV_BSIZE)); - /* update block count */ + /* Update block count. */ num--; blknum++; (int)addr += DEV_BSIZE; #if DO_NOT_KNOW_HOW - /* operator aborting dump? non-blocking getc() */ + /* Operator aborting dump? non-blocking getc() */ if (cngetc()) return EINTR; #endif @@ -1396,60 +1393,105 @@ wddump(dev) * Internalize the bad sector table. */ void -bad144intern(du) - struct disk *du; +bad144intern(wd) + struct wd_softc *wd; { int i; - if ((du->dk_flags & DKFL_BADSECT) == 0) + if ((wd->sc_flags & WDF_BADSECT) == 0) return; for (i = 0; i < 127; i++) - du->dk_badsect[i] = -1; + wd->sc_badsect[i] = -1; for (i = 0; i < 126; i++) { - if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) + if (wd->sc_cpulabel.bad.bt_bad[i].bt_cyl == 0xffff) break; - du->dk_badsect[i] = - du->dk_cpd.bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl + - (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * - du->dk_dd.d_nsectors + - (du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); + wd->sc_badsect[i] = + wd->sc_cpulabel.bad.bt_bad[i].bt_cyl * + wd->sc_label.d_secpercyl + + (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec >> 8) * + wd->sc_label.d_nsectors + + (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec & 0x00ff); } } static int -wdreset(du, err) - struct disk *du; - int err; +wdcreset(wdc) + struct wdc_softc *wdc; { - u_short wdc = du->dk_port; - - if (err) - printf("wdc%d: busy too long, resetting\n", du->dk_ctrlr); + u_short iobase = wdc->sc_iobase; - /* reset the device */ - outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); + /* Reset the device. */ + outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS); delay(1000); - outb(wdc+wd_ctlr, WDCTL_IDS); + outb(iobase+wd_ctlr, WDCTL_IDS); delay(1000); - (void) inb(wdc+wd_error); - outb(wdc+wd_ctlr, WDCTL_4BIT); + (void) inb(iobase+wd_error); + outb(iobase+wd_ctlr, WDCTL_4BIT); + + if (wait_for_unbusy(wdc) < 0) { + printf("%s: reset failed\n", wdc->sc_dev.dv_xname); + return 1; + } + + return 0; +} + +static void +wdcrestart(wdc) + struct wdc_softc *wdc; +{ + int s = splbio(); + + wdc->sc_q.b_active = 0; + wdcstart(wdc); + splx(s); +} + +/* + * Unwedge the controller after an unexpected error. We do this by resetting + * it, marking all drives for recalibration, and stalling the queue for a short + * period to give the reset time to finish. + * NOTE: We use a timeout here, so this routine must not be called during + * autoconfig or dump. + */ +static void +wdcunwedge(wdc) + struct wdc_softc *wdc; +{ + int lunit; + + wdc->sc_timeout = 0; + (void) wdcreset(wdc); + + /* Schedule recalibrate for all drives on this controller. */ + for (lunit = 0; lunit < NWD; lunit++) { + struct wd_softc *wd = wd_softc[lunit]; + if (!wd || (void *)wd->sc_dev.dv_parent != wdc) + continue; + if (wd->sc_state > WANTOPEN) + wd->sc_state = WANTOPEN; + if (wd->sc_q.b_active && (wd->sc_flags & WDF_SINGLE) == 0) + wd->sc_flags |= WDF_ERROR; + } + + ++wdc->sc_q.b_errcnt; - if (wait_for_unbusy(du) < 0) - printf("wdc%d: failed to reset controller\n", du->dk_ctrlr); + /* Wake up in a little bit and restart the operation. */ + timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME); } int -wdwait(du, mask) - struct disk *du; +wdcwait(wdc, mask) + struct wdc_softc *wdc; int mask; { - u_short wdc = du->dk_port; + u_short iobase = wdc->sc_iobase; int timeout = 0; u_char status; for (;;) { - du->dk_status = status = inb(wdc+wd_altsts); + wdc->sc_status = status = inb(iobase+wd_altsts); if ((status & WDCS_BUSY) == 0 && (status & mask) == mask) break; if (++timeout > WDCNDELAY) @@ -1457,45 +1499,43 @@ wdwait(du, mask) delay(WDCDELAY); } if (status & WDCS_ERR) - du->dk_error = inb(wdc+wd_error); + wdc->sc_error = inb(iobase+wd_error); #ifdef WDCNDELAY_DEBUG if (timeout > WDCNDELAY_DEBUG) - printf("wdc%d: busy-wait took %dus\n", du->dk_ctrlr, + printf("%s: busy-wait took %dus\n", wdc->sc_dev.dv_xname, WDCDELAY * timeout); #endif return status & WDCS_ERR; } static void -wdtimeout(arg) - caddr_t arg; +wdctimeout(wdc) + struct wdc_softc *wdc; { int s = splbio(); - struct disk *du = (void *)arg; - - if (du->dk_timeout && --du->dk_timeout == 0) { - wderror(du, NULL, "lost interrupt"); - wdreset(du, 0); - /* XXX Need to recalibrate and upload geometry. */ - du->dk_skip = 0; - du->dk_flags |= DKFL_SINGLE; - wdstart(du->dk_ctrlr); + + if (wdc->sc_timeout && --wdc->sc_timeout == 0) { + wderror(wdc, NULL, "lost interrupt"); + wdcunwedge(wdc); } - timeout((timeout_t)wdtimeout, arg, hz); + timeout((timeout_t)wdctimeout, (caddr_t)wdc, hz); splx(s); } static void -wderror(du, bp, msg) - struct disk *du; +wderror(dev, bp, msg) + void *dev; struct buf *bp; char *msg; { + struct wd_softc *wd = dev; + struct wdc_softc *wdc = dev; + if (bp) - diskerr(bp, "wd", msg, LOG_PRINTF, du->dk_skip, &du->dk_dd); + diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip, &wd->sc_label); else - printf("wd%d: %s: status %b error %b\n", du->dk_lunit, msg, - du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS); + printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname, + msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS); } #endif /* NWDC > 0 */ diff --git a/sys/dev/ic/wdcreg.h b/sys/dev/ic/wdcreg.h index 41e40db99bc..b306dd27721 100644 --- a/sys/dev/ic/wdcreg.h +++ b/sys/dev/ic/wdcreg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91 - * $Id: wdcreg.h,v 1.4 1994/03/02 21:43:42 mycroft Exp $ + * $Id: wdcreg.h,v 1.5 1994/03/10 05:18:36 mycroft Exp $ */ /* @@ -126,19 +126,4 @@ struct wdparams { short wdp_nsecperint; /* sectors per interrupt */ short wdp_usedmovsd; /* can use double word read/write? */ }; - -/* - * wd driver entry points - */ -int wdprobe(struct isa_device *); -int wdattach(struct isa_device *); -int wdstrategy(struct buf *); -void wdintr(int); -int wdopen(dev_t, int, int, struct proc *); -int wdclose(dev_t, int, int); -int wdioctl(dev_t, int, caddr_t, int, struct proc *); -/* int wdformat(struct buf *bp); */ -int wdsize(dev_t); -int wddump(dev_t); - #endif KERNEL diff --git a/sys/dev/isa/wd.c b/sys/dev/isa/wd.c index 50068924530..4cccda603b2 100644 --- a/sys/dev/isa/wd.c +++ b/sys/dev/isa/wd.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.63 1994/03/07 05:54:44 mycroft Exp $ + * $Id: wd.c,v 1.64 1994/03/10 05:18:33 mycroft Exp $ */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */ @@ -55,6 +55,7 @@ #include <sys/buf.h> #include <sys/uio.h> #include <sys/malloc.h> +#include <sys/device.h> #include <sys/syslog.h> #ifdef INSTRUMENT #include <sys/dkstat.h> @@ -73,10 +74,11 @@ #define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */ #define WDCDELAY 100 +#define RECOVERYTIME hz/2 /* time to recover from an error */ #if 0 -/* if you enable this, it will report any delays more than 100us * N long */ -#define WDCNDELAY_DEBUG 100 +/* If you enable this, it will report any delays more than 100us * N long. */ +#define WDCNDELAY_DEBUG 50 #endif #define WDIORETRIES 5 /* number of retries before giving up */ @@ -92,7 +94,7 @@ /* * Drive states. Used to initialize drive. */ -#define CLOSED 0 /* disk is closed. */ +#define CLOSED 0 /* disk is closed */ #define WANTOPEN 1 /* open requested, not started */ #define RECAL 2 /* doing restore */ #define OPEN 3 /* done with open */ @@ -100,68 +102,68 @@ /* * Drive status. */ -struct disk { - long dk_bc; /* byte count left */ - long dk_bct; /* total byte count left */ - short dk_skip; /* blocks already transferred */ - short dk_skipm; /* blocks already transferred for multi */ - char dk_ctrlr; /* physical controller number */ - char dk_unit; /* physical unit number */ - char dk_lunit; /* logical unit number */ - char dk_state; /* control state */ - int dk_timeout; /* timeout counter */ - u_char dk_status; /* copy of status reg. */ - u_char dk_error; /* copy of error reg. */ - u_short dk_port; /* i/o port base */ +struct wd_softc { + struct device sc_dev; + + long sc_bcount; /* byte count left */ + long sc_mbcount; /* total byte count left */ + short sc_skip; /* blocks already transferred */ + short sc_mskip; /* blocks already transferred for multi */ + char sc_unit; /* physical unit number */ + char sc_lunit; /* logical unit number */ + char sc_state; /* control state */ - u_long dk_copenpart; /* character units open on this drive */ - u_long dk_bopenpart; /* block units open on this drive */ - u_long dk_openpart; /* all units open on this drive */ - short dk_wlabel; /* label writable? */ - short dk_flags; /* drive characteistics found */ -#define DKFL_SINGLE 0x00004 /* sector at a time mode */ -#define DKFL_ERROR 0x00008 /* processing a disk error */ -#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */ -#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */ -#define DKFL_WRITEPROT 0x00040 /* manual unit write protect */ - struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */ - struct disklabel dk_dd; /* device configuration data */ - struct cpu_disklabel dk_cpd; - long dk_badsect[127]; /* 126 plus trailing -1 marker */ -}; - -struct board { - short dkc_port; -}; - -struct board wdcontroller[NWDC]; -struct disk *wddrives[NWD]; /* table of units */ -struct buf wdtab[NWDC]; /* various per-controller info */ -struct buf wdutab[NWD]; /* head of queue per drive */ -struct buf rwdbuf[NWD]; /* buffers for raw IO */ -long wdxfer[NWD]; /* count of transfers */ - -int wdprobe(), wdattach(); + u_long sc_copenpart; /* character units open on this drive */ + u_long sc_bopenpart; /* block units open on this drive */ + u_long sc_openpart; /* all units open on this drive */ + short sc_wlabel; /* label writable? */ + short sc_flags; /* drive characteistics found */ +#define WDF_SINGLE 0x00004 /* sector at a time mode */ +#define WDF_ERROR 0x00008 /* processing a disk error */ +#define WDF_BSDLABEL 0x00010 /* has a BSD disk label */ +#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */ +#define WDF_WRITEPROT 0x00040 /* manual unit write protect */ + struct buf sc_q; + struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ + struct disklabel sc_label; /* device configuration data */ + struct cpu_disklabel sc_cpulabel; + long sc_badsect[127]; /* 126 plus trailing -1 marker */ +} *wd_softc[NWD]; + +struct wdc_softc { + struct device sc_dev; + + struct buf sc_q; + u_char sc_status; /* copy of status register */ + u_char sc_error; /* copy of error register */ + u_short sc_iobase; /* i/o port base */ + int sc_timeout; /* timeout counter */ +} wdc_softc[NWDC]; + +int wdprobe(), wdattach(), wdintr(); struct isa_driver wdcdriver = { wdprobe, wdattach, "wdc", }; -static void wdustart __P((struct disk *)); -static void wdstart __P((int)); -static int wdcommand __P((struct disk *, int, int, int, int, int)); +void wdfinish __P((struct wd_softc *, struct buf *)); +static void wdstart __P((struct wd_softc *)); +static void wdcstart __P((struct wdc_softc *)); +static int wdcommand __P((struct wd_softc *, int, int, int, int, int)); static int wdcontrol __P((struct buf *)); -static int wdsetctlr __P((struct disk *)); -static int wdgetctlr __P((struct disk *)); -static void bad144intern __P((struct disk *)); -static int wdreset __P((struct disk *, int)); -static void wdtimeout __P((caddr_t)); +static int wdsetctlr __P((struct wd_softc *)); +static int wdgetctlr __P((struct wd_softc *)); +static void bad144intern __P((struct wd_softc *)); +static int wdcreset __P((struct wdc_softc *)); +static void wdcrestart __P((struct wdc_softc *)); +static void wdcunwedge __P((struct wdc_softc *)); +static void wdctimeout __P((struct wdc_softc *)); void wddisksort __P((struct buf *, struct buf *)); -static void wderror __P((struct disk *, struct buf *, char *)); -int wdwait __P((struct disk *, int)); -#define wait_for_drq(d) wdwait(d, WDCS_DRQ) -#define wait_for_ready(d) wdwait(d, WDCS_READY | WDCS_SEEKCMPLT) -#define wait_for_unbusy(d) wdwait(d, 0) +static void wderror __P((void *, struct buf *, char *)); +int wdcwait __P((struct wdc_softc *, int)); +#define wait_for_drq(d) wdcwait(d, WDCS_DRQ) +#define wait_for_ready(d) wdcwait(d, WDCS_READY | WDCS_SEEKCMPLT) +#define wait_for_unbusy(d) wdcwait(d, 0) /* * Probe for controller. @@ -170,52 +172,66 @@ int wdprobe(isa_dev) struct isa_device *isa_dev; { - struct disk *du; - u_short wdc; + struct wd_softc *wd; + struct wdc_softc *wdc; + u_short iobase; if (isa_dev->id_unit >= NWDC) return 0; + wdc = &wdc_softc[isa_dev->id_unit]; - du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); - bzero(du, sizeof(struct disk)); + /* XXX HACK */ + sprintf(wdc->sc_dev.dv_xname, "%s%d", "wdc", isa_dev->id_unit); + wdc->sc_dev.dv_unit = isa_dev->id_unit; - du->dk_ctrlr = isa_dev->id_unit; - du->dk_unit = 0; - du->dk_lunit = 0; - wdcontroller[isa_dev->id_unit].dkc_port = isa_dev->id_iobase; + wdc->sc_iobase = iobase = isa_dev->id_iobase; - wdc = du->dk_port = isa_dev->id_iobase; + /* Check if we have registers that work. */ + outb(iobase+wd_error, 0x5a); /* Error register not writable. */ + outb(iobase+wd_cyl_lo, 0xa5); /* But all of cyllo are implemented. */ + if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5) + return 0; - /* check if we have registers that work */ - outb(wdc+wd_error, 0x5a); /* error register not writable */ - outb(wdc+wd_cyl_lo, 0xa5); /* but all of cyllo are implemented */ - if (inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5) - goto nodevice; + if (wdcreset(wdc) != 0) { + delay(500000); + if (wdcreset(wdc) != 0) + return 0; + } - wdreset(du, 0); + /* + * XXX wdcommand() accepts a wd_softc, so we have to make it one. + */ + wd = (void *)malloc(sizeof(struct wd_softc), M_TEMP, M_NOWAIT); + bzero(wd, sizeof(struct wd_softc)); + wd->sc_unit = 0; + wd->sc_lunit = 0; + wd->sc_dev.dv_parent = (void *)wdc; - /* execute a controller only command */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0) - goto nodevice; + /* Execute a controller only command. */ + if (wdcommand(wd, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0 || + wait_for_unbusy(wdc) != 0) + goto lose; - free(du, M_TEMP); + wdctimeout(wdc); + + free(wd, M_TEMP); return 8; -nodevice: - free(du, M_TEMP); +lose: + free(wd, M_TEMP); return 0; } /* - * Called for the controller too - * Attach each drive if possible. + * Called for the controller too. Attach each drive if possible. */ int wdattach(isa_dev) struct isa_device *isa_dev; { - int unit, lunit; - struct disk *du; + int lunit; + struct wd_softc *wd; + struct wdc_softc *wdc; int i, blank; if (isa_dev->id_masunit == -1) @@ -225,44 +241,40 @@ wdattach(isa_dev) lunit = isa_dev->id_unit; if (lunit == -1) { - printf("wdc%d: cannot support unit ?\n", isa_dev->id_masunit); + printf("%s: cannot support unit ?\n", wdc->sc_dev.dv_xname); return 0; } if (lunit >= NWD) return 0; - unit = isa_dev->id_physid; - du = wddrives[lunit] = - (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); - bzero(du, sizeof(struct disk)); - bzero(&wdutab[lunit], sizeof(struct buf)); - bzero(&rwdbuf[lunit], sizeof(struct buf)); - wdxfer[lunit] = 0; - du->dk_ctrlr = isa_dev->id_masunit; - du->dk_unit = unit; - du->dk_lunit = lunit; - du->dk_port = wdcontroller[isa_dev->id_masunit].dkc_port; - - if (wdgetctlr(du) != 0) { - /*printf("wd%d at wdc%d slave %d -- error\n", lunit, - isa_dev->id_masunit, unit);*/ - wddrives[lunit] = 0; - free(du, M_TEMP); + wdc = &wdc_softc[isa_dev->id_masunit]; + + wd_softc[lunit] = wd = + (void *)malloc(sizeof(struct wd_softc), M_TEMP, M_NOWAIT); + bzero(wd, sizeof(struct wd_softc)); + wd->sc_unit = isa_dev->id_physid; + wd->sc_lunit = lunit; + + /* XXX HACK */ + sprintf(wd->sc_dev.dv_xname, "%s%d", "wd", isa_dev->id_unit); + wd->sc_dev.dv_unit = isa_dev->id_unit; + wd->sc_dev.dv_parent = (void *)wdc; + + if (wdgetctlr(wd) != 0) return 0; - } - printf("wd%d at wdc%d targ %d: ", isa_dev->id_unit, - isa_dev->id_masunit, isa_dev->id_physid); - if (du->dk_params.wdp_heads == 0) + printf("%s at %s targ %d: ", wd->sc_dev.dv_xname, wdc->sc_dev.dv_xname, + isa_dev->id_physid); + if (wd->sc_params.wdp_heads == 0) printf("(unknown size) <"); else printf("%dMB %d cyl, %d head, %d sec <", - du->dk_dd.d_ncylinders * du->dk_dd.d_secpercyl / + wd->sc_label.d_ncylinders * wd->sc_label.d_secpercyl / (1048576 / DEV_BSIZE), - du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, - du->dk_dd.d_nsectors); - for (i = blank = 0; i < sizeof(du->dk_params.wdp_model); i++) { - char c = du->dk_params.wdp_model[i]; + wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks, + wd->sc_label.d_nsectors); + for (i = blank = 0; i < sizeof(wd->sc_params.wdp_model); i++) { + char c = wd->sc_params.wdp_model[i]; if (c == '\0') break; if (c != ' ') { @@ -276,68 +288,70 @@ wdattach(isa_dev) } printf(">\n"); - wdtimeout((caddr_t)du); - return 1; } -/* Read/write routine for a buffer. Finds the proper unit, range checks - * arguments, and schedules the transfer. Does not wait for the transfer - * to complete. Multi-page transfers are supported. All I/O requests must - * be a multiple of a sector in length. +/* + * Read/write routine for a buffer. Finds the proper unit, range checks + * arguments, and schedules the transfer. Does not wait for the transfer to + * complete. Multi-page transfers are supported. All I/O requests must be a + * multiple of a sector in length. */ -int +void wdstrategy(bp) struct buf *bp; { struct buf *dp; - struct disk *du; /* Disk unit to do the IO. */ + struct wd_softc *wd; /* disk unit to do the IO */ + struct wdc_softc *wdc; int lunit = WDUNIT(bp->b_dev); int s; - /* valid unit, controller, and request? */ + /* Valid unit, controller, and request? */ if (lunit >= NWD || bp->b_blkno < 0 || howmany(bp->b_bcount, DEV_BSIZE) >= (1 << NBBY) || - (du = wddrives[lunit]) == 0) { + (wd = wd_softc[lunit]) == 0) { bp->b_error = EINVAL; bp->b_flags |= B_ERROR; goto done; } - /* "soft" write protect check */ - if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) { + /* "Soft" write protect check. */ + if ((wd->sc_flags & WDF_WRITEPROT) && (bp->b_flags & B_READ) == 0) { bp->b_error = EROFS; bp->b_flags |= B_ERROR; goto done; } - /* have partitions and want to use them? */ - if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) { + /* Have partitions and want to use them? */ + if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) { /* - * do bounds checking, adjust transfer. if error, process. - * if end of partition, just return + * Do bounds checking, adjust transfer. if error, process. + * If end of partition, just return. */ - if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0) + if (bounds_check_with_label(bp, &wd->sc_label, + wd->sc_wlabel) <= 0) goto done; - /* otherwise, process transfer request */ + /* Otherwise, process transfer request. */ } - /* don't bother */ + /* Don't bother doing rotational optimization. */ bp->b_cylin = 0; - /* queue transfer on drive, activate drive and controller if idle */ - dp = &wdutab[lunit]; + /* Queue transfer on drive, activate drive and controller if idle. */ + dp = &wd->sc_q; s = splbio(); wddisksort(dp, bp); if (dp->b_active == 0) - wdustart(du); /* start drive */ - if (wdtab[du->dk_ctrlr].b_active == 0) - wdstart(du->dk_ctrlr); /* start controller */ + wdstart(wd); /* Start drive. */ + wdc = (void *)wd->sc_dev.dv_parent; + if (wdc->sc_q.b_active == 0) + wdcstart(wdc); /* Start controller. */ splx(s); - return 0; + return; done: - /* toss transfer, we're done early */ + /* Toss transfer; we're done early. */ biodone(bp); } @@ -356,192 +370,245 @@ wddisksort(dp, bp) } /* - * Routine to queue a command to the controller. The unit's - * request is linked into the active list for the controller. - * If the controller is idle, the transfer is started. + * Routine to queue a command to the controller. The unit's request is linked + * into the active list for the controller. If the controller is idle, the + * transfer is started. */ static void -wdustart(du) - struct disk *du; +wdstart(wd) + struct wd_softc *wd; { - struct buf *dp = &wdutab[du->dk_lunit]; - int ctrlr = du->dk_ctrlr; + struct buf *dp; + struct wdc_softc *wdc; + + dp = &wd->sc_q; - /* unit already active? */ + /* Unit already active? */ if (dp->b_active) return; - - /* anything to start? */ + /* Anything to start? */ if (dp->b_actf == NULL) return; - /* link onto controller queue */ + /* Link onto controller queue. */ dp->b_forw = NULL; - if (wdtab[ctrlr].b_forw == NULL) - wdtab[ctrlr].b_forw = dp; + wdc = (void *)wd->sc_dev.dv_parent; + if (wdc->sc_q.b_forw == NULL) + wdc->sc_q.b_forw = dp; else - wdtab[ctrlr].b_actl->b_forw = dp; - wdtab[ctrlr].b_actl = dp; + wdc->sc_q.b_actl->b_forw = dp; + wdc->sc_q.b_actl = dp; - /* mark the drive unit as busy */ + /* Mark the drive unit as busy. */ dp->b_active = 1; } +void +wdfinish(wd, bp) + struct wd_softc *wd; + struct buf *bp; +{ + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; + +#ifdef INSTRUMENT + dk_busy &= ~(1 << wd->sc_unit); +#endif + wd->sc_flags &= ~(WDF_SINGLE | WDF_ERROR); + wdc->sc_q.b_errcnt = 0; + /* + * If this is the only buf or the last buf in the transfer (taking into + * account any residual, in case we erred)... + */ + wd->sc_mbcount -= wd->sc_bcount; + if (wd->sc_mbcount == 0) { + /* + * ...then move this drive to the end of the queue to give + * others a `fair' chance. + */ + wdc->sc_q.b_forw = wd->sc_q.b_forw; + wd->sc_mskip = 0; + wd->sc_q.b_active = 0; + if (wd->sc_q.b_actf) + wdstart(wd); + } + bp->b_resid = wd->sc_bcount; + bp->b_flags &= ~B_XXX; + wd->sc_skip = 0; + wd->sc_q.b_actf = bp->b_actf; + biodone(bp); +} + /* - * Controller startup routine. This does the calculation, and starts - * a single-sector read or write operation. Called to start a transfer, - * or from the interrupt routine to continue a multi-sector transfer. + * Controller startup routine. This does the calculation, and starts a + * single-sector read or write operation. Called to start a transfer, or from + * the interrupt routine to continue a multi-sector transfer. * RESTRICTIONS: * 1. The transfer length must be an exact multiple of the sector size. */ static void -wdstart(ctrlr) - int ctrlr; +wdcstart(wdc) + struct wdc_softc *wdc; { - register struct disk *du; /* disk unit for IO */ - register struct buf *bp; + struct wd_softc *wd; /* disk unit for IO */ + struct buf *bp; struct disklabel *lp; struct buf *dp; long blknum, cylin, head, sector; long secpertrk, secpercyl; int xfrblknum; int lunit; - + loop: - /* is there a drive for the controller to do a transfer with? */ - dp = wdtab[ctrlr].b_forw; + /* Is there a drive for the controller to do a transfer with? */ + dp = wdc->sc_q.b_forw; if (dp == NULL) { - wdtab[ctrlr].b_active = 0; + wdc->sc_q.b_active = 0; return; } - /* is there a transfer to this drive ? if so, link it on - the controller's queue */ + /* Is there a transfer to this drive? If not, deactivate drive. */ bp = dp->b_actf; if (bp == NULL) { dp->b_active = 0; - wdtab[ctrlr].b_forw = dp->b_forw; + wdc->sc_q.b_forw = dp->b_forw; goto loop; } - /* obtain controller and drive information */ + /* Obtain controller and drive information */ lunit = WDUNIT(bp->b_dev); - du = wddrives[lunit]; + wd = wd_softc[lunit]; - /* clear any pending timeout, just in case */ - du->dk_timeout = 0; + if (wdc->sc_q.b_errcnt >= WDIORETRIES) { + wderror(wd, bp, "hard error"); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + wdfinish(wd, bp); + goto loop; + } - /* if not really a transfer, do control operations specially */ - if (du->dk_state < OPEN) { + /* Clear any pending timeout, just in case. */ + wdc->sc_timeout = 0; + + /* If not really a transfer, do control operations specially. */ + if (wd->sc_state < OPEN) { (void) wdcontrol(bp); return; } - - /* calculate transfer details */ - blknum = bp->b_blkno + du->dk_skip; + + /* + * WDF_ERROR is set by wdcunwedge() and wdintr() when an error is + * encountered *only* in multi-sector mode. We switch to single-sector + * mode and retry the operation from the start. + */ + if (wd->sc_flags & WDF_ERROR) { + /* Switch to single-sector mode. */ + wd->sc_flags &= ~WDF_ERROR; + wd->sc_flags |= WDF_SINGLE; + wd->sc_skip = 0; + wd->sc_mskip = 0; + } + + /* Calculate transfer details. */ + blknum = bp->b_blkno + wd->sc_skip; #ifdef WDDEBUG - if (du->dk_skip == 0) - printf("\nwdstart %d: %s %d@%d; map ", lunit, + if (wd->sc_skip == 0) + printf("\nwdcstart %d: %s %d@%d; map ", lunit, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else - printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts)); + printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts)); #endif - if (du->dk_skip == 0) - du->dk_bc = bp->b_bcount; - if (du->dk_skipm == 0) { + if (wd->sc_skip == 0) + wd->sc_bcount = bp->b_bcount; + if (wd->sc_mskip == 0) { struct buf *oldbp, *nextbp; oldbp = bp; nextbp = bp->b_actf; - du->dk_bct = du->dk_bc; + wd->sc_mbcount = wd->sc_bcount; oldbp->b_flags |= B_XXX; - while (nextbp && (oldbp->b_flags & DKFL_SINGLE) == 0 && + while (nextbp && (oldbp->b_flags & WDF_SINGLE) == 0 && oldbp->b_dev == nextbp->b_dev && nextbp->b_blkno == (oldbp->b_blkno + (oldbp->b_bcount / DEV_BSIZE)) && (oldbp->b_flags & B_READ) == (nextbp->b_flags & B_READ)) { - if ((du->dk_bct + nextbp->b_bcount) / DEV_BSIZE >= 240) + if ((wd->sc_mbcount + nextbp->b_bcount) / DEV_BSIZE >= 240) break; - du->dk_bct += nextbp->b_bcount; + wd->sc_mbcount += nextbp->b_bcount; nextbp->b_flags |= B_XXX; oldbp = nextbp; nextbp = nextbp->b_actf; } } - lp = &du->dk_dd; + lp = &wd->sc_label; secpertrk = lp->d_nsectors; secpercyl = lp->d_secpercyl; - if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) + if ((wd->sc_flags & WDF_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset; cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - /* Check for bad sectors if we have them, and not formatting */ - /* Only do this in single-sector mode, or when starting a */ - /* multiple-sector transfer. */ - if ((du->dk_flags & DKFL_BADSECT) && + /* + * Check for bad sectors if we have them, and not formatting. Only do + * this in single-sector mode, or when starting a multiple-sector + * transfer. + */ + if ((wd->sc_flags & WDF_BADSECT) && #ifdef B_FORMAT (bp->b_flags & B_FORMAT) == 0 && #endif - (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE))) { + (wd->sc_mskip == 0 || (wd->sc_flags & WDF_SINGLE))) { long blkchk, blkend, blknew; int i; - blkend = blknum + howmany(du->dk_bct, DEV_BSIZE) - 1; - for (i = 0; (blkchk = du->dk_badsect[i]) != -1; i++) { + blkend = blknum + howmany(wd->sc_mbcount, DEV_BSIZE) - 1; + for (i = 0; (blkchk = wd->sc_badsect[i]) != -1; i++) { if (blkchk > blkend) - break; /* transfer is completely OK; done */ + break; /* Transfer is completely OK; done. */ if (blkchk == blknum) { blknew = lp->d_secperunit - lp->d_nsectors - i - 1; cylin = blknew / secpercyl; head = (blknew % secpercyl) / secpertrk; sector = blknew % secpertrk; - du->dk_flags |= DKFL_SINGLE; - /* found and replaced first blk of transfer; done */ + wd->sc_flags |= WDF_SINGLE; + /* Found and replaced first blk of transfer; done. */ break; } else if (blkchk > blknum) { - du->dk_flags |= DKFL_SINGLE; - break; /* bad block inside transfer; done */ + wd->sc_flags |= WDF_SINGLE; + break; /* Bad block inside transfer; done. */ } } } - if (du->dk_flags & DKFL_SINGLE) { - du->dk_bct = du->dk_bc; - du->dk_skipm = du->dk_skip; + if (wd->sc_flags & WDF_SINGLE) { + wd->sc_mbcount = wd->sc_bcount; + wd->sc_mskip = wd->sc_skip; } #ifdef WDDEBUG printf("c%d h%d s%d ", cylin, head, sector); #endif - sector++; /* sectors begin with 1, not 0 */ + sector++; /* Sectors begin with 1, not 0. */ - wdtab[ctrlr].b_active = 1; /* mark controller active */ + wdc->sc_q.b_active = 1; /* Mark controller active. */ #ifdef INSTRUMENT - /* instrumentation */ - if (du->dk_unit >= 0 && du->dk_skip == 0) { - dk_busy |= 1 << du->dk_lunit; - dk_wds[du->dk_lunit] += bp->b_bcount >> 6; - } - if (du->dk_unit >= 0 && du->dk_skipm == 0) { - ++dk_seek[du->dk_lunit]; - ++dk_xfer[du->dk_lunit]; + if (wd->sc_skip == 0) { + dk_busy |= 1 << wd->sc_lunit; + dk_wds[wd->sc_lunit] += bp->b_bcount >> 6; } #endif -retry: - /* if starting a multisector transfer, or doing single transfers */ - if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) { + /* If starting a multisector transfer, or doing single transfers. */ + if (wd->sc_mskip == 0 || (wd->sc_flags & WDF_SINGLE)) { int command, count; - if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) { - du->dk_bc += DEV_BSIZE; - du->dk_bct += DEV_BSIZE; - } +#ifdef INSTRUMENT + ++dk_seek[wd->sc_lunit]; + ++dk_xfer[wd->sc_lunit]; +#endif #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { @@ -549,109 +616,103 @@ retry: count = lp->d_nsectors; command = WDCC_FORMAT; } else { - if (du->dk_flags & DKFL_SINGLE) + if (wd->sc_flags & WDF_SINGLE) count = 1; else - count = howmany(du->dk_bct, DEV_BSIZE); + count = howmany(wd->sc_mbcount, DEV_BSIZE); command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE; } #else - if (du->dk_flags & DKFL_SINGLE) + if (wd->sc_flags & WDF_SINGLE) count = 1; else - count = howmany(du->dk_bct, DEV_BSIZE); + count = howmany(wd->sc_mbcount, DEV_BSIZE); command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE; #endif - /* initiate command! */ - while (wdcommand(du, cylin, head, sector, count, command) < 0) { - wderror(du, NULL, - "wdstart: timeout waiting for unbusy"); - wdreset(du, 1); + /* Initiate command! */ + if (wdcommand(wd, cylin, head, sector, count, command) != 0) { + wderror(wd, NULL, + "wdcstart: timeout waiting for unbusy"); + wdcunwedge(wdc); + return; } #ifdef WDDEBUG printf("sector %d cylin %d head %d addr %x sts %x\n", sector, - cylin, head, bp->b_un.b_addr, inb(du->dk_port+wd_altsts)); + cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts)); #endif } - du->dk_timeout = 2; + wdc->sc_timeout = 4; - /* if this is a read operation, just go away until it's done. */ + /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; - if (wait_for_drq(du) < 0) { - /* XXX seems wrong */ - wdreset(du, 1); - goto retry; + if (wait_for_drq(wdc) < 0) { + wderror(wd, NULL, "wdcstart: timeout waiting for drq"); + wdcunwedge(wdc); + return; } - /* then send it! */ - outsw(du->dk_port+wd_data, bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, + /* Then send it! */ + outsw(wdc->sc_iobase+wd_data, bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE, DEV_BSIZE / sizeof(short)); - - du->dk_bc -= DEV_BSIZE; - du->dk_bct -= DEV_BSIZE; } -/* Interrupt routine for the controller. Acknowledge the interrupt, check for - * errors on the current operation, mark it done if necessary, and start - * the next request. Also check for a partially done transfer, and - * continue with the next chunk if so. +/* + * Interrupt routine for the controller. Acknowledge the interrupt, check for + * errors on the current operation, mark it done if necessary, and start the + * next request. Also check for a partially done transfer, and continue with + * the next chunk if so. */ -void +int wdintr(ctrlr) int ctrlr; { - register struct disk *du; - register struct buf *bp, *dp; + struct wdc_softc *wdc = &wdc_softc[ctrlr]; + struct wd_softc *wd; + struct buf *bp; - /* clear the pending interrupt */ - (void) inb(wdcontroller[ctrlr].dkc_port+wd_status); + /* Clear the pending interrupt. */ + (void) inb(wdc->sc_iobase+wd_status); - if (!wdtab[ctrlr].b_active) { - printf("wdc%d: extra interrupt\n", ctrlr); - return; + if (!wdc->sc_q.b_active) { + printf("%s: extra interrupt\n", wdc->sc_dev.dv_xname); + return 0; } - dp = wdtab[ctrlr].b_forw; - bp = dp->b_actf; - du = wddrives[WDUNIT(bp->b_dev)]; - du->dk_timeout = 0; + bp = wdc->sc_q.b_forw->b_actf; + wd = wd_softc[WDUNIT(bp->b_dev)]; + wdc->sc_timeout = 0; #ifdef WDDEBUG printf("I%d ", ctrlr); #endif - if (wait_for_unbusy(du) < 0) { - wderror(du, NULL, "wdintr: timeout waiting for unbusy"); - du->dk_status |= WDCS_ERR; /* XXX */ + if (wait_for_unbusy(wdc) < 0) { + wderror(wd, NULL, "wdintr: timeout waiting for unbusy"); + wdc->sc_status |= WDCS_ERR; /* XXX */ } - /* is it not a transfer, but a control operation? */ - if (du->dk_state < OPEN) { - wdtab[ctrlr].b_active = 0; - switch (wdcontrol(bp)) { - case -1: - goto done; - case 1: - wdstart(ctrlr); - break; - } - return; + /* Is it not a transfer, but a control operation? */ + if (wd->sc_state < OPEN) { + wdc->sc_q.b_active = 0; + if (wdcontrol(bp)) + wdcstart(wdc); + return 1; } - /* have we an error? */ - if (du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) { + /* Have we an error? */ + if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) { lose: #ifdef WDDEBUG - wderror(du, NULL, "wdintr"); + wderror(wd, NULL, "wdintr"); #endif - if ((du->dk_flags & DKFL_SINGLE) == 0) { - du->dk_flags |= DKFL_ERROR; - goto outt; + if ((wd->sc_flags & WDF_SINGLE) == 0) { + wd->sc_flags |= WDF_ERROR; + goto restart; } #ifdef B_FORMAT if (bp->b_flags & B_FORMAT) { @@ -661,102 +722,60 @@ wdintr(ctrlr) } #endif - /* error or error correction? */ - if (du->dk_status & WDCS_ERR) { - if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) - wdtab[ctrlr].b_active = 0; - else { - wderror(du, bp, "hard error"); + /* Error or error correction? */ + if (wdc->sc_status & WDCS_ERR) { + if (++wdc->sc_q.b_errcnt >= WDIORETRIES) { + wderror(wd, bp, "hard error"); bp->b_error = EIO; - bp->b_flags |= B_ERROR; /* flag the error */ - } + bp->b_flags |= B_ERROR; /* Flag the error. */ + goto done; + } else + goto restart; } else - wderror(du, bp, "soft ecc"); + wderror(wd, bp, "soft ecc"); } - /* - * If this was a successful read operation, fetch the data. - */ - if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && - wdtab[ctrlr].b_active) { - int chk; - - chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short)); - - /* ready to receive data? */ - if (wait_for_drq(du) != 0) { - wderror(du, NULL, "wdintr: read error detected late"); - goto lose; + /* If this was a read, fetch the data. */ + if (bp->b_flags & B_READ) { + /* Ready to receive data? */ + if (wait_for_drq(wdc) != 0) { + wderror(wd, NULL, "wdintr: read error detected late"); + wdcunwedge(wdc); + return 1; } - /* suck in data */ - insw(du->dk_port+wd_data, - bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk); - du->dk_bc -= chk * sizeof(short); - du->dk_bct -= chk * sizeof(short); - - /* for obselete fractional sector reads */ - while (chk++ < (DEV_BSIZE / sizeof(short))) - (void) inw(du->dk_port+wd_data); + /* Suck in data. */ + insw(wdc->sc_iobase+wd_data, + bp->b_un.b_addr + wd->sc_skip * DEV_BSIZE, + DEV_BSIZE / sizeof(short)); } - wdxfer[du->dk_lunit]++; -outt: - if (wdtab[ctrlr].b_active) { -#ifdef INSTRUMENT - if (du->dk_unit >= 0) - dk_busy &= ~(1 << du->dk_unit); -#endif - if ((bp->b_flags & B_ERROR) == 0) { - du->dk_skip++; /* Add to succ. sect */ - du->dk_skipm++; /* Add to succ. sect for multitransfer */ - if (wdtab[ctrlr].b_errcnt) - wderror(du, bp, "soft error"); - wdtab[ctrlr].b_errcnt = 0; - - /* see if more to transfer */ - if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) { - wdtab[ctrlr].b_active = 0; - wdstart(ctrlr); - return; /* next chunk is started */ - } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR)) == DKFL_ERROR) { - du->dk_skip = 0; - du->dk_skipm = 0; - du->dk_flags &= ~DKFL_ERROR; - du->dk_flags |= DKFL_SINGLE; - wdtab[ctrlr].b_active = 0; - wdstart(ctrlr); - return; /* redo xfer sector by sector */ - } - } - - done: - /* done with this transfer, with or without error */ - du->dk_flags &= ~DKFL_SINGLE; - wdtab[ctrlr].b_errcnt = 0; - if (du->dk_bct == 0) { - wdtab[ctrlr].b_forw = dp->b_forw; - du->dk_skipm = 0; - dp->b_active = 0; - } - bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE; - bp->b_flags &= ~B_XXX; - du->dk_skip = 0; - dp->b_actf = bp->b_actf; - dp->b_errcnt = 0; - biodone(bp); + /* If we encountered any abnormalities, flag it as a soft error. */ + if (wdc->sc_q.b_errcnt) { + wderror(wd, bp, "soft error"); + wdc->sc_q.b_errcnt = 0; } + + /* Ready for the next block, if any. */ + wd->sc_skip++; + wd->sc_mskip++; + wd->sc_bcount -= DEV_BSIZE; + wd->sc_mbcount -= DEV_BSIZE; - /* controller now idle */ - wdtab[ctrlr].b_active = 0; + /* See if more to transfer. */ + if (wd->sc_bcount > 0) + goto restart; - /* anything more on drive queue? */ - if (dp->b_actf && du->dk_bct == 0) - wdustart(du); +done: + /* Done with this transfer, with or without error. */ + wdfinish(wd, bp); + +restart: + /* Start the next transfer, if any. */ + wdc->sc_q.b_active = 0; + wdcstart(wdc); - /* anything more for controller to do? */ - if (wdtab[ctrlr].b_forw) - wdstart(ctrlr); + return 1; } /* @@ -770,7 +789,7 @@ wdopen(dev, flag, fmt, p) struct proc *p; { int lunit; - struct disk *du; + struct wd_softc *wd; int part = WDPART(dev), mask = 1 << part; struct partition *pp; char *msg; @@ -778,98 +797,98 @@ wdopen(dev, flag, fmt, p) lunit = WDUNIT(dev); if (lunit >= NWD) return ENXIO; - du = wddrives[lunit]; - if (du == 0) + wd = wd_softc[lunit]; + if (wd == 0) return ENXIO; - if ((du->dk_flags & DKFL_BSDLABEL) == 0) { - du->dk_flags |= DKFL_WRITEPROT; - wdutab[lunit].b_actf = NULL; + if ((wd->sc_flags & WDF_BSDLABEL) == 0) { + wd->sc_flags |= WDF_WRITEPROT; + wd->sc_q.b_actf = NULL; /* - * Use the default sizes until we've read the label, - * or longer if there isn't one there. + * Use the default sizes until we've read the label, or longer + * if there isn't one there. */ - bzero(&du->dk_dd, sizeof(du->dk_dd)); - du->dk_dd.d_type = DTYPE_ST506; - du->dk_dd.d_ncylinders = 1024; - du->dk_dd.d_secsize = DEV_BSIZE; - du->dk_dd.d_ntracks = 8; - du->dk_dd.d_nsectors = 17; - du->dk_dd.d_secpercyl = 17*8; - du->dk_dd.d_secperunit = 17*8*1024; - du->dk_state = WANTOPEN; - - /* read label using "raw" partition */ + bzero(&wd->sc_label, sizeof(wd->sc_label)); + wd->sc_label.d_type = DTYPE_ST506; + wd->sc_label.d_ncylinders = 1024; + wd->sc_label.d_secsize = DEV_BSIZE; + wd->sc_label.d_ntracks = 8; + wd->sc_label.d_nsectors = 17; + wd->sc_label.d_secpercyl = 17*8; + wd->sc_label.d_secperunit = 17*8*1024; + wd->sc_state = WANTOPEN; + + /* Read label using "raw" partition. */ #ifdef notdef - /* wdsetctlr(du); */ /* Maybe do this TIH */ + /* wdsetctlr(wd); */ /* Maybe do this TIH */ msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW), - wdstrategy, &du->dk_dd, &du->dk_cpd); - wdsetctlr(du); + wdstrategy, &wd->sc_label, &wd->sc_cpulabel); + wdsetctlr(wd); #endif if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), - WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) { - log(LOG_WARNING, "wd%d: cannot find label (%s)\n", - lunit, msg); + WDRAW), wdstrategy, &wd->sc_label, &wd->sc_cpulabel)) { + log(LOG_WARNING, "%s: cannot find label (%s)\n", + wd->sc_dev.dv_xname, msg); if (part != WDRAW) return EINVAL; /* XXX needs translation */ } else { - wdsetctlr(du); - du->dk_flags |= DKFL_BSDLABEL; - du->dk_flags &= ~DKFL_WRITEPROT; - if (du->dk_dd.d_flags & D_BADSECT) - du->dk_flags |= DKFL_BADSECT; + wdsetctlr(wd); + wd->sc_flags |= WDF_BSDLABEL; + wd->sc_flags &= ~WDF_WRITEPROT; + if (wd->sc_label.d_flags & D_BADSECT) + wd->sc_flags |= WDF_BADSECT; } } - if (du->dk_flags & DKFL_BADSECT) - bad144intern(du); + if (wd->sc_flags & WDF_BADSECT) + bad144intern(wd); /* * Warn if a partition is opened that overlaps another partition which * is open unless one is the "raw" partition (whole disk). */ - if ((du->dk_openpart & mask) == 0 && part != WDRAW) { + if ((wd->sc_openpart & mask) == 0 && part != WDRAW) { int start, end; - pp = &du->dk_dd.d_partitions[part]; + pp = &wd->sc_label.d_partitions[part]; start = pp->p_offset; end = pp->p_offset + pp->p_size; - for (pp = du->dk_dd.d_partitions; - pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; + for (pp = wd->sc_label.d_partitions; + pp < &wd->sc_label.d_partitions[wd->sc_label.d_npartitions]; pp++) { if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end) continue; - if (pp - du->dk_dd.d_partitions == WDRAW) + if (pp - wd->sc_label.d_partitions == WDRAW) continue; - if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions))) + if (wd->sc_openpart & (1 << (pp - wd->sc_label.d_partitions))) log(LOG_WARNING, - "wd%d%c: overlaps open partition (%c)\n", - lunit, part + 'a', - pp - du->dk_dd.d_partitions + 'a'); + "%s%c: overlaps open partition (%c)\n", + wd->sc_dev.dv_xname, part + 'a', + pp - wd->sc_label.d_partitions + 'a'); } } - if (part >= du->dk_dd.d_npartitions && part != WDRAW) + if (part >= wd->sc_label.d_npartitions && part != WDRAW) return ENXIO; - /* insure only one open at a time */ - du->dk_openpart |= mask; + /* Insure only one open at a time. */ switch (fmt) { case S_IFCHR: - du->dk_copenpart |= mask; + wd->sc_copenpart |= mask; break; case S_IFBLK: - du->dk_bopenpart |= mask; + wd->sc_bopenpart |= mask; break; } + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; return 0; } /* * Implement operations other than read/write. - * Called from wdstart or wdintr during opens and formats. + * Called from wdcstart or wdintr during opens and formats. * Uses finite-state-machine to track progress of operation in progress. * Returns 0 if operation still in progress, 1 if completed. */ @@ -877,39 +896,30 @@ static int wdcontrol(bp) struct buf *bp; { - struct disk *du; - int ctrlr; + struct wd_softc *wd = wd_softc[WDUNIT(bp->b_dev)]; + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; - du = wddrives[WDUNIT(bp->b_dev)]; - ctrlr = du->dk_ctrlr; - - switch (du->dk_state) { - case WANTOPEN: /* set SDH, step rate, do restore */ + switch (wd->sc_state) { + case WANTOPEN: /* Set SDH, step rate, do restore. */ tryagainrecal: - wdgetctlr(du); /* XXX Is this necessary? */ - wdtab[ctrlr].b_active = 1; - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) { - wderror(du, 0, "wdcontrol: wdcommand failed"); - goto lose; + wdgetctlr(wd); /* XXX Is this necessary? */ + wdc->sc_q.b_active = 1; + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) { + wderror(wd, NULL, "wdcontrol: wdcommand failed"); + wdcunwedge(wdc); + return 0; } - du->dk_state = RECAL; + wd->sc_state = RECAL; return 0; case RECAL: - if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) { - wderror(du, NULL, "wdcontrol: recal failed"); - lose: - if (du->dk_status & WDCS_ERR) - wdreset(du, 1); - du->dk_state = WANTOPEN; - if (++wdtab[ctrlr].b_errcnt < WDIORETRIES) - goto tryagainrecal; - bp->b_error = ENXIO; /* XXX needs translation */ - bp->b_flags |= B_ERROR; - return -1; + if (wdc->sc_status & WDCS_ERR || wdsetctlr(wd) != 0) { + wderror(wd, NULL, "wdcontrol: recal failed"); + wdcunwedge(wdc); + return 0; } - wdtab[ctrlr].b_errcnt = 0; - du->dk_state = OPEN; + wdc->sc_q.b_errcnt = 0; + wd->sc_state = OPEN; /* * The rest of the initialization can be done by normal means. */ @@ -922,136 +932,128 @@ wdcontrol(bp) } /* - * send a command and wait uninterruptibly until controller is finished. - * return -1 if controller busy for too long, otherwise - * return status. intended for brief controller commands at critical points. - * assumes interrupts are blocked. + * Send a command and wait uninterruptibly until controller is finished. + * Return -1 if controller busy for too long, otherwise return non-zero if + * error. Intended for brief controller commands at critical points. + * Assumes interrupts are blocked. */ static int -wdcommand(du, cylin, head, sector, count, cmd) - struct disk *du; +wdcommand(wd, cylin, head, sector, count, cmd) + struct wd_softc *wd; int cylin, head, sector, count; int cmd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; int stat; - u_short wdc; + u_short iobase; - /* controller ready for command? */ - if (wait_for_unbusy(du) < 0) + /* Controller ready for command? */ + if (wait_for_unbusy(wdc) < 0) return -1; - /* select drive */ - wdc = du->dk_port; - outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head); + /* Select drive. */ + iobase = wdc->sc_iobase; + outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_unit << 4) | head); if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC) - stat = wait_for_unbusy(du); + stat = wait_for_unbusy(wdc); else - stat = wdwait(du, WDCS_READY); + stat = wdcwait(wdc, WDCS_READY); if (stat < 0) return -1; - /* load parameters */ - outb(wdc+wd_precomp, du->dk_dd.d_precompcyl / 4); - outb(wdc+wd_cyl_lo, cylin); - outb(wdc+wd_cyl_hi, cylin >> 8); - outb(wdc+wd_sector, sector); - outb(wdc+wd_seccnt, count); + /* Load parameters. */ + outb(iobase+wd_precomp, wd->sc_label.d_precompcyl / 4); + outb(iobase+wd_cyl_lo, cylin); + outb(iobase+wd_cyl_hi, cylin >> 8); + outb(iobase+wd_sector, sector); + outb(iobase+wd_seccnt, count); - /* send command, await results */ - outb(wdc+wd_command, cmd); + /* Send command, await results. */ + outb(iobase+wd_command, cmd); - switch (cmd) { - default: -#if 0 - case WDCC_FORMAT: - case WDCC_RESTORE | WD_STEP: - case WDCC_DIAGNOSE: -#endif - return wait_for_unbusy(du); - case WDCC_READ: - case WDCC_WRITE: - return 0; - case WDCC_IDC: - return wdwait(du, WDCS_READY); - case WDCC_READP: - return wait_for_drq(du); - } + return 0; } /* - * issue IDC to drive to tell it just what geometry it is to be. + * Issue IDC to drive to tell it just what geometry it is to be. */ static int -wdsetctlr(du) - struct disk *du; +wdsetctlr(wd) + struct wd_softc *wd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; #ifdef WDDEBUG - printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit, - du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors); + printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_ctrlr, wd->sc_unit, + wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks, + wd->sc_label.d_nsectors); #endif - if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0, - du->dk_dd.d_nsectors, WDCC_IDC) != 0) { - wderror(du, NULL, "wdsetctlr: failed"); + if (wdcommand(wd, wd->sc_label.d_ncylinders, wd->sc_label.d_ntracks - 1, + 0, wd->sc_label.d_nsectors, WDCC_IDC) != 0 || + wdcwait(wdc, WDCS_READY) != 0) { + wderror(wd, NULL, "wdsetctlr: failed"); return -1; } return 0; } /* - * issue READP to drive to ask it what it is. + * Issue READP to drive to ask it what it is. */ static int -wdgetctlr(du) - struct disk *du; +wdgetctlr(wd) + struct wd_softc *wd; { + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; int i; char tb[DEV_BSIZE]; struct wdparams *wp; - if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0) { + if (wdcommand(wd, 0, 0, 0, 0, WDCC_READP) != 0 || + wait_for_drq(wdc) != 0) { /* - * If WDCC_READP fails then we might have an old drive - * so we try a seek to 0; if that passes then the - * drive is there but it's OLD AND KRUSTY. + * If WDCC_READP fails then we might have an old drive so we + * try a seek to 0; if that passes then the drive is there but + * it's OLD AND KRUSTY. */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || + wait_for_ready(wdc) != 0) return -1; - strncpy(du->dk_dd.d_typename, "ST506", - sizeof du->dk_dd.d_typename); - strncpy(du->dk_params.wdp_model, "Unknown Type", - sizeof du->dk_params.wdp_model); - du->dk_dd.d_type = DTYPE_ST506; + strncpy(wd->sc_label.d_typename, "ST506", + sizeof wd->sc_label.d_typename); + strncpy(wd->sc_params.wdp_model, "Unknown Type", + sizeof wd->sc_params.wdp_model); + wd->sc_label.d_type = DTYPE_ST506; } else { - /* obtain parameters */ - wp = &du->dk_params; - insw(du->dk_port+wd_data, tb, sizeof(tb) / sizeof(short)); + /* Obtain parameters. */ + wp = &wd->sc_params; + insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short)); bcopy(tb, wp, sizeof(struct wdparams)); - /* shuffle string byte order */ + /* Shuffle string byte order. */ for (i = 0; i < sizeof(wp->wdp_model); i += 2) { u_short *p; p = (u_short *)(wp->wdp_model + i); *p = ntohs(*p); } - strncpy(du->dk_dd.d_typename, "ESDI/IDE", - sizeof du->dk_dd.d_typename); - du->dk_dd.d_type = DTYPE_ESDI; - bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1); + strncpy(wd->sc_label.d_typename, "ESDI/IDE", + sizeof wd->sc_label.d_typename); + wd->sc_label.d_type = DTYPE_ESDI; + bcopy(wp->wdp_model+20, wd->sc_label.d_packname, 14-1); - /* update disklabel given drive information */ - du->dk_dd.d_ncylinders = + /* Update disklabel given drive information. */ + wd->sc_label.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/; - du->dk_dd.d_ntracks = wp->wdp_heads; - du->dk_dd.d_nsectors = wp->wdp_sectors; - du->dk_dd.d_secpercyl = - du->dk_dd.d_ntracks * du->dk_dd.d_nsectors; - du->dk_dd.d_partitions[1].p_size = - du->dk_dd.d_secpercyl * wp->wdp_sectors; - du->dk_dd.d_partitions[1].p_offset = 0; + wd->sc_label.d_ntracks = wp->wdp_heads; + wd->sc_label.d_nsectors = wp->wdp_sectors; + wd->sc_label.d_secpercyl = + wd->sc_label.d_ntracks * wd->sc_label.d_nsectors; + wd->sc_label.d_partitions[1].p_size = + wd->sc_label.d_secpercyl * wp->wdp_sectors; + wd->sc_label.d_partitions[1].p_offset = 0; } #if 0 @@ -1060,11 +1062,10 @@ wdgetctlr(du) wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model); #endif - /* better ... */ - du->dk_dd.d_subtype |= DSTYPE_GEOMETRY; + wd->sc_label.d_subtype |= DSTYPE_GEOMETRY; /* XXX sometimes possibly needed */ - (void) inb(du->dk_port+wd_status); + (void) inb(wdc->sc_iobase+wd_status); return 0; } @@ -1075,18 +1076,18 @@ wdclose(dev, flag, fmt) int flag; int fmt; { - struct disk *du = wddrives[WDUNIT(dev)]; + struct wd_softc *wd = wd_softc[WDUNIT(dev)]; int part = WDPART(dev), mask = 1 << part; - du->dk_openpart &= ~mask; switch (fmt) { case S_IFCHR: - du->dk_copenpart &= ~mask; + wd->sc_copenpart &= ~mask; break; case S_IFBLK: - du->dk_bopenpart &= ~mask; + wd->sc_bopenpart &= ~mask; break; } + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; return 0; } @@ -1100,75 +1101,75 @@ wdioctl(dev, cmd, addr, flag, p) struct proc *p; { int lunit = WDUNIT(dev); - struct disk *du = wddrives[lunit]; + struct wd_softc *wd = wd_softc[lunit]; int error; switch (cmd) { case DIOCSBAD: if ((flag & FWRITE) == 0) return EBADF; - du->dk_cpd.bad = *(struct dkbad *)addr; - bad144intern(du); + wd->sc_cpulabel.bad = *(struct dkbad *)addr; + bad144intern(wd); return 0; case DIOCGDINFO: - *(struct disklabel *)addr = du->dk_dd; + *(struct disklabel *)addr = wd->sc_label; return 0; case DIOCGPART: - ((struct partinfo *)addr)->disklab = &du->dk_dd; + ((struct partinfo *)addr)->disklab = &wd->sc_label; ((struct partinfo *)addr)->part = - &du->dk_dd.d_partitions[WDPART(dev)]; + &wd->sc_label.d_partitions[WDPART(dev)]; return 0; case DIOCSDINFO: if ((flag & FWRITE) == 0) return EBADF; - error = setdisklabel(&du->dk_dd, + error = setdisklabel(&wd->sc_label, (struct disklabel *)addr, - /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0, - &du->dk_cpd); + /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart : */0, + &wd->sc_cpulabel); if (error == 0) { - du->dk_flags |= DKFL_BSDLABEL; - wdsetctlr(du); + wd->sc_flags |= WDF_BSDLABEL; + wdsetctlr(wd); } return error; case DIOCWLABEL: - du->dk_flags &= ~DKFL_WRITEPROT; + wd->sc_flags &= ~WDF_WRITEPROT; if ((flag & FWRITE) == 0) return EBADF; - du->dk_wlabel = *(int *)addr; + wd->sc_wlabel = *(int *)addr; return 0; case DIOCWDINFO: - du->dk_flags &= ~DKFL_WRITEPROT; + wd->sc_flags &= ~WDF_WRITEPROT; if ((flag & FWRITE) == 0) return EBADF; - error = setdisklabel(&du->dk_dd, + error = setdisklabel(&wd->sc_label, (struct disklabel *)addr, - /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/0, - &du->dk_cpd); + /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_openpart :*/0, + &wd->sc_cpulabel); if (error == 0) { int wlab; - du->dk_flags |= DKFL_BSDLABEL; - wdsetctlr(du); + wd->sc_flags |= WDF_BSDLABEL; + wdsetctlr(wd); - /* simulate opening partition 0 so write succeeds */ - du->dk_openpart |= (1 << 0); /* XXX */ - wlab = du->dk_wlabel; - du->dk_wlabel = 1; - error = writedisklabel(dev, wdstrategy, &du->dk_dd, - &du->dk_cpd); - du->dk_openpart = du->dk_copenpart | du->dk_bopenpart; - du->dk_wlabel = wlab; + /* Simulate opening partition 0 so write succeeds. */ + wd->sc_openpart |= (1 << 0); /* XXX */ + wlab = wd->sc_wlabel; + wd->sc_wlabel = 1; + error = writedisklabel(dev, wdstrategy, &wd->sc_label, + &wd->sc_cpulabel); + wd->sc_openpart = wd->sc_copenpart | wd->sc_bopenpart; + wd->sc_wlabel = wlab; } return error; #ifdef notyet case DIOCGDINFOP: - *(struct disklabel **)addr = &du->dk_dd; + *(struct disklabel **)addr = &wd->sc_label; return 0; case DIOCWFORMAT: @@ -1187,12 +1188,12 @@ wdioctl(dev, cmd, addr, flag, p) auio.uio_resid = fop->df_count; auio.uio_segflg = 0; auio.uio_offset = - fop->df_startblk * du->dk_dd.d_secsize; - error = physio(wdformat, &rwdbuf[lunit], dev, B_WRITE, - minphys, &auio); + fop->df_startblk * wd->sc_label.d_secsize; + error = physio(wdformat, NULL, dev, B_WRITE, minphys, + &auio); fop->df_count -= auio.uio_resid; - fop->df_reg[0] = du->dk_status; - fop->df_reg[1] = du->dk_error; + fop->df_reg[0] = wdc->sc_status; + fop->df_reg[1] = wdc->sc_error; return error; } #endif @@ -1221,15 +1222,15 @@ wdsize(dev) dev_t dev; { int lunit = WDUNIT(dev), part = WDPART(dev); - struct disk *du; + struct wd_softc *wd; if (lunit >= NWD) return -1; - du = wddrives[lunit]; - if (du == 0) + wd = wd_softc[lunit]; + if (wd == 0) return -1; - if (du->dk_state < OPEN || (du->dk_flags & DKFL_BSDLABEL) == 0) { + if (wd->sc_state < OPEN || (wd->sc_flags & WDF_BSDLABEL) == 0) { int val; val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, S_IFBLK, 0); @@ -1238,20 +1239,23 @@ wdsize(dev) return -1; } - if ((du->dk_flags & (DKFL_WRITEPROT | DKFL_BSDLABEL)) != DKFL_BSDLABEL) + if ((wd->sc_flags & (WDF_WRITEPROT | WDF_BSDLABEL)) != WDF_BSDLABEL) return -1; - return (int)du->dk_dd.d_partitions[part].p_size; + return (int)wd->sc_label.d_partitions[part].p_size; } -/* dump core after a system crash */ +/* + * Dump core after a system crash. + */ int wddump(dev) dev_t dev; { - register struct disk *du; /* disk unit to do the IO */ - long num; /* number of sectors to write */ - int ctrlr, lunit, part; + struct wd_softc *wd; /* disk unit to do the IO */ + struct wdc_softc *wdc; + long num; /* number of sectors to write */ + int lunit, part; long blkoff, blknum; long cylin, head, sector; long secpertrk, secpercyl, nblocks; @@ -1260,81 +1264,74 @@ wddump(dev) extern caddr_t CADDR1; extern struct pte *CMAP1; - addr = (char *)0; /* starting address */ + addr = (char *)0; /* starting address */ #if DO_NOT_KNOW_HOW - /* toss any characters present prior to dump, ie. non-blocking getc */ + /* Toss any characters present prior to dump, ie. non-blocking getc. */ while (cngetc()) ; #endif - /* size of memory to dump */ lunit = WDUNIT(dev); - part = WDPART(dev); /* file system */ - /* check for acceptable drive number */ + /* Check for acceptable drive number. */ if (lunit >= NWD) return ENXIO; - du = wddrives[lunit]; - /* was it ever initialized ? */ - if (du == 0 || du->dk_state < OPEN || du->dk_flags & DKFL_WRITEPROT) + wd = wd_softc[lunit]; + /* Was it ever initialized? */ + if (wd == 0 || wd->sc_state < OPEN || wd->sc_flags & WDF_WRITEPROT) return ENXIO; - ctrlr = du->dk_ctrlr; - - /* Convert to disk sectors */ - num = ctob(physmem) / du->dk_dd.d_secsize; + wdc = (void *)wd->sc_dev.dv_parent; + + /* Convert to disk sectors. */ + num = ctob(physmem) / wd->sc_label.d_secsize; - secpertrk = du->dk_dd.d_nsectors; - secpercyl = du->dk_dd.d_secpercyl; - nblocks = du->dk_dd.d_partitions[part].p_size; - blkoff = du->dk_dd.d_partitions[part].p_offset; + secpertrk = wd->sc_label.d_nsectors; + secpercyl = wd->sc_label.d_secpercyl; + part = WDPART(dev); + nblocks = wd->sc_label.d_partitions[part].p_size; + blkoff = wd->sc_label.d_partitions[part].p_offset; /*printf("part %x, nblocks %d, dumplo %d, num %d\n", part, nblocks, dumplo, num);*/ - /* check transfer bounds against partition size */ + /* Check transfer bounds against partition size. */ if (dumplo < 0 || dumplo + num > nblocks) return EINVAL; - /* check if controller active */ - /*if (wdtab[ctrlr].b_active) - return EFAULT;*/ if (wddoingadump) return EFAULT; - - /* mark controller active for if we panic during the dump */ - /*wdtab[ctrlr].b_active = 1;*/ wddoingadump = 1; /* Recalibrate. */ - if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || - wdsetctlr(du) != 0) { - wderror(du, NULL, "wddump: recal failed"); + if (wdcommand(wd, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0 || + wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0) { + wderror(wd, NULL, "wddump: recal failed"); return EIO; } blknum = dumplo + blkoff; while (num > 0) { - /* compute disk address */ + /* Compute disk address. */ cylin = blknum / secpercyl; head = (blknum % secpercyl) / secpertrk; sector = blknum % secpertrk; - if (du->dk_flags & DKFL_BADSECT) { + if (wd->sc_flags & WDF_BADSECT) { long newblk; int i; - for (i = 0; du->dk_badsect[i] != -1; i++) { - if (blknum < du->dk_badsect[i]) { - /* sorted list, passed our block by */ + for (i = 0; wd->sc_badsect[i] != -1; i++) { + if (blknum < wd->sc_badsect[i]) { + /* Sorted list, passed our block by. */ break; - } else if (blknum == du->dk_badsect[i]) { - newblk = du->dk_dd.d_secperunit - - du->dk_dd.d_nsectors - i - 1; + } else if (blknum == wd->sc_badsect[i]) { + newblk = wd->sc_label.d_secperunit - + wd->sc_label.d_nsectors - i - 1; cylin = newblk / secpercyl; head = (newblk % secpercyl) / secpertrk; sector = newblk % secpertrk; - /* found and replaced; done */ + /* Found and replaced; done. */ break; } } @@ -1342,49 +1339,49 @@ wddump(dev) sector++; /* origin 1 */ #ifdef notdef - /* lets just talk about this first...*/ + /* Let's just talk about this first. */ printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head, sector, addr); #endif - if (wdcommand(du, cylin, head, sector, 1, WDCC_WRITE) != 0) { - wderror(du, NULL, "wddump: wdcommand failed"); + if (wdcommand(wd, cylin, head, sector, 1, WDCC_WRITE) != 0) { + wderror(wd, NULL, "wddump: wdcommand failed"); return EIO; } - if (wait_for_drq(du) != 0) { - wderror(du, NULL, "wddump: timeout waiting for drq"); + if (wait_for_drq(wdc) != 0) { + wderror(wd, NULL, "wddump: timeout waiting for drq"); return EIO; } -#ifdef notdef /* cannot use this since this address was mapped differently */ +#ifdef notdef /* Cannot use this since this address was mapped differently. */ pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); #else *(int *)CMAP1 = PG_V | PG_KW | ctob((long)addr); tlbflush(); #endif - outsw(du->dk_port+wd_data, CADDR1 + ((int)addr & PGOFSET), + outsw(wdc->sc_iobase+wd_data, CADDR1 + ((int)addr & PGOFSET), DEV_BSIZE / sizeof(short)); /* Check data request (should be done). */ - if (wait_for_ready(du) != 0) { - wderror(du, NULL, "wddump: timeout waiting for ready"); + if (wait_for_ready(wdc) != 0) { + wderror(wd, NULL, "wddump: timeout waiting for ready"); return EIO; } - if (du->dk_status & WDCS_DRQ) { - wderror(du, NULL, "wddump: extra drq"); + if (wdc->sc_status & WDCS_DRQ) { + wderror(wd, NULL, "wddump: extra drq"); return EIO; } if ((unsigned)addr % 1048576 == 0) printf("%d ", num / (1048576 / DEV_BSIZE)); - /* update block count */ + /* Update block count. */ num--; blknum++; (int)addr += DEV_BSIZE; #if DO_NOT_KNOW_HOW - /* operator aborting dump? non-blocking getc() */ + /* Operator aborting dump? non-blocking getc() */ if (cngetc()) return EINTR; #endif @@ -1396,60 +1393,105 @@ wddump(dev) * Internalize the bad sector table. */ void -bad144intern(du) - struct disk *du; +bad144intern(wd) + struct wd_softc *wd; { int i; - if ((du->dk_flags & DKFL_BADSECT) == 0) + if ((wd->sc_flags & WDF_BADSECT) == 0) return; for (i = 0; i < 127; i++) - du->dk_badsect[i] = -1; + wd->sc_badsect[i] = -1; for (i = 0; i < 126; i++) { - if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) + if (wd->sc_cpulabel.bad.bt_bad[i].bt_cyl == 0xffff) break; - du->dk_badsect[i] = - du->dk_cpd.bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl + - (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * - du->dk_dd.d_nsectors + - (du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); + wd->sc_badsect[i] = + wd->sc_cpulabel.bad.bt_bad[i].bt_cyl * + wd->sc_label.d_secpercyl + + (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec >> 8) * + wd->sc_label.d_nsectors + + (wd->sc_cpulabel.bad.bt_bad[i].bt_trksec & 0x00ff); } } static int -wdreset(du, err) - struct disk *du; - int err; +wdcreset(wdc) + struct wdc_softc *wdc; { - u_short wdc = du->dk_port; - - if (err) - printf("wdc%d: busy too long, resetting\n", du->dk_ctrlr); + u_short iobase = wdc->sc_iobase; - /* reset the device */ - outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); + /* Reset the device. */ + outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS); delay(1000); - outb(wdc+wd_ctlr, WDCTL_IDS); + outb(iobase+wd_ctlr, WDCTL_IDS); delay(1000); - (void) inb(wdc+wd_error); - outb(wdc+wd_ctlr, WDCTL_4BIT); + (void) inb(iobase+wd_error); + outb(iobase+wd_ctlr, WDCTL_4BIT); + + if (wait_for_unbusy(wdc) < 0) { + printf("%s: reset failed\n", wdc->sc_dev.dv_xname); + return 1; + } + + return 0; +} + +static void +wdcrestart(wdc) + struct wdc_softc *wdc; +{ + int s = splbio(); + + wdc->sc_q.b_active = 0; + wdcstart(wdc); + splx(s); +} + +/* + * Unwedge the controller after an unexpected error. We do this by resetting + * it, marking all drives for recalibration, and stalling the queue for a short + * period to give the reset time to finish. + * NOTE: We use a timeout here, so this routine must not be called during + * autoconfig or dump. + */ +static void +wdcunwedge(wdc) + struct wdc_softc *wdc; +{ + int lunit; + + wdc->sc_timeout = 0; + (void) wdcreset(wdc); + + /* Schedule recalibrate for all drives on this controller. */ + for (lunit = 0; lunit < NWD; lunit++) { + struct wd_softc *wd = wd_softc[lunit]; + if (!wd || (void *)wd->sc_dev.dv_parent != wdc) + continue; + if (wd->sc_state > WANTOPEN) + wd->sc_state = WANTOPEN; + if (wd->sc_q.b_active && (wd->sc_flags & WDF_SINGLE) == 0) + wd->sc_flags |= WDF_ERROR; + } + + ++wdc->sc_q.b_errcnt; - if (wait_for_unbusy(du) < 0) - printf("wdc%d: failed to reset controller\n", du->dk_ctrlr); + /* Wake up in a little bit and restart the operation. */ + timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME); } int -wdwait(du, mask) - struct disk *du; +wdcwait(wdc, mask) + struct wdc_softc *wdc; int mask; { - u_short wdc = du->dk_port; + u_short iobase = wdc->sc_iobase; int timeout = 0; u_char status; for (;;) { - du->dk_status = status = inb(wdc+wd_altsts); + wdc->sc_status = status = inb(iobase+wd_altsts); if ((status & WDCS_BUSY) == 0 && (status & mask) == mask) break; if (++timeout > WDCNDELAY) @@ -1457,45 +1499,43 @@ wdwait(du, mask) delay(WDCDELAY); } if (status & WDCS_ERR) - du->dk_error = inb(wdc+wd_error); + wdc->sc_error = inb(iobase+wd_error); #ifdef WDCNDELAY_DEBUG if (timeout > WDCNDELAY_DEBUG) - printf("wdc%d: busy-wait took %dus\n", du->dk_ctrlr, + printf("%s: busy-wait took %dus\n", wdc->sc_dev.dv_xname, WDCDELAY * timeout); #endif return status & WDCS_ERR; } static void -wdtimeout(arg) - caddr_t arg; +wdctimeout(wdc) + struct wdc_softc *wdc; { int s = splbio(); - struct disk *du = (void *)arg; - - if (du->dk_timeout && --du->dk_timeout == 0) { - wderror(du, NULL, "lost interrupt"); - wdreset(du, 0); - /* XXX Need to recalibrate and upload geometry. */ - du->dk_skip = 0; - du->dk_flags |= DKFL_SINGLE; - wdstart(du->dk_ctrlr); + + if (wdc->sc_timeout && --wdc->sc_timeout == 0) { + wderror(wdc, NULL, "lost interrupt"); + wdcunwedge(wdc); } - timeout((timeout_t)wdtimeout, arg, hz); + timeout((timeout_t)wdctimeout, (caddr_t)wdc, hz); splx(s); } static void -wderror(du, bp, msg) - struct disk *du; +wderror(dev, bp, msg) + void *dev; struct buf *bp; char *msg; { + struct wd_softc *wd = dev; + struct wdc_softc *wdc = dev; + if (bp) - diskerr(bp, "wd", msg, LOG_PRINTF, du->dk_skip, &du->dk_dd); + diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip, &wd->sc_label); else - printf("wd%d: %s: status %b error %b\n", du->dk_lunit, msg, - du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS); + printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname, + msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS); } #endif /* NWDC > 0 */ diff --git a/sys/dev/isa/wdreg.h b/sys/dev/isa/wdreg.h index 24bc9462ed0..54a6f7bd1b6 100644 --- a/sys/dev/isa/wdreg.h +++ b/sys/dev/isa/wdreg.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91 - * $Id: wdreg.h,v 1.4 1994/03/02 21:43:42 mycroft Exp $ + * $Id: wdreg.h,v 1.5 1994/03/10 05:18:36 mycroft Exp $ */ /* @@ -126,19 +126,4 @@ struct wdparams { short wdp_nsecperint; /* sectors per interrupt */ short wdp_usedmovsd; /* can use double word read/write? */ }; - -/* - * wd driver entry points - */ -int wdprobe(struct isa_device *); -int wdattach(struct isa_device *); -int wdstrategy(struct buf *); -void wdintr(int); -int wdopen(dev_t, int, int, struct proc *); -int wdclose(dev_t, int, int); -int wdioctl(dev_t, int, caddr_t, int, struct proc *); -/* int wdformat(struct buf *bp); */ -int wdsize(dev_t); -int wddump(dev_t); - #endif KERNEL |
