Make wdc_wait() do an implicit wait_for_unbusy(). Pass structure pointers

rahter than unit numbers where appropriate.  Fix conflict if two drives have
I/O pending at the same time.  Add some more sanity checks.  Some other minor
cleanup.
This commit is contained in:
mycroft 1994-03-02 21:42:31 +00:00
parent da17512980
commit e9326b3ba7
3 changed files with 453 additions and 402 deletions

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.50 1994/02/26 19:49:25 mycroft Exp $
* $Id: wd.c,v 1.51 1994/03/02 21:42:31 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -75,19 +75,18 @@
#include <i386/isa/icu.h>
#include <i386/isa/wdreg.h>
#ifndef WDCNDELAY
#define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
#endif
#define WDCDELAY 100
#if 0
/* if you enable this, it will report any delays more than 100us * N long */
/*#define WDCNDELAY_DEBUG 2*/
#define WDCNDELAY_DEBUG 100
#endif
#define WDIORETRIES 5 /* number of retries before giving up */
#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
#define wdunit(dev) ((minor(dev) & 0x38) >> 3)
#define wdpart(dev) (minor(dev) & 0x7)
#define WDUNIT(dev) ((minor(dev) & 0xf8) >> 3)
#define WDPART(dev) ((minor(dev) & 0x07) )
#define makewddev(maj, unit, part) (makedev(maj, ((unit << 3) + part)))
#define WDRAW 3 /* 'd' partition isn't a partition! */
@ -160,13 +159,13 @@ static int wdcontrol(struct buf *);
static int wdsetctlr(dev_t, struct disk *);
static int wdgetctlr(int, struct disk *);
static void bad144intern(struct disk *);
static int wdreset(int, int, int);
static int wdreset(struct disk *, int);
static int wdtimeout(caddr_t);
void wddisksort(struct buf *dp, struct buf *bp);
int wdc_wait(int, int, int);
#define wait_for_drq(p, u) wdc_wait(p, u, WDCS_DRQ)
#define wait_for_ready(p, u) wdc_wait(p, u, WDCS_READY)
#define wait_for_unbusy(p, u) wdc_wait(p, u, 0)
int wdc_wait(struct disk *, int);
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY)
#define wait_for_unbusy(d) wdc_wait(d, 0)
/*
* Probe for controller.
@ -196,11 +195,10 @@ wdprobe(struct isa_device *dvp)
if (inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
goto nodevice;
wdreset(dvp->id_unit, wdc, 0);
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0 ||
wait_for_unbusy(wdc, du->dk_ctrlr) < 0)
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -298,7 +296,7 @@ wdstrategy(register struct buf *bp)
{
register struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */
int lunit = wdunit(bp->b_dev);
int lunit = WDUNIT(bp->b_dev);
int s;
/* valid unit, controller, and request? */
@ -318,7 +316,7 @@ wdstrategy(register struct buf *bp)
}
/* have partitions and want to use them? */
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) {
/*
* do bounds checking, adjust transfer. if error, process.
* if end of partition, just return
@ -382,8 +380,8 @@ wdustart(register struct disk *du)
/* link onto controller queue */
dp->b_forw = NULL;
if (wdtab[ctrlr].b_actf == NULL)
wdtab[ctrlr].b_actf = dp;
if (wdtab[ctrlr].b_forw == NULL)
wdtab[ctrlr].b_forw = dp;
else
wdtab[ctrlr].b_actl->b_forw = dp;
wdtab[ctrlr].b_actl = dp;
@ -414,7 +412,7 @@ wdstart(int ctrlr)
loop:
/* is there a drive for the controller to do a transfer with? */
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
if (dp == NULL)
return;
@ -422,13 +420,16 @@ loop:
the controller's queue */
bp = dp->b_actf;
if (bp == NULL) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
goto loop;
}
/* obtain controller and drive information */
lunit = wdunit(bp->b_dev);
lunit = WDUNIT(bp->b_dev);
du = wddrives[lunit];
/* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0;
/* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) {
@ -471,8 +472,8 @@ loop:
lp = &du->dk_dd;
secpertrk = lp->d_nsectors;
secpercyl = lp->d_secpercyl;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset;
cylin = blknum / secpercyl;
head = (blknum % secpercyl) / secpertrk;
sector = blknum % secpertrk;
@ -514,7 +515,7 @@ loop:
}
#ifdef WDDEBUG
pg("c%d h%d s%d ", cylin, head, sector);
printf("c%d h%d s%d ", cylin, head, sector);
#endif
sector++; /* sectors begin with 1, not 0 */
@ -537,14 +538,18 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) {
du->dk_bc += DEV_BSIZE;
du->dk_bct += DEV_BSIZE;
}
/* controller idle? */
if (wait_for_unbusy(wdc, ctrlr) == -1)
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
@ -572,24 +577,26 @@ retry:
/* set up the SDH register (select drive) */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
/* wait for drive to become ready */
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
outb(wdc+wd_command, WDCC_FORMAT);
command = WDCC_FORMAT;
else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
wdreset(du, 1);
goto retry;
}
#ifdef WDDEBUG
printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
cylin, head, addr, inb(wdc+wd_altsts));
@ -602,15 +609,16 @@ retry:
return;
}
/* ready to send data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* clear interrupt from command upload */
(void) inb(wdc+wd_status);
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
@ -623,34 +631,37 @@ retry:
* continue with the next chunk if so.
*/
void
wdintr(struct intrframe wdif)
wdintr(int ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc, ctrlr;
ctrlr = wdif.if_vec;
int stat, wdc;
/* clear the pending interrupt */
stat = inb(wdcontroller[ctrlr].dkc_port+wd_status);
#ifdef WDDEBUG
printf("i%02x ", stat);
#endif
if (!wdtab[ctrlr].b_active) {
printf("wdc%d: extra interrupt\n", ctrlr);
return;
}
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
bp = dp->b_actf;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port;
wdtimeoutstatus[wdunit(bp->b_dev)] = 0;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0;
#ifdef WDDEBUG
printf("I%d ", ctrlr);
#endif
stat = wait_for_unbusy(wdc, ctrlr);
if (stat == -1) {
/* XXXX looks bogus */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_BUSY\n", ctrlr);
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
}
/* is it not a transfer, but a control operation? */
@ -663,6 +674,7 @@ wdintr(struct intrframe wdif)
/* have we an error? */
if (stat & (WDCS_ERR | WDCS_ECCCOR)) {
lose:
du->dk_status = stat;
du->dk_error = inb(wdc+wd_error);
#ifdef WDDEBUG
@ -708,15 +720,14 @@ wdintr(struct intrframe wdif)
*/
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) &&
wdtab[ctrlr].b_active) {
int chk, dummy;
int chk;
chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
/* ready to receive data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
/* XXXX abort here? */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_DRQ\n", ctrlr);
if (wait_for_drq(du) < 0) {
printf("wdc%d: timeout waiting for drq\n", ctrlr);
goto lose;
}
/* suck in data */
@ -727,7 +738,7 @@ wdintr(struct intrframe wdif)
/* for obselete fractional sector reads */
while (chk++ < (DEV_BSIZE / sizeof(short)))
insw(wdc+wd_data, &dummy, 1);
(void) inw(wdc+wd_data);
}
wdxfer[du->dk_lunit]++;
@ -752,13 +763,13 @@ outt:
wdstart(ctrlr);
return; /* next chunk is started */
} else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR)) == DKFL_ERROR) {
wdtab[ctrlr].b_active = 0;
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
return; /* redo xfer sector by sector */
}
}
@ -767,7 +778,7 @@ done:
du->dk_flags &= ~DKFL_SINGLE;
wdtab[ctrlr].b_errcnt = 0;
if (du->dk_bct == 0) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
du->dk_skipm = 0;
dp->b_active = 0;
}
@ -787,7 +798,7 @@ done:
wdustart(du);
/* anything more for controller to do? */
if (wdtab[ctrlr].b_actf)
if (wdtab[ctrlr].b_forw)
wdstart(ctrlr);
}
@ -799,11 +810,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
{
register unsigned int lunit;
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
struct partition *pp;
char *msg;
lunit = wdunit(dev);
lunit = WDUNIT(dev);
if (lunit >= NWD)
return ENXIO;
du = wddrives[lunit];
@ -840,11 +851,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
/* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage)
/* wdsetctlr(dev, 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);
wdsetctlr(dev, du);
#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)) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
log(LOG_WARNING,
@ -921,7 +932,7 @@ wdcontrol(register struct buf *bp)
int s, ctrlr;
int wdc;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
@ -936,22 +947,27 @@ wdcontrol(register struct buf *bp)
s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1;
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
@ -1001,20 +1017,26 @@ wdcommand(struct disk *du, int cmd)
wdc = du->dk_port;
/* controller ready for command? */
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1)
if (wait_for_unbusy(du) < 0)
return -1;
/* send command, await results */
outb(wdc+wd_command, cmd);
stat = wait_for_unbusy(wdc, du->dk_ctrlr);
if (stat == -1)
return -1;
if (cmd != WDCC_READP)
return stat;
/* is controller ready to return data? */
return wdc_wait(wdc, du->dk_ctrlr, WDCS_ERR | WDCS_DRQ);
switch (cmd) {
default:
#if 0
case WDCC_READ:
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_IDC:
case WDCC_DIAGNOSE:
case WDCC_WRITE:
#endif
return wait_for_unbusy(du);
case WDCC_READP:
return wait_for_drq(du);
}
}
/*
@ -1033,14 +1055,17 @@ wdsetctlr(dev_t dev, struct disk *du)
wdc = du->dk_port;
x = splbio();
if (wait_for_unbusy(du) < 0)
return -1;
outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); /* TIH: was ...ders+1 */
outb(wdc+wd_cyl_hi, du->dk_dd.d_ncylinders>>8); /* TIH: was ...ders+1 */
outb(wdc+wd_sdh,
WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks - 1);
outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
if (wait_for_ready(du) < 0)
return -1;
stat = wdcommand(du, WDCC_IDC);
if (stat & WDCS_ERR)
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(x);
@ -1059,26 +1084,21 @@ wdgetctlr(int u, struct disk *du)
x = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1) {
if (wait_for_unbusy(du) < 0) {
splx(x);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
if (wait_for_ready(du) < 0) {
splx(x);
return -1;
}
stat = wdcommand(du, WDCC_READP);
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
splx(x);
return -1;
}
if (stat < 0) {
splx(x);
return stat;
return -1;
}
if ((stat & WDCS_ERR) == 0) {
@ -1116,7 +1136,7 @@ wdgetctlr(int u, struct disk *du)
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat & WDCS_ERR) {
if (stat < 0 || stat & WDCS_ERR) {
splx(x);
return inb(wdc+wd_error);
}
@ -1149,9 +1169,9 @@ int
wdclose(dev_t dev, int flags, int fmt)
{
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
du = wddrives[wdunit(dev)];
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
@ -1169,7 +1189,7 @@ wdclose(dev_t dev, int flags, int fmt)
int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lunit = wdunit(dev);
int lunit = WDUNIT(dev);
register struct disk *du;
int error = 0;
struct uio auio;
@ -1194,7 +1214,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
case DIOCGPART:
((struct partinfo *)addr)->disklab = &du->dk_dd;
((struct partinfo *)addr)->part =
&du->dk_dd.d_partitions[wdpart(dev)];
&du->dk_dd.d_partitions[WDPART(dev)];
break;
case DIOCSDINFO:
@ -1291,7 +1311,7 @@ wdformat(struct buf *bp)
int
wdsize(dev_t dev)
{
int lunit = wdunit(dev), part = wdpart(dev);
int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du;
if (lunit >= NWD)
@ -1340,8 +1360,8 @@ wddump(dev_t dev)
#endif
/* size of memory to dump */
lunit = wdunit(dev);
part = wdpart(dev); /* file system */
lunit = WDUNIT(dev);
part = WDPART(dev); /* file system */
/* check for acceptable drive number */
if (lunit >= NWD)
return ENXIO;
@ -1367,8 +1387,8 @@ wddump(dev_t dev)
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks, dumplo,
num);*/
/*printf("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks,
dumplo, num);*/
/* check transfer bounds against partition size */
if (dumplo < 0 || dumplo + num > nblocks)
return EINVAL;
@ -1377,12 +1397,13 @@ wddump(dev_t dev)
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0))
;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
while (inb(wdc+wd_status) & WDCS_BUSY)
;
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(dev, du);
@ -1415,10 +1436,12 @@ wddump(dev_t dev)
}
sector++; /* origin 1 */
if (wait_for_unbusy(du) < 0)
return EIO;
/* select drive. */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | (head & 0xf));
while ((inb(wdc+wd_status) & WDCS_READY) == 0)
;
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
@ -1427,11 +1450,13 @@ wddump(dev_t dev)
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
pg("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
printf("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
inb(wdc+wd_sector),
(inb(wdc+wd_cyl_hi) << 8) + inb(wdc+wd_cyl_lo), addr);
#endif
outb(wdc+wd_command, WDCC_WRITE);
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
@ -1440,26 +1465,15 @@ wddump(dev_t dev)
tlbflush();
#endif
/* Ready to send data? */
while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
;
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
outsw(wdc+wd_data, CADDR1 + ((int)addr & PGOFSET),
DEV_BSIZE / 2);
DEV_BSIZE / sizeof(short));
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
/* Check data request (should be done). */
if (inb(wdc+wd_status) & WDCS_DRQ)
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
/* wait for completion */
for (i = 200000000; inb(wdc+wd_status) & WDCS_BUSY; i--) {
if (i < 0)
return EIO;
}
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
@ -1506,32 +1520,34 @@ bad144intern(struct disk *du)
}
static int
wdreset(int ctrlr, int wdc, int err)
wdreset(struct disk *du, int err)
{
int wdc = du->dk_port;
int stat;
if (err)
printf("wdc%d: busy too long, resetting\n", ctrlr);
printf("wdc%d: busy too long, resetting\n", du->dk_ctrlr);
/* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(wdc, ctrlr) == -1)
printf("wdc%d: failed to reset controller\n", ctrlr);
if (wait_for_unbusy(du) < 0)
printf("wdc%d: failed to reset controller\n", du->dk_ctrlr);
}
int
wdc_wait(wdc, ctrlr, mask)
int wdc, ctrlr;
wdc_wait(du, mask)
struct disk *du;
int mask;
{
int wdc = du->dk_port;
int timeout = 0;
int stat;
for (;;) {
stat = inb(wdc+wd_status);
stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0)
/* XXXX Yuck. Need to redo this junk. */
if (mask == 0 || (stat & mask) != 0)
@ -1542,7 +1558,8 @@ wdc_wait(wdc, ctrlr, mask)
}
#ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG)
printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout);
printf("wdc%d: timeout took %dus\n", du->dk_ctrlr,
WDCDELAY * timeout);
#endif
return stat;
}
@ -1569,7 +1586,7 @@ wdtimeout(caddr_t arg)
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
}
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz/2);
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2);
splx(x);
return 0;
}

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.50 1994/02/26 19:49:25 mycroft Exp $
* $Id: wd.c,v 1.51 1994/03/02 21:42:31 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -75,19 +75,18 @@
#include <i386/isa/icu.h>
#include <i386/isa/wdreg.h>
#ifndef WDCNDELAY
#define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
#endif
#define WDCDELAY 100
#if 0
/* if you enable this, it will report any delays more than 100us * N long */
/*#define WDCNDELAY_DEBUG 2*/
#define WDCNDELAY_DEBUG 100
#endif
#define WDIORETRIES 5 /* number of retries before giving up */
#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
#define wdunit(dev) ((minor(dev) & 0x38) >> 3)
#define wdpart(dev) (minor(dev) & 0x7)
#define WDUNIT(dev) ((minor(dev) & 0xf8) >> 3)
#define WDPART(dev) ((minor(dev) & 0x07) )
#define makewddev(maj, unit, part) (makedev(maj, ((unit << 3) + part)))
#define WDRAW 3 /* 'd' partition isn't a partition! */
@ -160,13 +159,13 @@ static int wdcontrol(struct buf *);
static int wdsetctlr(dev_t, struct disk *);
static int wdgetctlr(int, struct disk *);
static void bad144intern(struct disk *);
static int wdreset(int, int, int);
static int wdreset(struct disk *, int);
static int wdtimeout(caddr_t);
void wddisksort(struct buf *dp, struct buf *bp);
int wdc_wait(int, int, int);
#define wait_for_drq(p, u) wdc_wait(p, u, WDCS_DRQ)
#define wait_for_ready(p, u) wdc_wait(p, u, WDCS_READY)
#define wait_for_unbusy(p, u) wdc_wait(p, u, 0)
int wdc_wait(struct disk *, int);
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY)
#define wait_for_unbusy(d) wdc_wait(d, 0)
/*
* Probe for controller.
@ -196,11 +195,10 @@ wdprobe(struct isa_device *dvp)
if (inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
goto nodevice;
wdreset(dvp->id_unit, wdc, 0);
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0 ||
wait_for_unbusy(wdc, du->dk_ctrlr) < 0)
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -298,7 +296,7 @@ wdstrategy(register struct buf *bp)
{
register struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */
int lunit = wdunit(bp->b_dev);
int lunit = WDUNIT(bp->b_dev);
int s;
/* valid unit, controller, and request? */
@ -318,7 +316,7 @@ wdstrategy(register struct buf *bp)
}
/* have partitions and want to use them? */
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) {
/*
* do bounds checking, adjust transfer. if error, process.
* if end of partition, just return
@ -382,8 +380,8 @@ wdustart(register struct disk *du)
/* link onto controller queue */
dp->b_forw = NULL;
if (wdtab[ctrlr].b_actf == NULL)
wdtab[ctrlr].b_actf = dp;
if (wdtab[ctrlr].b_forw == NULL)
wdtab[ctrlr].b_forw = dp;
else
wdtab[ctrlr].b_actl->b_forw = dp;
wdtab[ctrlr].b_actl = dp;
@ -414,7 +412,7 @@ wdstart(int ctrlr)
loop:
/* is there a drive for the controller to do a transfer with? */
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
if (dp == NULL)
return;
@ -422,13 +420,16 @@ loop:
the controller's queue */
bp = dp->b_actf;
if (bp == NULL) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
goto loop;
}
/* obtain controller and drive information */
lunit = wdunit(bp->b_dev);
lunit = WDUNIT(bp->b_dev);
du = wddrives[lunit];
/* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0;
/* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) {
@ -471,8 +472,8 @@ loop:
lp = &du->dk_dd;
secpertrk = lp->d_nsectors;
secpercyl = lp->d_secpercyl;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset;
cylin = blknum / secpercyl;
head = (blknum % secpercyl) / secpertrk;
sector = blknum % secpertrk;
@ -514,7 +515,7 @@ loop:
}
#ifdef WDDEBUG
pg("c%d h%d s%d ", cylin, head, sector);
printf("c%d h%d s%d ", cylin, head, sector);
#endif
sector++; /* sectors begin with 1, not 0 */
@ -537,14 +538,18 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) {
du->dk_bc += DEV_BSIZE;
du->dk_bct += DEV_BSIZE;
}
/* controller idle? */
if (wait_for_unbusy(wdc, ctrlr) == -1)
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
@ -572,24 +577,26 @@ retry:
/* set up the SDH register (select drive) */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
/* wait for drive to become ready */
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
outb(wdc+wd_command, WDCC_FORMAT);
command = WDCC_FORMAT;
else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
wdreset(du, 1);
goto retry;
}
#ifdef WDDEBUG
printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
cylin, head, addr, inb(wdc+wd_altsts));
@ -602,15 +609,16 @@ retry:
return;
}
/* ready to send data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* clear interrupt from command upload */
(void) inb(wdc+wd_status);
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
@ -623,34 +631,37 @@ retry:
* continue with the next chunk if so.
*/
void
wdintr(struct intrframe wdif)
wdintr(int ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc, ctrlr;
ctrlr = wdif.if_vec;
int stat, wdc;
/* clear the pending interrupt */
stat = inb(wdcontroller[ctrlr].dkc_port+wd_status);
#ifdef WDDEBUG
printf("i%02x ", stat);
#endif
if (!wdtab[ctrlr].b_active) {
printf("wdc%d: extra interrupt\n", ctrlr);
return;
}
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
bp = dp->b_actf;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port;
wdtimeoutstatus[wdunit(bp->b_dev)] = 0;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0;
#ifdef WDDEBUG
printf("I%d ", ctrlr);
#endif
stat = wait_for_unbusy(wdc, ctrlr);
if (stat == -1) {
/* XXXX looks bogus */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_BUSY\n", ctrlr);
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
}
/* is it not a transfer, but a control operation? */
@ -663,6 +674,7 @@ wdintr(struct intrframe wdif)
/* have we an error? */
if (stat & (WDCS_ERR | WDCS_ECCCOR)) {
lose:
du->dk_status = stat;
du->dk_error = inb(wdc+wd_error);
#ifdef WDDEBUG
@ -708,15 +720,14 @@ wdintr(struct intrframe wdif)
*/
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) &&
wdtab[ctrlr].b_active) {
int chk, dummy;
int chk;
chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
/* ready to receive data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
/* XXXX abort here? */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_DRQ\n", ctrlr);
if (wait_for_drq(du) < 0) {
printf("wdc%d: timeout waiting for drq\n", ctrlr);
goto lose;
}
/* suck in data */
@ -727,7 +738,7 @@ wdintr(struct intrframe wdif)
/* for obselete fractional sector reads */
while (chk++ < (DEV_BSIZE / sizeof(short)))
insw(wdc+wd_data, &dummy, 1);
(void) inw(wdc+wd_data);
}
wdxfer[du->dk_lunit]++;
@ -752,13 +763,13 @@ outt:
wdstart(ctrlr);
return; /* next chunk is started */
} else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR)) == DKFL_ERROR) {
wdtab[ctrlr].b_active = 0;
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
return; /* redo xfer sector by sector */
}
}
@ -767,7 +778,7 @@ done:
du->dk_flags &= ~DKFL_SINGLE;
wdtab[ctrlr].b_errcnt = 0;
if (du->dk_bct == 0) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
du->dk_skipm = 0;
dp->b_active = 0;
}
@ -787,7 +798,7 @@ done:
wdustart(du);
/* anything more for controller to do? */
if (wdtab[ctrlr].b_actf)
if (wdtab[ctrlr].b_forw)
wdstart(ctrlr);
}
@ -799,11 +810,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
{
register unsigned int lunit;
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
struct partition *pp;
char *msg;
lunit = wdunit(dev);
lunit = WDUNIT(dev);
if (lunit >= NWD)
return ENXIO;
du = wddrives[lunit];
@ -840,11 +851,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
/* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage)
/* wdsetctlr(dev, 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);
wdsetctlr(dev, du);
#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)) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
log(LOG_WARNING,
@ -921,7 +932,7 @@ wdcontrol(register struct buf *bp)
int s, ctrlr;
int wdc;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
@ -936,22 +947,27 @@ wdcontrol(register struct buf *bp)
s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1;
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
@ -1001,20 +1017,26 @@ wdcommand(struct disk *du, int cmd)
wdc = du->dk_port;
/* controller ready for command? */
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1)
if (wait_for_unbusy(du) < 0)
return -1;
/* send command, await results */
outb(wdc+wd_command, cmd);
stat = wait_for_unbusy(wdc, du->dk_ctrlr);
if (stat == -1)
return -1;
if (cmd != WDCC_READP)
return stat;
/* is controller ready to return data? */
return wdc_wait(wdc, du->dk_ctrlr, WDCS_ERR | WDCS_DRQ);
switch (cmd) {
default:
#if 0
case WDCC_READ:
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_IDC:
case WDCC_DIAGNOSE:
case WDCC_WRITE:
#endif
return wait_for_unbusy(du);
case WDCC_READP:
return wait_for_drq(du);
}
}
/*
@ -1033,14 +1055,17 @@ wdsetctlr(dev_t dev, struct disk *du)
wdc = du->dk_port;
x = splbio();
if (wait_for_unbusy(du) < 0)
return -1;
outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); /* TIH: was ...ders+1 */
outb(wdc+wd_cyl_hi, du->dk_dd.d_ncylinders>>8); /* TIH: was ...ders+1 */
outb(wdc+wd_sdh,
WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks - 1);
outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
if (wait_for_ready(du) < 0)
return -1;
stat = wdcommand(du, WDCC_IDC);
if (stat & WDCS_ERR)
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(x);
@ -1059,26 +1084,21 @@ wdgetctlr(int u, struct disk *du)
x = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1) {
if (wait_for_unbusy(du) < 0) {
splx(x);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
if (wait_for_ready(du) < 0) {
splx(x);
return -1;
}
stat = wdcommand(du, WDCC_READP);
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
splx(x);
return -1;
}
if (stat < 0) {
splx(x);
return stat;
return -1;
}
if ((stat & WDCS_ERR) == 0) {
@ -1116,7 +1136,7 @@ wdgetctlr(int u, struct disk *du)
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat & WDCS_ERR) {
if (stat < 0 || stat & WDCS_ERR) {
splx(x);
return inb(wdc+wd_error);
}
@ -1149,9 +1169,9 @@ int
wdclose(dev_t dev, int flags, int fmt)
{
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
du = wddrives[wdunit(dev)];
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
@ -1169,7 +1189,7 @@ wdclose(dev_t dev, int flags, int fmt)
int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lunit = wdunit(dev);
int lunit = WDUNIT(dev);
register struct disk *du;
int error = 0;
struct uio auio;
@ -1194,7 +1214,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
case DIOCGPART:
((struct partinfo *)addr)->disklab = &du->dk_dd;
((struct partinfo *)addr)->part =
&du->dk_dd.d_partitions[wdpart(dev)];
&du->dk_dd.d_partitions[WDPART(dev)];
break;
case DIOCSDINFO:
@ -1291,7 +1311,7 @@ wdformat(struct buf *bp)
int
wdsize(dev_t dev)
{
int lunit = wdunit(dev), part = wdpart(dev);
int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du;
if (lunit >= NWD)
@ -1340,8 +1360,8 @@ wddump(dev_t dev)
#endif
/* size of memory to dump */
lunit = wdunit(dev);
part = wdpart(dev); /* file system */
lunit = WDUNIT(dev);
part = WDPART(dev); /* file system */
/* check for acceptable drive number */
if (lunit >= NWD)
return ENXIO;
@ -1367,8 +1387,8 @@ wddump(dev_t dev)
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks, dumplo,
num);*/
/*printf("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks,
dumplo, num);*/
/* check transfer bounds against partition size */
if (dumplo < 0 || dumplo + num > nblocks)
return EINVAL;
@ -1377,12 +1397,13 @@ wddump(dev_t dev)
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0))
;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
while (inb(wdc+wd_status) & WDCS_BUSY)
;
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(dev, du);
@ -1415,10 +1436,12 @@ wddump(dev_t dev)
}
sector++; /* origin 1 */
if (wait_for_unbusy(du) < 0)
return EIO;
/* select drive. */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | (head & 0xf));
while ((inb(wdc+wd_status) & WDCS_READY) == 0)
;
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
@ -1427,11 +1450,13 @@ wddump(dev_t dev)
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
pg("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
printf("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
inb(wdc+wd_sector),
(inb(wdc+wd_cyl_hi) << 8) + inb(wdc+wd_cyl_lo), addr);
#endif
outb(wdc+wd_command, WDCC_WRITE);
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
@ -1440,26 +1465,15 @@ wddump(dev_t dev)
tlbflush();
#endif
/* Ready to send data? */
while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
;
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
outsw(wdc+wd_data, CADDR1 + ((int)addr & PGOFSET),
DEV_BSIZE / 2);
DEV_BSIZE / sizeof(short));
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
/* Check data request (should be done). */
if (inb(wdc+wd_status) & WDCS_DRQ)
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
/* wait for completion */
for (i = 200000000; inb(wdc+wd_status) & WDCS_BUSY; i--) {
if (i < 0)
return EIO;
}
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
@ -1506,32 +1520,34 @@ bad144intern(struct disk *du)
}
static int
wdreset(int ctrlr, int wdc, int err)
wdreset(struct disk *du, int err)
{
int wdc = du->dk_port;
int stat;
if (err)
printf("wdc%d: busy too long, resetting\n", ctrlr);
printf("wdc%d: busy too long, resetting\n", du->dk_ctrlr);
/* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(wdc, ctrlr) == -1)
printf("wdc%d: failed to reset controller\n", ctrlr);
if (wait_for_unbusy(du) < 0)
printf("wdc%d: failed to reset controller\n", du->dk_ctrlr);
}
int
wdc_wait(wdc, ctrlr, mask)
int wdc, ctrlr;
wdc_wait(du, mask)
struct disk *du;
int mask;
{
int wdc = du->dk_port;
int timeout = 0;
int stat;
for (;;) {
stat = inb(wdc+wd_status);
stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0)
/* XXXX Yuck. Need to redo this junk. */
if (mask == 0 || (stat & mask) != 0)
@ -1542,7 +1558,8 @@ wdc_wait(wdc, ctrlr, mask)
}
#ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG)
printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout);
printf("wdc%d: timeout took %dus\n", du->dk_ctrlr,
WDCDELAY * timeout);
#endif
return stat;
}
@ -1569,7 +1586,7 @@ wdtimeout(caddr_t arg)
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
}
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz/2);
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2);
splx(x);
return 0;
}

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.50 1994/02/26 19:49:25 mycroft Exp $
* $Id: wd.c,v 1.51 1994/03/02 21:42:31 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -75,19 +75,18 @@
#include <i386/isa/icu.h>
#include <i386/isa/wdreg.h>
#ifndef WDCNDELAY
#define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */
#endif
#define WDCDELAY 100
#if 0
/* if you enable this, it will report any delays more than 100us * N long */
/*#define WDCNDELAY_DEBUG 2*/
#define WDCNDELAY_DEBUG 100
#endif
#define WDIORETRIES 5 /* number of retries before giving up */
#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
#define wdunit(dev) ((minor(dev) & 0x38) >> 3)
#define wdpart(dev) (minor(dev) & 0x7)
#define WDUNIT(dev) ((minor(dev) & 0xf8) >> 3)
#define WDPART(dev) ((minor(dev) & 0x07) )
#define makewddev(maj, unit, part) (makedev(maj, ((unit << 3) + part)))
#define WDRAW 3 /* 'd' partition isn't a partition! */
@ -160,13 +159,13 @@ static int wdcontrol(struct buf *);
static int wdsetctlr(dev_t, struct disk *);
static int wdgetctlr(int, struct disk *);
static void bad144intern(struct disk *);
static int wdreset(int, int, int);
static int wdreset(struct disk *, int);
static int wdtimeout(caddr_t);
void wddisksort(struct buf *dp, struct buf *bp);
int wdc_wait(int, int, int);
#define wait_for_drq(p, u) wdc_wait(p, u, WDCS_DRQ)
#define wait_for_ready(p, u) wdc_wait(p, u, WDCS_READY)
#define wait_for_unbusy(p, u) wdc_wait(p, u, 0)
int wdc_wait(struct disk *, int);
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
#define wait_for_ready(d) wdc_wait(d, WDCS_READY)
#define wait_for_unbusy(d) wdc_wait(d, 0)
/*
* Probe for controller.
@ -196,11 +195,10 @@ wdprobe(struct isa_device *dvp)
if (inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
goto nodevice;
wdreset(dvp->id_unit, wdc, 0);
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0 ||
wait_for_unbusy(wdc, du->dk_ctrlr) < 0)
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -298,7 +296,7 @@ wdstrategy(register struct buf *bp)
{
register struct buf *dp;
struct disk *du; /* Disk unit to do the IO. */
int lunit = wdunit(bp->b_dev);
int lunit = WDUNIT(bp->b_dev);
int s;
/* valid unit, controller, and request? */
@ -318,7 +316,7 @@ wdstrategy(register struct buf *bp)
}
/* have partitions and want to use them? */
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW) {
/*
* do bounds checking, adjust transfer. if error, process.
* if end of partition, just return
@ -382,8 +380,8 @@ wdustart(register struct disk *du)
/* link onto controller queue */
dp->b_forw = NULL;
if (wdtab[ctrlr].b_actf == NULL)
wdtab[ctrlr].b_actf = dp;
if (wdtab[ctrlr].b_forw == NULL)
wdtab[ctrlr].b_forw = dp;
else
wdtab[ctrlr].b_actl->b_forw = dp;
wdtab[ctrlr].b_actl = dp;
@ -414,7 +412,7 @@ wdstart(int ctrlr)
loop:
/* is there a drive for the controller to do a transfer with? */
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
if (dp == NULL)
return;
@ -422,13 +420,16 @@ loop:
the controller's queue */
bp = dp->b_actf;
if (bp == NULL) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
goto loop;
}
/* obtain controller and drive information */
lunit = wdunit(bp->b_dev);
lunit = WDUNIT(bp->b_dev);
du = wddrives[lunit];
/* clear any pending timeout, just in case */
wdtimeoutstatus[lunit] = 0;
/* if not really a transfer, do control operations specially */
if (du->dk_state < OPEN) {
@ -471,8 +472,8 @@ loop:
lp = &du->dk_dd;
secpertrk = lp->d_nsectors;
secpercyl = lp->d_secpercyl;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
if ((du->dk_flags & DKFL_BSDLABEL) != 0 && WDPART(bp->b_dev) != WDRAW)
blknum += lp->d_partitions[WDPART(bp->b_dev)].p_offset;
cylin = blknum / secpercyl;
head = (blknum % secpercyl) / secpertrk;
sector = blknum % secpertrk;
@ -514,7 +515,7 @@ loop:
}
#ifdef WDDEBUG
pg("c%d h%d s%d ", cylin, head, sector);
printf("c%d h%d s%d ", cylin, head, sector);
#endif
sector++; /* sectors begin with 1, not 0 */
@ -537,14 +538,18 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) {
du->dk_bc += DEV_BSIZE;
du->dk_bct += DEV_BSIZE;
}
/* controller idle? */
if (wait_for_unbusy(wdc, ctrlr) == -1)
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
@ -572,24 +577,26 @@ retry:
/* set up the SDH register (select drive) */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
/* wait for drive to become ready */
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
outb(wdc+wd_command, WDCC_FORMAT);
command = WDCC_FORMAT;
else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
outb(wdc+wd_command,
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
wdreset(du, 1);
goto retry;
}
#ifdef WDDEBUG
printf("sector %d cylin %d head %d addr %x sts %x\n", sector,
cylin, head, addr, inb(wdc+wd_altsts));
@ -602,15 +609,16 @@ retry:
return;
}
/* ready to send data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* clear interrupt from command upload */
(void) inb(wdc+wd_status);
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
@ -623,34 +631,37 @@ retry:
* continue with the next chunk if so.
*/
void
wdintr(struct intrframe wdif)
wdintr(int ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc, ctrlr;
ctrlr = wdif.if_vec;
int stat, wdc;
/* clear the pending interrupt */
stat = inb(wdcontroller[ctrlr].dkc_port+wd_status);
#ifdef WDDEBUG
printf("i%02x ", stat);
#endif
if (!wdtab[ctrlr].b_active) {
printf("wdc%d: extra interrupt\n", ctrlr);
return;
}
dp = wdtab[ctrlr].b_actf;
dp = wdtab[ctrlr].b_forw;
bp = dp->b_actf;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
wdc = du->dk_port;
wdtimeoutstatus[wdunit(bp->b_dev)] = 0;
wdtimeoutstatus[WDUNIT(bp->b_dev)] = 0;
#ifdef WDDEBUG
printf("I%d ", ctrlr);
#endif
stat = wait_for_unbusy(wdc, ctrlr);
if (stat == -1) {
/* XXXX looks bogus */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_BUSY\n", ctrlr);
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
}
/* is it not a transfer, but a control operation? */
@ -663,6 +674,7 @@ wdintr(struct intrframe wdif)
/* have we an error? */
if (stat & (WDCS_ERR | WDCS_ECCCOR)) {
lose:
du->dk_status = stat;
du->dk_error = inb(wdc+wd_error);
#ifdef WDDEBUG
@ -708,15 +720,14 @@ wdintr(struct intrframe wdif)
*/
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) &&
wdtab[ctrlr].b_active) {
int chk, dummy;
int chk;
chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
/* ready to receive data? */
if (wait_for_drq(wdc, ctrlr) == -1) {
/* XXXX abort here? */
wdstart(ctrlr);
printf("wdc%d: timeout in wdintr WDCS_DRQ\n", ctrlr);
if (wait_for_drq(du) < 0) {
printf("wdc%d: timeout waiting for drq\n", ctrlr);
goto lose;
}
/* suck in data */
@ -727,7 +738,7 @@ wdintr(struct intrframe wdif)
/* for obselete fractional sector reads */
while (chk++ < (DEV_BSIZE / sizeof(short)))
insw(wdc+wd_data, &dummy, 1);
(void) inw(wdc+wd_data);
}
wdxfer[du->dk_lunit]++;
@ -752,13 +763,13 @@ outt:
wdstart(ctrlr);
return; /* next chunk is started */
} else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR)) == DKFL_ERROR) {
wdtab[ctrlr].b_active = 0;
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
return; /* redo xfer sector by sector */
}
}
@ -767,7 +778,7 @@ done:
du->dk_flags &= ~DKFL_SINGLE;
wdtab[ctrlr].b_errcnt = 0;
if (du->dk_bct == 0) {
wdtab[ctrlr].b_actf = dp->b_forw;
wdtab[ctrlr].b_forw = dp->b_forw;
du->dk_skipm = 0;
dp->b_active = 0;
}
@ -787,7 +798,7 @@ done:
wdustart(du);
/* anything more for controller to do? */
if (wdtab[ctrlr].b_actf)
if (wdtab[ctrlr].b_forw)
wdstart(ctrlr);
}
@ -799,11 +810,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
{
register unsigned int lunit;
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
struct partition *pp;
char *msg;
lunit = wdunit(dev);
lunit = WDUNIT(dev);
if (lunit >= NWD)
return ENXIO;
du = wddrives[lunit];
@ -840,11 +851,11 @@ wdopen(dev_t dev, int flags, int fmt, struct proc *p)
/* read label using "raw" partition */
#if defined(TIHMODS) && defined(garbage)
/* wdsetctlr(dev, 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);
wdsetctlr(dev, du);
#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)) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
log(LOG_WARNING,
@ -921,7 +932,7 @@ wdcontrol(register struct buf *bp)
int s, ctrlr;
int wdc;
du = wddrives[wdunit(bp->b_dev)];
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
@ -936,22 +947,27 @@ wdcontrol(register struct buf *bp)
s = splbio(); /* not called from intr level ... */
wdgetctlr(unit, du);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wait_for_unbusy(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
wdtab[ctrlr].b_active = 1;
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
if (wait_for_ready(wdc, ctrlr) == -1) {
wdreset(ctrlr, wdc, 1);
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
goto tryagainrecal;
}
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
@ -1001,20 +1017,26 @@ wdcommand(struct disk *du, int cmd)
wdc = du->dk_port;
/* controller ready for command? */
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1)
if (wait_for_unbusy(du) < 0)
return -1;
/* send command, await results */
outb(wdc+wd_command, cmd);
stat = wait_for_unbusy(wdc, du->dk_ctrlr);
if (stat == -1)
return -1;
if (cmd != WDCC_READP)
return stat;
/* is controller ready to return data? */
return wdc_wait(wdc, du->dk_ctrlr, WDCS_ERR | WDCS_DRQ);
switch (cmd) {
default:
#if 0
case WDCC_READ:
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_IDC:
case WDCC_DIAGNOSE:
case WDCC_WRITE:
#endif
return wait_for_unbusy(du);
case WDCC_READP:
return wait_for_drq(du);
}
}
/*
@ -1033,14 +1055,17 @@ wdsetctlr(dev_t dev, struct disk *du)
wdc = du->dk_port;
x = splbio();
if (wait_for_unbusy(du) < 0)
return -1;
outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); /* TIH: was ...ders+1 */
outb(wdc+wd_cyl_hi, du->dk_dd.d_ncylinders>>8); /* TIH: was ...ders+1 */
outb(wdc+wd_sdh,
WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks - 1);
outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
if (wait_for_ready(du) < 0)
return -1;
stat = wdcommand(du, WDCC_IDC);
if (stat & WDCS_ERR)
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(x);
@ -1059,26 +1084,21 @@ wdgetctlr(int u, struct disk *du)
x = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(wdc, du->dk_ctrlr) == -1) {
if (wait_for_unbusy(du) < 0) {
splx(x);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
if (wait_for_ready(du) < 0) {
splx(x);
return -1;
}
stat = wdcommand(du, WDCC_READP);
if (wait_for_ready(wdc, du->dk_ctrlr) == -1) {
splx(x);
return -1;
}
if (stat < 0) {
splx(x);
return stat;
return -1;
}
if ((stat & WDCS_ERR) == 0) {
@ -1116,7 +1136,7 @@ wdgetctlr(int u, struct disk *du)
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat & WDCS_ERR) {
if (stat < 0 || stat & WDCS_ERR) {
splx(x);
return inb(wdc+wd_error);
}
@ -1149,9 +1169,9 @@ int
wdclose(dev_t dev, int flags, int fmt)
{
register struct disk *du;
int part = wdpart(dev), mask = 1 << part;
int part = WDPART(dev), mask = 1 << part;
du = wddrives[wdunit(dev)];
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
@ -1169,7 +1189,7 @@ wdclose(dev_t dev, int flags, int fmt)
int
wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
{
int lunit = wdunit(dev);
int lunit = WDUNIT(dev);
register struct disk *du;
int error = 0;
struct uio auio;
@ -1194,7 +1214,7 @@ wdioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
case DIOCGPART:
((struct partinfo *)addr)->disklab = &du->dk_dd;
((struct partinfo *)addr)->part =
&du->dk_dd.d_partitions[wdpart(dev)];
&du->dk_dd.d_partitions[WDPART(dev)];
break;
case DIOCSDINFO:
@ -1291,7 +1311,7 @@ wdformat(struct buf *bp)
int
wdsize(dev_t dev)
{
int lunit = wdunit(dev), part = wdpart(dev);
int lunit = WDUNIT(dev), part = WDPART(dev);
struct disk *du;
if (lunit >= NWD)
@ -1340,8 +1360,8 @@ wddump(dev_t dev)
#endif
/* size of memory to dump */
lunit = wdunit(dev);
part = wdpart(dev); /* file system */
lunit = WDUNIT(dev);
part = WDPART(dev); /* file system */
/* check for acceptable drive number */
if (lunit >= NWD)
return ENXIO;
@ -1367,8 +1387,8 @@ wddump(dev_t dev)
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks, dumplo,
num);*/
/*printf("xunit %x, nblocks %d, dumplo %d num %d\n", part, nblocks,
dumplo, num);*/
/* check transfer bounds against partition size */
if (dumplo < 0 || dumplo + num > nblocks)
return EINVAL;
@ -1377,12 +1397,13 @@ wddump(dev_t dev)
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0))
;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
while (inb(wdc+wd_status) & WDCS_BUSY)
;
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(dev, du);
@ -1415,10 +1436,12 @@ wddump(dev_t dev)
}
sector++; /* origin 1 */
if (wait_for_unbusy(du) < 0)
return EIO;
/* select drive. */
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | (head & 0xf));
while ((inb(wdc+wd_status) & WDCS_READY) == 0)
;
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
@ -1427,11 +1450,13 @@ wddump(dev_t dev)
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
pg("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
printf("sdh 0%o sector %d cyl %d addr 0x%x", inb(wdc+wd_sdh),
inb(wdc+wd_sector),
(inb(wdc+wd_cyl_hi) << 8) + inb(wdc+wd_cyl_lo), addr);
#endif
outb(wdc+wd_command, WDCC_WRITE);
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
@ -1440,26 +1465,15 @@ wddump(dev_t dev)
tlbflush();
#endif
/* Ready to send data? */
while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
;
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
outsw(wdc+wd_data, CADDR1 + ((int)addr & PGOFSET),
DEV_BSIZE / 2);
DEV_BSIZE / sizeof(short));
if (inb(wdc+wd_status) & WDCS_ERR)
return EIO;
/* Check data request (should be done). */
if (inb(wdc+wd_status) & WDCS_DRQ)
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
/* wait for completion */
for (i = 200000000; inb(wdc+wd_status) & WDCS_BUSY; i--) {
if (i < 0)
return EIO;
}
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
@ -1506,32 +1520,34 @@ bad144intern(struct disk *du)
}
static int
wdreset(int ctrlr, int wdc, int err)
wdreset(struct disk *du, int err)
{
int wdc = du->dk_port;
int stat;
if (err)
printf("wdc%d: busy too long, resetting\n", ctrlr);
printf("wdc%d: busy too long, resetting\n", du->dk_ctrlr);
/* reset the device */
outb(wdc+wd_ctlr, WDCTL_RST | WDCTL_IDS);
DELAY(1000);
outb(wdc+wd_ctlr, WDCTL_4BIT);
if (wait_for_unbusy(wdc, ctrlr) == -1)
printf("wdc%d: failed to reset controller\n", ctrlr);
if (wait_for_unbusy(du) < 0)
printf("wdc%d: failed to reset controller\n", du->dk_ctrlr);
}
int
wdc_wait(wdc, ctrlr, mask)
int wdc, ctrlr;
wdc_wait(du, mask)
struct disk *du;
int mask;
{
int wdc = du->dk_port;
int timeout = 0;
int stat;
for (;;) {
stat = inb(wdc+wd_status);
stat = inb(wdc+wd_altsts);
if ((stat & WDCS_BUSY) == 0)
/* XXXX Yuck. Need to redo this junk. */
if (mask == 0 || (stat & mask) != 0)
@ -1542,7 +1558,8 @@ wdc_wait(wdc, ctrlr, mask)
}
#ifdef WDCNDELAY_DEBUG
if (timeout > WDCNDELAY_DEBUG)
printf("wdc%d: timeout took %dus\n", ctrlr, WDCDELAY * timeout);
printf("wdc%d: timeout took %dus\n", du->dk_ctrlr,
WDCDELAY * timeout);
#endif
return stat;
}
@ -1569,7 +1586,7 @@ wdtimeout(caddr_t arg)
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
}
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz/2);
timeout((timeout_t)wdtimeout, (caddr_t)unit, hz*2);
splx(x);
return 0;
}