De-ANSIfy. Move the timeout counter into struct disk. Remove unneeded args

to wd[gs]etctlr().  Other minor changes.
This commit is contained in:
mycroft 1994-03-04 03:43:48 +00:00
parent 499a02a6a9
commit 220512c2a8
3 changed files with 399 additions and 360 deletions

View File

@ -35,15 +35,12 @@
* 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.54 1994/03/03 01:58:21 mycroft Exp $ * $Id: wd.c,v 1.55 1994/03/04 03:43:48 mycroft Exp $
*/ */
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */ #define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
#define INSTRUMENT /* instrumentation stuff by Brad Parker */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */
/* TODO: peel out buffer at low ipl, speed improvement */
/* TODO: find and fix the timing bugs apparent on some controllers */
#include "wd.h" #include "wd.h"
#if NWDC > 0 #if NWDC > 0
@ -113,6 +110,7 @@ struct disk {
char dk_unit; /* physical unit number */ char dk_unit; /* physical unit number */
char dk_lunit; /* logical unit number */ char dk_lunit; /* logical unit number */
char dk_state; /* control state */ char dk_state; /* control state */
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */ u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */ u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */ short dk_port; /* i/o port base */
@ -144,7 +142,6 @@ struct buf wdtab[NWDC]; /* various per-controller info */
struct buf wdutab[NWD]; /* head of queue per drive */ struct buf wdutab[NWD]; /* head of queue per drive */
struct buf rwdbuf[NWD]; /* buffers for raw IO */ struct buf rwdbuf[NWD]; /* buffers for raw IO */
long wdxfer[NWD]; /* count of transfers */ long wdxfer[NWD]; /* count of transfers */
int wdtimeoutstatus[NWD]; /* timeout counters */
int wdprobe(), wdattach(); int wdprobe(), wdattach();
@ -152,17 +149,17 @@ struct isa_driver wdcdriver = {
wdprobe, wdattach, "wdc", wdprobe, wdattach, "wdc",
}; };
static void wdustart(struct disk *); static void wdustart __P((struct disk *));
static void wdstart(int); static void wdstart __P((int));
static int wdcommand(struct disk *, int); static int wdcommand __P((struct disk *, int));
static int wdcontrol(struct buf *); static int wdcontrol __P((struct buf *));
static int wdsetctlr(dev_t, struct disk *); static int wdsetctlr __P((struct disk *));
static int wdgetctlr(int, struct disk *); static int wdgetctlr __P((struct disk *));
static void bad144intern(struct disk *); static void bad144intern __P((struct disk *));
static int wdreset(struct disk *, int); static int wdreset __P((struct disk *, int));
static int wdtimeout(caddr_t); static int wdtimeout __P((caddr_t));
void wddisksort(struct buf *dp, struct buf *bp); void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait(struct disk *, int); int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ) #define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT) #define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT)
#define wait_for_unbusy(d) wdc_wait(d, 0) #define wait_for_unbusy(d) wdc_wait(d, 0)
@ -171,23 +168,24 @@ int wdc_wait(struct disk *, int);
* Probe for controller. * Probe for controller.
*/ */
int int
wdprobe(struct isa_device *dvp) wdprobe(isa_dev)
struct isa_device *isa_dev;
{ {
struct disk *du; struct disk *du;
int wdc; int wdc;
if (dvp->id_unit >= NWDC) if (isa_dev->id_unit >= NWDC)
return 0; return 0;
du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
bzero(du, sizeof(struct disk)); bzero(du, sizeof(struct disk));
du->dk_ctrlr = dvp->id_unit; du->dk_ctrlr = isa_dev->id_unit;
du->dk_unit = 0; du->dk_unit = 0;
du->dk_lunit = 0; du->dk_lunit = 0;
wdcontroller[dvp->id_unit].dkc_port = dvp->id_iobase; wdcontroller[isa_dev->id_unit].dkc_port = isa_dev->id_iobase;
wdc = du->dk_port = dvp->id_iobase; wdc = du->dk_port = isa_dev->id_iobase;
/* check if we have registers that work */ /* check if we have registers that work */
outb(wdc+wd_error, 0x5a); /* error register not writable */ outb(wdc+wd_error, 0x5a); /* error register not writable */
@ -214,24 +212,25 @@ nodevice:
* Attach each drive if possible. * Attach each drive if possible.
*/ */
int int
wdattach(struct isa_device *dvp) wdattach(isa_dev)
struct isa_device *isa_dev;
{ {
int unit, lunit; int unit, lunit;
struct disk *du; struct disk *du;
if (dvp->id_masunit == -1) if (isa_dev->id_masunit == -1)
return 0; return 0;
if (dvp->id_masunit >= NWDC) if (isa_dev->id_masunit >= NWDC)
return 0; return 0;
lunit = dvp->id_unit; lunit = isa_dev->id_unit;
if (lunit == -1) { if (lunit == -1) {
printf("wdc%d: cannot support unit ?\n", dvp->id_masunit); printf("wdc%d: cannot support unit ?\n", isa_dev->id_masunit);
return 0; return 0;
} }
if (lunit >= NWD) if (lunit >= NWD)
return 0; return 0;
unit = dvp->id_physid; unit = isa_dev->id_physid;
du = wddrives[lunit] = du = wddrives[lunit] =
(struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
@ -239,18 +238,17 @@ wdattach(struct isa_device *dvp)
bzero(&wdutab[lunit], sizeof(struct buf)); bzero(&wdutab[lunit], sizeof(struct buf));
bzero(&rwdbuf[lunit], sizeof(struct buf)); bzero(&rwdbuf[lunit], sizeof(struct buf));
wdxfer[lunit] = 0; wdxfer[lunit] = 0;
wdtimeoutstatus[lunit] = 0; wdtimeout((caddr_t)du);
wdtimeout(lunit); du->dk_ctrlr = isa_dev->id_masunit;
du->dk_ctrlr = dvp->id_masunit;
du->dk_unit = unit; du->dk_unit = unit;
du->dk_lunit = lunit; du->dk_lunit = lunit;
du->dk_port = wdcontroller[dvp->id_masunit].dkc_port; du->dk_port = wdcontroller[isa_dev->id_masunit].dkc_port;
if (wdgetctlr(unit, du) == 0) { if (wdgetctlr(du) == 0) {
int i, blank; int i, blank;
printf("wd%d at wdc%d targ %d: ", dvp->id_unit, printf("wd%d at wdc%d targ %d: ", isa_dev->id_unit,
dvp->id_masunit, dvp->id_physid); isa_dev->id_masunit, isa_dev->id_physid);
if (du->dk_params.wdp_heads == 0) if (du->dk_params.wdp_heads == 0)
printf("(unknown size) <"); printf("(unknown size) <");
else else
@ -278,7 +276,7 @@ wdattach(struct isa_device *dvp)
printf(">\n"); printf(">\n");
} else { } else {
/*printf("wd%d at wdc%d slave %d -- error\n", lunit, /*printf("wd%d at wdc%d slave %d -- error\n", lunit,
dvp->id_masunit, unit);*/ isa_dev->id_masunit, unit);*/
wddrives[lunit] = 0; wddrives[lunit] = 0;
free(du, M_TEMP); free(du, M_TEMP);
return 0; return 0;
@ -292,9 +290,10 @@ wdattach(struct isa_device *dvp)
* be a multiple of a sector in length. * be a multiple of a sector in length.
*/ */
int int
wdstrategy(register struct buf *bp) wdstrategy(bp)
struct buf *bp;
{ {
register struct buf *dp; struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */ struct disk *du; /* Disk unit to do the IO. */
int lunit = WDUNIT(bp->b_dev); int lunit = WDUNIT(bp->b_dev);
int s; int s;
@ -349,9 +348,10 @@ done:
* Need to skip over multitransfer bufs. * Need to skip over multitransfer bufs.
*/ */
void void
wddisksort(struct buf *dp, struct buf *bp) wddisksort(dp, bp)
struct buf *dp, *bp;
{ {
register struct buf *ap; struct buf *ap;
while ((ap = dp->b_actf) && ap->b_flags & B_XXX) while ((ap = dp->b_actf) && ap->b_flags & B_XXX)
dp = ap; dp = ap;
@ -364,9 +364,10 @@ wddisksort(struct buf *dp, struct buf *bp)
* If the controller is idle, the transfer is started. * If the controller is idle, the transfer is started.
*/ */
static void static void
wdustart(register struct disk *du) wdustart(du)
struct disk *du;
{ {
register struct buf *dp = &wdutab[du->dk_lunit]; struct buf *dp = &wdutab[du->dk_lunit];
int ctrlr = du->dk_ctrlr; int ctrlr = du->dk_ctrlr;
/* unit already active? */ /* unit already active? */
@ -397,7 +398,8 @@ wdustart(register struct disk *du)
* 1. The transfer length must be an exact multiple of the sector size. * 1. The transfer length must be an exact multiple of the sector size.
*/ */
static void static void
wdstart(int ctrlr) wdstart(ctrlr)
int ctrlr;
{ {
register struct disk *du; /* disk unit for IO */ register struct disk *du; /* disk unit for IO */
register struct buf *bp; register struct buf *bp;
@ -430,7 +432,7 @@ loop:
du = wddrives[lunit]; du = wddrives[lunit];
/* clear any pending timeout, just in case */ /* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0; du->dk_timeout = 0;
/* if not really a transfer, do control operations specially */ /* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) { if (du->dk_state < OPEN) {
@ -606,7 +608,7 @@ retry:
/* if this is a read operation, just go away until it's done. */ /* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) { if (bp->b_flags & B_READ) {
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
return; return;
} }
@ -621,7 +623,7 @@ retry:
du->dk_bc -= DEV_BSIZE; du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE; du->dk_bct -= DEV_BSIZE;
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
} }
/* Interrupt routine for the controller. Acknowledge the interrupt, check for /* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -630,7 +632,8 @@ retry:
* continue with the next chunk if so. * continue with the next chunk if so.
*/ */
void void
wdintr(int ctrlr) wdintr(ctrlr)
int ctrlr;
{ {
register struct disk *du; register struct disk *du;
register struct buf *bp, *dp; register struct buf *bp, *dp;
@ -645,7 +648,7 @@ wdintr(int ctrlr)
bp = dp->b_actf; bp = dp->b_actf;
du = wddrives[WDUNIT(bp->b_dev)]; du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port; wdc = du->dk_port;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0; du->dk_timeout = 0;
#ifdef WDDEBUG #ifdef WDDEBUG
printf("I%d ", ctrlr); printf("I%d ", ctrlr);
@ -799,7 +802,11 @@ done:
* Initialize a drive. * Initialize a drive.
*/ */
int int
wdopen(dev_t dev, int flags, int fmt, struct proc *p) wdopen(dev, flag, fmt, p)
dev_t dev;
int flag;
int fmt;
struct proc *p;
{ {
int lunit; int lunit;
struct disk *du; struct disk *du;
@ -842,11 +849,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
du->dk_state = WANTOPEN; du->dk_state = WANTOPEN;
/* read label using "raw" partition */ /* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage) #ifdef notdef
/* wdsetctlr(dev, du); */ /* Maybe do this TIH */ /* wdsetctlr(du); */ /* Maybe do this TIH */
msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW), msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW),
wdstrategy, &du->dk_dd, &du->dk_cpd); wdstrategy, &du->dk_dd, &du->dk_cpd);
wdsetctlr(dev, du); wdsetctlr(du);
#endif #endif
if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev),
WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) { WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) {
@ -857,7 +864,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
return EINVAL; /* XXX needs translation */ return EINVAL; /* XXX needs translation */
} }
} else { } else {
wdsetctlr(dev, du); wdsetctlr(du);
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
du->dk_flags &= ~DKFL_WRITEPROT; du->dk_flags &= ~DKFL_WRITEPROT;
if (du->dk_dd.d_flags & D_BADSECT) if (du->dk_dd.d_flags & D_BADSECT)
@ -917,7 +924,8 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
* Returns 0 if operation still in progress, 1 if completed. * Returns 0 if operation still in progress, 1 if completed.
*/ */
static int static int
wdcontrol(register struct buf *bp) wdcontrol(bp)
struct buf *bp;
{ {
struct disk *du; struct disk *du;
int unit, lunit; int unit, lunit;
@ -938,27 +946,23 @@ wdcontrol(register struct buf *bp)
printf("wd%d: recal ", lunit); printf("wd%d: recal ", lunit);
#endif #endif
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du); wdgetctlr(du);
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
wdreset(du, 1); wdreset(du, 1);
goto tryagainrecal; goto tryagainrecal;
} }
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) { if (wait_for_ready(du) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1; wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) { if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
du->dk_state = RECAL; du->dk_state = RECAL;
splx(s); splx(s);
return 0; return 0;
case RECAL: case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) { if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) { if ((du->dk_flags & DKFL_QUIET) == 0) {
@ -973,7 +977,7 @@ wdcontrol(register struct buf *bp)
} }
/* some controllers require this ... */ /* some controllers require this ... */
wdsetctlr(bp->b_dev, du); wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0; wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN; du->dk_state = OPEN;
@ -982,6 +986,7 @@ wdcontrol(register struct buf *bp)
* by normal means. * by normal means.
*/ */
return 1; return 1;
default: default:
panic("wdcontrol"); panic("wdcontrol");
} }
@ -1002,7 +1007,9 @@ badopen:
* assumes interrupts are blocked. * assumes interrupts are blocked.
*/ */
static int static int
wdcommand(struct disk *du, int cmd) wdcommand(du, cmd)
struct disk *du;
int cmd;
{ {
int stat, wdc; int stat, wdc;
@ -1037,7 +1044,8 @@ wdcommand(struct disk *du, int cmd)
* issue IDC to drive to tell it just what geometry it is to be. * issue IDC to drive to tell it just what geometry it is to be.
*/ */
static int static int
wdsetctlr(dev_t dev, struct disk *du) wdsetctlr(du)
struct disk *du;
{ {
int stat, s, wdc; int stat, s, wdc;
@ -1070,7 +1078,8 @@ wdsetctlr(dev_t dev, struct disk *du)
* issue READP to drive to ask it what it is. * issue READP to drive to ask it what it is.
*/ */
static int static int
wdgetctlr(int u, struct disk *du) wdgetctlr(du)
struct disk *du;
{ {
int stat, s, i, wdc; int stat, s, i, wdc;
char tb[DEV_BSIZE]; char tb[DEV_BSIZE];
@ -1079,21 +1088,16 @@ wdgetctlr(int u, struct disk *du)
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdc = du->dk_port; wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
splx(s); splx(s);
return -1; return -1;
} }
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); if (wait_for_ready(du) < 0)
if (wait_for_ready(du) < 0) { goto lose;
splx(s);
return -1;
}
stat = wdcommand(du, WDCC_READP); stat = wdcommand(du, WDCC_READP);
if (stat < 0) { if (stat < 0)
splx(s); goto lose;
return -1;
}
if ((stat & WDCS_ERR) == 0) { if ((stat & WDCS_ERR) == 0) {
/* obtain parameters */ /* obtain parameters */
@ -1157,10 +1161,11 @@ wdgetctlr(int u, struct disk *du)
return 0; return 0;
} }
/* ARGSUSED */
int int
wdclose(dev_t dev, int flags, int fmt) wdclose(dev, flag, fmt)
dev_t dev;
int flag;
int fmt;
{ {
struct disk *du; struct disk *du;
int part = WDPART(dev), mask = 1 << part; int part = WDPART(dev), mask = 1 << part;
@ -1181,7 +1186,12 @@ wdclose(dev_t dev, int flags, int fmt)
} }
int int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) wdioctl(dev, cmd, addr, flag, p)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
struct proc *p;
{ {
int lunit = WDUNIT(dev); int lunit = WDUNIT(dev);
struct disk *du = wddrives[lunit]; struct disk *du = wddrives[lunit];
@ -1214,7 +1224,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
&du->dk_cpd); &du->dk_cpd);
if (error == 0) { if (error == 0) {
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
} }
return error; return error;
@ -1237,7 +1247,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
int wlab; int wlab;
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
/* simulate opening partition 0 so write succeeds */ /* simulate opening partition 0 so write succeeds */
du->dk_openpart |= (1 << 0); /* XXX */ du->dk_openpart |= (1 << 0); /* XXX */
@ -1300,7 +1310,8 @@ wdformat(struct buf *bp)
#endif #endif
int int
wdsize(dev_t dev) wdsize(dev)
dev_t dev;
{ {
int lunit = WDUNIT(dev), part = WDPART(dev); int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du; struct disk *du;
@ -1315,6 +1326,7 @@ wdsize(dev_t dev)
int val; int val;
val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD,
S_IFBLK, 0); S_IFBLK, 0);
/* XXX Clear the open flag? */
if (val != 0) if (val != 0)
return -1; return -1;
} }
@ -1325,11 +1337,10 @@ wdsize(dev_t dev)
return (int)du->dk_dd.d_partitions[part].p_size; return (int)du->dk_dd.d_partitions[part].p_size;
} }
extern char *vmmap; /* poor name! */
/* dump core after a system crash */ /* dump core after a system crash */
int int
wddump(dev_t dev) wddump(dev)
dev_t dev;
{ {
register struct disk *du; /* disk unit to do the IO */ register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */ long num; /* number of sectors to write */
@ -1397,7 +1408,7 @@ wddump(dev_t dev)
return EIO; return EIO;
/* some compaq controllers require this ... */ /* some compaq controllers require this ... */
wdsetctlr(dev, du); wdsetctlr(du);
blknum = dumplo + blkoff; blknum = dumplo + blkoff;
while (num > 0) { while (num > 0) {
@ -1491,27 +1502,31 @@ wddump(dev_t dev)
* Internalize the bad sector table. * Internalize the bad sector table.
*/ */
void void
bad144intern(struct disk *du) bad144intern(du)
struct disk *du;
{ {
int i; int i;
if (du->dk_flags & DKFL_BADSECT) {
for (i = 0; i < 127; i++) if ((du->dk_flags & DKFL_BADSECT) == 0)
du->dk_badsect[i] = -1; return;
for (i = 0; i < 126; i++) {
if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) for (i = 0; i < 127; i++)
break; du->dk_badsect[i] = -1;
du->dk_badsect[i] = for (i = 0; i < 126; i++) {
du->dk_cpd.bad.bt_bad[i].bt_cyl * if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff)
du->dk_dd.d_secpercyl + break;
(du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * du->dk_badsect[i] =
du->dk_dd.d_nsectors + du->dk_cpd.bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) *
} du->dk_dd.d_nsectors +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff);
} }
} }
static int static int
wdreset(struct disk *du, int err) wdreset(du, err)
struct disk *du;
int err;
{ {
int wdc = du->dk_port; int wdc = du->dk_port;
int stat; int stat;
@ -1522,6 +1537,9 @@ wdreset(struct disk *du, int err)
/* reset the device */ /* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000); DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT); outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(du) < 0) if (wait_for_unbusy(du) < 0)
@ -1541,9 +1559,9 @@ wdc_wait(du, mask)
stat = inb(wdc+wd_altsts); stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask) if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask)
break; break;
DELAY(WDCDELAY);
if (++timeout > WDCNDELAY) if (++timeout > WDCNDELAY)
return -1; return -1;
DELAY(WDCDELAY);
} }
#ifdef WDCNDELAY_DEBUG #ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG) if (timeout > WDCNDELAY_DEBUG)
@ -1554,29 +1572,24 @@ wdc_wait(du, mask)
} }
static int static int
wdtimeout(caddr_t arg) wdtimeout(arg)
caddr_t arg;
{ {
int x = splbio(); int s = splbio();
register int unit = (int)arg; struct disk *du = (void *)arg;
if (wdtimeoutstatus[unit] && --wdtimeoutstatus[unit] == 0) { if (du->dk_timeout && --du->dk_timeout == 0) {
struct disk *du = wddrives[unit];
int wdc = du->dk_port; int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n", printf("wd%d: lost interrupt - status %x, error %x\n",
unit, inb(wdc+wd_status), inb(wdc+wd_error)); du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); wdreset(du, 0);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT);
du->dk_skip = 0; du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE; du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */ wdstart(du->dk_ctrlr); /* start controller */
} }
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2); timeout((timeout_t)wdtimeout, arg, hz);
splx(x); splx(s);
return 0; return 0;
} }

View File

@ -35,15 +35,12 @@
* 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.54 1994/03/03 01:58:21 mycroft Exp $ * $Id: wd.c,v 1.55 1994/03/04 03:43:48 mycroft Exp $
*/ */
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */ #define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
#define INSTRUMENT /* instrumentation stuff by Brad Parker */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */
/* TODO: peel out buffer at low ipl, speed improvement */
/* TODO: find and fix the timing bugs apparent on some controllers */
#include "wd.h" #include "wd.h"
#if NWDC > 0 #if NWDC > 0
@ -113,6 +110,7 @@ struct disk {
char dk_unit; /* physical unit number */ char dk_unit; /* physical unit number */
char dk_lunit; /* logical unit number */ char dk_lunit; /* logical unit number */
char dk_state; /* control state */ char dk_state; /* control state */
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */ u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */ u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */ short dk_port; /* i/o port base */
@ -144,7 +142,6 @@ struct buf wdtab[NWDC]; /* various per-controller info */
struct buf wdutab[NWD]; /* head of queue per drive */ struct buf wdutab[NWD]; /* head of queue per drive */
struct buf rwdbuf[NWD]; /* buffers for raw IO */ struct buf rwdbuf[NWD]; /* buffers for raw IO */
long wdxfer[NWD]; /* count of transfers */ long wdxfer[NWD]; /* count of transfers */
int wdtimeoutstatus[NWD]; /* timeout counters */
int wdprobe(), wdattach(); int wdprobe(), wdattach();
@ -152,17 +149,17 @@ struct isa_driver wdcdriver = {
wdprobe, wdattach, "wdc", wdprobe, wdattach, "wdc",
}; };
static void wdustart(struct disk *); static void wdustart __P((struct disk *));
static void wdstart(int); static void wdstart __P((int));
static int wdcommand(struct disk *, int); static int wdcommand __P((struct disk *, int));
static int wdcontrol(struct buf *); static int wdcontrol __P((struct buf *));
static int wdsetctlr(dev_t, struct disk *); static int wdsetctlr __P((struct disk *));
static int wdgetctlr(int, struct disk *); static int wdgetctlr __P((struct disk *));
static void bad144intern(struct disk *); static void bad144intern __P((struct disk *));
static int wdreset(struct disk *, int); static int wdreset __P((struct disk *, int));
static int wdtimeout(caddr_t); static int wdtimeout __P((caddr_t));
void wddisksort(struct buf *dp, struct buf *bp); void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait(struct disk *, int); int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ) #define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT) #define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT)
#define wait_for_unbusy(d) wdc_wait(d, 0) #define wait_for_unbusy(d) wdc_wait(d, 0)
@ -171,23 +168,24 @@ int wdc_wait(struct disk *, int);
* Probe for controller. * Probe for controller.
*/ */
int int
wdprobe(struct isa_device *dvp) wdprobe(isa_dev)
struct isa_device *isa_dev;
{ {
struct disk *du; struct disk *du;
int wdc; int wdc;
if (dvp->id_unit >= NWDC) if (isa_dev->id_unit >= NWDC)
return 0; return 0;
du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
bzero(du, sizeof(struct disk)); bzero(du, sizeof(struct disk));
du->dk_ctrlr = dvp->id_unit; du->dk_ctrlr = isa_dev->id_unit;
du->dk_unit = 0; du->dk_unit = 0;
du->dk_lunit = 0; du->dk_lunit = 0;
wdcontroller[dvp->id_unit].dkc_port = dvp->id_iobase; wdcontroller[isa_dev->id_unit].dkc_port = isa_dev->id_iobase;
wdc = du->dk_port = dvp->id_iobase; wdc = du->dk_port = isa_dev->id_iobase;
/* check if we have registers that work */ /* check if we have registers that work */
outb(wdc+wd_error, 0x5a); /* error register not writable */ outb(wdc+wd_error, 0x5a); /* error register not writable */
@ -214,24 +212,25 @@ nodevice:
* Attach each drive if possible. * Attach each drive if possible.
*/ */
int int
wdattach(struct isa_device *dvp) wdattach(isa_dev)
struct isa_device *isa_dev;
{ {
int unit, lunit; int unit, lunit;
struct disk *du; struct disk *du;
if (dvp->id_masunit == -1) if (isa_dev->id_masunit == -1)
return 0; return 0;
if (dvp->id_masunit >= NWDC) if (isa_dev->id_masunit >= NWDC)
return 0; return 0;
lunit = dvp->id_unit; lunit = isa_dev->id_unit;
if (lunit == -1) { if (lunit == -1) {
printf("wdc%d: cannot support unit ?\n", dvp->id_masunit); printf("wdc%d: cannot support unit ?\n", isa_dev->id_masunit);
return 0; return 0;
} }
if (lunit >= NWD) if (lunit >= NWD)
return 0; return 0;
unit = dvp->id_physid; unit = isa_dev->id_physid;
du = wddrives[lunit] = du = wddrives[lunit] =
(struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
@ -239,18 +238,17 @@ wdattach(struct isa_device *dvp)
bzero(&wdutab[lunit], sizeof(struct buf)); bzero(&wdutab[lunit], sizeof(struct buf));
bzero(&rwdbuf[lunit], sizeof(struct buf)); bzero(&rwdbuf[lunit], sizeof(struct buf));
wdxfer[lunit] = 0; wdxfer[lunit] = 0;
wdtimeoutstatus[lunit] = 0; wdtimeout((caddr_t)du);
wdtimeout(lunit); du->dk_ctrlr = isa_dev->id_masunit;
du->dk_ctrlr = dvp->id_masunit;
du->dk_unit = unit; du->dk_unit = unit;
du->dk_lunit = lunit; du->dk_lunit = lunit;
du->dk_port = wdcontroller[dvp->id_masunit].dkc_port; du->dk_port = wdcontroller[isa_dev->id_masunit].dkc_port;
if (wdgetctlr(unit, du) == 0) { if (wdgetctlr(du) == 0) {
int i, blank; int i, blank;
printf("wd%d at wdc%d targ %d: ", dvp->id_unit, printf("wd%d at wdc%d targ %d: ", isa_dev->id_unit,
dvp->id_masunit, dvp->id_physid); isa_dev->id_masunit, isa_dev->id_physid);
if (du->dk_params.wdp_heads == 0) if (du->dk_params.wdp_heads == 0)
printf("(unknown size) <"); printf("(unknown size) <");
else else
@ -278,7 +276,7 @@ wdattach(struct isa_device *dvp)
printf(">\n"); printf(">\n");
} else { } else {
/*printf("wd%d at wdc%d slave %d -- error\n", lunit, /*printf("wd%d at wdc%d slave %d -- error\n", lunit,
dvp->id_masunit, unit);*/ isa_dev->id_masunit, unit);*/
wddrives[lunit] = 0; wddrives[lunit] = 0;
free(du, M_TEMP); free(du, M_TEMP);
return 0; return 0;
@ -292,9 +290,10 @@ wdattach(struct isa_device *dvp)
* be a multiple of a sector in length. * be a multiple of a sector in length.
*/ */
int int
wdstrategy(register struct buf *bp) wdstrategy(bp)
struct buf *bp;
{ {
register struct buf *dp; struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */ struct disk *du; /* Disk unit to do the IO. */
int lunit = WDUNIT(bp->b_dev); int lunit = WDUNIT(bp->b_dev);
int s; int s;
@ -349,9 +348,10 @@ done:
* Need to skip over multitransfer bufs. * Need to skip over multitransfer bufs.
*/ */
void void
wddisksort(struct buf *dp, struct buf *bp) wddisksort(dp, bp)
struct buf *dp, *bp;
{ {
register struct buf *ap; struct buf *ap;
while ((ap = dp->b_actf) && ap->b_flags & B_XXX) while ((ap = dp->b_actf) && ap->b_flags & B_XXX)
dp = ap; dp = ap;
@ -364,9 +364,10 @@ wddisksort(struct buf *dp, struct buf *bp)
* If the controller is idle, the transfer is started. * If the controller is idle, the transfer is started.
*/ */
static void static void
wdustart(register struct disk *du) wdustart(du)
struct disk *du;
{ {
register struct buf *dp = &wdutab[du->dk_lunit]; struct buf *dp = &wdutab[du->dk_lunit];
int ctrlr = du->dk_ctrlr; int ctrlr = du->dk_ctrlr;
/* unit already active? */ /* unit already active? */
@ -397,7 +398,8 @@ wdustart(register struct disk *du)
* 1. The transfer length must be an exact multiple of the sector size. * 1. The transfer length must be an exact multiple of the sector size.
*/ */
static void static void
wdstart(int ctrlr) wdstart(ctrlr)
int ctrlr;
{ {
register struct disk *du; /* disk unit for IO */ register struct disk *du; /* disk unit for IO */
register struct buf *bp; register struct buf *bp;
@ -430,7 +432,7 @@ loop:
du = wddrives[lunit]; du = wddrives[lunit];
/* clear any pending timeout, just in case */ /* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0; du->dk_timeout = 0;
/* if not really a transfer, do control operations specially */ /* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) { if (du->dk_state < OPEN) {
@ -606,7 +608,7 @@ retry:
/* if this is a read operation, just go away until it's done. */ /* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) { if (bp->b_flags & B_READ) {
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
return; return;
} }
@ -621,7 +623,7 @@ retry:
du->dk_bc -= DEV_BSIZE; du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE; du->dk_bct -= DEV_BSIZE;
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
} }
/* Interrupt routine for the controller. Acknowledge the interrupt, check for /* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -630,7 +632,8 @@ retry:
* continue with the next chunk if so. * continue with the next chunk if so.
*/ */
void void
wdintr(int ctrlr) wdintr(ctrlr)
int ctrlr;
{ {
register struct disk *du; register struct disk *du;
register struct buf *bp, *dp; register struct buf *bp, *dp;
@ -645,7 +648,7 @@ wdintr(int ctrlr)
bp = dp->b_actf; bp = dp->b_actf;
du = wddrives[WDUNIT(bp->b_dev)]; du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port; wdc = du->dk_port;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0; du->dk_timeout = 0;
#ifdef WDDEBUG #ifdef WDDEBUG
printf("I%d ", ctrlr); printf("I%d ", ctrlr);
@ -799,7 +802,11 @@ done:
* Initialize a drive. * Initialize a drive.
*/ */
int int
wdopen(dev_t dev, int flags, int fmt, struct proc *p) wdopen(dev, flag, fmt, p)
dev_t dev;
int flag;
int fmt;
struct proc *p;
{ {
int lunit; int lunit;
struct disk *du; struct disk *du;
@ -842,11 +849,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
du->dk_state = WANTOPEN; du->dk_state = WANTOPEN;
/* read label using "raw" partition */ /* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage) #ifdef notdef
/* wdsetctlr(dev, du); */ /* Maybe do this TIH */ /* wdsetctlr(du); */ /* Maybe do this TIH */
msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW), msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW),
wdstrategy, &du->dk_dd, &du->dk_cpd); wdstrategy, &du->dk_dd, &du->dk_cpd);
wdsetctlr(dev, du); wdsetctlr(du);
#endif #endif
if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev),
WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) { WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) {
@ -857,7 +864,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
return EINVAL; /* XXX needs translation */ return EINVAL; /* XXX needs translation */
} }
} else { } else {
wdsetctlr(dev, du); wdsetctlr(du);
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
du->dk_flags &= ~DKFL_WRITEPROT; du->dk_flags &= ~DKFL_WRITEPROT;
if (du->dk_dd.d_flags & D_BADSECT) if (du->dk_dd.d_flags & D_BADSECT)
@ -917,7 +924,8 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
* Returns 0 if operation still in progress, 1 if completed. * Returns 0 if operation still in progress, 1 if completed.
*/ */
static int static int
wdcontrol(register struct buf *bp) wdcontrol(bp)
struct buf *bp;
{ {
struct disk *du; struct disk *du;
int unit, lunit; int unit, lunit;
@ -938,27 +946,23 @@ wdcontrol(register struct buf *bp)
printf("wd%d: recal ", lunit); printf("wd%d: recal ", lunit);
#endif #endif
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du); wdgetctlr(du);
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
wdreset(du, 1); wdreset(du, 1);
goto tryagainrecal; goto tryagainrecal;
} }
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) { if (wait_for_ready(du) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1; wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) { if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
du->dk_state = RECAL; du->dk_state = RECAL;
splx(s); splx(s);
return 0; return 0;
case RECAL: case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) { if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) { if ((du->dk_flags & DKFL_QUIET) == 0) {
@ -973,7 +977,7 @@ wdcontrol(register struct buf *bp)
} }
/* some controllers require this ... */ /* some controllers require this ... */
wdsetctlr(bp->b_dev, du); wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0; wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN; du->dk_state = OPEN;
@ -982,6 +986,7 @@ wdcontrol(register struct buf *bp)
* by normal means. * by normal means.
*/ */
return 1; return 1;
default: default:
panic("wdcontrol"); panic("wdcontrol");
} }
@ -1002,7 +1007,9 @@ badopen:
* assumes interrupts are blocked. * assumes interrupts are blocked.
*/ */
static int static int
wdcommand(struct disk *du, int cmd) wdcommand(du, cmd)
struct disk *du;
int cmd;
{ {
int stat, wdc; int stat, wdc;
@ -1037,7 +1044,8 @@ wdcommand(struct disk *du, int cmd)
* issue IDC to drive to tell it just what geometry it is to be. * issue IDC to drive to tell it just what geometry it is to be.
*/ */
static int static int
wdsetctlr(dev_t dev, struct disk *du) wdsetctlr(du)
struct disk *du;
{ {
int stat, s, wdc; int stat, s, wdc;
@ -1070,7 +1078,8 @@ wdsetctlr(dev_t dev, struct disk *du)
* issue READP to drive to ask it what it is. * issue READP to drive to ask it what it is.
*/ */
static int static int
wdgetctlr(int u, struct disk *du) wdgetctlr(du)
struct disk *du;
{ {
int stat, s, i, wdc; int stat, s, i, wdc;
char tb[DEV_BSIZE]; char tb[DEV_BSIZE];
@ -1079,21 +1088,16 @@ wdgetctlr(int u, struct disk *du)
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdc = du->dk_port; wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
splx(s); splx(s);
return -1; return -1;
} }
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); if (wait_for_ready(du) < 0)
if (wait_for_ready(du) < 0) { goto lose;
splx(s);
return -1;
}
stat = wdcommand(du, WDCC_READP); stat = wdcommand(du, WDCC_READP);
if (stat < 0) { if (stat < 0)
splx(s); goto lose;
return -1;
}
if ((stat & WDCS_ERR) == 0) { if ((stat & WDCS_ERR) == 0) {
/* obtain parameters */ /* obtain parameters */
@ -1157,10 +1161,11 @@ wdgetctlr(int u, struct disk *du)
return 0; return 0;
} }
/* ARGSUSED */
int int
wdclose(dev_t dev, int flags, int fmt) wdclose(dev, flag, fmt)
dev_t dev;
int flag;
int fmt;
{ {
struct disk *du; struct disk *du;
int part = WDPART(dev), mask = 1 << part; int part = WDPART(dev), mask = 1 << part;
@ -1181,7 +1186,12 @@ wdclose(dev_t dev, int flags, int fmt)
} }
int int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) wdioctl(dev, cmd, addr, flag, p)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
struct proc *p;
{ {
int lunit = WDUNIT(dev); int lunit = WDUNIT(dev);
struct disk *du = wddrives[lunit]; struct disk *du = wddrives[lunit];
@ -1214,7 +1224,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
&du->dk_cpd); &du->dk_cpd);
if (error == 0) { if (error == 0) {
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
} }
return error; return error;
@ -1237,7 +1247,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
int wlab; int wlab;
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
/* simulate opening partition 0 so write succeeds */ /* simulate opening partition 0 so write succeeds */
du->dk_openpart |= (1 << 0); /* XXX */ du->dk_openpart |= (1 << 0); /* XXX */
@ -1300,7 +1310,8 @@ wdformat(struct buf *bp)
#endif #endif
int int
wdsize(dev_t dev) wdsize(dev)
dev_t dev;
{ {
int lunit = WDUNIT(dev), part = WDPART(dev); int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du; struct disk *du;
@ -1315,6 +1326,7 @@ wdsize(dev_t dev)
int val; int val;
val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD,
S_IFBLK, 0); S_IFBLK, 0);
/* XXX Clear the open flag? */
if (val != 0) if (val != 0)
return -1; return -1;
} }
@ -1325,11 +1337,10 @@ wdsize(dev_t dev)
return (int)du->dk_dd.d_partitions[part].p_size; return (int)du->dk_dd.d_partitions[part].p_size;
} }
extern char *vmmap; /* poor name! */
/* dump core after a system crash */ /* dump core after a system crash */
int int
wddump(dev_t dev) wddump(dev)
dev_t dev;
{ {
register struct disk *du; /* disk unit to do the IO */ register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */ long num; /* number of sectors to write */
@ -1397,7 +1408,7 @@ wddump(dev_t dev)
return EIO; return EIO;
/* some compaq controllers require this ... */ /* some compaq controllers require this ... */
wdsetctlr(dev, du); wdsetctlr(du);
blknum = dumplo + blkoff; blknum = dumplo + blkoff;
while (num > 0) { while (num > 0) {
@ -1491,27 +1502,31 @@ wddump(dev_t dev)
* Internalize the bad sector table. * Internalize the bad sector table.
*/ */
void void
bad144intern(struct disk *du) bad144intern(du)
struct disk *du;
{ {
int i; int i;
if (du->dk_flags & DKFL_BADSECT) {
for (i = 0; i < 127; i++) if ((du->dk_flags & DKFL_BADSECT) == 0)
du->dk_badsect[i] = -1; return;
for (i = 0; i < 126; i++) {
if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) for (i = 0; i < 127; i++)
break; du->dk_badsect[i] = -1;
du->dk_badsect[i] = for (i = 0; i < 126; i++) {
du->dk_cpd.bad.bt_bad[i].bt_cyl * if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff)
du->dk_dd.d_secpercyl + break;
(du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * du->dk_badsect[i] =
du->dk_dd.d_nsectors + du->dk_cpd.bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) *
} du->dk_dd.d_nsectors +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff);
} }
} }
static int static int
wdreset(struct disk *du, int err) wdreset(du, err)
struct disk *du;
int err;
{ {
int wdc = du->dk_port; int wdc = du->dk_port;
int stat; int stat;
@ -1522,6 +1537,9 @@ wdreset(struct disk *du, int err)
/* reset the device */ /* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000); DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT); outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(du) < 0) if (wait_for_unbusy(du) < 0)
@ -1541,9 +1559,9 @@ wdc_wait(du, mask)
stat = inb(wdc+wd_altsts); stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask) if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask)
break; break;
DELAY(WDCDELAY);
if (++timeout > WDCNDELAY) if (++timeout > WDCNDELAY)
return -1; return -1;
DELAY(WDCDELAY);
} }
#ifdef WDCNDELAY_DEBUG #ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG) if (timeout > WDCNDELAY_DEBUG)
@ -1554,29 +1572,24 @@ wdc_wait(du, mask)
} }
static int static int
wdtimeout(caddr_t arg) wdtimeout(arg)
caddr_t arg;
{ {
int x = splbio(); int s = splbio();
register int unit = (int)arg; struct disk *du = (void *)arg;
if (wdtimeoutstatus[unit] && --wdtimeoutstatus[unit] == 0) { if (du->dk_timeout && --du->dk_timeout == 0) {
struct disk *du = wddrives[unit];
int wdc = du->dk_port; int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n", printf("wd%d: lost interrupt - status %x, error %x\n",
unit, inb(wdc+wd_status), inb(wdc+wd_error)); du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); wdreset(du, 0);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT);
du->dk_skip = 0; du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE; du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */ wdstart(du->dk_ctrlr); /* start controller */
} }
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2); timeout((timeout_t)wdtimeout, arg, hz);
splx(x); splx(s);
return 0; return 0;
} }

View File

@ -35,15 +35,12 @@
* 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.54 1994/03/03 01:58:21 mycroft Exp $ * $Id: wd.c,v 1.55 1994/03/04 03:43:48 mycroft Exp $
*/ */
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */ #define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
#define INSTRUMENT /* instrumentation stuff by Brad Parker */ #define INSTRUMENT /* instrumentation stuff by Brad Parker */
/* TODO: peel out buffer at low ipl, speed improvement */
/* TODO: find and fix the timing bugs apparent on some controllers */
#include "wd.h" #include "wd.h"
#if NWDC > 0 #if NWDC > 0
@ -113,6 +110,7 @@ struct disk {
char dk_unit; /* physical unit number */ char dk_unit; /* physical unit number */
char dk_lunit; /* logical unit number */ char dk_lunit; /* logical unit number */
char dk_state; /* control state */ char dk_state; /* control state */
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */ u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */ u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */ short dk_port; /* i/o port base */
@ -144,7 +142,6 @@ struct buf wdtab[NWDC]; /* various per-controller info */
struct buf wdutab[NWD]; /* head of queue per drive */ struct buf wdutab[NWD]; /* head of queue per drive */
struct buf rwdbuf[NWD]; /* buffers for raw IO */ struct buf rwdbuf[NWD]; /* buffers for raw IO */
long wdxfer[NWD]; /* count of transfers */ long wdxfer[NWD]; /* count of transfers */
int wdtimeoutstatus[NWD]; /* timeout counters */
int wdprobe(), wdattach(); int wdprobe(), wdattach();
@ -152,17 +149,17 @@ struct isa_driver wdcdriver = {
wdprobe, wdattach, "wdc", wdprobe, wdattach, "wdc",
}; };
static void wdustart(struct disk *); static void wdustart __P((struct disk *));
static void wdstart(int); static void wdstart __P((int));
static int wdcommand(struct disk *, int); static int wdcommand __P((struct disk *, int));
static int wdcontrol(struct buf *); static int wdcontrol __P((struct buf *));
static int wdsetctlr(dev_t, struct disk *); static int wdsetctlr __P((struct disk *));
static int wdgetctlr(int, struct disk *); static int wdgetctlr __P((struct disk *));
static void bad144intern(struct disk *); static void bad144intern __P((struct disk *));
static int wdreset(struct disk *, int); static int wdreset __P((struct disk *, int));
static int wdtimeout(caddr_t); static int wdtimeout __P((caddr_t));
void wddisksort(struct buf *dp, struct buf *bp); void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait(struct disk *, int); int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ) #define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT) #define wait_for_ready(d) wdc_wait(d, WDCS_READY | WDCS_SEEKCMPLT)
#define wait_for_unbusy(d) wdc_wait(d, 0) #define wait_for_unbusy(d) wdc_wait(d, 0)
@ -171,23 +168,24 @@ int wdc_wait(struct disk *, int);
* Probe for controller. * Probe for controller.
*/ */
int int
wdprobe(struct isa_device *dvp) wdprobe(isa_dev)
struct isa_device *isa_dev;
{ {
struct disk *du; struct disk *du;
int wdc; int wdc;
if (dvp->id_unit >= NWDC) if (isa_dev->id_unit >= NWDC)
return 0; return 0;
du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); du = (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
bzero(du, sizeof(struct disk)); bzero(du, sizeof(struct disk));
du->dk_ctrlr = dvp->id_unit; du->dk_ctrlr = isa_dev->id_unit;
du->dk_unit = 0; du->dk_unit = 0;
du->dk_lunit = 0; du->dk_lunit = 0;
wdcontroller[dvp->id_unit].dkc_port = dvp->id_iobase; wdcontroller[isa_dev->id_unit].dkc_port = isa_dev->id_iobase;
wdc = du->dk_port = dvp->id_iobase; wdc = du->dk_port = isa_dev->id_iobase;
/* check if we have registers that work */ /* check if we have registers that work */
outb(wdc+wd_error, 0x5a); /* error register not writable */ outb(wdc+wd_error, 0x5a); /* error register not writable */
@ -214,24 +212,25 @@ nodevice:
* Attach each drive if possible. * Attach each drive if possible.
*/ */
int int
wdattach(struct isa_device *dvp) wdattach(isa_dev)
struct isa_device *isa_dev;
{ {
int unit, lunit; int unit, lunit;
struct disk *du; struct disk *du;
if (dvp->id_masunit == -1) if (isa_dev->id_masunit == -1)
return 0; return 0;
if (dvp->id_masunit >= NWDC) if (isa_dev->id_masunit >= NWDC)
return 0; return 0;
lunit = dvp->id_unit; lunit = isa_dev->id_unit;
if (lunit == -1) { if (lunit == -1) {
printf("wdc%d: cannot support unit ?\n", dvp->id_masunit); printf("wdc%d: cannot support unit ?\n", isa_dev->id_masunit);
return 0; return 0;
} }
if (lunit >= NWD) if (lunit >= NWD)
return 0; return 0;
unit = dvp->id_physid; unit = isa_dev->id_physid;
du = wddrives[lunit] = du = wddrives[lunit] =
(struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT); (struct disk *)malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
@ -239,18 +238,17 @@ wdattach(struct isa_device *dvp)
bzero(&wdutab[lunit], sizeof(struct buf)); bzero(&wdutab[lunit], sizeof(struct buf));
bzero(&rwdbuf[lunit], sizeof(struct buf)); bzero(&rwdbuf[lunit], sizeof(struct buf));
wdxfer[lunit] = 0; wdxfer[lunit] = 0;
wdtimeoutstatus[lunit] = 0; wdtimeout((caddr_t)du);
wdtimeout(lunit); du->dk_ctrlr = isa_dev->id_masunit;
du->dk_ctrlr = dvp->id_masunit;
du->dk_unit = unit; du->dk_unit = unit;
du->dk_lunit = lunit; du->dk_lunit = lunit;
du->dk_port = wdcontroller[dvp->id_masunit].dkc_port; du->dk_port = wdcontroller[isa_dev->id_masunit].dkc_port;
if (wdgetctlr(unit, du) == 0) { if (wdgetctlr(du) == 0) {
int i, blank; int i, blank;
printf("wd%d at wdc%d targ %d: ", dvp->id_unit, printf("wd%d at wdc%d targ %d: ", isa_dev->id_unit,
dvp->id_masunit, dvp->id_physid); isa_dev->id_masunit, isa_dev->id_physid);
if (du->dk_params.wdp_heads == 0) if (du->dk_params.wdp_heads == 0)
printf("(unknown size) <"); printf("(unknown size) <");
else else
@ -278,7 +276,7 @@ wdattach(struct isa_device *dvp)
printf(">\n"); printf(">\n");
} else { } else {
/*printf("wd%d at wdc%d slave %d -- error\n", lunit, /*printf("wd%d at wdc%d slave %d -- error\n", lunit,
dvp->id_masunit, unit);*/ isa_dev->id_masunit, unit);*/
wddrives[lunit] = 0; wddrives[lunit] = 0;
free(du, M_TEMP); free(du, M_TEMP);
return 0; return 0;
@ -292,9 +290,10 @@ wdattach(struct isa_device *dvp)
* be a multiple of a sector in length. * be a multiple of a sector in length.
*/ */
int int
wdstrategy(register struct buf *bp) wdstrategy(bp)
struct buf *bp;
{ {
register struct buf *dp; struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */ struct disk *du; /* Disk unit to do the IO. */
int lunit = WDUNIT(bp->b_dev); int lunit = WDUNIT(bp->b_dev);
int s; int s;
@ -349,9 +348,10 @@ done:
* Need to skip over multitransfer bufs. * Need to skip over multitransfer bufs.
*/ */
void void
wddisksort(struct buf *dp, struct buf *bp) wddisksort(dp, bp)
struct buf *dp, *bp;
{ {
register struct buf *ap; struct buf *ap;
while ((ap = dp->b_actf) && ap->b_flags & B_XXX) while ((ap = dp->b_actf) && ap->b_flags & B_XXX)
dp = ap; dp = ap;
@ -364,9 +364,10 @@ wddisksort(struct buf *dp, struct buf *bp)
* If the controller is idle, the transfer is started. * If the controller is idle, the transfer is started.
*/ */
static void static void
wdustart(register struct disk *du) wdustart(du)
struct disk *du;
{ {
register struct buf *dp = &wdutab[du->dk_lunit]; struct buf *dp = &wdutab[du->dk_lunit];
int ctrlr = du->dk_ctrlr; int ctrlr = du->dk_ctrlr;
/* unit already active? */ /* unit already active? */
@ -397,7 +398,8 @@ wdustart(register struct disk *du)
* 1. The transfer length must be an exact multiple of the sector size. * 1. The transfer length must be an exact multiple of the sector size.
*/ */
static void static void
wdstart(int ctrlr) wdstart(ctrlr)
int ctrlr;
{ {
register struct disk *du; /* disk unit for IO */ register struct disk *du; /* disk unit for IO */
register struct buf *bp; register struct buf *bp;
@ -430,7 +432,7 @@ loop:
du = wddrives[lunit]; du = wddrives[lunit];
/* clear any pending timeout, just in case */ /* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0; du->dk_timeout = 0;
/* if not really a transfer, do control operations specially */ /* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) { if (du->dk_state < OPEN) {
@ -606,7 +608,7 @@ retry:
/* if this is a read operation, just go away until it's done. */ /* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) { if (bp->b_flags & B_READ) {
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
return; return;
} }
@ -621,7 +623,7 @@ retry:
du->dk_bc -= DEV_BSIZE; du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE; du->dk_bct -= DEV_BSIZE;
wdtimeoutstatus[lunit] = 2; du->dk_timeout = 2;
} }
/* Interrupt routine for the controller. Acknowledge the interrupt, check for /* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -630,7 +632,8 @@ retry:
* continue with the next chunk if so. * continue with the next chunk if so.
*/ */
void void
wdintr(int ctrlr) wdintr(ctrlr)
int ctrlr;
{ {
register struct disk *du; register struct disk *du;
register struct buf *bp, *dp; register struct buf *bp, *dp;
@ -645,7 +648,7 @@ wdintr(int ctrlr)
bp = dp->b_actf; bp = dp->b_actf;
du = wddrives[WDUNIT(bp->b_dev)]; du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port; wdc = du->dk_port;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0; du->dk_timeout = 0;
#ifdef WDDEBUG #ifdef WDDEBUG
printf("I%d ", ctrlr); printf("I%d ", ctrlr);
@ -799,7 +802,11 @@ done:
* Initialize a drive. * Initialize a drive.
*/ */
int int
wdopen(dev_t dev, int flags, int fmt, struct proc *p) wdopen(dev, flag, fmt, p)
dev_t dev;
int flag;
int fmt;
struct proc *p;
{ {
int lunit; int lunit;
struct disk *du; struct disk *du;
@ -842,11 +849,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
du->dk_state = WANTOPEN; du->dk_state = WANTOPEN;
/* read label using "raw" partition */ /* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage) #ifdef notdef
/* wdsetctlr(dev, du); */ /* Maybe do this TIH */ /* wdsetctlr(du); */ /* Maybe do this TIH */
msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW), msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), WDRAW),
wdstrategy, &du->dk_dd, &du->dk_cpd); wdstrategy, &du->dk_dd, &du->dk_cpd);
wdsetctlr(dev, du); wdsetctlr(du);
#endif #endif
if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev), if (msg = readdisklabel(makewddev(major(dev), WDUNIT(dev),
WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) { WDRAW), wdstrategy, &du->dk_dd, &du->dk_cpd)) {
@ -857,7 +864,7 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
return EINVAL; /* XXX needs translation */ return EINVAL; /* XXX needs translation */
} }
} else { } else {
wdsetctlr(dev, du); wdsetctlr(du);
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
du->dk_flags &= ~DKFL_WRITEPROT; du->dk_flags &= ~DKFL_WRITEPROT;
if (du->dk_dd.d_flags & D_BADSECT) if (du->dk_dd.d_flags & D_BADSECT)
@ -917,7 +924,8 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
* Returns 0 if operation still in progress, 1 if completed. * Returns 0 if operation still in progress, 1 if completed.
*/ */
static int static int
wdcontrol(register struct buf *bp) wdcontrol(bp)
struct buf *bp;
{ {
struct disk *du; struct disk *du;
int unit, lunit; int unit, lunit;
@ -938,27 +946,23 @@ wdcontrol(register struct buf *bp)
printf("wd%d: recal ", lunit); printf("wd%d: recal ", lunit);
#endif #endif
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du); wdgetctlr(du);
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
wdreset(du, 1); wdreset(du, 1);
goto tryagainrecal; goto tryagainrecal;
} }
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) { if (wait_for_ready(du) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1; wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) { if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
wdreset(du, 1); goto lose;
goto tryagainrecal;
}
du->dk_state = RECAL; du->dk_state = RECAL;
splx(s); splx(s);
return 0; return 0;
case RECAL: case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) { if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) { if ((du->dk_flags & DKFL_QUIET) == 0) {
@ -973,7 +977,7 @@ wdcontrol(register struct buf *bp)
} }
/* some controllers require this ... */ /* some controllers require this ... */
wdsetctlr(bp->b_dev, du); wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0; wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN; du->dk_state = OPEN;
@ -982,6 +986,7 @@ wdcontrol(register struct buf *bp)
* by normal means. * by normal means.
*/ */
return 1; return 1;
default: default:
panic("wdcontrol"); panic("wdcontrol");
} }
@ -1002,7 +1007,9 @@ badopen:
* assumes interrupts are blocked. * assumes interrupts are blocked.
*/ */
static int static int
wdcommand(struct disk *du, int cmd) wdcommand(du, cmd)
struct disk *du;
int cmd;
{ {
int stat, wdc; int stat, wdc;
@ -1037,7 +1044,8 @@ wdcommand(struct disk *du, int cmd)
* issue IDC to drive to tell it just what geometry it is to be. * issue IDC to drive to tell it just what geometry it is to be.
*/ */
static int static int
wdsetctlr(dev_t dev, struct disk *du) wdsetctlr(du)
struct disk *du;
{ {
int stat, s, wdc; int stat, s, wdc;
@ -1070,7 +1078,8 @@ wdsetctlr(dev_t dev, struct disk *du)
* issue READP to drive to ask it what it is. * issue READP to drive to ask it what it is.
*/ */
static int static int
wdgetctlr(int u, struct disk *du) wdgetctlr(du)
struct disk *du;
{ {
int stat, s, i, wdc; int stat, s, i, wdc;
char tb[DEV_BSIZE]; char tb[DEV_BSIZE];
@ -1079,21 +1088,16 @@ wdgetctlr(int u, struct disk *du)
s = splbio(); /* not called from intr level ... */ s = splbio(); /* not called from intr level ... */
wdc = du->dk_port; wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) { if (wait_for_unbusy(du) < 0) {
lose:
splx(s); splx(s);
return -1; return -1;
} }
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_sdh, WDSD_IBM | (u << 4)); if (wait_for_ready(du) < 0)
if (wait_for_ready(du) < 0) { goto lose;
splx(s);
return -1;
}
stat = wdcommand(du, WDCC_READP); stat = wdcommand(du, WDCC_READP);
if (stat < 0) { if (stat < 0)
splx(s); goto lose;
return -1;
}
if ((stat & WDCS_ERR) == 0) { if ((stat & WDCS_ERR) == 0) {
/* obtain parameters */ /* obtain parameters */
@ -1157,10 +1161,11 @@ wdgetctlr(int u, struct disk *du)
return 0; return 0;
} }
/* ARGSUSED */
int int
wdclose(dev_t dev, int flags, int fmt) wdclose(dev, flag, fmt)
dev_t dev;
int flag;
int fmt;
{ {
struct disk *du; struct disk *du;
int part = WDPART(dev), mask = 1 << part; int part = WDPART(dev), mask = 1 << part;
@ -1181,7 +1186,12 @@ wdclose(dev_t dev, int flags, int fmt)
} }
int int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) wdioctl(dev, cmd, addr, flag, p)
dev_t dev;
int cmd;
caddr_t addr;
int flag;
struct proc *p;
{ {
int lunit = WDUNIT(dev); int lunit = WDUNIT(dev);
struct disk *du = wddrives[lunit]; struct disk *du = wddrives[lunit];
@ -1214,7 +1224,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
&du->dk_cpd); &du->dk_cpd);
if (error == 0) { if (error == 0) {
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
} }
return error; return error;
@ -1237,7 +1247,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
int wlab; int wlab;
du->dk_flags |= DKFL_BSDLABEL; du->dk_flags |= DKFL_BSDLABEL;
wdsetctlr(dev, du); wdsetctlr(du);
/* simulate opening partition 0 so write succeeds */ /* simulate opening partition 0 so write succeeds */
du->dk_openpart |= (1 << 0); /* XXX */ du->dk_openpart |= (1 << 0); /* XXX */
@ -1300,7 +1310,8 @@ wdformat(struct buf *bp)
#endif #endif
int int
wdsize(dev_t dev) wdsize(dev)
dev_t dev;
{ {
int lunit = WDUNIT(dev), part = WDPART(dev); int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du; struct disk *du;
@ -1315,6 +1326,7 @@ wdsize(dev_t dev)
int val; int val;
val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD,
S_IFBLK, 0); S_IFBLK, 0);
/* XXX Clear the open flag? */
if (val != 0) if (val != 0)
return -1; return -1;
} }
@ -1325,11 +1337,10 @@ wdsize(dev_t dev)
return (int)du->dk_dd.d_partitions[part].p_size; return (int)du->dk_dd.d_partitions[part].p_size;
} }
extern char *vmmap; /* poor name! */
/* dump core after a system crash */ /* dump core after a system crash */
int int
wddump(dev_t dev) wddump(dev)
dev_t dev;
{ {
register struct disk *du; /* disk unit to do the IO */ register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */ long num; /* number of sectors to write */
@ -1397,7 +1408,7 @@ wddump(dev_t dev)
return EIO; return EIO;
/* some compaq controllers require this ... */ /* some compaq controllers require this ... */
wdsetctlr(dev, du); wdsetctlr(du);
blknum = dumplo + blkoff; blknum = dumplo + blkoff;
while (num > 0) { while (num > 0) {
@ -1491,27 +1502,31 @@ wddump(dev_t dev)
* Internalize the bad sector table. * Internalize the bad sector table.
*/ */
void void
bad144intern(struct disk *du) bad144intern(du)
struct disk *du;
{ {
int i; int i;
if (du->dk_flags & DKFL_BADSECT) {
for (i = 0; i < 127; i++) if ((du->dk_flags & DKFL_BADSECT) == 0)
du->dk_badsect[i] = -1; return;
for (i = 0; i < 126; i++) {
if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff) for (i = 0; i < 127; i++)
break; du->dk_badsect[i] = -1;
du->dk_badsect[i] = for (i = 0; i < 126; i++) {
du->dk_cpd.bad.bt_bad[i].bt_cyl * if (du->dk_cpd.bad.bt_bad[i].bt_cyl == 0xffff)
du->dk_dd.d_secpercyl + break;
(du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) * du->dk_badsect[i] =
du->dk_dd.d_nsectors + du->dk_cpd.bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff); (du->dk_cpd.bad.bt_bad[i].bt_trksec >> 8) *
} du->dk_dd.d_nsectors +
(du->dk_cpd.bad.bt_bad[i].bt_trksec & 0x00ff);
} }
} }
static int static int
wdreset(struct disk *du, int err) wdreset(du, err)
struct disk *du;
int err;
{ {
int wdc = du->dk_port; int wdc = du->dk_port;
int stat; int stat;
@ -1522,6 +1537,9 @@ wdreset(struct disk *du, int err)
/* reset the device */ /* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000); DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT); outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(du) < 0) if (wait_for_unbusy(du) < 0)
@ -1541,9 +1559,9 @@ wdc_wait(du, mask)
stat = inb(wdc+wd_altsts); stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask) if ((stat & WDCS_BUSY) == 0 && (stat & mask) == mask)
break; break;
DELAY(WDCDELAY);
if (++timeout > WDCNDELAY) if (++timeout > WDCNDELAY)
return -1; return -1;
DELAY(WDCDELAY);
} }
#ifdef WDCNDELAY_DEBUG #ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG) if (timeout > WDCNDELAY_DEBUG)
@ -1554,29 +1572,24 @@ wdc_wait(du, mask)
} }
static int static int
wdtimeout(caddr_t arg) wdtimeout(arg)
caddr_t arg;
{ {
int x = splbio(); int s = splbio();
register int unit = (int)arg; struct disk *du = (void *)arg;
if (wdtimeoutstatus[unit] && --wdtimeoutstatus[unit] == 0) { if (du->dk_timeout && --du->dk_timeout == 0) {
struct disk *du = wddrives[unit];
int wdc = du->dk_port; int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n", printf("wd%d: lost interrupt - status %x, error %x\n",
unit, inb(wdc+wd_status), inb(wdc+wd_error)); du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS); wdreset(du, 0);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_IDS);
DELAY(1000);
(void) inb(wdc+wd_error);
outb(wdc+wd_ctlr, WDCTL_4BIT);
du->dk_skip = 0; du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE; du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */ wdstart(du->dk_ctrlr); /* start controller */
} }
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2); timeout((timeout_t)wdtimeout, arg, hz);
splx(x); splx(s);
return 0; return 0;
} }