summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/i386/isa/wd.c68
-rw-r--r--sys/kern/subr_disklabel.c95
-rw-r--r--sys/sys/disk.h3
-rw-r--r--sys/ufs/ufs/ufs_disksubr.c95
4 files changed, 229 insertions, 32 deletions
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
index 9416bc7..49ab5ce 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)
+
+ bp = drive_queue[du->dk_lunit].tqh_first;
+ if (bp == NULL) { /* yes, an assign */
return;
+ }
+ TAILQ_REMOVE( &drive_queue[du->dk_lunit], bp, b_act);
- 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;
- }
- wdtab[ctrlr].b_actb = &bp->b_actf;
+ 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 be8e81a..3598a69 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 <sys/param.h>
@@ -69,6 +69,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 c90eca5..04d7d1c 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 be8e81a..3598a69 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 <sys/param.h>
@@ -69,6 +69,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;
{
OpenPOWER on IntegriCloud