Use TAILQ_*() to maintain the drive activation queues.

This commit is contained in:
mycroft 1994-04-20 07:23:52 +00:00
parent 1ffc6c23e3
commit 893be926ec
4 changed files with 246 additions and 268 deletions

View File

@ -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 <sys/param.h>
@ -52,6 +52,7 @@
#include <sys/buf.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <machine/cpu.h>
#include <machine/pio.h>
@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);