WD INITIALIZATION AND PARTITION BOUNDARY
[unix-history] / usr / src / sys.386bsd / i386 / isa / wd.c
index 2086260..775284a 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)wd.c        7.2 (Berkeley) 5/9/91
+ *     from:@(#)wd.c   7.2 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
+ * --------------------         -----   ----------------------
+ * CURRENT PATCH LEVEL:         4       00072
+ * --------------------         -----   ----------------------
+ *
+ * 17 Sep 92   Frank Maclachlan        Fixed I/O error reporting on raw device
+ * 31 Jul 92   Christoph Robitschko    Fixed second disk recognition,
+ *                                     bzero of malloced memory for warm
+ *                                     boot problem.
+ * 19 Aug 92    Frank Maclachlan       Fixed bug when first sector of a
+ *                                     multisector read is in bad144 table.
+ * 17 Jan 93   B. Evans & A.Chernov    Fixed bugs from previous patches,
+ *                                     driver initialization, and cylinder
+ *                                     boundary conditions.
  */
 
  */
 
-/* TODO:peel out buffer at low ipl,
-   speed improvement, rewrite to clean code from garbage artifacts */
+/* TODO:peel out buffer at low ipl, speed improvement */
 
 
 #include "wd.h"
 
 
 #include "wd.h"
 #include "disklabel.h"
 #include "buf.h"
 #include "uio.h"
 #include "disklabel.h"
 #include "buf.h"
 #include "uio.h"
+#include "malloc.h"
+#include "machine/cpu.h"
 #include "i386/isa/isa_device.h"
 #include "i386/isa/icu.h"
 #include "i386/isa/wdreg.h"
 #include "syslog.h"
 #include "vm/vm.h"
 
 #include "i386/isa/isa_device.h"
 #include "i386/isa/icu.h"
 #include "i386/isa/wdreg.h"
 #include "syslog.h"
 #include "vm/vm.h"
 
+#define _NWD  (NWD - 1)       /* One is for the controller XXX 31 Jul 92*/
+
 #define        RETRIES         5       /* number of retries before giving up */
 #define        MAXTRANSFER     32      /* max size of transfer in page clusters */
 
 #define        RETRIES         5       /* number of retries before giving up */
 #define        MAXTRANSFER     32      /* max size of transfer in page clusters */
 
-#define wdctlr(dev)    ((minor(dev) & 0x20) >> 5)
-#define wdunit(dev)    ((minor(dev) & 0x18) >> 3)
-#define wdpart(dev)    ((minor(dev) & 0x7))
+#define wdnoreloc(dev) (minor(dev) & 0x80)     /* ignore partition table */
+#define wddospart(dev) (minor(dev) & 0x40)     /* use dos partitions */
+#define wdunit(dev)    ((minor(dev) & 0x38) >> 3)
+#define wdpart(dev)    (minor(dev) & 0x7)
+#define makewddev(maj, unit, part)     (makedev(maj,((unit<<3)+part)))
+#define WDRAW  3               /* 'd' partition isn't a partition! */
 
 #define b_cylin        b_resid         /* cylinder number for doing IO to */
                                /* shares an entry in the buf struct */
 
 /*
 
 #define b_cylin        b_resid         /* cylinder number for doing IO to */
                                /* shares an entry in the buf struct */
 
 /*
- * Drive states.  Used for open and format operations.
- * States < OPEN (> 0) are transient, during an open operation.
- * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
- * bad-sector forwarding.
+ * Drive states.  Used to initialize drive.
  */
  */
-#define RAWDISK                8               /* raw disk operation, no translation*/
-#define ISRAWSTATE(s)  (RAWDISK&(s))   /* are we in a raw state? */
-#define DISKSTATE(s)   (~RAWDISK&(s))  /* are we in a given state regardless
-                                          of raw or cooked mode? */
 
 #define        CLOSED          0               /* disk is closed. */
 
 #define        CLOSED          0               /* disk is closed. */
-                                       /* "cooked" disk states */
 #define        WANTOPEN        1               /* open requested, not started */
 #define        RECAL           2               /* doing restore */
 #define        WANTOPEN        1               /* open requested, not started */
 #define        RECAL           2               /* doing restore */
-#define        RDLABEL         3               /* reading pack label */
-#define        RDBADTBL        4               /* reading bad-sector table */
-#define        OPEN            5               /* done with open */
-
-#define        WANTOPENRAW     (WANTOPEN|RAWDISK)      /* raw WANTOPEN */
-#define        RECALRAW        (RECAL|RAWDISK) /* raw open, doing restore */
-#define        OPENRAW         (OPEN|RAWDISK)  /* open, but unlabeled disk or floppy */
-
+#define        OPEN            3               /* done with open */
 
 /*
  * The structure of a disk drive.
  */
 struct disk {
 
 /*
  * The structure of a disk drive.
  */
 struct disk {
-       struct disklabel dk_dd; /* device configuration data */
        long    dk_bc;          /* byte count left */
        short   dk_skip;        /* blocks already transferred */
        char    dk_unit;        /* physical unit number */
        char    dk_state;       /* control state */
        u_char  dk_status;      /* copy of status reg. */
        u_char  dk_error;       /* copy of error reg. */
        long    dk_bc;          /* byte count left */
        short   dk_skip;        /* blocks already transferred */
        char    dk_unit;        /* physical unit number */
        char    dk_state;       /* control state */
        u_char  dk_status;      /* copy of status reg. */
        u_char  dk_error;       /* copy of error reg. */
-       short   dk_open;        /* open/closed refcnt */
+       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 */
         u_long  dk_openpart;    /* all units open on this drive */
        short   dk_wlabel;      /* label writable? */
         u_long  dk_copenpart;   /* character units open on this drive */
         u_long  dk_bopenpart;   /* block units open on this drive */
         u_long  dk_openpart;    /* all units open on this drive */
        short   dk_wlabel;      /* label writable? */
+       short   dk_flags;       /* drive characteistics found */
+#define        DKFL_DOSPART    0x00001  /* has DOS partition table */
+#define        DKFL_QUIET      0x00002  /* report errors back, but don't complain */
+#define        DKFL_SINGLE     0x00004  /* sector at a time mode */
+#define        DKFL_ERROR      0x00008  /* processing a disk error */
+#define        DKFL_BSDLABEL   0x00010  /* has a BSD disk label */
+#define        DKFL_BADSECT    0x00020  /* has a bad144 badsector table */
+#define        DKFL_WRITEPROT  0x00040  /* manual unit write protect */
+       struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
+       struct disklabel dk_dd; /* device configuration data */
+       struct  dos_partition
+               dk_dospartitions[NDOSPART];     /* DOS view of disk */
+       struct  dkbad   dk_bad; /* bad sector table */
 };
 
 };
 
-/*
- * This label is used as a default when initializing a new or raw disk.
- * It really only lets us access the first track until we know more.
- */
-struct disklabel dflt_sizes = {
-       DISKMAGIC, DTYPE_ST506, 0, "default", "",
-               512,            /* sector size */
-               17,             /* # of sectors per track */
-               8,              /* # of tracks per cylinder */
-               766,            /* # of cylinders per unit */
-               17*8,           /* # of sectors per cylinder */
-               766*8*17,       /* # of sectors per unit */
-               0,              /* # of spare sectors per track */
-               0,              /* # of spare sectors per cylinder */
-               0,              /* # of alt. cylinders per unit */
-               3600,           /* rotational speed */
-               1,              /* hardware sector interleave */
-               0,              /* sector 0 skew, per track */
-               0,              /* sector 0 skew, per cylinder */
-               0,              /* head switch time, usec */
-               0,              /* track-to-track seek, usec */
-               0,              /* generic flags */
-               0,0,0,0,0,
-               0,0,0,0,0,
-               DISKMAGIC,
-               0,
-               8,
-               8192,
-               8192,
-       
-       {{21600,        0, 0,0,0,0},    /* A=root filesystem */
-       {21600, 21600, 0,0,0,0},
-       {660890, 0, 0,0,0,0},   /* C=whole disk */
-       {216000,        80, 0,0,0,0},
-       {0,     0, 0,0,0,0},
-       {0,     0, 0,0,0,0},
-       {0,     0, 0,0,0,0},
-       {399600,        480, 0,0,0,0}}
-};
+struct disk    *wddrives[_NWD];                /* table of units */
+struct buf     wdtab;
+struct buf     wdutab[_NWD];           /* head of queue per drive */
+struct buf     rwdbuf[_NWD];           /* buffers for raw IO */
+long   wdxfer[_NWD];                   /* count of transfers */
+#ifdef WDDEBUG
+int    wddebug;
+#endif
 
 
-static struct  dkbad   dkbad[NWD];
-struct disk    wddrives[NWD] = {0};    /* table of units */
-struct buf     wdtab = {0};
-struct buf     wdutab[NWD] = {0};      /* head of queue per drive */
-struct buf     rwdbuf[NWD] = {0};      /* buffers for raw IO */
-long   wdxfer[NWD] = {0};              /* count of transfers */
-int    writeprotected[NWD] = { 0 };
-int    wdprobe(), wdattach(), wdintr();
 struct isa_driver wddriver = {
        wdprobe, wdattach, "wd",
 };
 struct isa_driver wddriver = {
        wdprobe, wdattach, "wd",
 };
-\f
-static wdc;
+
+void wdustart(struct disk *);
+void wdstart();
+int wdcommand(struct disk *, int);
+int wdcontrol(struct buf *);
+int wdsetctlr(dev_t, struct disk *);
+int wdgetctlr(int, struct disk *);
+
 /*
 /*
- * Probe routine
+ * Probe for controller.
  */
  */
-wdprobe(dvp)
-       struct isa_device *dvp;
+int
+wdprobe(struct isa_device *dvp)
 {
 {
-wdc = dvp->id_iobase;
+       int unit = dvp->id_unit;
+       struct disk *du;
+       int wdc;
 
 
-#ifdef lint
-       wdintr(0);
-#endif
-       /* XXX sorry, needs to be better */
-       outb(wdc+wd_error, 0x5a) ;      /* error register not writable */
-       outb(wdc+wd_cyl_lo, 0xa5) ;     /* but all of cyllo are implemented */
-       if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)
-               return(1) ;
+       if (unit >= _NWD)                               /* 31 Jul 92*/
+               return(0);
+
+       if ((du = wddrives[unit]) == 0) {
+               du = wddrives[unit] = (struct disk *)
+                       malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
+               bzero (du, sizeof(struct disk));        /* 31 Jul 92*/
+               du->dk_unit = unit;
+       }
+
+       wdc = du->dk_port = dvp->id_iobase;
+       
+       /* check if we have registers that work */
+       outb(wdc+wd_cyl_lo, 0xa5) ;     /* wd_cyl_lo is read/write */
+       if(inb(wdc+wd_cyl_lo) != 0xa5)
+               goto nodevice;
+
+       /* reset the device */
+       outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
+       DELAY(1000);
+       outb(wdc+wd_ctlr, WDCTL_IDS);
+       DELAY(1000);
+
+       /* execute a controller only command */
+       if (wdcommand(du, WDCC_DIAGNOSE) < 0)
+               goto nodevice;
+
+       (void) inb(wdc+wd_error);       /* XXX! */
+       outb(wdc+wd_ctlr, WDCTL_4BIT);
+       return (1);
+
+nodevice:
+       free(du, M_TEMP);
+       wddrives[unit] = 0;
        return (0);
 }
 
 /*
        return (0);
 }
 
 /*
- * attach each drive if possible.
+ * Attach each drive if possible.
  */
  */
-wdattach(dvp)
-       struct isa_device *dvp;
+int
+wdattach(struct isa_device *dvp)
 {
 {
-       int unit = dvp->id_unit;
+       int unit;
+/*     int unit = dvp->id_unit;*/
+
+       for (unit=0; unit< _NWD; unit++) {
+               struct disk *du;
+               if ((du = wddrives[unit]) == 0) {
+                       du = wddrives[unit] = (struct disk *)
+                               malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
+                       bzero (du, sizeof(struct disk));
+                       du->dk_unit = unit;
+                       du->dk_port = dvp->id_iobase;
+               }
 
 
-       outb(wdc+wd_ctlr,12);
-       DELAY(1000);
-       outb(wdc+wd_ctlr,8);
+               /* print out description of drive, suppressing multiple blanks*/
+               if(wdgetctlr(unit, du) == 0)  {
+                       int i, blank;
+                       char c;
+                       printf(" %d:<", unit);
+                       for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) {
+                               char c = du->dk_params.wdp_model[i];
+
+                               if (blank && c == ' ') continue;
+                               if (blank && c != ' ') {
+                                       printf(" %c", c);
+                                       blank = 0;
+                                       continue;
+                               }
+                               if (c == ' ')
+                                       blank = 1;
+                               else
+                                       printf("%c", c);
+                       }
+                       printf(">");
+                       du->dk_unit = unit;
+               }
+               else {
+                       /* old ST506 controller */
+                       printf(" %d:<wdgetctlr failed, assuming OK>",
+                              unit);
+               }
+       }
+       return(1);
 }
 
 /* Read/write routine for a buffer.  Finds the proper unit, range checks
 }
 
 /* Read/write routine for a buffer.  Finds the proper unit, range checks
@@ -201,121 +252,90 @@ wdattach(dvp)
  * to complete.  Multi-page transfers are supported.  All I/O requests must
  * be a multiple of a sector in length.
  */
  * to complete.  Multi-page transfers are supported.  All I/O requests must
  * be a multiple of a sector in length.
  */
-wdstrategy(bp)
-       register struct buf *bp;        /* IO operation to perform */
+int
+wdstrategy(register struct buf *bp)
 {
        register struct buf *dp;
 {
        register struct buf *dp;
-       register struct disk *du;       /* Disk unit to do the IO.      */
+       struct disklabel *lp;
        register struct partition *p;
        register struct partition *p;
+       struct disk *du;        /* Disk unit to do the IO.      */
        long maxsz, sz;
        int     unit = wdunit(bp->b_dev);
        int     s;
 
        long maxsz, sz;
        int     unit = wdunit(bp->b_dev);
        int     s;
 
-       if ((unit >= NWD) || (bp->b_blkno < 0)) {
-               printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
-                       unit, bp->b_blkno, bp->b_bcount);
-               pg("wd:error in wdstrategy");
+       /* valid unit, controller, and request?  */
+       if (unit >= _NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) {
+
+               bp->b_error = EINVAL;
                bp->b_flags |= B_ERROR;
                bp->b_flags |= B_ERROR;
-               goto bad;
-       }
-       if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
-               printf("wd%d: write protected\n", unit);
-               goto bad;
+               goto done;
        }
        }
-       du = &wddrives[unit];
-       if (DISKSTATE(du->dk_state) != OPEN)
-               goto q;
-#ifdef old
-       /*
-        * Convert DEV_BSIZE "blocks" to sectors.
-        * Note: doing the conversions this way limits the partition size
-        * to about 8 million sectors (1-8 Gb).
-        */
-       blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;
-       if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||
-           bp->b_bcount >= MAXTRANSFER * CLBYTES) {
+
+       /* "soft" write protect check */
+       if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
+               bp->b_error = EROFS;
                bp->b_flags |= B_ERROR;
                bp->b_flags |= B_ERROR;
-               goto bad;
+               goto done;
        }
        }
