mirror of
https://github.com/freebsd/freebsd-src
synced 2024-11-05 18:22:52 +00:00
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:
parent
09a67ffa0e
commit
dc4a0cee58
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=12460
4 changed files with 230 additions and 33 deletions
|
@ -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 @@ wdintr(int unit)
|
|||
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
|
||||
|
|
|
@ -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 <sys/param.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 <sys/param.h>
|
||||
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue