Move the drive select and various other things into wdcommand(), to avoid

duplicating code.
This commit is contained in:
mycroft 1994-03-05 08:17:06 +00:00
parent ec44c19a27
commit 87ed28e74e
3 changed files with 399 additions and 621 deletions

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.59 1994/03/04 23:43:14 mycroft Exp $
* $Id: wd.c,v 1.60 1994/03/05 08:17:06 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -113,7 +113,7 @@ struct disk {
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */
u_short dk_port; /* i/o port base */
u_long dk_copenpart; /* character units open on this drive */
u_long dk_bopenpart; /* block units open on this drive */
@ -151,13 +151,13 @@ struct isa_driver wdcdriver = {
static void wdustart __P((struct disk *));
static void wdstart __P((int));
static int wdcommand __P((struct disk *, int));
static int wdcommand __P((struct disk *, int, int, int, int, int));
static int wdcontrol __P((struct buf *));
static int wdsetctlr __P((struct disk *));
static int wdgetctlr __P((struct disk *));
static void bad144intern __P((struct disk *));
static int wdreset __P((struct disk *, int));
static int wdtimeout __P((caddr_t));
static void wdtimeout __P((caddr_t));
void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
@ -172,7 +172,7 @@ wdprobe(isa_dev)
struct isa_device *isa_dev;
{
struct disk *du;
int wdc;
u_short wdc;
if (isa_dev->id_unit >= NWDC)
return 0;
@ -196,7 +196,7 @@ wdprobe(isa_dev)
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -404,9 +404,10 @@ wdstart(ctrlr)
struct disklabel *lp;
struct buf *dp;
long blknum, cylin, head, sector;
long secpertrk, secpercyl, addr;
int lunit, wdc;
long secpertrk, secpercyl;
int xfrblknum;
int lunit;
u_short wdc;
loop:
/* is there a drive for the controller to do a transfer with? */
@ -448,7 +449,6 @@ loop:
else
printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts));
#endif
addr = (int)bp->b_un.b_addr;
if (du->dk_skip == 0)
du->dk_bc = bp->b_bcount;
if (du->dk_skipm == 0) {
@ -539,89 +539,62 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
int command, count;
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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT) {
outb(wdc+wd_sector, lp->d_gap3);
outb(wdc+wd_seccnt, lp->d_nsectors);
sector = lp->d_gap3;
count = lp->d_nsectors;
command = WDCC_FORMAT;
} else {
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt,
howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
count = howmany(du->dk_bct, DEV_BSIZE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
}
#else
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
#endif
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
/* 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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
command = WDCC_FORMAT;
else
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
count = howmany(du->dk_bct, DEV_BSIZE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
/* initiate command! */
if (wdcommand(du, cylin, head, sector, count, 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));
cylin, head, bp->b_un.b_addr, inb(wdc+wd_altsts));
#endif
}
du->dk_timeout = 2;
/* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) {
du->dk_timeout = 2;
if (bp->b_flags & B_READ)
return;
}
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
outsw(wdc+wd_data, bp->b_un.b_addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
du->dk_timeout = 2;
}
/* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -635,7 +608,8 @@ wdintr(ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc;
int stat;
u_short wdc;
/* clear the pending interrupt */
(void) inb(wdcontroller[ctrlr].dkc_port+wd_status);
@ -658,7 +632,7 @@ wdintr(ctrlr)
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
stat |= WDCS_ERR; /* XXX */
}
/* is it not a transfer, but a control operation? */
@ -729,7 +703,7 @@ wdintr(ctrlr)
/* suck in data */
insw(wdc+wd_data,
(int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
du->dk_bc -= chk * sizeof(short);
du->dk_bct -= chk * sizeof(short);
@ -763,7 +737,7 @@ outt:
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
@ -877,9 +851,8 @@ wdopen(dev, flag, fmt, p)
bad144intern(du);
/*
* Warn if a partion is opened
* that overlaps another partition which is open
* unless one is the "raw" partition (whole disk).
* Warn if a partition is opened that overlaps another partition which
* is open unless one is the "raw" partition (whole disk).
*/
if ((du->dk_openpart & mask) == 0 && part != WDRAW) {
int start, end;
@ -915,6 +888,7 @@ wdopen(dev, flag, fmt, p)
du->dk_bopenpart |= mask;
break;
}
return 0;
}
@ -929,58 +903,44 @@ wdcontrol(bp)
struct buf *bp;
{
struct disk *du;
int unit, lunit;
int stat;
int s, ctrlr;
int wdc;
u_short wdc;
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
wdc = du->dk_port;
switch (du->dk_state) {
case WANTOPEN: /* set SDH, step rate, do restore */
tryagainrecal:
#ifdef WDDEBUG
printf("wd%d: recal ", lunit);
#endif
s = splbio(); /* not called from intr level ... */
wdgetctlr(du);
if (wait_for_unbusy(du) < 0) {
lose:
wdgetctlr(du); /* XXX Is this necessary? */
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
splx(s);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
goto lose;
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
stat = inb(wdc+wd_altsts);
if (stat & WDCS_ERR || wdsetctlr(du) < 0) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
printf("wd%d: recal failed: stat %b error %b\n",
du->dk_lunit, stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
}
du->dk_state = WANTOPEN;
if (++wdtab[ctrlr].b_errcnt < WDIORETRIES)
goto tryagainrecal;
bp->b_error = ENXIO; /* XXX needs translation */
goto badopen;
bp->b_flags |= B_ERROR;
return 1;
}
/* some controllers require this ... */
wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN;
/*
@ -988,18 +948,11 @@ wdcontrol(bp)
* by normal means.
*/
return 1;
default:
panic("wdcontrol");
}
/* NOTREACHED */
badopen:
if ((du->dk_flags & DKFL_QUIET) == 0)
printf(": status %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
bp->b_flags |= B_ERROR;
return 1;
#ifdef DIAGNOSTIC
panic("wdcontrol: impossible");
#endif
}
/*
@ -1009,18 +962,35 @@ badopen:
* assumes interrupts are blocked.
*/
static int
wdcommand(du, cmd)
wdcommand(du, cylin, head, sector, count, cmd)
struct disk *du;
int cylin, head, sector, count;
int cmd;
{
int stat, wdc;
wdc = du->dk_port;
int stat;
u_short wdc;
/* controller ready for command? */
if (wait_for_unbusy(du) < 0)
return -1;
/* select drive */
wdc = du->dk_port;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC)
stat = wait_for_unbusy(du);
else
stat = wdc_wait(du, WDCS_READY);
if (stat < 0)
return -1;
/* load parameters */
outb(wdc+wd_precomp, du->dk_dd.d_precompcyl / 4);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, count);
/* send command, await results */
outb(wdc+wd_command, cmd);
@ -1029,13 +999,13 @@ wdcommand(du, cmd)
#if 0
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_DIAGNOSE:
#endif
return wait_for_unbusy(du);
case WDCC_READ:
case WDCC_WRITE:
return 0;
case WDCC_IDC:
case WDCC_DIAGNOSE:
return wdc_wait(du, WDCS_READY);
case WDCC_READP:
return wait_for_drq(du);
@ -1049,34 +1019,23 @@ static int
wdsetctlr(du)
struct disk *du;
{
int stat, s, wdc;
int stat, s;
#ifdef WDDEBUG
printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit,
du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);
#endif
wdc = du->dk_port;
s = splbio();
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
stat = wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
du->dk_dd.d_nsectors, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR) {
printf("wd%d: wdsetctlr: stat %b error %b\n", du->dk_lunit,
stat, WDCS_BITS, inb(du->dk_port+wd_error), WDERR_BITS);
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)
goto lose;
stat = wdcommand(du, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(s);
return stat;
return 0;
}
/*
@ -1086,28 +1045,34 @@ static int
wdgetctlr(du)
struct disk *du;
{
int stat, s, i, wdc;
int stat, s, i;
char tb[DEV_BSIZE];
struct wdparams *wp;
s = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
stat = wdcommand(du, WDCC_READP);
if (stat < 0)
goto lose;
if ((stat & WDCS_ERR) == 0) {
stat = wdcommand(du, 0, 0, 0, 0, WDCC_READP);
if (stat < 0 || stat & WDCS_ERR) {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR) {
splx(s);
return -1;
}
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
} else {
/* obtain parameters */
wp = &du->dk_params;
insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
insw(du->dk_port+wd_data, tb, sizeof(tb) / sizeof(short));
bcopy(tb, wp, sizeof(struct wdparams));
/* shuffle string byte order */
@ -1132,21 +1097,6 @@ wdgetctlr(du)
du->dk_dd.d_partitions[1].p_size =
du->dk_dd.d_secpercyl * wp->wdp_sectors;
du->dk_dd.d_partitions[1].p_offset = 0;
} else {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR)
goto lose;
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
}
#if 0
@ -1159,7 +1109,7 @@ wdgetctlr(du)
du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
/* XXX sometimes possibly needed */
(void) inb(wdc+wd_status);
(void) inb(du->dk_port+wd_status);
splx(s);
return 0;
}
@ -1170,12 +1120,9 @@ wdclose(dev, flag, fmt)
int flag;
int fmt;
{
struct disk *du;
struct disk *du = wddrives[WDUNIT(dev)];
int part = WDPART(dev), mask = 1 << part;
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
switch (fmt) {
case S_IFCHR:
@ -1185,6 +1132,7 @@ wdclose(dev, flag, fmt)
du->dk_bopenpart &= ~mask;
break;
}
return 0;
}
@ -1256,7 +1204,8 @@ wdioctl(dev, cmd, addr, flag, p)
du->dk_openpart |= (1 << 0); /* XXX */
wlab = du->dk_wlabel;
du->dk_wlabel = 1;
error = writedisklabel(dev, wdstrategy, &du->dk_dd, &du->dk_cpd);
error = writedisklabel(dev, wdstrategy, &du->dk_dd,
&du->dk_cpd);
du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
du->dk_wlabel = wlab;
}
@ -1347,10 +1296,11 @@ wddump(dev)
{
register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */
int ctrlr, lunit, part, wdc;
int ctrlr, lunit, part;
u_short wdc;
long blkoff, blknum;
long cylin, head, sector, stat;
long secpertrk, secpercyl, nblocks, i;
long secpertrk, secpercyl, nblocks;
char *addr;
static wddoingadump = 0;
extern caddr_t CADDR1;
@ -1381,37 +1331,32 @@ wddump(dev)
/* Convert to disk sectors */
num = ctob(physmem) / du->dk_dd.d_secsize;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*printf("part %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;
/* check if controller active */
/*if (wdtab[ctrlr].b_active)
return EFAULT;*/
if (wddoingadump)
return EFAULT;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*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;
/* mark controller active for if we panic during the dump */
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(du);
/* Recalibrate. */
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0 ||
wdsetctlr(du) < 0)
return EIO;
blknum = dumplo + blkoff;
while (num > 0) {
@ -1441,26 +1386,13 @@ wddump(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));
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, 1);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
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);
printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head,
sector, addr);
#endif
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
stat = wdcommand(du, cylin, head, sector, 1, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR || wait_for_drq(du) < 0)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
@ -1474,14 +1406,8 @@ wddump(dev)
DEV_BSIZE / sizeof(short));
/* Check data request (should be done). */
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
stat = wait_for_ready(du);
if (stat < 0 || stat & (WDCS_ERR | WDCS_DRQ))
return EIO;
if ((unsigned)addr % 1048576 == 0)
@ -1574,7 +1500,7 @@ wdc_wait(du, mask)
return stat;
}
static int
static void
wdtimeout(arg)
caddr_t arg;
{
@ -1584,16 +1510,16 @@ wdtimeout(arg)
if (du->dk_timeout && --du->dk_timeout == 0) {
int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n",
printf("wd%d: lost interrupt: stat %x error %x\n",
du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
wdreset(du, 0);
/* XXX Need to recalibrate and upload geometry. */
du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
wdstart(du->dk_ctrlr);
}
timeout((timeout_t)wdtimeout, arg, hz);
splx(s);
return 0;
}
#endif /* NWDC > 0 */

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.59 1994/03/04 23:43:14 mycroft Exp $
* $Id: wd.c,v 1.60 1994/03/05 08:17:06 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -113,7 +113,7 @@ struct disk {
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */
u_short dk_port; /* i/o port base */
u_long dk_copenpart; /* character units open on this drive */
u_long dk_bopenpart; /* block units open on this drive */
@ -151,13 +151,13 @@ struct isa_driver wdcdriver = {
static void wdustart __P((struct disk *));
static void wdstart __P((int));
static int wdcommand __P((struct disk *, int));
static int wdcommand __P((struct disk *, int, int, int, int, int));
static int wdcontrol __P((struct buf *));
static int wdsetctlr __P((struct disk *));
static int wdgetctlr __P((struct disk *));
static void bad144intern __P((struct disk *));
static int wdreset __P((struct disk *, int));
static int wdtimeout __P((caddr_t));
static void wdtimeout __P((caddr_t));
void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
@ -172,7 +172,7 @@ wdprobe(isa_dev)
struct isa_device *isa_dev;
{
struct disk *du;
int wdc;
u_short wdc;
if (isa_dev->id_unit >= NWDC)
return 0;
@ -196,7 +196,7 @@ wdprobe(isa_dev)
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -404,9 +404,10 @@ wdstart(ctrlr)
struct disklabel *lp;
struct buf *dp;
long blknum, cylin, head, sector;
long secpertrk, secpercyl, addr;
int lunit, wdc;
long secpertrk, secpercyl;
int xfrblknum;
int lunit;
u_short wdc;
loop:
/* is there a drive for the controller to do a transfer with? */
@ -448,7 +449,6 @@ loop:
else
printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts));
#endif
addr = (int)bp->b_un.b_addr;
if (du->dk_skip == 0)
du->dk_bc = bp->b_bcount;
if (du->dk_skipm == 0) {
@ -539,89 +539,62 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
int command, count;
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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT) {
outb(wdc+wd_sector, lp->d_gap3);
outb(wdc+wd_seccnt, lp->d_nsectors);
sector = lp->d_gap3;
count = lp->d_nsectors;
command = WDCC_FORMAT;
} else {
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt,
howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
count = howmany(du->dk_bct, DEV_BSIZE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
}
#else
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
#endif
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
/* 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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
command = WDCC_FORMAT;
else
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
count = howmany(du->dk_bct, DEV_BSIZE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
/* initiate command! */
if (wdcommand(du, cylin, head, sector, count, 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));
cylin, head, bp->b_un.b_addr, inb(wdc+wd_altsts));
#endif
}
du->dk_timeout = 2;
/* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) {
du->dk_timeout = 2;
if (bp->b_flags & B_READ)
return;
}
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
outsw(wdc+wd_data, bp->b_un.b_addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
du->dk_timeout = 2;
}
/* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -635,7 +608,8 @@ wdintr(ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc;
int stat;
u_short wdc;
/* clear the pending interrupt */
(void) inb(wdcontroller[ctrlr].dkc_port+wd_status);
@ -658,7 +632,7 @@ wdintr(ctrlr)
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
stat |= WDCS_ERR; /* XXX */
}
/* is it not a transfer, but a control operation? */
@ -729,7 +703,7 @@ wdintr(ctrlr)
/* suck in data */
insw(wdc+wd_data,
(int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
du->dk_bc -= chk * sizeof(short);
du->dk_bct -= chk * sizeof(short);
@ -763,7 +737,7 @@ outt:
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
@ -877,9 +851,8 @@ wdopen(dev, flag, fmt, p)
bad144intern(du);
/*
* Warn if a partion is opened
* that overlaps another partition which is open
* unless one is the "raw" partition (whole disk).
* Warn if a partition is opened that overlaps another partition which
* is open unless one is the "raw" partition (whole disk).
*/
if ((du->dk_openpart & mask) == 0 && part != WDRAW) {
int start, end;
@ -915,6 +888,7 @@ wdopen(dev, flag, fmt, p)
du->dk_bopenpart |= mask;
break;
}
return 0;
}
@ -929,58 +903,44 @@ wdcontrol(bp)
struct buf *bp;
{
struct disk *du;
int unit, lunit;
int stat;
int s, ctrlr;
int wdc;
u_short wdc;
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
wdc = du->dk_port;
switch (du->dk_state) {
case WANTOPEN: /* set SDH, step rate, do restore */
tryagainrecal:
#ifdef WDDEBUG
printf("wd%d: recal ", lunit);
#endif
s = splbio(); /* not called from intr level ... */
wdgetctlr(du);
if (wait_for_unbusy(du) < 0) {
lose:
wdgetctlr(du); /* XXX Is this necessary? */
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
splx(s);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
goto lose;
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
stat = inb(wdc+wd_altsts);
if (stat & WDCS_ERR || wdsetctlr(du) < 0) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
printf("wd%d: recal failed: stat %b error %b\n",
du->dk_lunit, stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
}
du->dk_state = WANTOPEN;
if (++wdtab[ctrlr].b_errcnt < WDIORETRIES)
goto tryagainrecal;
bp->b_error = ENXIO; /* XXX needs translation */
goto badopen;
bp->b_flags |= B_ERROR;
return 1;
}
/* some controllers require this ... */
wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN;
/*
@ -988,18 +948,11 @@ wdcontrol(bp)
* by normal means.
*/
return 1;
default:
panic("wdcontrol");
}
/* NOTREACHED */
badopen:
if ((du->dk_flags & DKFL_QUIET) == 0)
printf(": status %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
bp->b_flags |= B_ERROR;
return 1;
#ifdef DIAGNOSTIC
panic("wdcontrol: impossible");
#endif
}
/*
@ -1009,18 +962,35 @@ badopen:
* assumes interrupts are blocked.
*/
static int
wdcommand(du, cmd)
wdcommand(du, cylin, head, sector, count, cmd)
struct disk *du;
int cylin, head, sector, count;
int cmd;
{
int stat, wdc;
wdc = du->dk_port;
int stat;
u_short wdc;
/* controller ready for command? */
if (wait_for_unbusy(du) < 0)
return -1;
/* select drive */
wdc = du->dk_port;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC)
stat = wait_for_unbusy(du);
else
stat = wdc_wait(du, WDCS_READY);
if (stat < 0)
return -1;
/* load parameters */
outb(wdc+wd_precomp, du->dk_dd.d_precompcyl / 4);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, count);
/* send command, await results */
outb(wdc+wd_command, cmd);
@ -1029,13 +999,13 @@ wdcommand(du, cmd)
#if 0
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_DIAGNOSE:
#endif
return wait_for_unbusy(du);
case WDCC_READ:
case WDCC_WRITE:
return 0;
case WDCC_IDC:
case WDCC_DIAGNOSE:
return wdc_wait(du, WDCS_READY);
case WDCC_READP:
return wait_for_drq(du);
@ -1049,34 +1019,23 @@ static int
wdsetctlr(du)
struct disk *du;
{
int stat, s, wdc;
int stat, s;
#ifdef WDDEBUG
printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit,
du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);
#endif
wdc = du->dk_port;
s = splbio();
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
stat = wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
du->dk_dd.d_nsectors, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR) {
printf("wd%d: wdsetctlr: stat %b error %b\n", du->dk_lunit,
stat, WDCS_BITS, inb(du->dk_port+wd_error), WDERR_BITS);
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)
goto lose;
stat = wdcommand(du, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(s);
return stat;
return 0;
}
/*
@ -1086,28 +1045,34 @@ static int
wdgetctlr(du)
struct disk *du;
{
int stat, s, i, wdc;
int stat, s, i;
char tb[DEV_BSIZE];
struct wdparams *wp;
s = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
stat = wdcommand(du, WDCC_READP);
if (stat < 0)
goto lose;
if ((stat & WDCS_ERR) == 0) {
stat = wdcommand(du, 0, 0, 0, 0, WDCC_READP);
if (stat < 0 || stat & WDCS_ERR) {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR) {
splx(s);
return -1;
}
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
} else {
/* obtain parameters */
wp = &du->dk_params;
insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
insw(du->dk_port+wd_data, tb, sizeof(tb) / sizeof(short));
bcopy(tb, wp, sizeof(struct wdparams));
/* shuffle string byte order */
@ -1132,21 +1097,6 @@ wdgetctlr(du)
du->dk_dd.d_partitions[1].p_size =
du->dk_dd.d_secpercyl * wp->wdp_sectors;
du->dk_dd.d_partitions[1].p_offset = 0;
} else {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR)
goto lose;
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
}
#if 0
@ -1159,7 +1109,7 @@ wdgetctlr(du)
du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
/* XXX sometimes possibly needed */
(void) inb(wdc+wd_status);
(void) inb(du->dk_port+wd_status);
splx(s);
return 0;
}
@ -1170,12 +1120,9 @@ wdclose(dev, flag, fmt)
int flag;
int fmt;
{
struct disk *du;
struct disk *du = wddrives[WDUNIT(dev)];
int part = WDPART(dev), mask = 1 << part;
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
switch (fmt) {
case S_IFCHR:
@ -1185,6 +1132,7 @@ wdclose(dev, flag, fmt)
du->dk_bopenpart &= ~mask;
break;
}
return 0;
}
@ -1256,7 +1204,8 @@ wdioctl(dev, cmd, addr, flag, p)
du->dk_openpart |= (1 << 0); /* XXX */
wlab = du->dk_wlabel;
du->dk_wlabel = 1;
error = writedisklabel(dev, wdstrategy, &du->dk_dd, &du->dk_cpd);
error = writedisklabel(dev, wdstrategy, &du->dk_dd,
&du->dk_cpd);
du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
du->dk_wlabel = wlab;
}
@ -1347,10 +1296,11 @@ wddump(dev)
{
register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */
int ctrlr, lunit, part, wdc;
int ctrlr, lunit, part;
u_short wdc;
long blkoff, blknum;
long cylin, head, sector, stat;
long secpertrk, secpercyl, nblocks, i;
long secpertrk, secpercyl, nblocks;
char *addr;
static wddoingadump = 0;
extern caddr_t CADDR1;
@ -1381,37 +1331,32 @@ wddump(dev)
/* Convert to disk sectors */
num = ctob(physmem) / du->dk_dd.d_secsize;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*printf("part %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;
/* check if controller active */
/*if (wdtab[ctrlr].b_active)
return EFAULT;*/
if (wddoingadump)
return EFAULT;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*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;
/* mark controller active for if we panic during the dump */
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(du);
/* Recalibrate. */
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0 ||
wdsetctlr(du) < 0)
return EIO;
blknum = dumplo + blkoff;
while (num > 0) {
@ -1441,26 +1386,13 @@ wddump(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));
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, 1);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
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);
printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head,
sector, addr);
#endif
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
stat = wdcommand(du, cylin, head, sector, 1, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR || wait_for_drq(du) < 0)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
@ -1474,14 +1406,8 @@ wddump(dev)
DEV_BSIZE / sizeof(short));
/* Check data request (should be done). */
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
stat = wait_for_ready(du);
if (stat < 0 || stat & (WDCS_ERR | WDCS_DRQ))
return EIO;
if ((unsigned)addr % 1048576 == 0)
@ -1574,7 +1500,7 @@ wdc_wait(du, mask)
return stat;
}
static int
static void
wdtimeout(arg)
caddr_t arg;
{
@ -1584,16 +1510,16 @@ wdtimeout(arg)
if (du->dk_timeout && --du->dk_timeout == 0) {
int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n",
printf("wd%d: lost interrupt: stat %x error %x\n",
du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
wdreset(du, 0);
/* XXX Need to recalibrate and upload geometry. */
du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
wdstart(du->dk_ctrlr);
}
timeout((timeout_t)wdtimeout, arg, hz);
splx(s);
return 0;
}
#endif /* NWDC > 0 */

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
* $Id: wd.c,v 1.59 1994/03/04 23:43:14 mycroft Exp $
* $Id: wd.c,v 1.60 1994/03/05 08:17:06 mycroft Exp $
*/
#define QUIETWORKS /* define this to make wdopen() set DKFL_QUIET */
@ -113,7 +113,7 @@ struct disk {
int dk_timeout; /* timeout counter */
u_char dk_status; /* copy of status reg. */
u_char dk_error; /* copy of error reg. */
short dk_port; /* i/o port base */
u_short dk_port; /* i/o port base */
u_long dk_copenpart; /* character units open on this drive */
u_long dk_bopenpart; /* block units open on this drive */
@ -151,13 +151,13 @@ struct isa_driver wdcdriver = {
static void wdustart __P((struct disk *));
static void wdstart __P((int));
static int wdcommand __P((struct disk *, int));
static int wdcommand __P((struct disk *, int, int, int, int, int));
static int wdcontrol __P((struct buf *));
static int wdsetctlr __P((struct disk *));
static int wdgetctlr __P((struct disk *));
static void bad144intern __P((struct disk *));
static int wdreset __P((struct disk *, int));
static int wdtimeout __P((caddr_t));
static void wdtimeout __P((caddr_t));
void wddisksort __P((struct buf *dp, struct buf *bp));
int wdc_wait __P((struct disk *, int));
#define wait_for_drq(d) wdc_wait(d, WDCS_DRQ)
@ -172,7 +172,7 @@ wdprobe(isa_dev)
struct isa_device *isa_dev;
{
struct disk *du;
int wdc;
u_short wdc;
if (isa_dev->id_unit >= NWDC)
return 0;
@ -196,7 +196,7 @@ wdprobe(isa_dev)
wdreset(du, 0);
/* execute a controller only command */
if (wdcommand(du, WDCC_DIAGNOSE) < 0)
if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) < 0)
goto nodevice;
free(du, M_TEMP);
@ -404,9 +404,10 @@ wdstart(ctrlr)
struct disklabel *lp;
struct buf *dp;
long blknum, cylin, head, sector;
long secpertrk, secpercyl, addr;
int lunit, wdc;
long secpertrk, secpercyl;
int xfrblknum;
int lunit;
u_short wdc;
loop:
/* is there a drive for the controller to do a transfer with? */
@ -448,7 +449,6 @@ loop:
else
printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts));
#endif
addr = (int)bp->b_un.b_addr;
if (du->dk_skip == 0)
du->dk_bc = bp->b_bcount;
if (du->dk_skipm == 0) {
@ -539,89 +539,62 @@ loop:
retry:
/* if starting a multisector transfer, or doing single transfers */
if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
int command;
int command, count;
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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* stuff the task file */
outb(wdc+wd_precomp, lp->d_precompcyl / 4);
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT) {
outb(wdc+wd_sector, lp->d_gap3);
outb(wdc+wd_seccnt, lp->d_nsectors);
sector = lp->d_gap3;
count = lp->d_nsectors;
command = WDCC_FORMAT;
} else {
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt,
howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
count = howmany(du->dk_bct, DEV_BSIZE);
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
}
#else
if (du->dk_flags & DKFL_SINGLE)
outb(wdc+wd_seccnt, 1);
count = 1;
else
outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
outb(wdc+wd_sector, sector);
#endif
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
/* 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(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* initiate command! */
#ifdef B_FORMAT
if (bp->b_flags & B_FORMAT)
command = WDCC_FORMAT;
else
command =
(bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#else
count = howmany(du->dk_bct, DEV_BSIZE);
command = (bp->b_flags & B_READ) ? WDCC_READ : WDCC_WRITE;
#endif
if (wdcommand(du, command) < 0) {
/* initiate command! */
if (wdcommand(du, cylin, head, sector, count, 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));
cylin, head, bp->b_un.b_addr, inb(wdc+wd_altsts));
#endif
}
du->dk_timeout = 2;
/* if this is a read operation, just go away until it's done. */
if (bp->b_flags & B_READ) {
du->dk_timeout = 2;
if (bp->b_flags & B_READ)
return;
}
if (wait_for_drq(du) < 0) {
wdreset(du, 1);
goto retry;
}
/* then send it! */
outsw(wdc+wd_data, addr + du->dk_skip * DEV_BSIZE,
outsw(wdc+wd_data, bp->b_un.b_addr + du->dk_skip * DEV_BSIZE,
DEV_BSIZE / sizeof(short));
du->dk_bc -= DEV_BSIZE;
du->dk_bct -= DEV_BSIZE;
du->dk_timeout = 2;
}
/* Interrupt routine for the controller. Acknowledge the interrupt, check for
@ -635,7 +608,8 @@ wdintr(ctrlr)
{
register struct disk *du;
register struct buf *bp, *dp;
int stat, wdc;
int stat;
u_short wdc;
/* clear the pending interrupt */
(void) inb(wdcontroller[ctrlr].dkc_port+wd_status);
@ -658,7 +632,7 @@ wdintr(ctrlr)
stat = wait_for_unbusy(du);
if (stat < 0) {
printf("wdc%d: timeout waiting for unbusy\n", ctrlr);
goto lose;
stat |= WDCS_ERR; /* XXX */
}
/* is it not a transfer, but a control operation? */
@ -729,7 +703,7 @@ wdintr(ctrlr)
/* suck in data */
insw(wdc+wd_data,
(int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
du->dk_bc -= chk * sizeof(short);
du->dk_bct -= chk * sizeof(short);
@ -763,7 +737,7 @@ outt:
du->dk_skip = 0;
du->dk_skipm = 0;
du->dk_flags &= ~DKFL_ERROR;
du->dk_flags |= DKFL_SINGLE;
du->dk_flags |= DKFL_SINGLE;
wdtab[ctrlr].b_active = 0;
wdstart(ctrlr);
return; /* redo xfer sector by sector */
@ -877,9 +851,8 @@ wdopen(dev, flag, fmt, p)
bad144intern(du);
/*
* Warn if a partion is opened
* that overlaps another partition which is open
* unless one is the "raw" partition (whole disk).
* Warn if a partition is opened that overlaps another partition which
* is open unless one is the "raw" partition (whole disk).
*/
if ((du->dk_openpart & mask) == 0 && part != WDRAW) {
int start, end;
@ -915,6 +888,7 @@ wdopen(dev, flag, fmt, p)
du->dk_bopenpart |= mask;
break;
}
return 0;
}
@ -929,58 +903,44 @@ wdcontrol(bp)
struct buf *bp;
{
struct disk *du;
int unit, lunit;
int stat;
int s, ctrlr;
int wdc;
u_short wdc;
du = wddrives[WDUNIT(bp->b_dev)];
ctrlr = du->dk_ctrlr;
unit = du->dk_unit;
lunit = du->dk_lunit;
wdc = du->dk_port;
switch (du->dk_state) {
case WANTOPEN: /* set SDH, step rate, do restore */
tryagainrecal:
#ifdef WDDEBUG
printf("wd%d: recal ", lunit);
#endif
s = splbio(); /* not called from intr level ... */
wdgetctlr(du);
if (wait_for_unbusy(du) < 0) {
lose:
wdgetctlr(du); /* XXX Is this necessary? */
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0) {
wdreset(du, 1);
splx(s);
goto tryagainrecal;
}
outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
wdtab[ctrlr].b_active = 1;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
goto lose;
du->dk_state = RECAL;
splx(s);
return 0;
case RECAL:
if ((stat = inb(wdc+wd_altsts)) & WDCS_ERR) {
stat = inb(wdc+wd_altsts);
if (stat & WDCS_ERR || wdsetctlr(du) < 0) {
if ((du->dk_flags & DKFL_QUIET) == 0) {
printf("wd%d: recal", du->dk_lunit);
printf(": status %b error %b\n", stat,
WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
printf("wd%d: recal failed: stat %b error %b\n",
du->dk_lunit, stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
}
du->dk_state = WANTOPEN;
if (++wdtab[ctrlr].b_errcnt < WDIORETRIES)
goto tryagainrecal;
bp->b_error = ENXIO; /* XXX needs translation */
goto badopen;
bp->b_flags |= B_ERROR;
return 1;
}
/* some controllers require this ... */
wdsetctlr(du);
wdtab[ctrlr].b_errcnt = 0;
du->dk_state = OPEN;
/*
@ -988,18 +948,11 @@ wdcontrol(bp)
* by normal means.
*/
return 1;
default:
panic("wdcontrol");
}
/* NOTREACHED */
badopen:
if ((du->dk_flags & DKFL_QUIET) == 0)
printf(": status %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
bp->b_flags |= B_ERROR;
return 1;
#ifdef DIAGNOSTIC
panic("wdcontrol: impossible");
#endif
}
/*
@ -1009,18 +962,35 @@ badopen:
* assumes interrupts are blocked.
*/
static int
wdcommand(du, cmd)
wdcommand(du, cylin, head, sector, count, cmd)
struct disk *du;
int cylin, head, sector, count;
int cmd;
{
int stat, wdc;
wdc = du->dk_port;
int stat;
u_short wdc;
/* controller ready for command? */
if (wait_for_unbusy(du) < 0)
return -1;
/* select drive */
wdc = du->dk_port;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
if (cmd == WDCC_DIAGNOSE || cmd == WDCC_IDC)
stat = wait_for_unbusy(du);
else
stat = wdc_wait(du, WDCS_READY);
if (stat < 0)
return -1;
/* load parameters */
outb(wdc+wd_precomp, du->dk_dd.d_precompcyl / 4);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, count);
/* send command, await results */
outb(wdc+wd_command, cmd);
@ -1029,13 +999,13 @@ wdcommand(du, cmd)
#if 0
case WDCC_FORMAT:
case WDCC_RESTORE | WD_STEP:
case WDCC_DIAGNOSE:
#endif
return wait_for_unbusy(du);
case WDCC_READ:
case WDCC_WRITE:
return 0;
case WDCC_IDC:
case WDCC_DIAGNOSE:
return wdc_wait(du, WDCS_READY);
case WDCC_READP:
return wait_for_drq(du);
@ -1049,34 +1019,23 @@ static int
wdsetctlr(du)
struct disk *du;
{
int stat, s, wdc;
int stat, s;
#ifdef WDDEBUG
printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit,
du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);
#endif
wdc = du->dk_port;
s = splbio();
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
stat = wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
du->dk_dd.d_nsectors, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR) {
printf("wd%d: wdsetctlr: stat %b error %b\n", du->dk_lunit,
stat, WDCS_BITS, inb(du->dk_port+wd_error), WDERR_BITS);
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)
goto lose;
stat = wdcommand(du, WDCC_IDC);
if (stat < 0 || stat & WDCS_ERR)
printf("wdsetctlr: stat %b error %b\n", stat, WDCS_BITS,
inb(wdc+wd_error), WDERR_BITS);
splx(s);
return stat;
return 0;
}
/*
@ -1086,28 +1045,34 @@ static int
wdgetctlr(du)
struct disk *du;
{
int stat, s, i, wdc;
int stat, s, i;
char tb[DEV_BSIZE];
struct wdparams *wp;
s = splbio(); /* not called from intr level ... */
wdc = du->dk_port;
if (wait_for_unbusy(du) < 0) {
lose:
splx(s);
return -1;
}
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
goto lose;
stat = wdcommand(du, WDCC_READP);
if (stat < 0)
goto lose;
if ((stat & WDCS_ERR) == 0) {
stat = wdcommand(du, 0, 0, 0, 0, WDCC_READP);
if (stat < 0 || stat & WDCS_ERR) {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR) {
splx(s);
return -1;
}
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
} else {
/* obtain parameters */
wp = &du->dk_params;
insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
insw(du->dk_port+wd_data, tb, sizeof(tb) / sizeof(short));
bcopy(tb, wp, sizeof(struct wdparams));
/* shuffle string byte order */
@ -1132,21 +1097,6 @@ wdgetctlr(du)
du->dk_dd.d_partitions[1].p_size =
du->dk_dd.d_secpercyl * wp->wdp_sectors;
du->dk_dd.d_partitions[1].p_offset = 0;
} else {
/*
* If WDCC_READP fails then we might have an old drive
* so we try a seek to 0; if that passes then the
* drive is there but it's OLD AND KRUSTY.
*/
stat = wdcommand(du, WDCC_RESTORE | WD_STEP);
if (stat < 0 || stat & WDCS_ERR)
goto lose;
strncpy(du->dk_dd.d_typename, "ST506",
sizeof du->dk_dd.d_typename);
strncpy(du->dk_params.wdp_model, "Unknown Type",
sizeof du->dk_params.wdp_model);
du->dk_dd.d_type = DTYPE_ST506;
}
#if 0
@ -1159,7 +1109,7 @@ wdgetctlr(du)
du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
/* XXX sometimes possibly needed */
(void) inb(wdc+wd_status);
(void) inb(du->dk_port+wd_status);
splx(s);
return 0;
}
@ -1170,12 +1120,9 @@ wdclose(dev, flag, fmt)
int flag;
int fmt;
{
struct disk *du;
struct disk *du = wddrives[WDUNIT(dev)];
int part = WDPART(dev), mask = 1 << part;
du = wddrives[WDUNIT(dev)];
/* insure only one open at a time */
du->dk_openpart &= ~mask;
switch (fmt) {
case S_IFCHR:
@ -1185,6 +1132,7 @@ wdclose(dev, flag, fmt)
du->dk_bopenpart &= ~mask;
break;
}
return 0;
}
@ -1256,7 +1204,8 @@ wdioctl(dev, cmd, addr, flag, p)
du->dk_openpart |= (1 << 0); /* XXX */
wlab = du->dk_wlabel;
du->dk_wlabel = 1;
error = writedisklabel(dev, wdstrategy, &du->dk_dd, &du->dk_cpd);
error = writedisklabel(dev, wdstrategy, &du->dk_dd,
&du->dk_cpd);
du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
du->dk_wlabel = wlab;
}
@ -1347,10 +1296,11 @@ wddump(dev)
{
register struct disk *du; /* disk unit to do the IO */
long num; /* number of sectors to write */
int ctrlr, lunit, part, wdc;
int ctrlr, lunit, part;
u_short wdc;
long blkoff, blknum;
long cylin, head, sector, stat;
long secpertrk, secpercyl, nblocks, i;
long secpertrk, secpercyl, nblocks;
char *addr;
static wddoingadump = 0;
extern caddr_t CADDR1;
@ -1381,37 +1331,32 @@ wddump(dev)
/* Convert to disk sectors */
num = ctob(physmem) / du->dk_dd.d_secsize;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*printf("part %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;
/* check if controller active */
/*if (wdtab[ctrlr].b_active)
return EFAULT;*/
if (wddoingadump)
return EFAULT;
secpertrk = du->dk_dd.d_nsectors;
secpercyl = du->dk_dd.d_secpercyl;
nblocks = du->dk_dd.d_partitions[part].p_size;
blkoff = du->dk_dd.d_partitions[part].p_offset;
/*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;
/* mark controller active for if we panic during the dump */
/*wdtab[ctrlr].b_active = 1;*/
wddoingadump = 1;
i = 200000000;
if (wait_for_unbusy(du) < 0)
return EIO;
outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
if (wait_for_ready(du) < 0)
return EIO;
if (wdcommand(du, WDCC_RESTORE | WD_STEP) < 0)
return EIO;
/* some compaq controllers require this ... */
wdsetctlr(du);
/* Recalibrate. */
if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) < 0 ||
wdsetctlr(du) < 0)
return EIO;
blknum = dumplo + blkoff;
while (num > 0) {
@ -1441,26 +1386,13 @@ wddump(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));
if (wait_for_ready(du) < 0)
return EIO;
/* transfer some blocks */
outb(wdc+wd_sector, sector);
outb(wdc+wd_seccnt, 1);
outb(wdc+wd_cyl_lo, cylin);
outb(wdc+wd_cyl_hi, cylin >> 8);
#ifdef notdef
/* lets just talk about this first...*/
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);
printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head,
sector, addr);
#endif
stat = wdcommand(du, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR)
stat = wdcommand(du, cylin, head, sector, 1, WDCC_WRITE);
if (stat < 0 || stat & WDCS_ERR || wait_for_drq(du) < 0)
return EIO;
#ifdef notdef /* cannot use this since this address was mapped differently */
@ -1474,14 +1406,8 @@ wddump(dev)
DEV_BSIZE / sizeof(short));
/* Check data request (should be done). */
if (inb(wdc+wd_status) & (WDCS_ERR | WDCS_DRQ))
return EIO;
if (wait_for_unbusy(du) < 0)
return EIO;
/* error check the xfer */
if (inb(wdc+wd_status) & WDCS_ERR)
stat = wait_for_ready(du);
if (stat < 0 || stat & (WDCS_ERR | WDCS_DRQ))
return EIO;
if ((unsigned)addr % 1048576 == 0)
@ -1574,7 +1500,7 @@ wdc_wait(du, mask)
return stat;
}
static int
static void
wdtimeout(arg)
caddr_t arg;
{
@ -1584,16 +1510,16 @@ wdtimeout(arg)
if (du->dk_timeout && --du->dk_timeout == 0) {
int wdc = du->dk_port;
printf("wd%d: lost interrupt - status %x, error %x\n",
printf("wd%d: lost interrupt: stat %x error %x\n",
du->dk_lunit, inb(wdc+wd_status), inb(wdc+wd_error));
wdreset(du, 0);
/* XXX Need to recalibrate and upload geometry. */
du->dk_skip = 0;
du->dk_flags |= DKFL_SINGLE;
wdstart(du->dk_ctrlr); /* start controller */
wdstart(du->dk_ctrlr);
}
timeout((timeout_t)wdtimeout, arg, hz);
splx(s);
return 0;
}
#endif /* NWDC > 0 */