-       nblocks = du->dk_dd.d_partitions[part].p_size;
-       cyloff = du->dk_dd.d_partitions[part].p_offset;
-       if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {
-               if (blknum == nblocks)
-                       bp->b_resid = bp->b_bcount;
-               else
-                       bp->b_flags |= B_ERROR;
-               goto bad;
+
+       /* have partitions and want to use them? */
+       if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
+
+               /*
+                * do bounds checking, adjust transfer. if error, process.
+                * if end of partition, just return
+                */
+               if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0)
+                       goto done;
+               /* otherwise, process transfer request */
        }
        }
-       bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;
-#else
-        /*
-         * Determine the size of the transfer, and make sure it is
-         * within the boundaries of the partition.
-         */
-        p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];
-        maxsz = p->p_size;
-        sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
-        if (bp->b_blkno + p->p_offset <= LABELSECTOR &&
-#if LABELSECTOR != 0
-            bp->b_blkno + p->p_offset + sz > LABELSECTOR &&
-#endif
-            (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {
-                bp->b_error = EROFS;
-                goto bad;
-        }
-        if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
-                /* if exactly at end of disk, return an EOF */
-                if (bp->b_blkno == maxsz) {
-                        bp->b_resid = bp->b_bcount;
-                        biodone(bp);
-                        return;
-                }
-                /* or truncate if part of it fits */
-                sz = maxsz - bp->b_blkno;
-                if (sz <= 0)
-                        goto bad;
-                bp->b_bcount = sz << DEV_BSHIFT;
-        }
-        bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;
-#endif
+
 q:
 q:
+       /* queue transfer on drive, activate drive and controller if idle */
        dp = &wdutab[unit];
        dp = &wdutab[unit];
-       s = splhigh();
+       s = splbio();
        disksort(dp, bp);
        if (dp->b_active == 0)
        disksort(dp, bp);
        if (dp->b_active == 0)
-               wdustart(du);           /* start drive if idle */
+               wdustart(du);           /* start drive */
        if (wdtab.b_active == 0)
        if (wdtab.b_active == 0)
-               wdstart(s);             /* start IO if controller idle */
+               wdstart(s);             /* start controller */
        splx(s);
        return;
 
        splx(s);
        return;
 
-bad:
-       bp->b_error = EINVAL;
+done:
+       /* toss transfer, we're done early */
        biodone(bp);
 }
 
        biodone(bp);
 }
 
