From 893be926ec19323167691ac04d8c5a4654331a9d Mon Sep 17 00:00:00 2001 From: mycroft Date: Wed, 20 Apr 1994 07:23:52 +0000 Subject: [PATCH] Use TAILQ_*() to maintain the drive activation queues. --- sys/arch/i386/isa/fd.c | 151 ++++++++++++++++++++++------------------- sys/arch/i386/isa/wd.c | 121 +++++++++++++++------------------ sys/dev/ata/wd.c | 121 +++++++++++++++------------------ sys/dev/isa/wd.c | 121 +++++++++++++++------------------ 4 files changed, 246 insertions(+), 268 deletions(-) diff --git a/sys/arch/i386/isa/fd.c b/sys/arch/i386/isa/fd.c index c99319e01d29..c18495c2d550 100644 --- a/sys/arch/i386/isa/fd.c +++ b/sys/arch/i386/isa/fd.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.39 1994/04/09 02:57:14 mycroft Exp $ + * $Id: fd.c,v 1.40 1994/04/20 07:23:52 mycroft Exp $ */ #include @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -102,8 +103,7 @@ struct fdc_softc { u_short sc_drq; struct fd_softc *sc_fd[4]; /* pointers to children */ - struct fd_softc *sc_afd; /* active drive */ - struct buf sc_q; + TAILQ_HEAD(drivehead, fd_softc) sc_drives; enum fdc_state sc_state; int sc_retry; /* number of retries so far */ u_char sc_status[7]; /* copy of registers */ @@ -159,6 +159,7 @@ struct fd_softc { #endif struct fd_type *sc_deftype; /* default type descriptor */ + TAILQ_ENTRY(fd_softc) sc_drivechain; struct buf sc_q; /* head of buf chain */ int sc_drive; /* unit number on this controller */ int sc_flags; @@ -186,6 +187,7 @@ struct dkdriver fddkdriver = { fdstrategy }; #endif struct fd_type *fd_nvtotype __P((char *, int, int)); +void fdstart __P((struct fd_softc *fd)); void fd_set_motor __P((struct fdc_softc *fdc, int reset)); void fd_motor_off __P((struct fd_softc *fd)); void fd_motor_on __P((struct fd_softc *fd)); @@ -197,6 +199,7 @@ void fdctimeout __P((struct fdc_softc *fdc)); void fdcpseudointr __P((struct fdc_softc *fdc)); int fdcintr __P((struct fdc_softc *fdc)); void fdcretry __P((struct fdc_softc *fdc)); +void fdfinish __P((struct fd_softc *fd, struct buf *bp)); int fdcprobe(parent, self, aux) @@ -294,6 +297,8 @@ fdcattach(parent, self, aux) fdc->sc_iobase = ia->ia_iobase; fdc->sc_drq = ia->ia_drq; fdc->sc_state = DEVIDLE; + TAILQ_INIT(&fdc->sc_drives); + printf("\n"); #ifdef NEWCONFIG @@ -512,38 +517,39 @@ fdstrategy(bp) bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, nblks); #endif s = splbio(); - dp = &fd->sc_q; - disksort(dp, bp); + disksort(&fd->sc_q, bp); untimeout((timeout_t)fd_motor_off, (caddr_t)fd); /* a good idea */ - if (!dp->b_active) { - register struct buf *cp; - dp->b_forw = NULL; - dp->b_active = 1; - cp = &fdc->sc_q; - if (!cp->b_forw) - cp->b_forw = dp; - else - cp->b_back->b_forw = dp; - cp->b_back = dp; - if (!cp->b_active) { - cp->b_active = 1; - fdcstart(fdc); - } - } + if (!fd->sc_q.b_active) + fdstart(fd); #ifdef DIAGNOSTIC - else if (!fdc->sc_q.b_active) { + else if (fdc->sc_state == DEVIDLE) { printf("fdstrategy: controller inactive\n"); - fdc->sc_q.b_active = 1; fdcstart(fdc); } #endif splx(s); return; - bad: +bad: biodone(bp); } +void +fdstart(fd) + struct fd_softc *fd; +{ + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + int active = fdc->sc_drives.tqh_first != 0; + + /* Link into controller queue. */ + fd->sc_q.b_active = 1; + TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); + + /* If controller not already active, start it. */ + if (!active) + fdcstart(fdc); +} + void fd_set_motor(fdc, reset) struct fdc_softc *fdc; @@ -553,7 +559,7 @@ fd_set_motor(fdc, reset) u_char status; int n; - if (fd = fdc->sc_afd) + if (fd = fdc->sc_drives.tqh_first) status = fd->sc_drive; else status = 0; @@ -584,7 +590,7 @@ fd_motor_on(fd) int s = splbio(); fd->sc_flags &= ~FD_MOTOR_WAIT; - if ((fdc->sc_afd == fd) && (fdc->sc_state == MOTORWAIT)) + if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) (void) fdcintr(fdc); splx(s); } @@ -718,17 +724,17 @@ void fdctimeout(fdc) struct fdc_softc *fdc; { - struct fd_softc *fd = fdc->sc_afd; + struct fd_softc *fd; int s = splbio(); + fd = fdc->sc_drives.tqh_first; + fdcstatus(&fd->sc_dev, 0, "timeout"); - if (fd->sc_q.b_actf) { + if (fd->sc_q.b_actf) fdc->sc_state++; - } else { - fdc->sc_afd = NULL; + else fdc->sc_state = DEVIDLE; - } (void) fdcintr(fdc); splx(s); @@ -752,43 +758,29 @@ fdcintr(fdc) #define st0 fdc->sc_status[0] #define cyl fdc->sc_status[1] struct fd_softc *fd; - struct buf *dp, *bp; + struct buf *bp; u_short iobase = fdc->sc_iobase; int read, head, trac, sec, i, s, sectrac, blkno, nblks; struct fd_type *type; again: - dp = fdc->sc_q.b_forw; - if (!dp) { + fd = fdc->sc_drives.tqh_first; + if (!fd) { /* no drives waiting; end */ fdc->sc_state = DEVIDLE; - fdc->sc_q.b_active = 0; -#ifdef DIAGNOSTIC - if (fd = fdc->sc_afd) { - printf("%s: stray afd %s\n", fdc->sc_dev.dv_xname, - fd->sc_dev.dv_xname); - fdc->sc_afd = NULL; - } -#endif return 1; } - bp = dp->b_actf; + bp = fd->sc_q.b_actf; if (!bp) { /* nothing queued on this drive; try next */ - fdc->sc_q.b_forw = dp->b_forw; - dp->b_active = 0; + TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); + fd->sc_q.b_active = 0; goto again; } - fd = fdcd.cd_devs[FDUNIT(bp->b_dev)]; -#ifdef DIAGNOSTIC - if (fdc->sc_afd && (fd != fdc->sc_afd)) - printf("%s: confused fd pointers\n", fdc->sc_dev.dv_xname); -#endif switch (fdc->sc_state) { case DEVIDLE: fdc->sc_retry = 0; - fdc->sc_afd = fd; fd->sc_skip = 0; fd->sc_blkno = bp->b_blkno * DEV_BSIZE / FDC_BSIZE; untimeout((timeout_t)fd_motor_off, (caddr_t)fd); @@ -954,14 +946,7 @@ again: bp->b_cylin = (blkno / (type->sectrac * type->heads)) * type->step; goto doseek; } else { - bp->b_resid = 0; - fd->sc_q.b_actf = bp->b_actf; - biodone(bp); - /* turn off motor 5s from now */ - timeout((timeout_t)fd_motor_off, (caddr_t)fd, hz*5); - fd->sc_skip = 0; - fdc->sc_afd = NULL; - fdc->sc_state = DEVIDLE; + fdfinish(fd, bp); goto again; } @@ -1027,9 +1012,10 @@ void fdcretry(fdc) struct fdc_softc *fdc; { - register struct buf *bp; - struct fd_softc *fd = fdc->sc_afd; + struct fd_softc *fd; + struct buf *bp; + fd = fdc->sc_drives.tqh_first; bp = fd->sc_q.b_actf; switch (fdc->sc_retry) { @@ -1049,8 +1035,6 @@ fdcretry(fdc) break; default: - fd = fdc->sc_afd; - diskerr(bp, "fd", "hard error", LOG_PRINTF, fd->sc_skip, (struct disklabel *)NULL); printf(" (st0 %b ", fdc->sc_status[0], NE7_ST0BITS); @@ -1061,18 +1045,45 @@ fdcretry(fdc) bp->b_flags |= B_ERROR; bp->b_error = EIO; - bp->b_resid = bp->b_bcount - fd->sc_skip; - fd->sc_q.b_actf = bp->b_actf; - biodone(bp); - /* turn off motor 5s from now */ - timeout((timeout_t)fd_motor_off, (caddr_t)fd, hz*5); - fd->sc_skip = 0; - fdc->sc_afd = NULL; - fdc->sc_state = DEVIDLE; + fdfinish(fd, bp); } fdc->sc_retry++; } +void +fdfinish(fd, bp) + struct fd_softc *fd; + struct buf *bp; +{ + struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent; + +#if 0 + /* + * This might seem like a good idea, but each drive switch takes .25 + * second because we can't keep both motors running at the same time + * and we have to wait for the new one to stabilize for each I/O. + */ + /* + * Move this drive to the end of the queue to give others a `fair' + * chance. + */ + if (fd->sc_drivechain.tqe_next) { + TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain); + if (bp->b_actf) { + TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain); + } else + fd->sc_q.b_active = 0; + } +#endif + bp->b_resid = bp->b_bcount - fd->sc_skip; + fd->sc_skip = 0; + fd->sc_q.b_actf = bp->b_actf; + biodone(bp); + /* turn off motor 5s from now */ + timeout((timeout_t)fd_motor_off, (caddr_t)fd, hz*5); + fdc->sc_state = DEVIDLE; +} + int fdioctl(dev, cmd, addr, flag) dev_t dev; diff --git a/sys/arch/i386/isa/wd.c b/sys/arch/i386/isa/wd.c index 45cacfe515f2..5f1ed0b8f481 100644 --- a/sys/arch/i386/isa/wd.c +++ b/sys/arch/i386/isa/wd.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.77 1994/04/09 03:43:36 mycroft Exp $ + * $Id: wd.c,v 1.78 1994/04/20 07:23:54 mycroft Exp $ */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */ @@ -122,6 +122,7 @@ struct wd_softc { #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 */ + TAILQ_ENTRY(wd_softc) sc_drivechain; struct buf sc_q; struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ struct disklabel sc_label; /* device configuration data */ @@ -133,14 +134,16 @@ struct wdc_softc { struct device sc_dev; struct intrhand sc_ih; - struct buf sc_q; u_char sc_flags; +#define WDCF_ACTIVE 0x00001 /* controller is active */ #define WDCF_SINGLE 0x00004 /* sector at a time mode */ #define WDCF_ERROR 0x00008 /* processing a disk error */ 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 */ + int sc_errors; /* count of errors during current transfer */ + TAILQ_HEAD(drivehead, wd_softc) sc_drives; }; int wdcprobe(), wdprobe(), wdcintr(); @@ -254,6 +257,7 @@ wdcattach(parent, self, aux) for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++) (void)config_found(self, &wa, wdprint); + TAILQ_INIT(&wdc->sc_drives); wdctimeout(wdc); wdc->sc_ih.ih_fun = wdcintr; wdc->sc_ih.ih_arg = wdc; @@ -333,7 +337,6 @@ void wdstrategy(bp) struct buf *bp; { - struct buf *dp; struct wd_softc *wd; /* disk unit to do the IO */ struct wdc_softc *wdc; int lunit = WDUNIT(bp->b_dev); @@ -371,14 +374,16 @@ wdstrategy(bp) bp->b_cylin = 0; /* Queue transfer on drive, activate drive and controller if idle. */ - dp = &wd->sc_q; s = splbio(); - wddisksort(dp, bp); - if (dp->b_active == 0) + wddisksort(&wd->sc_q, bp); + if (!wd->sc_q.b_active) wdstart(wd); /* Start drive. */ - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_active == 0) - wdcstart(wdc); /* Start controller. */ +#ifdef DIAGNOSTIC + else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) { + printf("wdstrategy: controller inactive\n"); + wdcstart(wdc); + } +#endif splx(s); return; @@ -410,29 +415,16 @@ static void wdstart(wd) struct wd_softc *wd; { - struct buf *dp; - struct wdc_softc *wdc; + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; + int active = wdc->sc_drives.tqh_first != 0; - dp = &wd->sc_q; - - /* Unit already active? */ - if (dp->b_active) - return; - /* Anything to start? */ - if (dp->b_actf == NULL) - return; - /* Link onto controller queue. */ - dp->b_forw = NULL; - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_forw == NULL) - wdc->sc_q.b_forw = dp; - else - wdc->sc_q.b_actl->b_forw = dp; - wdc->sc_q.b_actl = dp; + wd->sc_q.b_active = 1; + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain); - /* Mark the drive unit as busy. */ - dp->b_active = 1; + /* If controller not already active, start it. */ + if (!active) + wdcstart(wdc); } void @@ -446,22 +438,26 @@ wdfinish(wd, bp) dk_busy &= ~(1 << wd->sc_drive); #endif wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 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) { + wd->sc_mskip = 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); + if (wd->sc_drivechain.tqe_next) { + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + if (bp->b_actf) { + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, + sc_drivechain); + } else + wd->sc_q.b_active = 0; + } } bp->b_resid = wd->sc_bcount; bp->b_flags &= ~B_XXX; @@ -484,42 +480,34 @@ wdcstart(wdc) 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 = wdc->sc_q.b_forw; - if (dp == NULL) { - wdc->sc_q.b_active = 0; + wd = wdc->sc_drives.tqh_first; + if (wd == NULL) return; - } /* Is there a transfer to this drive? If not, deactivate drive. */ - bp = dp->b_actf; + bp = wd->sc_q.b_actf; if (bp == NULL) { - dp->b_active = 0; - wdc->sc_q.b_forw = dp->b_forw; + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + wd->sc_q.b_active = 0; goto loop; } - /* Obtain controller and drive information */ - lunit = WDUNIT(bp->b_dev); - wd = wdcd.cd_devs[lunit]; - - if (wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; wdfinish(wd, bp); goto loop; } - - /* Mark controller active and set a timeout. */ - wdc->sc_q.b_active = 1; + + /* Mark the controller active and set a timeout. */ + wdc->sc_flags |= WDCF_ACTIVE; wdc->sc_timeout = 4; /* Do control operations specially. */ @@ -551,7 +539,7 @@ loop: blknum = bp->b_blkno + wd->sc_skip; #ifdef WDDEBUG if (wd->sc_skip == 0) - printf("\nwdcstart %d: %s %d@%d; map ", lunit, + printf("\nwdcstart %s: %s %d@%d; map ", wd->sc_dev.dv_xname, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else @@ -680,7 +668,7 @@ loop: cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts)); #endif } - + /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; @@ -712,13 +700,12 @@ wdcintr(wdc) /* Clear the pending interrupt. */ (void) inb(wdc->sc_iobase+wd_status); - if (!wdc->sc_q.b_active) + if ((wdc->sc_flags & WDCF_ACTIVE) == 0) return 0; - - bp = wdc->sc_q.b_forw->b_actf; - wd = wdcd.cd_devs[WDUNIT(bp->b_dev)]; - wdc->sc_timeout = 0; - + + wd = wdc->sc_drives.tqh_first; + bp = wd->sc_q.b_actf; + #ifdef WDDEBUG printf("I%d ", ctrlr); #endif @@ -734,6 +721,9 @@ wdcintr(wdc) wdcstart(wdc); return 1; } + + wdc->sc_flags &= ~WDCF_ACTIVE; + wdc->sc_timeout = 0; /* Have we an error? */ if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) { @@ -755,7 +745,7 @@ wdcintr(wdc) /* Error or error correction? */ if (wdc->sc_status & WDCS_ERR) { - if (++wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (++wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; /* Flag the error. */ @@ -782,9 +772,9 @@ wdcintr(wdc) } /* If we encountered any abnormalities, flag it as a soft error. */ - if (wdc->sc_q.b_errcnt) { + if (wdc->sc_errors) { wderror(wd, bp, "soft error"); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; } /* Ready for the next block, if any. */ @@ -970,7 +960,7 @@ wdcontrol(wd) return 0; } - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; wd->sc_state = OPEN; /* * The rest of the initialization can be done by normal means. @@ -1498,7 +1488,6 @@ wdcrestart(wdc) { int s = splbio(); - wdc->sc_q.b_active = 0; wdcstart(wdc); splx(s); } @@ -1529,7 +1518,7 @@ wdcunwedge(wdc) } wdc->sc_flags |= WDCF_ERROR; - ++wdc->sc_q.b_errcnt; + ++wdc->sc_errors; /* Wake up in a little bit and restart the operation. */ timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME); diff --git a/sys/dev/ata/wd.c b/sys/dev/ata/wd.c index 45cacfe515f2..5f1ed0b8f481 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.77 1994/04/09 03:43:36 mycroft Exp $ + * $Id: wd.c,v 1.78 1994/04/20 07:23:54 mycroft Exp $ */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */ @@ -122,6 +122,7 @@ struct wd_softc { #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 */ + TAILQ_ENTRY(wd_softc) sc_drivechain; struct buf sc_q; struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ struct disklabel sc_label; /* device configuration data */ @@ -133,14 +134,16 @@ struct wdc_softc { struct device sc_dev; struct intrhand sc_ih; - struct buf sc_q; u_char sc_flags; +#define WDCF_ACTIVE 0x00001 /* controller is active */ #define WDCF_SINGLE 0x00004 /* sector at a time mode */ #define WDCF_ERROR 0x00008 /* processing a disk error */ 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 */ + int sc_errors; /* count of errors during current transfer */ + TAILQ_HEAD(drivehead, wd_softc) sc_drives; }; int wdcprobe(), wdprobe(), wdcintr(); @@ -254,6 +257,7 @@ wdcattach(parent, self, aux) for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++) (void)config_found(self, &wa, wdprint); + TAILQ_INIT(&wdc->sc_drives); wdctimeout(wdc); wdc->sc_ih.ih_fun = wdcintr; wdc->sc_ih.ih_arg = wdc; @@ -333,7 +337,6 @@ void wdstrategy(bp) struct buf *bp; { - struct buf *dp; struct wd_softc *wd; /* disk unit to do the IO */ struct wdc_softc *wdc; int lunit = WDUNIT(bp->b_dev); @@ -371,14 +374,16 @@ wdstrategy(bp) bp->b_cylin = 0; /* Queue transfer on drive, activate drive and controller if idle. */ - dp = &wd->sc_q; s = splbio(); - wddisksort(dp, bp); - if (dp->b_active == 0) + wddisksort(&wd->sc_q, bp); + if (!wd->sc_q.b_active) wdstart(wd); /* Start drive. */ - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_active == 0) - wdcstart(wdc); /* Start controller. */ +#ifdef DIAGNOSTIC + else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) { + printf("wdstrategy: controller inactive\n"); + wdcstart(wdc); + } +#endif splx(s); return; @@ -410,29 +415,16 @@ static void wdstart(wd) struct wd_softc *wd; { - struct buf *dp; - struct wdc_softc *wdc; + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; + int active = wdc->sc_drives.tqh_first != 0; - dp = &wd->sc_q; - - /* Unit already active? */ - if (dp->b_active) - return; - /* Anything to start? */ - if (dp->b_actf == NULL) - return; - /* Link onto controller queue. */ - dp->b_forw = NULL; - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_forw == NULL) - wdc->sc_q.b_forw = dp; - else - wdc->sc_q.b_actl->b_forw = dp; - wdc->sc_q.b_actl = dp; + wd->sc_q.b_active = 1; + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain); - /* Mark the drive unit as busy. */ - dp->b_active = 1; + /* If controller not already active, start it. */ + if (!active) + wdcstart(wdc); } void @@ -446,22 +438,26 @@ wdfinish(wd, bp) dk_busy &= ~(1 << wd->sc_drive); #endif wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 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) { + wd->sc_mskip = 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); + if (wd->sc_drivechain.tqe_next) { + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + if (bp->b_actf) { + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, + sc_drivechain); + } else + wd->sc_q.b_active = 0; + } } bp->b_resid = wd->sc_bcount; bp->b_flags &= ~B_XXX; @@ -484,42 +480,34 @@ wdcstart(wdc) 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 = wdc->sc_q.b_forw; - if (dp == NULL) { - wdc->sc_q.b_active = 0; + wd = wdc->sc_drives.tqh_first; + if (wd == NULL) return; - } /* Is there a transfer to this drive? If not, deactivate drive. */ - bp = dp->b_actf; + bp = wd->sc_q.b_actf; if (bp == NULL) { - dp->b_active = 0; - wdc->sc_q.b_forw = dp->b_forw; + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + wd->sc_q.b_active = 0; goto loop; } - /* Obtain controller and drive information */ - lunit = WDUNIT(bp->b_dev); - wd = wdcd.cd_devs[lunit]; - - if (wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; wdfinish(wd, bp); goto loop; } - - /* Mark controller active and set a timeout. */ - wdc->sc_q.b_active = 1; + + /* Mark the controller active and set a timeout. */ + wdc->sc_flags |= WDCF_ACTIVE; wdc->sc_timeout = 4; /* Do control operations specially. */ @@ -551,7 +539,7 @@ loop: blknum = bp->b_blkno + wd->sc_skip; #ifdef WDDEBUG if (wd->sc_skip == 0) - printf("\nwdcstart %d: %s %d@%d; map ", lunit, + printf("\nwdcstart %s: %s %d@%d; map ", wd->sc_dev.dv_xname, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else @@ -680,7 +668,7 @@ loop: cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts)); #endif } - + /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; @@ -712,13 +700,12 @@ wdcintr(wdc) /* Clear the pending interrupt. */ (void) inb(wdc->sc_iobase+wd_status); - if (!wdc->sc_q.b_active) + if ((wdc->sc_flags & WDCF_ACTIVE) == 0) return 0; - - bp = wdc->sc_q.b_forw->b_actf; - wd = wdcd.cd_devs[WDUNIT(bp->b_dev)]; - wdc->sc_timeout = 0; - + + wd = wdc->sc_drives.tqh_first; + bp = wd->sc_q.b_actf; + #ifdef WDDEBUG printf("I%d ", ctrlr); #endif @@ -734,6 +721,9 @@ wdcintr(wdc) wdcstart(wdc); return 1; } + + wdc->sc_flags &= ~WDCF_ACTIVE; + wdc->sc_timeout = 0; /* Have we an error? */ if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) { @@ -755,7 +745,7 @@ wdcintr(wdc) /* Error or error correction? */ if (wdc->sc_status & WDCS_ERR) { - if (++wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (++wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; /* Flag the error. */ @@ -782,9 +772,9 @@ wdcintr(wdc) } /* If we encountered any abnormalities, flag it as a soft error. */ - if (wdc->sc_q.b_errcnt) { + if (wdc->sc_errors) { wderror(wd, bp, "soft error"); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; } /* Ready for the next block, if any. */ @@ -970,7 +960,7 @@ wdcontrol(wd) return 0; } - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; wd->sc_state = OPEN; /* * The rest of the initialization can be done by normal means. @@ -1498,7 +1488,6 @@ wdcrestart(wdc) { int s = splbio(); - wdc->sc_q.b_active = 0; wdcstart(wdc); splx(s); } @@ -1529,7 +1518,7 @@ wdcunwedge(wdc) } wdc->sc_flags |= WDCF_ERROR; - ++wdc->sc_q.b_errcnt; + ++wdc->sc_errors; /* Wake up in a little bit and restart the operation. */ timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME); diff --git a/sys/dev/isa/wd.c b/sys/dev/isa/wd.c index 45cacfe515f2..5f1ed0b8f481 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.77 1994/04/09 03:43:36 mycroft Exp $ + * $Id: wd.c,v 1.78 1994/04/20 07:23:54 mycroft Exp $ */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */ @@ -122,6 +122,7 @@ struct wd_softc { #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 */ + TAILQ_ENTRY(wd_softc) sc_drivechain; struct buf sc_q; struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ struct disklabel sc_label; /* device configuration data */ @@ -133,14 +134,16 @@ struct wdc_softc { struct device sc_dev; struct intrhand sc_ih; - struct buf sc_q; u_char sc_flags; +#define WDCF_ACTIVE 0x00001 /* controller is active */ #define WDCF_SINGLE 0x00004 /* sector at a time mode */ #define WDCF_ERROR 0x00008 /* processing a disk error */ 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 */ + int sc_errors; /* count of errors during current transfer */ + TAILQ_HEAD(drivehead, wd_softc) sc_drives; }; int wdcprobe(), wdprobe(), wdcintr(); @@ -254,6 +257,7 @@ wdcattach(parent, self, aux) for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++) (void)config_found(self, &wa, wdprint); + TAILQ_INIT(&wdc->sc_drives); wdctimeout(wdc); wdc->sc_ih.ih_fun = wdcintr; wdc->sc_ih.ih_arg = wdc; @@ -333,7 +337,6 @@ void wdstrategy(bp) struct buf *bp; { - struct buf *dp; struct wd_softc *wd; /* disk unit to do the IO */ struct wdc_softc *wdc; int lunit = WDUNIT(bp->b_dev); @@ -371,14 +374,16 @@ wdstrategy(bp) bp->b_cylin = 0; /* Queue transfer on drive, activate drive and controller if idle. */ - dp = &wd->sc_q; s = splbio(); - wddisksort(dp, bp); - if (dp->b_active == 0) + wddisksort(&wd->sc_q, bp); + if (!wd->sc_q.b_active) wdstart(wd); /* Start drive. */ - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_active == 0) - wdcstart(wdc); /* Start controller. */ +#ifdef DIAGNOSTIC + else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) { + printf("wdstrategy: controller inactive\n"); + wdcstart(wdc); + } +#endif splx(s); return; @@ -410,29 +415,16 @@ static void wdstart(wd) struct wd_softc *wd; { - struct buf *dp; - struct wdc_softc *wdc; + struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; + int active = wdc->sc_drives.tqh_first != 0; - dp = &wd->sc_q; - - /* Unit already active? */ - if (dp->b_active) - return; - /* Anything to start? */ - if (dp->b_actf == NULL) - return; - /* Link onto controller queue. */ - dp->b_forw = NULL; - wdc = (void *)wd->sc_dev.dv_parent; - if (wdc->sc_q.b_forw == NULL) - wdc->sc_q.b_forw = dp; - else - wdc->sc_q.b_actl->b_forw = dp; - wdc->sc_q.b_actl = dp; + wd->sc_q.b_active = 1; + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain); - /* Mark the drive unit as busy. */ - dp->b_active = 1; + /* If controller not already active, start it. */ + if (!active) + wdcstart(wdc); } void @@ -446,22 +438,26 @@ wdfinish(wd, bp) dk_busy &= ~(1 << wd->sc_drive); #endif wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 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) { + wd->sc_mskip = 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); + if (wd->sc_drivechain.tqe_next) { + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + if (bp->b_actf) { + TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, + sc_drivechain); + } else + wd->sc_q.b_active = 0; + } } bp->b_resid = wd->sc_bcount; bp->b_flags &= ~B_XXX; @@ -484,42 +480,34 @@ wdcstart(wdc) 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 = wdc->sc_q.b_forw; - if (dp == NULL) { - wdc->sc_q.b_active = 0; + wd = wdc->sc_drives.tqh_first; + if (wd == NULL) return; - } /* Is there a transfer to this drive? If not, deactivate drive. */ - bp = dp->b_actf; + bp = wd->sc_q.b_actf; if (bp == NULL) { - dp->b_active = 0; - wdc->sc_q.b_forw = dp->b_forw; + TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); + wd->sc_q.b_active = 0; goto loop; } - /* Obtain controller and drive information */ - lunit = WDUNIT(bp->b_dev); - wd = wdcd.cd_devs[lunit]; - - if (wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; wdfinish(wd, bp); goto loop; } - - /* Mark controller active and set a timeout. */ - wdc->sc_q.b_active = 1; + + /* Mark the controller active and set a timeout. */ + wdc->sc_flags |= WDCF_ACTIVE; wdc->sc_timeout = 4; /* Do control operations specially. */ @@ -551,7 +539,7 @@ loop: blknum = bp->b_blkno + wd->sc_skip; #ifdef WDDEBUG if (wd->sc_skip == 0) - printf("\nwdcstart %d: %s %d@%d; map ", lunit, + printf("\nwdcstart %s: %s %d@%d; map ", wd->sc_dev.dv_xname, (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, blknum); else @@ -680,7 +668,7 @@ loop: cylin, head, bp->b_un.b_addr, inb(wd->sc_iobase+wd_altsts)); #endif } - + /* If this is a read operation, just go away until it's done. */ if (bp->b_flags & B_READ) return; @@ -712,13 +700,12 @@ wdcintr(wdc) /* Clear the pending interrupt. */ (void) inb(wdc->sc_iobase+wd_status); - if (!wdc->sc_q.b_active) + if ((wdc->sc_flags & WDCF_ACTIVE) == 0) return 0; - - bp = wdc->sc_q.b_forw->b_actf; - wd = wdcd.cd_devs[WDUNIT(bp->b_dev)]; - wdc->sc_timeout = 0; - + + wd = wdc->sc_drives.tqh_first; + bp = wd->sc_q.b_actf; + #ifdef WDDEBUG printf("I%d ", ctrlr); #endif @@ -734,6 +721,9 @@ wdcintr(wdc) wdcstart(wdc); return 1; } + + wdc->sc_flags &= ~WDCF_ACTIVE; + wdc->sc_timeout = 0; /* Have we an error? */ if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) { @@ -755,7 +745,7 @@ wdcintr(wdc) /* Error or error correction? */ if (wdc->sc_status & WDCS_ERR) { - if (++wdc->sc_q.b_errcnt >= WDIORETRIES) { + if (++wdc->sc_errors >= WDIORETRIES) { wderror(wd, bp, "hard error"); bp->b_error = EIO; bp->b_flags |= B_ERROR; /* Flag the error. */ @@ -782,9 +772,9 @@ wdcintr(wdc) } /* If we encountered any abnormalities, flag it as a soft error. */ - if (wdc->sc_q.b_errcnt) { + if (wdc->sc_errors) { wderror(wd, bp, "soft error"); - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; } /* Ready for the next block, if any. */ @@ -970,7 +960,7 @@ wdcontrol(wd) return 0; } - wdc->sc_q.b_errcnt = 0; + wdc->sc_errors = 0; wd->sc_state = OPEN; /* * The rest of the initialization can be done by normal means. @@ -1498,7 +1488,6 @@ wdcrestart(wdc) { int s = splbio(); - wdc->sc_q.b_active = 0; wdcstart(wdc); splx(s); } @@ -1529,7 +1518,7 @@ wdcunwedge(wdc) } wdc->sc_flags |= WDCF_ERROR; - ++wdc->sc_q.b_errcnt; + ++wdc->sc_errors; /* Wake up in a little bit and restart the operation. */ timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);