Use TAILQ_*() to maintain the drive activation queues.
This commit is contained in:
parent
1ffc6c23e3
commit
893be926ec
@ -35,7 +35,7 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
|
* 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>
|
#include <sys/param.h>
|
||||||
@ -52,6 +52,7 @@
|
|||||||
#include <sys/buf.h>
|
#include <sys/buf.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include <machine/cpu.h>
|
#include <machine/cpu.h>
|
||||||
#include <machine/pio.h>
|
#include <machine/pio.h>
|
||||||
@ -102,8 +103,7 @@ struct fdc_softc {
|
|||||||
u_short sc_drq;
|
u_short sc_drq;
|
||||||
|
|
||||||
struct fd_softc *sc_fd[4]; /* pointers to children */
|
struct fd_softc *sc_fd[4]; /* pointers to children */
|
||||||
struct fd_softc *sc_afd; /* active drive */
|
TAILQ_HEAD(drivehead, fd_softc) sc_drives;
|
||||||
struct buf sc_q;
|
|
||||||
enum fdc_state sc_state;
|
enum fdc_state sc_state;
|
||||||
int sc_retry; /* number of retries so far */
|
int sc_retry; /* number of retries so far */
|
||||||
u_char sc_status[7]; /* copy of registers */
|
u_char sc_status[7]; /* copy of registers */
|
||||||
@ -159,6 +159,7 @@ struct fd_softc {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct fd_type *sc_deftype; /* default type descriptor */
|
struct fd_type *sc_deftype; /* default type descriptor */
|
||||||
|
TAILQ_ENTRY(fd_softc) sc_drivechain;
|
||||||
struct buf sc_q; /* head of buf chain */
|
struct buf sc_q; /* head of buf chain */
|
||||||
int sc_drive; /* unit number on this controller */
|
int sc_drive; /* unit number on this controller */
|
||||||
int sc_flags;
|
int sc_flags;
|
||||||
@ -186,6 +187,7 @@ struct dkdriver fddkdriver = { fdstrategy };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct fd_type *fd_nvtotype __P((char *, int, int));
|
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_set_motor __P((struct fdc_softc *fdc, int reset));
|
||||||
void fd_motor_off __P((struct fd_softc *fd));
|
void fd_motor_off __P((struct fd_softc *fd));
|
||||||
void fd_motor_on __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));
|
void fdcpseudointr __P((struct fdc_softc *fdc));
|
||||||
int fdcintr __P((struct fdc_softc *fdc));
|
int fdcintr __P((struct fdc_softc *fdc));
|
||||||
void fdcretry __P((struct fdc_softc *fdc));
|
void fdcretry __P((struct fdc_softc *fdc));
|
||||||
|
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
|
||||||
|
|
||||||
int
|
int
|
||||||
fdcprobe(parent, self, aux)
|
fdcprobe(parent, self, aux)
|
||||||
@ -294,6 +297,8 @@ fdcattach(parent, self, aux)
|
|||||||
fdc->sc_iobase = ia->ia_iobase;
|
fdc->sc_iobase = ia->ia_iobase;
|
||||||
fdc->sc_drq = ia->ia_drq;
|
fdc->sc_drq = ia->ia_drq;
|
||||||
fdc->sc_state = DEVIDLE;
|
fdc->sc_state = DEVIDLE;
|
||||||
|
TAILQ_INIT(&fdc->sc_drives);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
#ifdef NEWCONFIG
|
#ifdef NEWCONFIG
|
||||||
@ -512,28 +517,13 @@ fdstrategy(bp)
|
|||||||
bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, nblks);
|
bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, nblks);
|
||||||
#endif
|
#endif
|
||||||
s = splbio();
|
s = splbio();
|
||||||
dp = &fd->sc_q;
|
disksort(&fd->sc_q, bp);
|
||||||
disksort(dp, bp);
|
|
||||||
untimeout((timeout_t)fd_motor_off, (caddr_t)fd); /* a good idea */
|
untimeout((timeout_t)fd_motor_off, (caddr_t)fd); /* a good idea */
|
||||||
if (!dp->b_active) {
|
if (!fd->sc_q.b_active)
|
||||||
register struct buf *cp;
|
fdstart(fd);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
else if (!fdc->sc_q.b_active) {
|
else if (fdc->sc_state == DEVIDLE) {
|
||||||
printf("fdstrategy: controller inactive\n");
|
printf("fdstrategy: controller inactive\n");
|
||||||
fdc->sc_q.b_active = 1;
|
|
||||||
fdcstart(fdc);
|
fdcstart(fdc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -544,6 +534,22 @@ fdstrategy(bp)
|
|||||||
biodone(bp);
|
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
|
void
|
||||||
fd_set_motor(fdc, reset)
|
fd_set_motor(fdc, reset)
|
||||||
struct fdc_softc *fdc;
|
struct fdc_softc *fdc;
|
||||||
@ -553,7 +559,7 @@ fd_set_motor(fdc, reset)
|
|||||||
u_char status;
|
u_char status;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if (fd = fdc->sc_afd)
|
if (fd = fdc->sc_drives.tqh_first)
|
||||||
status = fd->sc_drive;
|
status = fd->sc_drive;
|
||||||
else
|
else
|
||||||
status = 0;
|
status = 0;
|
||||||
@ -584,7 +590,7 @@ fd_motor_on(fd)
|
|||||||
int s = splbio();
|
int s = splbio();
|
||||||
|
|
||||||
fd->sc_flags &= ~FD_MOTOR_WAIT;
|
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);
|
(void) fdcintr(fdc);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
@ -718,17 +724,17 @@ void
|
|||||||
fdctimeout(fdc)
|
fdctimeout(fdc)
|
||||||
struct fdc_softc *fdc;
|
struct fdc_softc *fdc;
|
||||||
{
|
{
|
||||||
struct fd_softc *fd = fdc->sc_afd;
|
struct fd_softc *fd;
|
||||||
int s = splbio();
|
int s = splbio();
|
||||||
|
|
||||||
|
fd = fdc->sc_drives.tqh_first;
|
||||||
|
|
||||||
fdcstatus(&fd->sc_dev, 0, "timeout");
|
fdcstatus(&fd->sc_dev, 0, "timeout");
|
||||||
|
|
||||||
if (fd->sc_q.b_actf) {
|
if (fd->sc_q.b_actf)
|
||||||
fdc->sc_state++;
|
fdc->sc_state++;
|
||||||
} else {
|
else
|
||||||
fdc->sc_afd = NULL;
|
|
||||||
fdc->sc_state = DEVIDLE;
|
fdc->sc_state = DEVIDLE;
|
||||||
}
|
|
||||||
|
|
||||||
(void) fdcintr(fdc);
|
(void) fdcintr(fdc);
|
||||||
splx(s);
|
splx(s);
|
||||||
@ -752,43 +758,29 @@ fdcintr(fdc)
|
|||||||
#define st0 fdc->sc_status[0]
|
#define st0 fdc->sc_status[0]
|
||||||
#define cyl fdc->sc_status[1]
|
#define cyl fdc->sc_status[1]
|
||||||
struct fd_softc *fd;
|
struct fd_softc *fd;
|
||||||
struct buf *dp, *bp;
|
struct buf *bp;
|
||||||
u_short iobase = fdc->sc_iobase;
|
u_short iobase = fdc->sc_iobase;
|
||||||
int read, head, trac, sec, i, s, sectrac, blkno, nblks;
|
int read, head, trac, sec, i, s, sectrac, blkno, nblks;
|
||||||
struct fd_type *type;
|
struct fd_type *type;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
dp = fdc->sc_q.b_forw;
|
fd = fdc->sc_drives.tqh_first;
|
||||||
if (!dp) {
|
if (!fd) {
|
||||||
/* no drives waiting; end */
|
/* no drives waiting; end */
|
||||||
fdc->sc_state = DEVIDLE;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
bp = dp->b_actf;
|
bp = fd->sc_q.b_actf;
|
||||||
if (!bp) {
|
if (!bp) {
|
||||||
/* nothing queued on this drive; try next */
|
/* nothing queued on this drive; try next */
|
||||||
fdc->sc_q.b_forw = dp->b_forw;
|
TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
|
||||||
dp->b_active = 0;
|
fd->sc_q.b_active = 0;
|
||||||
goto again;
|
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) {
|
switch (fdc->sc_state) {
|
||||||
case DEVIDLE:
|
case DEVIDLE:
|
||||||
fdc->sc_retry = 0;
|
fdc->sc_retry = 0;
|
||||||
fdc->sc_afd = fd;
|
|
||||||
fd->sc_skip = 0;
|
fd->sc_skip = 0;
|
||||||
fd->sc_blkno = bp->b_blkno * DEV_BSIZE / FDC_BSIZE;
|
fd->sc_blkno = bp->b_blkno * DEV_BSIZE / FDC_BSIZE;
|
||||||
untimeout((timeout_t)fd_motor_off, (caddr_t)fd);
|
untimeout((timeout_t)fd_motor_off, (caddr_t)fd);
|
||||||
@ -954,14 +946,7 @@ again:
|
|||||||
bp->b_cylin = (blkno / (type->sectrac * type->heads)) * type->step;
|
bp->b_cylin = (blkno / (type->sectrac * type->heads)) * type->step;
|
||||||
goto doseek;
|
goto doseek;
|
||||||
} else {
|
} else {
|
||||||
bp->b_resid = 0;
|
fdfinish(fd, bp);
|
||||||
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;
|
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,9 +1012,10 @@ void
|
|||||||
fdcretry(fdc)
|
fdcretry(fdc)
|
||||||
struct fdc_softc *fdc;
|
struct fdc_softc *fdc;
|
||||||
{
|
{
|
||||||
register struct buf *bp;
|
struct fd_softc *fd;
|
||||||
struct fd_softc *fd = fdc->sc_afd;
|
struct buf *bp;
|
||||||
|
|
||||||
|
fd = fdc->sc_drives.tqh_first;
|
||||||
bp = fd->sc_q.b_actf;
|
bp = fd->sc_q.b_actf;
|
||||||
|
|
||||||
switch (fdc->sc_retry) {
|
switch (fdc->sc_retry) {
|
||||||
@ -1049,8 +1035,6 @@ fdcretry(fdc)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fd = fdc->sc_afd;
|
|
||||||
|
|
||||||
diskerr(bp, "fd", "hard error", LOG_PRINTF,
|
diskerr(bp, "fd", "hard error", LOG_PRINTF,
|
||||||
fd->sc_skip, (struct disklabel *)NULL);
|
fd->sc_skip, (struct disklabel *)NULL);
|
||||||
printf(" (st0 %b ", fdc->sc_status[0], NE7_ST0BITS);
|
printf(" (st0 %b ", fdc->sc_status[0], NE7_ST0BITS);
|
||||||
@ -1061,17 +1045,44 @@ fdcretry(fdc)
|
|||||||
|
|
||||||
bp->b_flags |= B_ERROR;
|
bp->b_flags |= B_ERROR;
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
|
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;
|
bp->b_resid = bp->b_bcount - fd->sc_skip;
|
||||||
|
fd->sc_skip = 0;
|
||||||
fd->sc_q.b_actf = bp->b_actf;
|
fd->sc_q.b_actf = bp->b_actf;
|
||||||
biodone(bp);
|
biodone(bp);
|
||||||
/* turn off motor 5s from now */
|
/* turn off motor 5s from now */
|
||||||
timeout((timeout_t)fd_motor_off, (caddr_t)fd, hz*5);
|
timeout((timeout_t)fd_motor_off, (caddr_t)fd, hz*5);
|
||||||
fd->sc_skip = 0;
|
|
||||||
fdc->sc_afd = NULL;
|
|
||||||
fdc->sc_state = DEVIDLE;
|
fdc->sc_state = DEVIDLE;
|
||||||
}
|
}
|
||||||
fdc->sc_retry++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
fdioctl(dev, cmd, addr, flag)
|
fdioctl(dev, cmd, addr, flag)
|
||||||
|
@ -35,7 +35,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.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 */
|
#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_BSDLABEL 0x00010 /* has a BSD disk label */
|
||||||
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
||||||
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
||||||
|
TAILQ_ENTRY(wd_softc) sc_drivechain;
|
||||||
struct buf sc_q;
|
struct buf sc_q;
|
||||||
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
||||||
struct disklabel sc_label; /* device configuration data */
|
struct disklabel sc_label; /* device configuration data */
|
||||||
@ -133,14 +134,16 @@ struct wdc_softc {
|
|||||||
struct device sc_dev;
|
struct device sc_dev;
|
||||||
struct intrhand sc_ih;
|
struct intrhand sc_ih;
|
||||||
|
|
||||||
struct buf sc_q;
|
|
||||||
u_char sc_flags;
|
u_char sc_flags;
|
||||||
|
#define WDCF_ACTIVE 0x00001 /* controller is active */
|
||||||
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
||||||
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
||||||
u_char sc_status; /* copy of status register */
|
u_char sc_status; /* copy of status register */
|
||||||
u_char sc_error; /* copy of error register */
|
u_char sc_error; /* copy of error register */
|
||||||
u_short sc_iobase; /* i/o port base */
|
u_short sc_iobase; /* i/o port base */
|
||||||
int sc_timeout; /* timeout counter */
|
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();
|
int wdcprobe(), wdprobe(), wdcintr();
|
||||||
@ -254,6 +257,7 @@ wdcattach(parent, self, aux)
|
|||||||
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
||||||
(void)config_found(self, &wa, wdprint);
|
(void)config_found(self, &wa, wdprint);
|
||||||
|
|
||||||
|
TAILQ_INIT(&wdc->sc_drives);
|
||||||
wdctimeout(wdc);
|
wdctimeout(wdc);
|
||||||
wdc->sc_ih.ih_fun = wdcintr;
|
wdc->sc_ih.ih_fun = wdcintr;
|
||||||
wdc->sc_ih.ih_arg = wdc;
|
wdc->sc_ih.ih_arg = wdc;
|
||||||
@ -333,7 +337,6 @@ void
|
|||||||
wdstrategy(bp)
|
wdstrategy(bp)
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
|
||||||
struct wd_softc *wd; /* disk unit to do the IO */
|
struct wd_softc *wd; /* disk unit to do the IO */
|
||||||
struct wdc_softc *wdc;
|
struct wdc_softc *wdc;
|
||||||
int lunit = WDUNIT(bp->b_dev);
|
int lunit = WDUNIT(bp->b_dev);
|
||||||
@ -371,14 +374,16 @@ wdstrategy(bp)
|
|||||||
bp->b_cylin = 0;
|
bp->b_cylin = 0;
|
||||||
|
|
||||||
/* Queue transfer on drive, activate drive and controller if idle. */
|
/* Queue transfer on drive, activate drive and controller if idle. */
|
||||||
dp = &wd->sc_q;
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
wddisksort(dp, bp);
|
wddisksort(&wd->sc_q, bp);
|
||||||
if (dp->b_active == 0)
|
if (!wd->sc_q.b_active)
|
||||||
wdstart(wd); /* Start drive. */
|
wdstart(wd); /* Start drive. */
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
#ifdef DIAGNOSTIC
|
||||||
if (wdc->sc_q.b_active == 0)
|
else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
|
||||||
wdcstart(wdc); /* Start controller. */
|
printf("wdstrategy: controller inactive\n");
|
||||||
|
wdcstart(wdc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
splx(s);
|
splx(s);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -410,29 +415,16 @@ static void
|
|||||||
wdstart(wd)
|
wdstart(wd)
|
||||||
struct wd_softc *wd;
|
struct wd_softc *wd;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
|
||||||
struct wdc_softc *wdc;
|
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. */
|
/* Link onto controller queue. */
|
||||||
dp->b_forw = NULL;
|
wd->sc_q.b_active = 1;
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Mark the drive unit as busy. */
|
/* If controller not already active, start it. */
|
||||||
dp->b_active = 1;
|
if (!active)
|
||||||
|
wdcstart(wdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -446,22 +438,26 @@ wdfinish(wd, bp)
|
|||||||
dk_busy &= ~(1 << wd->sc_drive);
|
dk_busy &= ~(1 << wd->sc_drive);
|
||||||
#endif
|
#endif
|
||||||
wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
|
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
|
* If this is the only buf or the last buf in the transfer (taking into
|
||||||
* account any residual, in case we erred)...
|
* account any residual, in case we erred)...
|
||||||
*/
|
*/
|
||||||
wd->sc_mbcount -= wd->sc_bcount;
|
wd->sc_mbcount -= wd->sc_bcount;
|
||||||
if (wd->sc_mbcount == 0) {
|
if (wd->sc_mbcount == 0) {
|
||||||
|
wd->sc_mskip = 0;
|
||||||
/*
|
/*
|
||||||
* ...then move this drive to the end of the queue to give
|
* ...then move this drive to the end of the queue to give
|
||||||
* others a `fair' chance.
|
* others a `fair' chance.
|
||||||
*/
|
*/
|
||||||
wdc->sc_q.b_forw = wd->sc_q.b_forw;
|
if (wd->sc_drivechain.tqe_next) {
|
||||||
wd->sc_mskip = 0;
|
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;
|
wd->sc_q.b_active = 0;
|
||||||
if (wd->sc_q.b_actf)
|
}
|
||||||
wdstart(wd);
|
|
||||||
}
|
}
|
||||||
bp->b_resid = wd->sc_bcount;
|
bp->b_resid = wd->sc_bcount;
|
||||||
bp->b_flags &= ~B_XXX;
|
bp->b_flags &= ~B_XXX;
|
||||||
@ -484,33 +480,25 @@ wdcstart(wdc)
|
|||||||
struct wd_softc *wd; /* disk unit for IO */
|
struct wd_softc *wd; /* disk unit for IO */
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct disklabel *lp;
|
struct disklabel *lp;
|
||||||
struct buf *dp;
|
|
||||||
long blknum, cylin, head, sector;
|
long blknum, cylin, head, sector;
|
||||||
long secpertrk, secpercyl;
|
long secpertrk, secpercyl;
|
||||||
int xfrblknum;
|
int xfrblknum;
|
||||||
int lunit;
|
|
||||||
|
|
||||||
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? */
|
||||||
dp = wdc->sc_q.b_forw;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
if (dp == NULL) {
|
if (wd == NULL)
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a transfer to this drive? If not, deactivate drive. */
|
/* Is there a transfer to this drive? If not, deactivate drive. */
|
||||||
bp = dp->b_actf;
|
bp = wd->sc_q.b_actf;
|
||||||
if (bp == NULL) {
|
if (bp == NULL) {
|
||||||
dp->b_active = 0;
|
TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
wdc->sc_q.b_forw = dp->b_forw;
|
wd->sc_q.b_active = 0;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obtain controller and drive information */
|
if (wdc->sc_errors >= WDIORETRIES) {
|
||||||
lunit = WDUNIT(bp->b_dev);
|
|
||||||
wd = wdcd.cd_devs[lunit];
|
|
||||||
|
|
||||||
if (wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR;
|
bp->b_flags |= B_ERROR;
|
||||||
@ -518,8 +506,8 @@ loop:
|
|||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark controller active and set a timeout. */
|
/* Mark the controller active and set a timeout. */
|
||||||
wdc->sc_q.b_active = 1;
|
wdc->sc_flags |= WDCF_ACTIVE;
|
||||||
wdc->sc_timeout = 4;
|
wdc->sc_timeout = 4;
|
||||||
|
|
||||||
/* Do control operations specially. */
|
/* Do control operations specially. */
|
||||||
@ -551,7 +539,7 @@ loop:
|
|||||||
blknum = bp->b_blkno + wd->sc_skip;
|
blknum = bp->b_blkno + wd->sc_skip;
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
if (wd->sc_skip == 0)
|
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,
|
(bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
|
||||||
blknum);
|
blknum);
|
||||||
else
|
else
|
||||||
@ -712,12 +700,11 @@ wdcintr(wdc)
|
|||||||
/* Clear the pending interrupt. */
|
/* Clear the pending interrupt. */
|
||||||
(void) inb(wdc->sc_iobase+wd_status);
|
(void) inb(wdc->sc_iobase+wd_status);
|
||||||
|
|
||||||
if (!wdc->sc_q.b_active)
|
if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bp = wdc->sc_q.b_forw->b_actf;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
wd = wdcd.cd_devs[WDUNIT(bp->b_dev)];
|
bp = wd->sc_q.b_actf;
|
||||||
wdc->sc_timeout = 0;
|
|
||||||
|
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
printf("I%d ", ctrlr);
|
printf("I%d ", ctrlr);
|
||||||
@ -735,6 +722,9 @@ wdcintr(wdc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wdc->sc_flags &= ~WDCF_ACTIVE;
|
||||||
|
wdc->sc_timeout = 0;
|
||||||
|
|
||||||
/* Have we an error? */
|
/* Have we an error? */
|
||||||
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
||||||
lose:
|
lose:
|
||||||
@ -755,7 +745,7 @@ wdcintr(wdc)
|
|||||||
|
|
||||||
/* Error or error correction? */
|
/* Error or error correction? */
|
||||||
if (wdc->sc_status & WDCS_ERR) {
|
if (wdc->sc_status & WDCS_ERR) {
|
||||||
if (++wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
if (++wdc->sc_errors >= WDIORETRIES) {
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR; /* Flag the error. */
|
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 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");
|
wderror(wd, bp, "soft error");
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ready for the next block, if any. */
|
/* Ready for the next block, if any. */
|
||||||
@ -970,7 +960,7 @@ wdcontrol(wd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
wd->sc_state = OPEN;
|
wd->sc_state = OPEN;
|
||||||
/*
|
/*
|
||||||
* The rest of the initialization can be done by normal means.
|
* The rest of the initialization can be done by normal means.
|
||||||
@ -1498,7 +1488,6 @@ wdcrestart(wdc)
|
|||||||
{
|
{
|
||||||
int s = splbio();
|
int s = splbio();
|
||||||
|
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
wdcstart(wdc);
|
wdcstart(wdc);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
@ -1529,7 +1518,7 @@ wdcunwedge(wdc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_flags |= WDCF_ERROR;
|
wdc->sc_flags |= WDCF_ERROR;
|
||||||
++wdc->sc_q.b_errcnt;
|
++wdc->sc_errors;
|
||||||
|
|
||||||
/* Wake up in a little bit and restart the operation. */
|
/* Wake up in a little bit and restart the operation. */
|
||||||
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
||||||
|
111
sys/dev/ata/wd.c
111
sys/dev/ata/wd.c
@ -35,7 +35,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.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 */
|
#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_BSDLABEL 0x00010 /* has a BSD disk label */
|
||||||
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
||||||
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
||||||
|
TAILQ_ENTRY(wd_softc) sc_drivechain;
|
||||||
struct buf sc_q;
|
struct buf sc_q;
|
||||||
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
||||||
struct disklabel sc_label; /* device configuration data */
|
struct disklabel sc_label; /* device configuration data */
|
||||||
@ -133,14 +134,16 @@ struct wdc_softc {
|
|||||||
struct device sc_dev;
|
struct device sc_dev;
|
||||||
struct intrhand sc_ih;
|
struct intrhand sc_ih;
|
||||||
|
|
||||||
struct buf sc_q;
|
|
||||||
u_char sc_flags;
|
u_char sc_flags;
|
||||||
|
#define WDCF_ACTIVE 0x00001 /* controller is active */
|
||||||
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
||||||
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
||||||
u_char sc_status; /* copy of status register */
|
u_char sc_status; /* copy of status register */
|
||||||
u_char sc_error; /* copy of error register */
|
u_char sc_error; /* copy of error register */
|
||||||
u_short sc_iobase; /* i/o port base */
|
u_short sc_iobase; /* i/o port base */
|
||||||
int sc_timeout; /* timeout counter */
|
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();
|
int wdcprobe(), wdprobe(), wdcintr();
|
||||||
@ -254,6 +257,7 @@ wdcattach(parent, self, aux)
|
|||||||
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
||||||
(void)config_found(self, &wa, wdprint);
|
(void)config_found(self, &wa, wdprint);
|
||||||
|
|
||||||
|
TAILQ_INIT(&wdc->sc_drives);
|
||||||
wdctimeout(wdc);
|
wdctimeout(wdc);
|
||||||
wdc->sc_ih.ih_fun = wdcintr;
|
wdc->sc_ih.ih_fun = wdcintr;
|
||||||
wdc->sc_ih.ih_arg = wdc;
|
wdc->sc_ih.ih_arg = wdc;
|
||||||
@ -333,7 +337,6 @@ void
|
|||||||
wdstrategy(bp)
|
wdstrategy(bp)
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
|
||||||
struct wd_softc *wd; /* disk unit to do the IO */
|
struct wd_softc *wd; /* disk unit to do the IO */
|
||||||
struct wdc_softc *wdc;
|
struct wdc_softc *wdc;
|
||||||
int lunit = WDUNIT(bp->b_dev);
|
int lunit = WDUNIT(bp->b_dev);
|
||||||
@ -371,14 +374,16 @@ wdstrategy(bp)
|
|||||||
bp->b_cylin = 0;
|
bp->b_cylin = 0;
|
||||||
|
|
||||||
/* Queue transfer on drive, activate drive and controller if idle. */
|
/* Queue transfer on drive, activate drive and controller if idle. */
|
||||||
dp = &wd->sc_q;
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
wddisksort(dp, bp);
|
wddisksort(&wd->sc_q, bp);
|
||||||
if (dp->b_active == 0)
|
if (!wd->sc_q.b_active)
|
||||||
wdstart(wd); /* Start drive. */
|
wdstart(wd); /* Start drive. */
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
#ifdef DIAGNOSTIC
|
||||||
if (wdc->sc_q.b_active == 0)
|
else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
|
||||||
wdcstart(wdc); /* Start controller. */
|
printf("wdstrategy: controller inactive\n");
|
||||||
|
wdcstart(wdc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
splx(s);
|
splx(s);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -410,29 +415,16 @@ static void
|
|||||||
wdstart(wd)
|
wdstart(wd)
|
||||||
struct wd_softc *wd;
|
struct wd_softc *wd;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
|
||||||
struct wdc_softc *wdc;
|
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. */
|
/* Link onto controller queue. */
|
||||||
dp->b_forw = NULL;
|
wd->sc_q.b_active = 1;
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Mark the drive unit as busy. */
|
/* If controller not already active, start it. */
|
||||||
dp->b_active = 1;
|
if (!active)
|
||||||
|
wdcstart(wdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -446,22 +438,26 @@ wdfinish(wd, bp)
|
|||||||
dk_busy &= ~(1 << wd->sc_drive);
|
dk_busy &= ~(1 << wd->sc_drive);
|
||||||
#endif
|
#endif
|
||||||
wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
|
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
|
* If this is the only buf or the last buf in the transfer (taking into
|
||||||
* account any residual, in case we erred)...
|
* account any residual, in case we erred)...
|
||||||
*/
|
*/
|
||||||
wd->sc_mbcount -= wd->sc_bcount;
|
wd->sc_mbcount -= wd->sc_bcount;
|
||||||
if (wd->sc_mbcount == 0) {
|
if (wd->sc_mbcount == 0) {
|
||||||
|
wd->sc_mskip = 0;
|
||||||
/*
|
/*
|
||||||
* ...then move this drive to the end of the queue to give
|
* ...then move this drive to the end of the queue to give
|
||||||
* others a `fair' chance.
|
* others a `fair' chance.
|
||||||
*/
|
*/
|
||||||
wdc->sc_q.b_forw = wd->sc_q.b_forw;
|
if (wd->sc_drivechain.tqe_next) {
|
||||||
wd->sc_mskip = 0;
|
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;
|
wd->sc_q.b_active = 0;
|
||||||
if (wd->sc_q.b_actf)
|
}
|
||||||
wdstart(wd);
|
|
||||||
}
|
}
|
||||||
bp->b_resid = wd->sc_bcount;
|
bp->b_resid = wd->sc_bcount;
|
||||||
bp->b_flags &= ~B_XXX;
|
bp->b_flags &= ~B_XXX;
|
||||||
@ -484,33 +480,25 @@ wdcstart(wdc)
|
|||||||
struct wd_softc *wd; /* disk unit for IO */
|
struct wd_softc *wd; /* disk unit for IO */
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct disklabel *lp;
|
struct disklabel *lp;
|
||||||
struct buf *dp;
|
|
||||||
long blknum, cylin, head, sector;
|
long blknum, cylin, head, sector;
|
||||||
long secpertrk, secpercyl;
|
long secpertrk, secpercyl;
|
||||||
int xfrblknum;
|
int xfrblknum;
|
||||||
int lunit;
|
|
||||||
|
|
||||||
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? */
|
||||||
dp = wdc->sc_q.b_forw;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
if (dp == NULL) {
|
if (wd == NULL)
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a transfer to this drive? If not, deactivate drive. */
|
/* Is there a transfer to this drive? If not, deactivate drive. */
|
||||||
bp = dp->b_actf;
|
bp = wd->sc_q.b_actf;
|
||||||
if (bp == NULL) {
|
if (bp == NULL) {
|
||||||
dp->b_active = 0;
|
TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
wdc->sc_q.b_forw = dp->b_forw;
|
wd->sc_q.b_active = 0;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obtain controller and drive information */
|
if (wdc->sc_errors >= WDIORETRIES) {
|
||||||
lunit = WDUNIT(bp->b_dev);
|
|
||||||
wd = wdcd.cd_devs[lunit];
|
|
||||||
|
|
||||||
if (wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR;
|
bp->b_flags |= B_ERROR;
|
||||||
@ -518,8 +506,8 @@ loop:
|
|||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark controller active and set a timeout. */
|
/* Mark the controller active and set a timeout. */
|
||||||
wdc->sc_q.b_active = 1;
|
wdc->sc_flags |= WDCF_ACTIVE;
|
||||||
wdc->sc_timeout = 4;
|
wdc->sc_timeout = 4;
|
||||||
|
|
||||||
/* Do control operations specially. */
|
/* Do control operations specially. */
|
||||||
@ -551,7 +539,7 @@ loop:
|
|||||||
blknum = bp->b_blkno + wd->sc_skip;
|
blknum = bp->b_blkno + wd->sc_skip;
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
if (wd->sc_skip == 0)
|
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,
|
(bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
|
||||||
blknum);
|
blknum);
|
||||||
else
|
else
|
||||||
@ -712,12 +700,11 @@ wdcintr(wdc)
|
|||||||
/* Clear the pending interrupt. */
|
/* Clear the pending interrupt. */
|
||||||
(void) inb(wdc->sc_iobase+wd_status);
|
(void) inb(wdc->sc_iobase+wd_status);
|
||||||
|
|
||||||
if (!wdc->sc_q.b_active)
|
if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bp = wdc->sc_q.b_forw->b_actf;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
wd = wdcd.cd_devs[WDUNIT(bp->b_dev)];
|
bp = wd->sc_q.b_actf;
|
||||||
wdc->sc_timeout = 0;
|
|
||||||
|
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
printf("I%d ", ctrlr);
|
printf("I%d ", ctrlr);
|
||||||
@ -735,6 +722,9 @@ wdcintr(wdc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wdc->sc_flags &= ~WDCF_ACTIVE;
|
||||||
|
wdc->sc_timeout = 0;
|
||||||
|
|
||||||
/* Have we an error? */
|
/* Have we an error? */
|
||||||
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
||||||
lose:
|
lose:
|
||||||
@ -755,7 +745,7 @@ wdcintr(wdc)
|
|||||||
|
|
||||||
/* Error or error correction? */
|
/* Error or error correction? */
|
||||||
if (wdc->sc_status & WDCS_ERR) {
|
if (wdc->sc_status & WDCS_ERR) {
|
||||||
if (++wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
if (++wdc->sc_errors >= WDIORETRIES) {
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR; /* Flag the error. */
|
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 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");
|
wderror(wd, bp, "soft error");
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ready for the next block, if any. */
|
/* Ready for the next block, if any. */
|
||||||
@ -970,7 +960,7 @@ wdcontrol(wd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
wd->sc_state = OPEN;
|
wd->sc_state = OPEN;
|
||||||
/*
|
/*
|
||||||
* The rest of the initialization can be done by normal means.
|
* The rest of the initialization can be done by normal means.
|
||||||
@ -1498,7 +1488,6 @@ wdcrestart(wdc)
|
|||||||
{
|
{
|
||||||
int s = splbio();
|
int s = splbio();
|
||||||
|
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
wdcstart(wdc);
|
wdcstart(wdc);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
@ -1529,7 +1518,7 @@ wdcunwedge(wdc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_flags |= WDCF_ERROR;
|
wdc->sc_flags |= WDCF_ERROR;
|
||||||
++wdc->sc_q.b_errcnt;
|
++wdc->sc_errors;
|
||||||
|
|
||||||
/* Wake up in a little bit and restart the operation. */
|
/* Wake up in a little bit and restart the operation. */
|
||||||
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
||||||
|
111
sys/dev/isa/wd.c
111
sys/dev/isa/wd.c
@ -35,7 +35,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.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 */
|
#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_BSDLABEL 0x00010 /* has a BSD disk label */
|
||||||
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
#define WDF_BADSECT 0x00020 /* has a bad144 badsector table */
|
||||||
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
#define WDF_WRITEPROT 0x00040 /* manual unit write protect */
|
||||||
|
TAILQ_ENTRY(wd_softc) sc_drivechain;
|
||||||
struct buf sc_q;
|
struct buf sc_q;
|
||||||
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */
|
||||||
struct disklabel sc_label; /* device configuration data */
|
struct disklabel sc_label; /* device configuration data */
|
||||||
@ -133,14 +134,16 @@ struct wdc_softc {
|
|||||||
struct device sc_dev;
|
struct device sc_dev;
|
||||||
struct intrhand sc_ih;
|
struct intrhand sc_ih;
|
||||||
|
|
||||||
struct buf sc_q;
|
|
||||||
u_char sc_flags;
|
u_char sc_flags;
|
||||||
|
#define WDCF_ACTIVE 0x00001 /* controller is active */
|
||||||
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
#define WDCF_SINGLE 0x00004 /* sector at a time mode */
|
||||||
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
#define WDCF_ERROR 0x00008 /* processing a disk error */
|
||||||
u_char sc_status; /* copy of status register */
|
u_char sc_status; /* copy of status register */
|
||||||
u_char sc_error; /* copy of error register */
|
u_char sc_error; /* copy of error register */
|
||||||
u_short sc_iobase; /* i/o port base */
|
u_short sc_iobase; /* i/o port base */
|
||||||
int sc_timeout; /* timeout counter */
|
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();
|
int wdcprobe(), wdprobe(), wdcintr();
|
||||||
@ -254,6 +257,7 @@ wdcattach(parent, self, aux)
|
|||||||
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++)
|
||||||
(void)config_found(self, &wa, wdprint);
|
(void)config_found(self, &wa, wdprint);
|
||||||
|
|
||||||
|
TAILQ_INIT(&wdc->sc_drives);
|
||||||
wdctimeout(wdc);
|
wdctimeout(wdc);
|
||||||
wdc->sc_ih.ih_fun = wdcintr;
|
wdc->sc_ih.ih_fun = wdcintr;
|
||||||
wdc->sc_ih.ih_arg = wdc;
|
wdc->sc_ih.ih_arg = wdc;
|
||||||
@ -333,7 +337,6 @@ void
|
|||||||
wdstrategy(bp)
|
wdstrategy(bp)
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
|
||||||
struct wd_softc *wd; /* disk unit to do the IO */
|
struct wd_softc *wd; /* disk unit to do the IO */
|
||||||
struct wdc_softc *wdc;
|
struct wdc_softc *wdc;
|
||||||
int lunit = WDUNIT(bp->b_dev);
|
int lunit = WDUNIT(bp->b_dev);
|
||||||
@ -371,14 +374,16 @@ wdstrategy(bp)
|
|||||||
bp->b_cylin = 0;
|
bp->b_cylin = 0;
|
||||||
|
|
||||||
/* Queue transfer on drive, activate drive and controller if idle. */
|
/* Queue transfer on drive, activate drive and controller if idle. */
|
||||||
dp = &wd->sc_q;
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
wddisksort(dp, bp);
|
wddisksort(&wd->sc_q, bp);
|
||||||
if (dp->b_active == 0)
|
if (!wd->sc_q.b_active)
|
||||||
wdstart(wd); /* Start drive. */
|
wdstart(wd); /* Start drive. */
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
#ifdef DIAGNOSTIC
|
||||||
if (wdc->sc_q.b_active == 0)
|
else if ((wdc->sc_flags & WDCF_ACTIVE) == 0) {
|
||||||
wdcstart(wdc); /* Start controller. */
|
printf("wdstrategy: controller inactive\n");
|
||||||
|
wdcstart(wdc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
splx(s);
|
splx(s);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -410,29 +415,16 @@ static void
|
|||||||
wdstart(wd)
|
wdstart(wd)
|
||||||
struct wd_softc *wd;
|
struct wd_softc *wd;
|
||||||
{
|
{
|
||||||
struct buf *dp;
|
struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent;
|
||||||
struct wdc_softc *wdc;
|
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. */
|
/* Link onto controller queue. */
|
||||||
dp->b_forw = NULL;
|
wd->sc_q.b_active = 1;
|
||||||
wdc = (void *)wd->sc_dev.dv_parent;
|
TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Mark the drive unit as busy. */
|
/* If controller not already active, start it. */
|
||||||
dp->b_active = 1;
|
if (!active)
|
||||||
|
wdcstart(wdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -446,22 +438,26 @@ wdfinish(wd, bp)
|
|||||||
dk_busy &= ~(1 << wd->sc_drive);
|
dk_busy &= ~(1 << wd->sc_drive);
|
||||||
#endif
|
#endif
|
||||||
wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR);
|
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
|
* If this is the only buf or the last buf in the transfer (taking into
|
||||||
* account any residual, in case we erred)...
|
* account any residual, in case we erred)...
|
||||||
*/
|
*/
|
||||||
wd->sc_mbcount -= wd->sc_bcount;
|
wd->sc_mbcount -= wd->sc_bcount;
|
||||||
if (wd->sc_mbcount == 0) {
|
if (wd->sc_mbcount == 0) {
|
||||||
|
wd->sc_mskip = 0;
|
||||||
/*
|
/*
|
||||||
* ...then move this drive to the end of the queue to give
|
* ...then move this drive to the end of the queue to give
|
||||||
* others a `fair' chance.
|
* others a `fair' chance.
|
||||||
*/
|
*/
|
||||||
wdc->sc_q.b_forw = wd->sc_q.b_forw;
|
if (wd->sc_drivechain.tqe_next) {
|
||||||
wd->sc_mskip = 0;
|
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;
|
wd->sc_q.b_active = 0;
|
||||||
if (wd->sc_q.b_actf)
|
}
|
||||||
wdstart(wd);
|
|
||||||
}
|
}
|
||||||
bp->b_resid = wd->sc_bcount;
|
bp->b_resid = wd->sc_bcount;
|
||||||
bp->b_flags &= ~B_XXX;
|
bp->b_flags &= ~B_XXX;
|
||||||
@ -484,33 +480,25 @@ wdcstart(wdc)
|
|||||||
struct wd_softc *wd; /* disk unit for IO */
|
struct wd_softc *wd; /* disk unit for IO */
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
struct disklabel *lp;
|
struct disklabel *lp;
|
||||||
struct buf *dp;
|
|
||||||
long blknum, cylin, head, sector;
|
long blknum, cylin, head, sector;
|
||||||
long secpertrk, secpercyl;
|
long secpertrk, secpercyl;
|
||||||
int xfrblknum;
|
int xfrblknum;
|
||||||
int lunit;
|
|
||||||
|
|
||||||
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? */
|
||||||
dp = wdc->sc_q.b_forw;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
if (dp == NULL) {
|
if (wd == NULL)
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a transfer to this drive? If not, deactivate drive. */
|
/* Is there a transfer to this drive? If not, deactivate drive. */
|
||||||
bp = dp->b_actf;
|
bp = wd->sc_q.b_actf;
|
||||||
if (bp == NULL) {
|
if (bp == NULL) {
|
||||||
dp->b_active = 0;
|
TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain);
|
||||||
wdc->sc_q.b_forw = dp->b_forw;
|
wd->sc_q.b_active = 0;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Obtain controller and drive information */
|
if (wdc->sc_errors >= WDIORETRIES) {
|
||||||
lunit = WDUNIT(bp->b_dev);
|
|
||||||
wd = wdcd.cd_devs[lunit];
|
|
||||||
|
|
||||||
if (wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR;
|
bp->b_flags |= B_ERROR;
|
||||||
@ -518,8 +506,8 @@ loop:
|
|||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark controller active and set a timeout. */
|
/* Mark the controller active and set a timeout. */
|
||||||
wdc->sc_q.b_active = 1;
|
wdc->sc_flags |= WDCF_ACTIVE;
|
||||||
wdc->sc_timeout = 4;
|
wdc->sc_timeout = 4;
|
||||||
|
|
||||||
/* Do control operations specially. */
|
/* Do control operations specially. */
|
||||||
@ -551,7 +539,7 @@ loop:
|
|||||||
blknum = bp->b_blkno + wd->sc_skip;
|
blknum = bp->b_blkno + wd->sc_skip;
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
if (wd->sc_skip == 0)
|
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,
|
(bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount,
|
||||||
blknum);
|
blknum);
|
||||||
else
|
else
|
||||||
@ -712,12 +700,11 @@ wdcintr(wdc)
|
|||||||
/* Clear the pending interrupt. */
|
/* Clear the pending interrupt. */
|
||||||
(void) inb(wdc->sc_iobase+wd_status);
|
(void) inb(wdc->sc_iobase+wd_status);
|
||||||
|
|
||||||
if (!wdc->sc_q.b_active)
|
if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bp = wdc->sc_q.b_forw->b_actf;
|
wd = wdc->sc_drives.tqh_first;
|
||||||
wd = wdcd.cd_devs[WDUNIT(bp->b_dev)];
|
bp = wd->sc_q.b_actf;
|
||||||
wdc->sc_timeout = 0;
|
|
||||||
|
|
||||||
#ifdef WDDEBUG
|
#ifdef WDDEBUG
|
||||||
printf("I%d ", ctrlr);
|
printf("I%d ", ctrlr);
|
||||||
@ -735,6 +722,9 @@ wdcintr(wdc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wdc->sc_flags &= ~WDCF_ACTIVE;
|
||||||
|
wdc->sc_timeout = 0;
|
||||||
|
|
||||||
/* Have we an error? */
|
/* Have we an error? */
|
||||||
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
if (wdc->sc_status & (WDCS_ERR | WDCS_ECCCOR)) {
|
||||||
lose:
|
lose:
|
||||||
@ -755,7 +745,7 @@ wdcintr(wdc)
|
|||||||
|
|
||||||
/* Error or error correction? */
|
/* Error or error correction? */
|
||||||
if (wdc->sc_status & WDCS_ERR) {
|
if (wdc->sc_status & WDCS_ERR) {
|
||||||
if (++wdc->sc_q.b_errcnt >= WDIORETRIES) {
|
if (++wdc->sc_errors >= WDIORETRIES) {
|
||||||
wderror(wd, bp, "hard error");
|
wderror(wd, bp, "hard error");
|
||||||
bp->b_error = EIO;
|
bp->b_error = EIO;
|
||||||
bp->b_flags |= B_ERROR; /* Flag the error. */
|
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 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");
|
wderror(wd, bp, "soft error");
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ready for the next block, if any. */
|
/* Ready for the next block, if any. */
|
||||||
@ -970,7 +960,7 @@ wdcontrol(wd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_q.b_errcnt = 0;
|
wdc->sc_errors = 0;
|
||||||
wd->sc_state = OPEN;
|
wd->sc_state = OPEN;
|
||||||
/*
|
/*
|
||||||
* The rest of the initialization can be done by normal means.
|
* The rest of the initialization can be done by normal means.
|
||||||
@ -1498,7 +1488,6 @@ wdcrestart(wdc)
|
|||||||
{
|
{
|
||||||
int s = splbio();
|
int s = splbio();
|
||||||
|
|
||||||
wdc->sc_q.b_active = 0;
|
|
||||||
wdcstart(wdc);
|
wdcstart(wdc);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
@ -1529,7 +1518,7 @@ wdcunwedge(wdc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wdc->sc_flags |= WDCF_ERROR;
|
wdc->sc_flags |= WDCF_ERROR;
|
||||||
++wdc->sc_q.b_errcnt;
|
++wdc->sc_errors;
|
||||||
|
|
||||||
/* Wake up in a little bit and restart the operation. */
|
/* Wake up in a little bit and restart the operation. */
|
||||||
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
timeout((timeout_t)wdcrestart, (caddr_t)wdc, RECOVERYTIME);
|
||||||
|
Loading…
Reference in New Issue
Block a user