-/* Routine to queue a read or write command to the controller.  The request is
- * linked into the active list for the controller.  If the controller is idle,
- * the transfer is started.
+/*
+ * Routine to queue a command to the controller.  The unit's
+ * request is linked into the active list for the controller.
+ * If the controller is idle, the transfer is started.
  */
  */
-wdustart(du)
-       register struct disk *du;
+static void
+wdustart(register struct disk *du)
 {
 {
-       register struct buf *bp, *dp;
+       register struct buf *bp, *dp = &wdutab[du->dk_unit];
 
 
-       dp = &wdutab[du->dk_unit];
+       /* unit already active? */
        if (dp->b_active)
                return;
        if (dp->b_active)
                return;
+
+       /* anything to start? */
        bp = dp->b_actf;
        if (bp == NULL)
                return; 
        bp = dp->b_actf;
        if (bp == NULL)
                return; 
+
+       /* link onto controller queue */
        dp->b_forw = NULL;
        dp->b_forw = NULL;
-       if (wdtab.b_actf  == NULL)              /* link unit into active list */
+       if (wdtab.b_actf  == NULL)
                wdtab.b_actf = dp;
        else
                wdtab.b_actl->b_forw = dp;
        wdtab.b_actl = dp;
                wdtab.b_actf = dp;
        else
                wdtab.b_actl->b_forw = dp;
        wdtab.b_actl = dp;
-       dp->b_active = 1;               /* mark the drive as busy */
+
+       /* mark the drive unit as busy */
+       dp->b_active = 1;
 }
 
 /*
 }
 
 /*
@@ -326,68 +346,73 @@ wdustart(du)
  * 1.  The transfer length must be an exact multiple of the sector size.
  */
 
  * 1.  The transfer length must be an exact multiple of the sector size.
  */
 
-static wd_sebyse;
-
+static void
 wdstart()
 {
        register struct disk *du;       /* disk unit for IO */
        register struct buf *bp;
 wdstart()
 {
        register struct disk *du;       /* disk unit for IO */
        register struct buf *bp;
+       struct disklabel *lp;
        struct buf *dp;
        register struct bt_bad *bt_ptr;
        long    blknum, pagcnt, cylin, head, sector;
        long    secpertrk, secpercyl, addr, i;
        struct buf *dp;
        register struct bt_bad *bt_ptr;
        long    blknum, pagcnt, cylin, head, sector;
        long    secpertrk, secpercyl, addr, i;
-       int     unit, s;
+       int     unit, s, wdc;
 
 loop:
 
 loop:
+       /* is there a drive for the controller to do a transfer with? */
        dp = wdtab.b_actf;
        if (dp == NULL)
                return;
        dp = wdtab.b_actf;
        if (dp == NULL)
                return;
+
+       /* is there a transfer to this drive ? if so, link it on
+          the controller's queue */
        bp = dp->b_actf;
        if (bp == NULL) {
                wdtab.b_actf = dp->b_forw;
                goto loop;
        }
        bp = dp->b_actf;
        if (bp == NULL) {
                wdtab.b_actf = dp->b_forw;
                goto loop;
        }
+
+       /* obtain controller and drive information */
        unit = wdunit(bp->b_dev);
        unit = wdunit(bp->b_dev);
-       du = &wddrives[unit];
-       if (DISKSTATE(du->dk_state) <= RDLABEL) {
-               if (wdcontrol(bp)) {
-                       dp->b_actf = bp->av_forw;
-                       goto loop;      /* done */
-               }
+       du = wddrives[unit];
+
+       /* if not really a transfer, do control operations specially */
+       if (du->dk_state < OPEN) {
+               (void) wdcontrol(bp);
                return;
        }
                return;
        }
-       secpertrk = du->dk_dd.d_nsectors;
-       secpercyl = du->dk_dd.d_secpercyl;
-       /*
-        * Convert DEV_BSIZE "blocks" to sectors.
-        */
-       blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize
-               + du->dk_skip;
+
+       /* calculate transfer details */
+       blknum = bp->b_blkno + du->dk_skip;
+/*if(wddebug)printf("bn%d ", blknum);*/
 #ifdef WDDEBUG
 #ifdef WDDEBUG
-       if (du->dk_skip == 0) {
-               dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
+       if (du->dk_skip == 0)
+               printf("\nwdstart %d: %s %d@%d; map ", unit,
                        (bp->b_flags & B_READ) ? "read" : "write",
                        bp->b_bcount, blknum);
                        (bp->b_flags & B_READ) ? "read" : "write",
                        bp->b_bcount, blknum);
-       } else {
-               dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
-       }
+       else
+               printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts));
 #endif
 #endif
-
        addr = (int) bp->b_un.b_addr;
        addr = (int) bp->b_un.b_addr;
-       if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
+       if (du->dk_skip == 0)
+               du->dk_bc = bp->b_bcount;
+
+       lp = &du->dk_dd;
+       secpertrk = lp->d_nsectors;
+       secpercyl = lp->d_secpercyl;
+       if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
+               blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
        cylin = blknum / secpercyl;
        head = (blknum % secpercyl) / secpertrk;
        sector = blknum % secpertrk;
        cylin = blknum / secpercyl;
        head = (blknum % secpercyl) / secpertrk;
        sector = blknum % secpertrk;
-       if (DISKSTATE(du->dk_state) == OPEN)
-               cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset
-                               / secpercyl;
 
        /* 
         * See if the current block is in the bad block list.
         * (If we have one, and not formatting.)
         */
 
        /* 
         * See if the current block is in the bad block list.
         * (If we have one, and not formatting.)
         */
-       if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
-           for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
+       if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT))         /* 19 Aug 92*/
+               == (DKFL_SINGLE|DKFL_BADSECT))
+           for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
                if (bt_ptr->bt_cyl > cylin)
                        /* Sorted list, and we passed our cylinder. quit. */
                        break;
                if (bt_ptr->bt_cyl > cylin)
                        /* Sorted list, and we passed our cylinder. quit. */
                        break;
@@ -400,145 +425,170 @@ loop:
                         * and works backwards to the front of the disk.
                         */
 #ifdef WDDEBUG
                         * and works backwards to the front of the disk.
                         */
 #ifdef WDDEBUG
-                           dprintf(DDSK,"--- badblock code -> Old = %d; ",
+                           printf("--- badblock code -> Old = %d; ",
                                blknum);
 #endif
                                blknum);
 #endif
-                       blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
-                               - (bt_ptr - dkbad[unit].bt_bad) - 1;
+                       blknum = lp->d_secperunit - lp->d_nsectors
+                               - (bt_ptr - du->dk_bad.bt_bad) - 1;
                        cylin = blknum / secpercyl;
                        head = (blknum % secpercyl) / secpertrk;
                        sector = blknum % secpertrk;
 #ifdef WDDEBUG
                        cylin = blknum / secpercyl;
                        head = (blknum % secpercyl) / secpertrk;
                        sector = blknum % secpertrk;
 #ifdef WDDEBUG
-                           dprintf(DDSK, "new = %d\n", blknum);
+                           printf("new = %d\n", blknum);
 #endif
                        break;
                }
        }
 #endif
                        break;
                }
        }
+/*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/
        sector += 1;    /* sectors begin with 1, not 0 */
 
        wdtab.b_active = 1;             /* mark controller active */
        sector += 1;    /* sectors begin with 1, not 0 */
 
        wdtab.b_active = 1;             /* mark controller active */
+       wdc = du->dk_port;
+
+       /* if starting a multisector transfer, or doing single transfers */
+       if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
+               if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0)
+                       du->dk_bc += DEV_BSIZE;
+
+               /* controller idle? */
+               while (inb(wdc+wd_status) & WDCS_BUSY)
+                       ;
+
+               /* 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);
+               } else {
+#endif
+               if (du->dk_flags & DKFL_SINGLE)
+                       outb(wdc+wd_seccnt, 1);
+               else
+                       outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE));
+               outb(wdc+wd_sector, sector);
 
 
-       if(du->dk_skip==0 || wd_sebyse) {
-       if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
-       while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
-       /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
-       outb(wdc+wd_precomp, 0xff);
-       /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
-       /*if (bp->b_flags & B_FORMAT) {
-               wr(wdc+wd_sector, du->dk_dd.dk_gap3);
-               wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
-       } else {*/
-       if(wd_sebyse)
-               outb(wdc+wd_seccnt, 1);
-       else
-               outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
-       outb(wdc+wd_sector, sector);
+#ifdef B_FORMAT
+               }
+#endif
+
+               outb(wdc+wd_cyl_lo, cylin);
+               outb(wdc+wd_cyl_hi, cylin >> 8);
 
 
-       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 | (unit<<4) | (head & 0xf));
 
 
-       /* Set up the SDH register (select drive).     */
-       outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
-       while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
+               /* wait for drive to become ready */
+               while ((inb(wdc+wd_status) & WDCS_READY) == 0)
+                       ;
 
 
-       /*if (bp->b_flags & B_FORMAT)
-               wr(wdc+wd_command, WDCC_FORMAT);
-       else*/
+               /* initiate command! */
+#ifdef B_FORMAT
+               if (bp->b_flags & B_FORMAT)
+                       outb(wdc+wd_command, WDCC_FORMAT);
+               else
+#endif
                outb(wdc+wd_command,
                        (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
                outb(wdc+wd_command,
                        (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
-       /*printf("sector %d cylin %d head %d addr %x sts %x\n",
-           sector, cylin, head, addr, inb(wdc+wd_altsts));*/
-}
-               
-       /* If this is a read operation, just go away until it's done.   */
+#ifdef WDDEBUG
+               printf("sector %d cylin %d head %d addr %x sts %x\n",
+                       sector, cylin, head, addr, inb(wdc+wd_altsts));
+#endif
+       }
+
+       /* if this is a read operation, just go away until it's done.   */
        if (bp->b_flags & B_READ) return;
 
        if (bp->b_flags & B_READ) return;
 
-       /* Ready to send data?  */
-       while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
+       /* ready to send data?  */
+       while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
+               ;
 
 
-       /* ASSUMES CONTIGUOUS MEMORY */
-       outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
-       du->dk_bc -= 512;
+       /* then send it! */
+       outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
+               DEV_BSIZE/sizeof(short));
+       du->dk_bc -= DEV_BSIZE;
 }
 
 }
 
-/*
- * these are globally defined so they can be found
- * by the debugger easily in the case of a system crash
- */
-daddr_t wd_errsector;
-daddr_t wd_errbn;
-unsigned char wd_errstat;
-
 /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
  * errors on the current operation, mark it done if necessary, and start
  * the next request.  Also check for a partially done transfer, and
  * continue with the next chunk if so.
  */
 /* Interrupt routine for the controller.  Acknowledge the interrupt, check for
  * errors on the current operation, mark it done if necessary, and start
  * the next request.  Also check for a partially done transfer, and
  * continue with the next chunk if so.
  */
-wdintr(unit)
+void
+wdintr(struct intrframe wdif)
 {
        register struct disk *du;
        register struct buf *bp, *dp;
 {
        register struct disk *du;
        register struct buf *bp, *dp;
-       int status;
+       int status, wdc;
        char partch ;
        char partch ;
-       static wd_haderror;
 
 
-       /* Shouldn't need this, but it may be a slow controller.        */
-       while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
        if (!wdtab.b_active) {
        if (!wdtab.b_active) {
+#ifdef nyet
                printf("wd: extra interrupt\n");
                printf("wd: extra interrupt\n");
+#endif
                return;
        }
 
                return;
        }
 
-#ifdef WDDEBUG
-       dprintf(DDSK,"I ");
-#endif
        dp = wdtab.b_actf;
        bp = dp->b_actf;
        dp = wdtab.b_actf;
        bp = dp->b_actf;
-       du = &wddrives[wdunit(bp->b_dev)];
-       partch = wdpart(bp->b_dev) + 'a';
-       if (DISKSTATE(du->dk_state) <= RDLABEL) {
+       du = wddrives[wdunit(bp->b_dev)];
+       wdc = du->dk_port;
+
+#ifdef WDDEBUG
+       printf("I ");
+#endif
+
+       while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
+
+       /* is it not a transfer, but a control operation? */
+       if (du->dk_state < OPEN) {
                if (wdcontrol(bp))
                if (wdcontrol(bp))
-                       goto done;
+                       wdstart();
                return;
        }
                return;
        }
+
+       /* have we an error? */
        if (status & (WDCS_ERR | WDCS_ECCCOR)) {
        if (status & (WDCS_ERR | WDCS_ECCCOR)) {
-               wd_errstat = inb(wdc+wd_error);         /* save error status */
+
+               du->dk_status = status;
+               du->dk_error = inb(wdc + wd_error);
 #ifdef WDDEBUG
 #ifdef WDDEBUG
-               printf("status %x error %x\n", status, wd_errstat);
+               printf("status %x error %x\n", status, du->dk_error);
 #endif
 #endif
-               if(wd_sebyse == 0) {
-                       wd_haderror = 1;
+               if((du->dk_flags & DKFL_SINGLE) == 0) {
+                       du->dk_flags |=  DKFL_ERROR;
                        goto outt;
                }
                        goto outt;
                }
-               /*if (bp->b_flags & B_FORMAT) {
-                       du->dk_status = status;
-                       du->dk_error = wdp->wd_error;
+#ifdef B_FORMAT
+               if (bp->b_flags & B_FORMAT) {
+                       bp->b_error = EIO;              /* 17 Sep 92*/
                        bp->b_flags |= B_ERROR;
                        goto done;
                        bp->b_flags |= B_ERROR;
                        goto done;
-               }*/
+               }
+#endif
                
                
-               wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
-                       (((unsigned long) bp->b_blkno * DEV_BSIZE /
-                           du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
-                       du->dk_skip;
-               wd_errbn = bp->b_blkno
-                       + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
+               /* error or error correction? */
                if (status & WDCS_ERR) {
                        if (++wdtab.b_errcnt < RETRIES) {
                                wdtab.b_active = 0;
                        } else {
                if (status & WDCS_ERR) {
                        if (++wdtab.b_errcnt < RETRIES) {
                                wdtab.b_active = 0;
                        } else {
-                               printf("wd%d%c: ", du->dk_unit, partch);
-                               printf(
-                               "hard %s error, sn %d bn %d status %b error %b\n",
-                                       (bp->b_flags & B_READ)? "read":"write",
-                                       wd_errsector, wd_errbn, status, WDCS_BITS,
-                                       wd_errstat, WDERR_BITS);
+                               if((du->dk_flags&DKFL_QUIET) == 0) {
+                                       diskerr(bp, "wd", "hard error",
+                                               LOG_PRINTF, du->dk_skip,
+                                               &du->dk_dd);
+#ifdef WDDEBUG
+                                       printf( "status %b error %b\n",
+                                               status, WDCS_BITS,
+                                               inb(wdc+wd_error), WDERR_BITS);
+#endif
+                               }
+                               bp->b_error = EIO;      /* 17 Sep 92*/
                                bp->b_flags |= B_ERROR; /* flag the error */
                        }
                                bp->b_flags |= B_ERROR; /* flag the error */
                        }
-               } else
-                       log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
-                               du->dk_unit, partch, wd_errsector,
-                               wd_errbn);
+               } else if((du->dk_flags&DKFL_QUIET) == 0) {
+                               diskerr(bp, "wd", "soft ecc", 0,
+                                       du->dk_skip, &du->dk_dd);
+               }
        }
 outt:
 
        }
 outt:
 
@@ -548,48 +598,47 @@ outt:
        if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
                int chk, dummy;
 
        if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
                int chk, dummy;
 
-               chk = min(256,du->dk_bc/2);
-               /* Ready to receive data?       */
-               while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
+               chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
+
+               /* ready to receive data? */
+               while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
+                       ;
 
 
-/*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
-               insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
-               du->dk_bc -= 2*chk;
-               while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
+               /* suck in data */
+               insw (wdc+wd_data,
+                       (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
+               du->dk_bc -= chk * sizeof(short);
+
+               /* for obselete fractional sector reads */
+               while (chk++ < 256) insw (wdc+wd_data, &dummy, 1);
        }
 
        wdxfer[du->dk_unit]++;
        if (wdtab.b_active) {
                if ((bp->b_flags & B_ERROR) == 0) {
                        du->dk_skip++;          /* Add to successful sectors. */
        }
 
        wdxfer[du->dk_unit]++;
        if (wdtab.b_active) {
                if ((bp->b_flags & B_ERROR) == 0) {
                        du->dk_skip++;          /* Add to successful sectors. */
-                       if (wdtab.b_errcnt) {
-                               log(LOG_WARNING, "wd%d%c: ",
-                                               du->dk_unit, partch);
-                               log(LOG_WARNING,
-                       "soft %s error, sn %d bn %d error %b retries %d\n",
-                                   (bp->b_flags & B_READ) ? "read" : "write",
-                                   wd_errsector, wd_errbn, wd_errstat,
-                                   WDERR_BITS, wdtab.b_errcnt);
-                       }
+                       if (wdtab.b_errcnt && (du->dk_flags & DKFL_QUIET) == 0)
+                               diskerr(bp, "wd", "soft error", 0,
+                                       du->dk_skip, &du->dk_dd);
                        wdtab.b_errcnt = 0;
 
                        /* see if more to transfer */
                        wdtab.b_errcnt = 0;
 
                        /* see if more to transfer */
-                       /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
-                       if (du->dk_bc > 0 && wd_haderror == 0) {
+                       if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
                                wdstart();
                                return;         /* next chunk is started */
                                wdstart();
                                return;         /* next chunk is started */
-                       } else if (wd_haderror && wd_sebyse == 0) {
+                       } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR))
+                                       == DKFL_ERROR) {
                                du->dk_skip = 0;
                                du->dk_skip = 0;
-                               wd_haderror = 0;
-                               wd_sebyse = 1;
+                               du->dk_flags &= ~DKFL_ERROR;
+                               du->dk_flags |=  DKFL_SINGLE;
                                wdstart();
                                return;         /* redo xfer sector by sector */
                        }
                }
 
 done:
                                wdstart();
                                return;         /* redo xfer sector by sector */
                        }
                }
 
 done:
