Update the wd.c driver to use the new TAILQ scheme for device

buffer queue.  Also, create a new subroutine 'tqdisksort' that
is an improved version of the original disksort that also uses
TAILQs.
This commit is contained in:
dyson 1995-11-23 07:24:41 +00:00
parent 262d148036
commit 711711e9f3
4 changed files with 230 additions and 33 deletions

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91 * 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: /* TODO:
@ -245,8 +245,20 @@ struct disk {
static int wdtest = 0; static int wdtest = 0;
static struct disk *wddrives[NWD]; /* table of units */ 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 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 #ifdef notyet
static struct buf rwdbuf[NWD]; /* buffers for raw IO */ static struct buf rwdbuf[NWD]; /* buffers for raw IO */
#endif #endif
@ -399,6 +411,7 @@ wdattach(struct isa_device *dvp)
return (0); return (0);
kdc_wdc[dvp->id_unit].kdc_state = DC_UNKNOWN; /* XXX */ 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++) { for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) {
if (wdup->id_iobase != dvp->id_iobase) if (wdup->id_iobase != dvp->id_iobase)
@ -406,6 +419,7 @@ wdattach(struct isa_device *dvp)
lunit = wdup->id_unit; lunit = wdup->id_unit;
if (lunit >= NWD) if (lunit >= NWD)
continue; continue;
unit = wdup->id_physid; unit = wdup->id_physid;
du = malloc(sizeof *du, M_TEMP, M_NOWAIT); du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
@ -414,6 +428,7 @@ wdattach(struct isa_device *dvp)
if (wddrives[lunit] != NULL) if (wddrives[lunit] != NULL)
panic("drive attached twice"); panic("drive attached twice");
wddrives[lunit] = du; wddrives[lunit] = du;
TAILQ_INIT( &drive_queue[lunit]);
bzero(du, sizeof *du); bzero(du, sizeof *du);
du->dk_ctrlr = dvp->id_unit; du->dk_ctrlr = dvp->id_unit;
du->dk_unit = unit; du->dk_unit = unit;
@ -567,12 +582,11 @@ wdstrategy(register struct buf *bp)
} }
/* queue transfer on drive, activate drive and controller if idle */ /* queue transfer on drive, activate drive and controller if idle */
dp = &wdutab[lunit];
s = splbio(); 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 */ wdustart(du); /* start drive */
/* Pick up changes made by readdisklabel(). */ /* Pick up changes made by readdisklabel(). */
@ -628,30 +642,25 @@ wdstrategy1(struct buf *bp)
static void static void
wdustart(register struct disk *du) wdustart(register struct disk *du)
{ {
register struct buf *bp, *dp = &wdutab[du->dk_lunit]; register struct buf *bp;
int ctrlr = du->dk_ctrlr; int ctrlr = du->dk_ctrlr;
/* unit already active? */ /* unit already active? */
if (dp->b_active) if (wdutab[du->dk_lunit].b_active)
return; return;
/* anything to start? */
bp = dp->b_actf;
if (bp == NULL)
return;
dp->b_actf = bp->b_actf; bp = drive_queue[du->dk_lunit].tqh_first;
bp->b_actf = NULL; if (bp == NULL) { /* yes, an assign */
/* link onto controller queue */ return;
if (wdtab[ctrlr].b_actf == NULL) {
wdtab[ctrlr].b_actf = bp;
} else {
*wdtab[ctrlr].b_actb = bp;
} }
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 */ /* 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 #endif
loop: loop:
/* is there a drive for the controller to do a transfer with? */ /* 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) { if (bp == NULL) {
#ifdef ATAPI #ifdef ATAPI
if (atapi_start && atapi_start (ctrlr)) if (atapi_start && atapi_start (ctrlr))
@ -928,9 +937,8 @@ wdintr(int unit)
return; return;
} }
#endif #endif
bp = wdtab[unit].b_actf; bp = wdtab[unit].controller_queue.tqh_first;
du = wddrives[dkunit(bp->b_dev)]; du = wddrives[dkunit(bp->b_dev)];
dp = &wdutab[du->dk_lunit];
du->dk_timeout = 0; du->dk_timeout = 0;
if (wdwait(du, 0, TIMEOUT) < 0) { if (wdwait(du, 0, TIMEOUT) < 0) {
@ -1070,11 +1078,11 @@ outt:
done: ; done: ;
/* done with this transfer, with or without error */ /* done with this transfer, with or without error */
du->dk_flags &= ~DKFL_SINGLE; 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; wdtab[unit].b_errcnt = 0;
bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE; bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
dp->b_active = 0; wdutab[du->dk_lunit].b_active = 0;
dp->b_errcnt = 0; wdutab[du->dk_lunit].b_errcnt = 0;
du->dk_skip = 0; du->dk_skip = 0;
biodone(bp); biodone(bp);
} }
@ -1091,7 +1099,7 @@ done: ;
/* anything more for controller to do? */ /* anything more for controller to do? */
#ifndef ATAPI #ifndef ATAPI
/* This is not valid in ATAPI mode. */ /* This is not valid in ATAPI mode. */
if (wdtab[unit].b_actf) if (wdtab[unit].controller_queue.tqh_first)
#endif #endif
wdstart(unit); wdstart(unit);
} }
@ -1129,7 +1137,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
wdsleep(du->dk_ctrlr, "wdopn1"); wdsleep(du->dk_ctrlr, "wdopn1");
du->dk_flags |= DKFL_LABELLING; du->dk_flags |= DKFL_LABELLING;
du->dk_state = WANTOPEN; du->dk_state = WANTOPEN;
wdutab[lunit].b_actf = NULL; /* drive_queue[lunit].b_actf = NULL; */
{ {
struct disklabel label; 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) { if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
/* /*
* wdtab[ctrlr].b_active != 0 implies * 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). * so the following guards most things (until the next i/o).
* It doesn't guard against a new i/o starting and being * It doesn't guard against a new i/o starting and being
* affected by the label being changed. Sigh. * 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_flags |= DKFL_LABELLING;
du->dk_state = WANTOPEN; du->dk_state = WANTOPEN;
wdutab[lunit].b_actf = NULL; /* drive_queue[lunit].b_actf = NULL; */
error = dsinit(dkmodpart(dev, RAW_PART), wdstrategy, error = dsinit(dkmodpart(dev, RAW_PART), wdstrategy,
&du->dk_dd, &du->dk_slices); &du->dk_dd, &du->dk_slices);
@ -1962,8 +1970,10 @@ wdreset(struct disk *du)
static void static void
wdsleep(int ctrlr, char *wmesg) wdsleep(int ctrlr, char *wmesg)
{ {
int s = splbio();
while (wdtab[ctrlr].b_active) while (wdtab[ctrlr].b_active)
tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1); tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
splx(s);
} }
static void static void

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 * @(#)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 <sys/param.h> #include <sys/param.h>
@ -68,6 +68,99 @@
*/ */
#define b_cylinder b_resid #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 void
disksort(ap, bp) disksort(ap, bp)
register struct buf *ap, *bp; register struct buf *ap, *bp;

View File

@ -41,7 +41,7 @@
* *
* @(#)disk.h 8.1 (Berkeley) 6/2/93 * @(#)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_ #ifndef _SYS_DISK_H_
@ -108,6 +108,7 @@ struct disksort_stats {
#ifdef KERNEL #ifdef KERNEL
void disksort __P((struct buf *, struct buf *)); void disksort __P((struct buf *, struct buf *));
void tqdisksort __P((struct buf_queue_head *, struct buf *));
char *readdisklabel __P((struct dkdevice *, int)); char *readdisklabel __P((struct dkdevice *, int));
int setdisklabel __P((struct dkdevice *, struct disklabel *)); int setdisklabel __P((struct dkdevice *, struct disklabel *));
int writedisklabel __P((struct dkdevice *, int)); int writedisklabel __P((struct dkdevice *, int));

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 * @(#)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 <sys/param.h> #include <sys/param.h>
@ -68,6 +68,99 @@
*/ */
#define b_cylinder b_resid #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 void
disksort(ap, bp) disksort(ap, bp)
register struct buf *ap, *bp; register struct buf *ap, *bp;