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

View File

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

View File

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