-               wd_sebyse = 0;
                /* done with this transfer, with or without error */
                /* done with this transfer, with or without error */
+               du->dk_flags &= ~DKFL_SINGLE;
                wdtab.b_actf = dp->b_forw;
                wdtab.b_errcnt = 0;
                du->dk_skip = 0;
                wdtab.b_actf = dp->b_forw;
                wdtab.b_errcnt = 0;
                du->dk_skip = 0;
@@ -599,113 +648,91 @@ done:
                bp->b_resid = 0;
                biodone(bp);
        }
                bp->b_resid = 0;
                biodone(bp);
        }
+
+       /* controller idle */
        wdtab.b_active = 0;
        wdtab.b_active = 0;
+
+       /* anything more on drive queue? */
        if (dp->b_actf)
        if (dp->b_actf)
-               wdustart(du);           /* requeue disk if more io to do */
+               wdustart(du);
+       /* anything more for controller to do? */
        if (wdtab.b_actf)
        if (wdtab.b_actf)
-               wdstart();              /* start IO on next drive */
+               wdstart();
 }
 
 /*
  * Initialize a drive.
  */
 }
 
 /*
  * Initialize a drive.
  */
-wdopen(dev, flags, fmt)
-        dev_t dev;
-        int flags, fmt;
+int
+wdopen(dev_t dev, int flags, int fmt, struct proc *p)
 {
        register unsigned int unit;
 {
        register unsigned int unit;
-       register struct buf *bp;
        register struct disk *du;
         int part = wdpart(dev), mask = 1 << part;
         struct partition *pp;
        struct dkbad *db;
        int i, error = 0;
        register struct disk *du;
         int part = wdpart(dev), mask = 1 << part;
         struct partition *pp;
        struct dkbad *db;
        int i, error = 0;
+       char *msg;
 
        unit = wdunit(dev);
 
        unit = wdunit(dev);
-       if (unit >= NWD) return (ENXIO) ;
-       du = &wddrives[unit];
-#ifdef notdef
-       if (du->dk_open){
-               du->dk_open++ ;
-               return(0);      /* already is open, don't mess with it */
-       }
-#endif
-       du->dk_unit = unit;
-       wdutab[unit].b_actf = NULL;
-       /*if (flags & O_NDELAY)
-               du->dk_state = WANTOPENRAW;
-       else*/
-               du->dk_state = WANTOPEN;
-       /*
-        * Use the default sizes until we've read the label,
-        * or longer if there isn't one there.
-        */
-       du->dk_dd = dflt_sizes;
+       if (unit >= _NWD) return (ENXIO) ;
 
 
-       /*
-        * Recal, read of disk label will be done in wdcontrol
-        * during first read operation.
-        */
-       bp = geteblk(512);
-       bp->b_dev = dev & 0xff00;
-       bp->b_bcount = 0;
-       bp->b_blkno = LABELSECTOR;
-       bp->b_flags = B_READ;
-       wdstrategy(bp);
-       biowait(bp);
-       if (bp->b_flags & B_ERROR) {
-               error = ENXIO;
-               du->dk_state = CLOSED;
-               goto done;
-       }
-       if (du->dk_state == OPENRAW) {
-               du->dk_state = OPENRAW;
-               goto done;
-       }
-       /*
-        * Read bad sector table into memory.
-        */
-       i = 0;
-       do {
-               bp->b_flags = B_BUSY | B_READ;
-               bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
-                       + i;
-               if (du->dk_dd.d_secsize > DEV_BSIZE)
-                       bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
+       du = wddrives[unit];
+       if (du == 0) return (ENXIO) ;
+
+       if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
+               du->dk_flags |= DKFL_WRITEPROT;
+               wdutab[unit].b_actf = NULL;
+
+               /*
+                * Use the default sizes until we've read the label,
+                * or longer if there isn't one there.
+                */
+               bzero(&du->dk_dd, sizeof(du->dk_dd));
+#undef d_type /* fix goddamn segments.h! XXX */
+               du->dk_dd.d_type = DTYPE_ST506;
+               du->dk_dd.d_ncylinders = 1024;
+               du->dk_dd.d_secsize = DEV_BSIZE;
+               du->dk_dd.d_ntracks = 8;
+               du->dk_dd.d_nsectors = 17;
+               du->dk_dd.d_secpercyl = 17*8;
+               du->dk_state = WANTOPEN;
+               du->dk_unit = unit;
+               if (part == WDRAW)
+                       du->dk_flags |= DKFL_QUIET;
                else
                else
-                       bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
-               bp->b_bcount = du->dk_dd.d_secsize;
-               bp->b_cylin = du->dk_dd.d_ncylinders - 1;
-               wdstrategy(bp);
-               biowait(bp);
-       } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
-               i < du->dk_dd.d_nsectors);
-       db = (struct dkbad *)(bp->b_un.b_addr);
-#define DKBAD_MAGIC 0x4321
-       if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
-           db->bt_flag == DKBAD_MAGIC) {
-               dkbad[unit] = *db;
-               du->dk_state = OPEN;
-       } else {
-               printf("wd%d: %s bad-sector file\n", unit,
-                   (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
-               /*error = ENXIO ;
-               du->dk_state = OPENRAW;*/
-               du->dk_state = OPEN;
-       }
+                       du->dk_flags &= ~DKFL_QUIET;
+
+               /* read label using "c" partition */
+               if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
+                               wdstrategy, &du->dk_dd, du->dk_dospartitions,
+                               &du->dk_bad, 0)) {
+                       if((du->dk_flags&DKFL_QUIET) == 0) {
+                               log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
+                                       unit, msg);
+                               error = EINVAL;         /* XXX needs translation */
+                       }
+                       goto done;
+               } else {
+
+                       wdsetctlr(dev, du);
+                       du->dk_flags |= DKFL_BSDLABEL;
+                       du->dk_flags &= ~DKFL_WRITEPROT;
+                       if (du->dk_dd.d_flags & D_BADSECT)
+                               du->dk_flags |= DKFL_BADSECT;
+               }
+
 done:
 done:
-       bp->b_flags = B_INVAL | B_AGE;
-       brelse(bp);
-       if (error == 0)
-               du->dk_open = 1;
+               if (error)
+                       return(error);
 
 
+       }
         /*
          * Warn if a partion is opened
          * that overlaps another partition which is open
          * unless one is the "raw" partition (whole disk).
          */
         /*
          * Warn if a partion is opened
          * that overlaps another partition which is open
          * unless one is the "raw" partition (whole disk).
          */
-#define RAWPART         2               /* 'c' partition */     /* XXX */
-        if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
+        if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
                int     start, end;
 
                 pp = &du->dk_dd.d_partitions[part];
                int     start, end;
 
                 pp = &du->dk_dd.d_partitions[part];
@@ -717,7 +744,9 @@ done:
                         if (pp->p_offset + pp->p_size <= start ||
                             pp->p_offset >= end)
                                 continue;
                         if (pp->p_offset + pp->p_size <= start ||
                             pp->p_offset >= end)
                                 continue;
-                        if (pp - du->dk_dd.d_partitions == RAWPART)
+                        /*if (pp - du->dk_dd.d_partitions == RAWPART)
+                                continue; */
+                        if (pp - du->dk_dd.d_partitions == WDRAW)
                                 continue;
                         if (du->dk_openpart & (1 << (pp -
                                        du->dk_dd.d_partitions)))
                                 continue;
                         if (du->dk_openpart & (1 << (pp -
                                        du->dk_dd.d_partitions)))
@@ -727,8 +756,10 @@ done:
                                     pp - du->dk_dd.d_partitions + 'a');
                 }
         }
                                     pp - du->dk_dd.d_partitions + 'a');
                 }
         }
-        if (part >= du->dk_dd.d_npartitions)
+        if (part >= du->dk_dd.d_npartitions && part != WDRAW)
                 return (ENXIO);
                 return (ENXIO);
+
+       /* insure only one open at a time */
         du->dk_openpart |= mask;
         switch (fmt) {
         case S_IFCHR:
         du->dk_openpart |= mask;
         switch (fmt) {
         case S_IFCHR:
@@ -738,7 +769,7 @@ done:
                 du->dk_bopenpart |= mask;
                 break;
         }
                 du->dk_bopenpart |= mask;
                 break;
         }
-       return (error);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -747,27 +778,38 @@ done:
  * Uses finite-state-machine to track progress of operation in progress.
  * Returns 0 if operation still in progress, 1 if completed.
  */
  * Uses finite-state-machine to track progress of operation in progress.
  * Returns 0 if operation still in progress, 1 if completed.
  */
-wdcontrol(bp)
-       register struct buf *bp;
+static int
+wdcontrol(register struct buf *bp)
 {
        register struct disk *du;
        register unit;
        unsigned char  stat;
        int s, cnt;
 {
        register struct disk *du;
        register unit;
        unsigned char  stat;
        int s, cnt;
-       extern int bootdev, cyloffset;
+       extern int bootdev;
+       int cyl, trk, sec, i, wdc;
+       struct wdparams foo;
 
 
-       du = &wddrives[wdunit(bp->b_dev)];
+       du = wddrives[wdunit(bp->b_dev)];
        unit = du->dk_unit;
        unit = du->dk_unit;
-       switch (DISKSTATE(du->dk_state)) {
+       wdc = du->dk_port;
+       
+       switch (du->dk_state) {
 
        tryagainrecal:
        case WANTOPEN:                  /* set SDH, step rate, do restore */
 #ifdef WDDEBUG
 
        tryagainrecal:
        case WANTOPEN:                  /* set SDH, step rate, do restore */
 #ifdef WDDEBUG
-               dprintf(DDSK,"wd%d: recal ", unit);
+               printf("wd%d: recal ", unit);
 #endif
                s = splbio();           /* not called from intr level ... */
 #endif
                s = splbio();           /* not called from intr level ... */
+               wdgetctlr(unit, du);
+
                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                wdtab.b_active = 1;
                outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
                wdtab.b_active = 1;
+
+               /* wait for drive and controller to become ready */
+               for (i = 1000000; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY))
+                                 != WDCS_READY && i-- != 0; )
+                       ;
                outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                du->dk_state++;
                splx(s);
                outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
                du->dk_state++;
                splx(s);
@@ -775,83 +817,25 @@ wdcontrol(bp)
 
        case RECAL:
                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
 
        case RECAL:
                if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
-                       printf("wd%d: recal", du->dk_unit);
-                       if (unit == 0) {
+                       if ((du->dk_flags & DKFL_QUIET) == 0) {
+                               printf("wd%d: recal", du->dk_unit);
                                printf(": status %b error %b\n",
                                printf(": status %b error %b\n",
-                                       stat, WDCS_BITS,
-                                       inb(wdc+wd_error), WDERR_BITS);
-                               if (++wdtab.b_errcnt < RETRIES)
-                                       goto tryagainrecal;
+                                       stat, WDCS_BITS, inb(wdc+wd_error),
+                                       WDERR_BITS);
+                       }
+                       if (++wdtab.b_errcnt < RETRIES) {
+                               du->dk_state = WANTOPEN;
+                               goto tryagainrecal;
                        }
                        }
+                       bp->b_error = ENXIO;    /* XXX needs translation */
                        goto badopen;
                }
 
                        goto badopen;
                }
 
-               /* some compaq controllers require this ... */
+               /* some controllers require this ... */
                wdsetctlr(bp->b_dev, du);
 
                wdtab.b_errcnt = 0;
                wdsetctlr(bp->b_dev, du);
 
                wdtab.b_errcnt = 0;
-               if (ISRAWSTATE(du->dk_state)) {
-                       du->dk_state = OPENRAW;
-                       return(1);
-               }
-retry:
-#ifdef WDDEBUG
-               dprintf(DDSK,"rdlabel ");
-#endif
-/*if( cyloffset < 0 || cyloffset > 8192) */cyloffset=0;
-               /*
-                * Read in sector LABELSECTOR to get the pack label
-                * and geometry.
-                */
-               outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
-               outb(wdc+wd_seccnt, 1);
-               outb(wdc+wd_sector, LABELSECTOR+1);
-/*printf("sec %d ", LABELSECTOR);*/
-               /*if (bp->b_dev == bootdev) {
-                       (wdc+wd_cyl_lo = cyloffset & 0xff;
-                       (wdc+wd_cyl_hi = cyloffset >> 8;
-               } else {
-                       (wdc+wd_cyl_lo = 0;
-                       (wdc+wd_cyl_hi = 0;
-               }*/
-               outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
-               outb(wdc+wd_cyl_hi, (cyloffset >> 8));
-               outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
-               outb(wdc+wd_command, WDCC_READ);
-               du->dk_state = RDLABEL;
-               return(0);
-
-       case RDLABEL:
-               if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
-                       if (++wdtab.b_errcnt < RETRIES)
-                               goto retry;
-                       printf("wd%d: read label", unit);
-                       goto badopen;
-               }
-
-               insw(wdc+wd_data, bp->b_un.b_addr, 256);
-
-               if (((struct disklabel *)
-                   (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
-                      du->dk_dd =
-                        * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
-               } else {
-                       printf("wd%d: bad disk label (%x)\n", du->dk_unit,
-    ((struct disklabel *)(bp->b_un.b_addr + LABELOFFSET))->d_magic
-);
-                       du->dk_state = OPENRAW;
-               }
-
-               s = splbio();           /* not called from intr level ... */
-               while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
-
-               wdsetctlr(bp->b_dev, du);
-
-               outb(wdc+wd_seccnt, 0);
-               splx(s);
-
-               if (du->dk_state == RDLABEL)
-                       du->dk_state = RDBADTBL;
+               du->dk_state = OPEN;
                /*
                 * The rest of the initialization can be done
                 * by normal means.
                /*
                 * The rest of the initialization can be done
                 * by normal means.
@@ -864,54 +848,175 @@ retry:
        /* NOTREACHED */
 
 badopen:
        /* NOTREACHED */
 
 badopen:
-       printf(": status %b error %b\n",
-               stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
-       du->dk_state = OPENRAW;
+       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);
 }
 
        return(1);
 }
 
-wdsetctlr(dev, du) dev_t dev; struct disk *du; {
-       int stat;
+/*
+ * send a command and wait uninterruptibly until controller is finished.
+ * return -1 if controller busy for too long, otherwise
+ * return status. intended for brief controller commands at critical points.
+ * assumes interrupts are blocked.
+ */
+static int
+wdcommand(struct disk *du, int cmd) {
+       int timeout = 1000000, stat, wdc;
+
+       /* controller ready for command? */
+       wdc = du->dk_port;
+       while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
+               timeout--;
+       if (timeout <= 0)
+               return(-1);
+
+       /* send command, await results */
+       outb(wdc+wd_command, cmd);
+       while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
+               timeout--;
+       if (timeout <= 0)
+               return(-1);
+       if (cmd != WDCC_READP)
+               return (stat);
+
+       /* is controller ready to return data? */
+       while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
+               timeout > 0)
+               timeout--;
+       if (timeout <= 0)
+               return(-1);
+
+       return (stat);
+}
+
+/*
+ * issue IDC to drive to tell it just what geometry it is to be.
+ */
+static int
+wdsetctlr(dev_t dev, struct disk *du) {
+       int stat, x, wdc;
+
+/*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
+       du->dk_dd.d_nsectors);*/
 
 
+       x = splbio();
+       wdc = du->dk_port;
        outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
        outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
        outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
        outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
        outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
        outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
        outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
        outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
-       outb(wdc+wd_command, 0x91);
-
-       while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
-       stat = inb(wdc+wd_error);
+       stat = wdcommand(du, WDCC_IDC);
+
+       if (stat < 0)
+               return(stat);
+       if (stat & WDCS_ERR)
+               printf("wdsetctlr: status %b error %b\n",
+                       stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
+       splx(x);
        return(stat);
 }
 
        return(stat);
 }
 
+/*
+ * issue READP to drive to ask it what it is.
+ */
+static int
+wdgetctlr(int u, struct disk *du) {
+       int stat, x, i, wdc;
+       char tb[DEV_BSIZE];
+       struct wdparams *wp;
+
+       x = splbio();           /* not called from intr level ... */
+       wdc = du->dk_port;
+       outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
+       stat = wdcommand(du, WDCC_READP);
+
+       if (stat < 0)
+               return(stat);
+       if (stat & WDCS_ERR) {
+               splx(x);
+               return(inb(wdc+wd_error));
+       }
+
+       /* obtain parameters */
+       wp = &du->dk_params;
+       insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
+       bcopy(tb, wp, sizeof(struct wdparams));
+
+       /* shuffle string byte order */
+       for (i=0; i < sizeof(wp->wdp_model) ;i+=2) {
+               u_short *p;
+               p = (u_short *) (wp->wdp_model + i);
+               *p = ntohs(*p);
+       }
+/*printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config,
+wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors,
+wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);*/
+
+       /* update disklabel given drive information */
+       du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
+       du->dk_dd.d_ntracks = wp->wdp_heads;
+       du->dk_dd.d_nsectors = wp->wdp_sectors;
+       du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
+       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;
+       /* dubious ... */
+       bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
+       bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1);
+       /* better ... */
+       du->dk_dd.d_type = DTYPE_ESDI;
+       du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
+
+       /* XXX sometimes possibly needed */
+       (void) inb(wdc+wd_status);
+       return (0);
+}
+
+
 /* ARGSUSED */
 /* ARGSUSED */
-wdclose(dev, flags, fmt)
-        dev_t dev;
-        int flags, fmt;
+int
+wdclose(dev_t dev, int flags, int fmt)
 {
        register struct disk *du;
 {
        register struct disk *du;
+        int part = wdpart(dev), mask = 1 << part;
+
+       du = wddrives[wdunit(dev)];
 
 
-       du = &wddrives[wdunit(dev)];
-       du->dk_open-- ;
-       /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
+       /* insure only one open at a time */
+        du->dk_openpart &= ~mask;
+        switch (fmt) {
+        case S_IFCHR:
+                du->dk_copenpart &= ~mask;
+                break;
+        case S_IFBLK:
+                du->dk_bopenpart &= ~mask;
+                break;
+        }
        return(0);
 }
 
        return(0);
 }
 
-wdioctl(dev,cmd,addr,flag)
-       dev_t dev;
-       caddr_t addr;
+int
+wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
 {
        int unit = wdunit(dev);
        register struct disk *du;
        int error = 0;
        struct uio auio;
        struct iovec aiov;
 {
        int unit = wdunit(dev);
        register struct disk *du;
        int error = 0;
        struct uio auio;
        struct iovec aiov;
-       /*int wdformat();*/
 
 
-       du = &wddrives[unit];
+       du = wddrives[unit];
 
        switch (cmd) {
 
 
        switch (cmd) {
 
+       case DIOCSBAD:
+                if ((flag & FWRITE) == 0)
+                        error = EBADF;
+               else
+                       du->dk_bad = *(struct dkbad *)addr;
+               break;
+
        case DIOCGDINFO:
                *(struct disklabel *)addr = du->dk_dd;
                break;
        case DIOCGDINFO:
                *(struct disklabel *)addr = du->dk_dd;
                break;
@@ -928,14 +1033,16 @@ wdioctl(dev,cmd,addr,flag)
                 else
                         error = setdisklabel(&du->dk_dd,
                                        (struct disklabel *)addr,
                 else
                         error = setdisklabel(&du->dk_dd,
                                        (struct disklabel *)addr,
-                         0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
-                /*if (error == 0 && dk->dk_state == OPENRAW &&
-                    vdreset_drive(vddinfo[unit]))
-                        dk->dk_state = OPEN;*/
-               wdsetctlr(dev, du);
+                         /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0,
+                               du->dk_dospartitions);
+                if (error == 0) {
+                       du->dk_flags |= DKFL_BSDLABEL;
+                       wdsetctlr(dev, du);
+               }
                 break;
 
         case DIOCWLABEL:
                 break;
 
         case DIOCWLABEL:
+               du->dk_flags &= ~DKFL_WRITEPROT;
                 if ((flag & FWRITE) == 0)
                         error = EBADF;
                 else
                 if ((flag & FWRITE) == 0)
                         error = EBADF;
                 else
@@ -943,23 +1050,24 @@ wdioctl(dev,cmd,addr,flag)
                 break;
 
         case DIOCWDINFO:
                 break;
 
         case DIOCWDINFO:
+               du->dk_flags &= ~DKFL_WRITEPROT;
                 if ((flag & FWRITE) == 0)
                         error = EBADF;
                 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
                 if ((flag & FWRITE) == 0)
                         error = EBADF;
                 else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
-                  0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
+                         /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0,
+                               du->dk_dospartitions)) == 0) {
                         int wlab;
 
                         int wlab;
 
-                        /*if (error == 0 && dk->dk_state == OPENRAW &&
-                            vdreset_drive(vddinfo[unit]))
-                                dk->dk_state = OPEN; */
+                       du->dk_flags |= DKFL_BSDLABEL;
                        wdsetctlr(dev, du);
 
                         /* simulate opening partition 0 so write succeeds */
                        wdsetctlr(dev, du);
 
                         /* simulate opening partition 0 so write succeeds */
-                        /* dk->dk_openpart |= (1 << 0);            /* XXX */
+                        du->dk_openpart |= (1 << 0);            /* XXX */
                         wlab = du->dk_wlabel;
                         du->dk_wlabel = 1;
                         wlab = du->dk_wlabel;
                         du->dk_wlabel = 1;
-                        error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
-                        /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
+                        error = writedisklabel(dev, wdstrategy,
+                               &du->dk_dd, du->dk_dospartitions);
+                        du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
                         du->dk_wlabel = wlab;
                 }
                 break;
                         du->dk_wlabel = wlab;
                 }
                 break;
@@ -1000,66 +1108,70 @@ wdioctl(dev,cmd,addr,flag)
        return (error);
 }
 
        return (error);
 }
 
