diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 9416bc774cc2..49ab5ce81bf1 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.90 1995/10/29 17:34:17 bde Exp $ + * $Id: wd.c,v 1.91 1995/11/20 12:41:53 phk Exp $ */ /* TODO: @@ -245,8 +245,20 @@ struct disk { static int wdtest = 0; static struct disk *wddrives[NWD]; /* table of units */ +static struct buf_queue_head drive_queue[NWD]; /* head of queue per drive */ +static struct { + int b_errcnt; + int b_active; +} wdutab[NWD]; +/* static struct buf wdtab[NWDC]; -static struct buf wdutab[NWD]; /* head of queue per drive */ +*/ +static struct { + struct buf_queue_head controller_queue; + int b_errcnt; + int b_active; +} wdtab[NWDC]; + #ifdef notyet static struct buf rwdbuf[NWD]; /* buffers for raw IO */ #endif @@ -399,6 +411,7 @@ wdattach(struct isa_device *dvp) return (0); kdc_wdc[dvp->id_unit].kdc_state = DC_UNKNOWN; /* XXX */ + TAILQ_INIT( &wdtab[dvp->id_unit].controller_queue); for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) { if (wdup->id_iobase != dvp->id_iobase) @@ -406,6 +419,7 @@ wdattach(struct isa_device *dvp) lunit = wdup->id_unit; if (lunit >= NWD) continue; + unit = wdup->id_physid; du = malloc(sizeof *du, M_TEMP, M_NOWAIT); @@ -414,6 +428,7 @@ wdattach(struct isa_device *dvp) if (wddrives[lunit] != NULL) panic("drive attached twice"); wddrives[lunit] = du; + TAILQ_INIT( &drive_queue[lunit]); bzero(du, sizeof *du); du->dk_ctrlr = dvp->id_unit; du->dk_unit = unit; @@ -567,12 +582,11 @@ wdstrategy(register struct buf *bp) } /* queue transfer on drive, activate drive and controller if idle */ - dp = &wdutab[lunit]; s = splbio(); - disksort(dp, bp); + tqdisksort(&drive_queue[lunit], bp); - if (dp->b_active == 0) + if (wdutab[lunit].b_active == 0) wdustart(du); /* start drive */ /* Pick up changes made by readdisklabel(). */ @@ -628,30 +642,25 @@ wdstrategy1(struct buf *bp) static void wdustart(register struct disk *du) { - register struct buf *bp, *dp = &wdutab[du->dk_lunit]; + register struct buf *bp; int ctrlr = du->dk_ctrlr; /* unit already active? */ - if (dp->b_active) + if (wdutab[du->dk_lunit].b_active) return; - /* anything to start? */ - bp = dp->b_actf; - if (bp == NULL) - return; - dp->b_actf = bp->b_actf; - bp->b_actf = NULL; - /* link onto controller queue */ - if (wdtab[ctrlr].b_actf == NULL) { - wdtab[ctrlr].b_actf = bp; - } else { - *wdtab[ctrlr].b_actb = bp; + bp = drive_queue[du->dk_lunit].tqh_first; + if (bp == NULL) { /* yes, an assign */ + return; } - wdtab[ctrlr].b_actb = &bp->b_actf; + TAILQ_REMOVE( &drive_queue[du->dk_lunit], bp, b_act); + + /* link onto controller queue */ + TAILQ_INSERT_TAIL( &wdtab[ctrlr].controller_queue, bp, b_act); /* mark the drive unit as busy */ - dp->b_active = 1; + wdutab[du->dk_lunit].b_active = 1; } /* @@ -682,7 +691,7 @@ wdstart(int ctrlr) #endif loop: /* is there a drive for the controller to do a transfer with? */ - bp = wdtab[ctrlr].b_actf; + bp = wdtab[ctrlr].controller_queue.tqh_first; if (bp == NULL) { #ifdef ATAPI if (atapi_start && atapi_start (ctrlr)) @@ -928,9 +937,8 @@ wdintr(int unit) return; } #endif - bp = wdtab[unit].b_actf; + bp = wdtab[unit].controller_queue.tqh_first; du = wddrives[dkunit(bp->b_dev)]; - dp = &wdutab[du->dk_lunit]; du->dk_timeout = 0; if (wdwait(du, 0, TIMEOUT) < 0) { @@ -1070,11 +1078,11 @@ outt: done: ; /* done with this transfer, with or without error */ du->dk_flags &= ~DKFL_SINGLE; - wdtab[unit].b_actf = bp->b_actf; + TAILQ_REMOVE(&wdtab[unit].controller_queue, bp, b_act); wdtab[unit].b_errcnt = 0; bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE; - dp->b_active = 0; - dp->b_errcnt = 0; + wdutab[du->dk_lunit].b_active = 0; + wdutab[du->dk_lunit].b_errcnt = 0; du->dk_skip = 0; biodone(bp); } @@ -1091,7 +1099,7 @@ done: ; /* anything more for controller to do? */ #ifndef ATAPI /* This is not valid in ATAPI mode. */ - if (wdtab[unit].b_actf) + if (wdtab[unit].controller_queue.tqh_first) #endif wdstart(unit); } @@ -1129,7 +1137,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p) wdsleep(du->dk_ctrlr, "wdopn1"); du->dk_flags |= DKFL_LABELLING; du->dk_state = WANTOPEN; - wdutab[lunit].b_actf = NULL; + /* drive_queue[lunit].b_actf = NULL; */ { struct disklabel label; @@ -1150,7 +1158,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p) if ((du->dk_flags & DKFL_BSDLABEL) == 0) { /* * wdtab[ctrlr].b_active != 0 implies - * wdutab[lunit].b_actf == NULL (?) + * drive_queue[lunit].b_actf == NULL (?) * so the following guards most things (until the next i/o). * It doesn't guard against a new i/o starting and being * affected by the label being changed. Sigh. @@ -1159,7 +1167,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p) du->dk_flags |= DKFL_LABELLING; du->dk_state = WANTOPEN; - wdutab[lunit].b_actf = NULL; + /* drive_queue[lunit].b_actf = NULL; */ error = dsinit(dkmodpart(dev, RAW_PART), wdstrategy, &du->dk_dd, &du->dk_slices); @@ -1962,8 +1970,10 @@ wdreset(struct disk *du) static void wdsleep(int ctrlr, char *wmesg) { + int s = splbio(); while (wdtab[ctrlr].b_active) tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1); + splx(s); } static void diff --git a/sys/kern/subr_disklabel.c b/sys/kern/subr_disklabel.c index be8e81a06507..3598a690f3d4 100644 --- a/sys/kern/subr_disklabel.c +++ b/sys/kern/subr_disklabel.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 - * $Id: ufs_disksubr.c,v 1.18 1995/08/28 16:09:11 bde Exp $ + * $Id: ufs_disksubr.c,v 1.19 1995/09/16 17:04:06 bde Exp $ */ #include @@ -68,6 +68,99 @@ */ #define b_cylinder b_resid +void +tqdisksort(ap, bp) + struct buf_queue_head *ap; + register struct buf *bp; +{ + register struct buf *bq; + struct buf *bn; + + /* If the queue is empty, then it's easy. */ + if ((bq = ap->tqh_first) == NULL) { + TAILQ_INSERT_HEAD(ap, bp, b_act); + return; + } + +#if 1 + /* Put new writes after all reads */ + if ((bp->b_flags & B_READ) == 0) { + while (bn = bq->b_act.tqe_next) { + if ((bq->b_flags & B_READ) == 0) + break; + bq = bn; + } + } else { + while (bn = bq->b_act.tqe_next) { + if ((bq->b_flags & B_READ) == 0) { + if (ap->tqh_first != bq) { + bq = *bq->b_act.tqe_prev; + } + break; + } + bq = bn; + } + goto insert; + } +#endif + + /* + * If we lie after the first (currently active) request, then we + * must locate the second request list and add ourselves to it. + */ + if (bp->b_pblkno < bq->b_pblkno) { + while (bn = bq->b_act.tqe_next) { + /* + * Check for an ``inversion'' in the normally ascending + * cylinder numbers, indicating the start of the second + * request list. + */ + if (bn->b_pblkno < bq->b_pblkno) { + /* + * Search the second request list for the first + * request at a larger cylinder number. We go + * before that; if there is no such request, we + * go at end. + */ + do { + if (bp->b_pblkno < bn->b_pblkno) + goto insert; + bq = bn; + } while (bn = bq->b_act.tqe_next); + goto insert; /* after last */ + } + bq = bn; + } + /* + * No inversions... we will go after the last, and + * be the first request in the second request list. + */ + goto insert; + } + /* + * Request is at/after the current request... + * sort in the first request list. + */ + while (bn = bq->b_act.tqe_next) { + /* + * We want to go after the current request if there is an + * inversion after it (i.e. it is the end of the first + * request list), or if the next request is a larger cylinder + * than our request. + */ + if (bn->b_pblkno < bq->b_pblkno || + bp->b_pblkno < bn->b_pblkno) + goto insert; + bq = bn; + } + /* + * Neither a second list nor a larger request... we go at the end of + * the first list, which is the same as the end of the whole schebang. + */ +insert: + TAILQ_INSERT_AFTER(ap, bq, bp, b_act); +} + void disksort(ap, bp) register struct buf *ap, *bp; diff --git a/sys/sys/disk.h b/sys/sys/disk.h index c90eca5b0d32..04d7d1c1b3c4 100644 --- a/sys/sys/disk.h +++ b/sys/sys/disk.h @@ -41,7 +41,7 @@ * * @(#)disk.h 8.1 (Berkeley) 6/2/93 * - * $Id: disk.h,v 1.2 1994/08/02 07:52:48 davidg Exp $ + * $Id: disk.h,v 1.3 1994/08/21 04:41:39 paul Exp $ */ #ifndef _SYS_DISK_H_ @@ -108,6 +108,7 @@ struct disksort_stats { #ifdef KERNEL void disksort __P((struct buf *, struct buf *)); +void tqdisksort __P((struct buf_queue_head *, struct buf *)); char *readdisklabel __P((struct dkdevice *, int)); int setdisklabel __P((struct dkdevice *, struct disklabel *)); int writedisklabel __P((struct dkdevice *, int)); diff --git a/sys/ufs/ufs/ufs_disksubr.c b/sys/ufs/ufs/ufs_disksubr.c index be8e81a06507..3598a690f3d4 100644 --- a/sys/ufs/ufs/ufs_disksubr.c +++ b/sys/ufs/ufs/ufs_disksubr.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 - * $Id: ufs_disksubr.c,v 1.18 1995/08/28 16:09:11 bde Exp $ + * $Id: ufs_disksubr.c,v 1.19 1995/09/16 17:04:06 bde Exp $ */ #include @@ -68,6 +68,99 @@ */ #define b_cylinder b_resid +void +tqdisksort(ap, bp) + struct buf_queue_head *ap; + register struct buf *bp; +{ + register struct buf *bq; + struct buf *bn; + + /* If the queue is empty, then it's easy. */ + if ((bq = ap->tqh_first) == NULL) { + TAILQ_INSERT_HEAD(ap, bp, b_act); + return; + } + +#if 1 + /* Put new writes after all reads */ + if ((bp->b_flags & B_READ) == 0) { + while (bn = bq->b_act.tqe_next) { + if ((bq->b_flags & B_READ) == 0) + break; + bq = bn; + } + } else { + while (bn = bq->b_act.tqe_next) { + if ((bq->b_flags & B_READ) == 0) { + if (ap->tqh_first != bq) { + bq = *bq->b_act.tqe_prev; + } + break; + } + bq = bn; + } + goto insert; + } +#endif + + /* + * If we lie after the first (currently active) request, then we + * must locate the second request list and add ourselves to it. + */ + if (bp->b_pblkno < bq->b_pblkno) { + while (bn = bq->b_act.tqe_next) { + /* + * Check for an ``inversion'' in the normally ascending + * cylinder numbers, indicating the start of the second + * request list. + */ + if (bn->b_pblkno < bq->b_pblkno) { + /* + * Search the second request list for the first + * request at a larger cylinder number. We go + * before that; if there is no such request, we + * go at end. + */ + do { + if (bp->b_pblkno < bn->b_pblkno) + goto insert; + bq = bn; + } while (bn = bq->b_act.tqe_next); + goto insert; /* after last */ + } + bq = bn; + } + /* + * No inversions... we will go after the last, and + * be the first request in the second request list. + */ + goto insert; + } + /* + * Request is at/after the current request... + * sort in the first request list. + */ + while (bn = bq->b_act.tqe_next) { + /* + * We want to go after the current request if there is an + * inversion after it (i.e. it is the end of the first + * request list), or if the next request is a larger cylinder + * than our request. + */ + if (bn->b_pblkno < bq->b_pblkno || + bp->b_pblkno < bn->b_pblkno) + goto insert; + bq = bn; + } + /* + * Neither a second list nor a larger request... we go at the end of + * the first list, which is the same as the end of the whole schebang. + */ +insert: + TAILQ_INSERT_AFTER(ap, bq, bp, b_act); +} + void disksort(ap, bp) register struct buf *ap, *bp;