-/*wdformat(bp)
-       struct buf *bp;
+#ifdef B_FORMAT
+int
+wdformat(struct buf *bp)
 {
 
        bp->b_flags |= B_FORMAT;
        return (wdstrategy(bp));
 {
 
        bp->b_flags |= B_FORMAT;
        return (wdstrategy(bp));
-}*/
+}
+#endif
 
 
-wdsize(dev)
-       dev_t dev;
+int
+wdsize(dev_t dev)
 {
 {
-       register unit = wdunit(dev);
-       register part = wdpart(dev);
-       register struct disk *du;
-       register val ;
+       int unit = wdunit(dev), part = wdpart(dev), val;
+       struct disk *du;
 
 
-       if (unit >= NWD) return(-1);
-       if (wddrives[unit].dk_state == 0) {
-               val = wdopen (dev, 0);
-               if (val < 0)
-                       return (-1);
-       }
-       du = &wddrives[unit];
-       return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
-               du->dk_dd.d_secsize / 512));
+       if (unit >= _NWD)       /* 31 Jul 92*/
+               return(-1);
+
+       du = wddrives[unit];
+       if (du == 0 || du->dk_state == 0)
+               val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0);
+       if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT)
+               return (-1);
+
+       return((int)du->dk_dd.d_partitions[part].p_size);
 }
 
 extern        char *vmmap;            /* poor name! */
 
 }
 
 extern        char *vmmap;            /* poor name! */
 
-wddump(dev)                    /* dump core after a system crash */
-       dev_t dev;
+int
+wddump(dev_t dev)                      /* dump core after a system crash */
 {
        register struct disk *du;       /* disk unit to do the IO */
        register struct bt_bad *bt_ptr;
        long    num;                    /* number of sectors to write */
 {
        register struct disk *du;       /* disk unit to do the IO */
        register struct bt_bad *bt_ptr;
        long    num;                    /* number of sectors to write */
-       int     unit, part;
-       long    cyloff, blknum, blkcnt;
+       int     unit, part, wdc;
+       long    blkoff, blknum, blkcnt;
        long    cylin, head, sector, stat;
        long    secpertrk, secpercyl, nblocks, i;
        char *addr;
        extern  int Maxmem;
        static  wddoingadump = 0 ;
        long    cylin, head, sector, stat;
        long    secpertrk, secpercyl, nblocks, i;
        char *addr;
        extern  int Maxmem;
        static  wddoingadump = 0 ;
-       extern CMAP1;
-       extern char CADDR1[];
+       extern caddr_t CADDR1;
 
 
-       
-#ifdef ARGO
-outb(0x461,0); /* disable failsafe timer */
-#endif
        addr = (char *) 0;              /* starting address */
        addr = (char *) 0;              /* starting address */
+
+       /* toss any characters present prior to dump */
+       while (sgetc(1))
+               ;
+
        /* size of memory to dump */
        num = Maxmem;
        unit = wdunit(dev);             /* eventually support floppies? */
        part = wdpart(dev);             /* file system */
        /* check for acceptable drive number */
        /* size of memory to dump */
        num = Maxmem;
        unit = wdunit(dev);             /* eventually support floppies? */
        part = wdpart(dev);             /* file system */
        /* check for acceptable drive number */
-       if (unit >= NWD) return(ENXIO);
+       if (unit >= _NWD) return(ENXIO);                /* 31 Jul 92*/
 
 
-       du = &wddrives[unit];
+       du = wddrives[unit];
+       if (du == 0) return(ENXIO);
        /* was it ever initialized ? */
        if (du->dk_state < OPEN) return (ENXIO) ;
        /* was it ever initialized ? */
        if (du->dk_state < OPEN) return (ENXIO) ;
+       if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO);
+       wdc = du->dk_port;
 
        /* Convert to disk sectors */
        num = (u_long) num * NBPG / du->dk_dd.d_secsize;
 
        /* Convert to disk sectors */
        num = (u_long) num * NBPG / du->dk_dd.d_secsize;
@@ -1071,7 +1183,7 @@ outb(0x461,0);    /* disable failsafe timer */
        secpertrk = du->dk_dd.d_nsectors;
        secpercyl = du->dk_dd.d_secpercyl;
        nblocks = du->dk_dd.d_partitions[part].p_size;
        secpertrk = du->dk_dd.d_nsectors;
        secpercyl = du->dk_dd.d_secpercyl;
        nblocks = du->dk_dd.d_partitions[part].p_size;
-       cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
+       blkoff = du->dk_dd.d_partitions[part].p_offset;
 
 /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
        /* check transfer bounds against partition size */
 
 /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
        /* check transfer bounds against partition size */
@@ -1089,7 +1201,7 @@ outb(0x461,0);    /* disable failsafe timer */
        /* some compaq controllers require this ... */
        wdsetctlr(dev, du);
        
        /* some compaq controllers require this ... */
        wdsetctlr(dev, du);
        
-       blknum = dumplo;
+       blknum = dumplo + blkoff;
        while (num > 0) {
 #ifdef notdef
                if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
        while (num > 0) {
 #ifdef notdef
                if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
@@ -1097,20 +1209,19 @@ outb(0x461,0);  /* disable failsafe timer */
                        blkcnt = secpercyl - (blknum % secpercyl);
                            /* keep transfer within current cylinder */
 #endif
                        blkcnt = secpercyl - (blknum % secpercyl);
                            /* keep transfer within current cylinder */
 #endif
-               pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
+               pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
 
                /* compute disk address */
                cylin = blknum / secpercyl;
                head = (blknum % secpercyl) / secpertrk;
                sector = blknum % secpertrk;
 
                /* compute disk address */
                cylin = blknum / secpercyl;
                head = (blknum % secpercyl) / secpertrk;
                sector = blknum % secpertrk;
-               cylin += cyloff;
 
 #ifdef notyet
                /* 
                 * See if the current block is in the bad block list.
                 * (If we have one.)
                 */
 
 #ifdef notyet
                /* 
                 * See if the current block is in the bad block list.
                 * (If we have one.)
                 */
-                       for (bt_ptr = dkbad[unit].bt_bad;
+                       for (bt_ptr = du->dk_bad.bt_bad;
                                bt_ptr->bt_cyl != -1; bt_ptr++) {
                        if (bt_ptr->bt_cyl > cylin)
                                /* Sorted list, and we passed our cylinder.
                                bt_ptr->bt_cyl != -1; bt_ptr++) {
                        if (bt_ptr->bt_cyl > cylin)
                                /* Sorted list, and we passed our cylinder.
@@ -1126,7 +1237,7 @@ outb(0x461,0);    /* disable failsafe timer */
                         */
                                blknum = (du->dk_dd.d_secperunit)
                                        - du->dk_dd.d_nsectors
                         */
                                blknum = (du->dk_dd.d_secperunit)
                                        - du->dk_dd.d_nsectors
-                                       - (bt_ptr - dkbad[unit].bt_bad) - 1;
+                                       - (bt_ptr - du->dk_bad.bt_bad) - 1;
                                cylin = blknum / secpercyl;
                                head = (blknum % secpercyl) / secpertrk;
                                sector = blknum % secpertrk;
                                cylin = blknum / secpercyl;
                                head = (blknum % secpercyl) / secpertrk;
                                sector = blknum % secpertrk;
@@ -1150,12 +1261,6 @@ outb(0x461,0);   /* disable failsafe timer */
                pg ("sdh 0%o sector %d cyl %d addr 0x%x",
                        inb(wdc+wd_sdh), inb(wdc+wd_sector),
                        inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
                pg ("sdh 0%o sector %d cyl %d addr 0x%x",
                        inb(wdc+wd_sdh), inb(wdc+wd_sector),
                        inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
-#endif
-#ifdef ODYSSEUS
-if(cylin < 46 || cylin > 91)pg("oops");
-#endif
-#ifdef PRIAM
-if(cylin < 40 || cylin > 79)pg("oops");
 #endif
                outb(wdc+wd_command, WDCC_WRITE);
                
 #endif
                outb(wdc+wd_command, WDCC_WRITE);
                
@@ -1164,7 +1269,6 @@ if(cylin < 40 || cylin > 79)pg("oops");
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
 
                outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
 
                outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
-               (int) addr += 512;
 
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                /* Check data request (should be done).         */
 
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                /* Check data request (should be done).         */
@@ -1176,10 +1280,16 @@ if(cylin < 40 || cylin > 79)pg("oops");
                }
                /* error check the xfer */
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
                }
                /* error check the xfer */
                if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
+
+               if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ;
                /* update block count */
                num--;
                blknum++ ;
                /* update block count */
                num--;
                blknum++ ;
-if (num % 100 == 0) printf(".") ;
+               (int) addr += 512;
+
+               /* operator aborting dump? */
+               if (sgetc(1))
+                       return(EINTR);
        }
        return(0);
 }
        }
        return(0);
 }