from Keith Muller;
[unix-history] / usr / src / sys / tahoe / vba / vd.c
index 8a160da..31f9597 100644 (file)
-/*     vd.c    1.10    86/10/28        */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Computer Consoles Inc.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)vd.c        7.9 (Berkeley) %G%
+ */
 
 #include "dk.h"
 #if NVD > 0
 /*
 
 #include "dk.h"
 #if NVD > 0
 /*
- * VDDC - Versabus SMD/SMDE driver.
+ * Versabus VDDC/SMDE driver.
  */
  */
-#ifdef VDDCPERF
-#define        DOSCOPE
-#endif
-
-#include "../tahoe/mtpr.h"
-#include "../tahoe/pte.h"
-
 #include "param.h"
 #include "buf.h"
 #include "cmap.h"
 #include "conf.h"
 #include "dir.h"
 #include "dkstat.h"
 #include "param.h"
 #include "buf.h"
 #include "cmap.h"
 #include "conf.h"
 #include "dir.h"
 #include "dkstat.h"
+#include "disklabel.h"
 #include "map.h"
 #include "map.h"
+#include "file.h"
 #include "systm.h"
 #include "user.h"
 #include "vmmac.h"
 #include "proc.h"
 #include "uio.h"
 #include "systm.h"
 #include "user.h"
 #include "vmmac.h"
 #include "proc.h"
 #include "uio.h"
+#include "syslog.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "stat.h"
+
+#include "../tahoe/cpu.h"
+#include "../tahoe/mtpr.h"
+#include "../tahoe/pte.h"
 
 #include "../tahoevba/vbavar.h"
 
 #include "../tahoevba/vbavar.h"
-#define        VDGENDATA
 #include "../tahoevba/vdreg.h"
 #include "../tahoevba/vdreg.h"
-#undef VDGENDATA
-#include "../tahoevba/scope.h"
-
-#define        VDMAXIO         (MAXBPTE*NBPG)
-#define        DUMPSIZE        64      /* controller limit */
 
 
-#define VDUNIT(x)      (minor(x) >> 3)
-#define FILSYS(x)      (minor(x) & 0x07)
-#define PHYS(x)                (vtoph((struct proc *)0, (unsigned)(x)))
-
-#define CTLR_ERROR     1
-#define DRIVE_ERROR    2
-#define HARD_DATA_ERROR        3
-#define SOFT_DATA_ERROR        4
-#define        WRITE_PROTECT   5
+#ifndef        COMPAT_42
+#define        COMPAT_42
+#endif
+#define        B_FORMAT        B_XXX           /* XXX */
 
 
-#define b_cylin        b_resid
-#define b_daddr        b_error
+#define vdunit(dev)    (minor(dev) >> 3)
+#define vdpart(dev)    (minor(dev) & 0x07)
+#define        vdminor(unit,part)      (((unit) << 3) | (part))
 
 struct vba_ctlr *vdminfo[NVD];
 struct  vba_device *vddinfo[NDK];
 
 struct vba_ctlr *vdminfo[NVD];
 struct  vba_device *vddinfo[NDK];
-int    vdprobe(), vdslave(), vdattach(), vddgo();
+int    vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
+long   vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
 struct vba_driver vddriver =
 struct vba_driver vddriver =
-    { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "dk",
-      vddinfo, "vd", vdminfo };
+  { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
+
+/*
+ * Per-controller state.
+ */
+struct vdsoftc {
+       u_short vd_flags;
+#define        VD_INIT         0x1     /* controller initialized */
+#define        VD_STARTED      0x2     /* start command issued */
+#define        VD_DOSEEKS      0x4     /* should overlap seeks */
+#define        VD_SCATGATH     0x8     /* can do scatter-gather commands (correctly) */
+#define        VD_LOCKED       0x10    /* locked for direct controller access */
+#define        VD_WAIT         0x20    /* someone needs direct controller access */
+       u_short vd_type;        /* controller type */
+       u_short vd_wticks;      /* timeout */
+       struct  mdcb vd_mdcb;   /* master command block */
+       u_long  vd_mdcbphys;    /* physical address of vd_mdcb */
+       struct  dcb vd_dcb;     /* i/o command block */
+       u_long  vd_dcbphys;     /* physical address of vd_dcb */
+       struct  vb_buf vd_rbuf; /* vba resources */
+} vdsoftc[NVD];
+
+#define        VDMAXTIME       20      /* max time for operation, sec. */
 
 /*
  * Per-drive state.
  */
 
 /*
  * Per-drive state.
  */
-typedef struct {
-       struct  buf raw_q_element;
-       short   sec_per_blk;
-       short   sec_per_cyl;
-       char    status;
-       struct  buf xfer_queue;
-       int     drive_type;
-       fs_tab  info;
-} unit_tab;
+struct dksoftc {
+       int     dk_state;       /* open fsm */
+#ifndef SECSIZE
+       u_short dk_bshift;      /* shift for * (DEV_BSIZE / sectorsize) XXX */
+#endif SECSIZE
+       int     dk_wlabel;      /* label sector is currently 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 */
+       u_int   dk_curcyl;      /* last selected cylinder */
+       struct  skdcb dk_dcb;   /* seek command block */
+       u_long  dk_dcbphys;     /* physical address of dk_dcb */
+       int     df_reg[3];      /* for formatting, in-out parameters */
+} dksoftc[NDK];
 
 /*
 
 /*
- * Per-controller state.
+ * Drive states.  Used during steps of open/initialization.
+ * States < OPEN (> 0) are transient, during an open operation.
+ * OPENRAW is used for unlabeled disks, to allow format operations.
  */
  */
-typedef struct {
-       char    ctlr_type;      /* controller type */
-       struct  pte *map;       /* i/o page map */
-       caddr_t utl;            /* mapped i/o space */
-       u_int   cur_slave:8;    /* last active unit number */
-       u_int   int_expected:1; /* expect an interrupt */
-       u_int   ctlr_started:1; /* start command was issued */
-       u_int   overlap_seeks:1;/* should overlap seeks */
-       u_int   initdone:1;     /* controller initialization completed */
-       u_int   off_cylinder:16;/* off cylinder bit map */
-       u_int   unit_type[16];  /* slave types */
-       u_int   cur_cyl[16];    /* cylinder last selected */
-       long    cur_trk[16];    /* track last selected */
-       fmt_mdcb ctlr_mdcb;     /* controller mdcb */
-       fmt_dcb ctlr_dcb;       /* r/w dcb */
-       fmt_dcb seek_dcb[4];    /* dcbs for overlapped seeks */
-       caddr_t rawbuf;         /* buffer for raw+swap i/o */
-} ctlr_tab;
-
-ctlr_tab vdctlr_info[NVD];
-unit_tab vdunit_info[NDK];
+#define        CLOSED          0               /* disk is closed */
+#define        WANTOPEN        1               /* open requested, not started */
+#define        WANTOPENRAW     2               /* open requested, no label */
+#define        RDLABEL         3               /* reading pack label */
+#define        OPEN            4               /* intialized and ready */
+#define        OPENRAW         5               /* open, no label */
+
+struct buf dkutab[NDK];        /* i/o queue headers */
+struct disklabel dklabel[NDK]; /* pack labels */
+
+#define b_cylin        b_resid
+#define        b_track b_error         /* used for seek commands */
+#define        b_seekf b_forw          /* second queue on um_tab */
+#define        b_seekl b_back          /* second queue on um_tab */
+
+int    vdwstart, vdwatch();
 
 /*
  * See if the controller is really there; if so, initialize it.
 
 /*
  * See if the controller is really there; if so, initialize it.
@@ -100,253 +137,342 @@ vdprobe(reg, vm)
        struct vba_ctlr *vm;
 {
        register br, cvec;              /* must be r12, r11 */
        struct vba_ctlr *vm;
 {
        register br, cvec;              /* must be r12, r11 */
-       register cdr *addr = (cdr *)reg;
-       register ctlr_tab *ci;
-       int i;
+       register struct vddevice *vdaddr = (struct vddevice *)reg;
+       struct vdsoftc *vd;
+       int s;
 
 
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       vdintr(0);
+#endif
        if (badaddr((caddr_t)reg, 2))
                return (0);
        if (badaddr((caddr_t)reg, 2))
                return (0);
-       ci = &vdctlr_info[vm->um_ctlr];
-       addr->cdr_reset = 0xffffffff;
+       vd = &vdsoftc[vm->um_ctlr];
+       vdaddr->vdreset = 0xffffffff;
        DELAY(1000000);
        DELAY(1000000);
-       if (addr->cdr_reset != (unsigned)0xffffffff) {
-               ci->ctlr_type = SMDCTLR;
-               ci->overlap_seeks = 0;
+       if (vdaddr->vdreset != (unsigned)0xffffffff) {
+               vd->vd_type = VDTYPE_VDDC;
+               vd->vd_flags &= ~VD_DOSEEKS;
                DELAY(1000000);
        } else {
                DELAY(1000000);
        } else {
-               ci->overlap_seeks = 1;
-               ci->ctlr_type = SMD_ECTLR;
-               addr->cdr_reserved = 0x0;
+               vd->vd_type = VDTYPE_SMDE;
+               vd->vd_flags |= VD_DOSEEKS;
+               vdaddr->vdrstclr = 0;
                DELAY(3000000);
                DELAY(3000000);
-               addr->cdr_csr = 0;
-               addr->mdcb_tcf = AM_ENPDA;
-               addr->dcb_tcf = AM_ENPDA;
-               addr->trail_tcf = AM_ENPDA;
-               addr->data_tcf = AM_ENPDA;
-               addr->cdr_ccf = CCF_SEN | CCF_DER | CCF_STS |
+               vdaddr->vdcsr = 0;
+               vdaddr->vdtcf_mdcb = AM_ENPDA;
+               vdaddr->vdtcf_dcb = AM_ENPDA;
+               vdaddr->vdtcf_trail = AM_ENPDA;
+               vdaddr->vdtcf_data = AM_ENPDA;
+               vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS |
                    XMD_32BIT | BSZ_16WRD |
                    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
        }
                    XMD_32BIT | BSZ_16WRD |
                    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
        }
+       vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
+       vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
+       vm->um_addr = reg;              /* XXX */
+       s = spl7();
+       if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
+               printf("vd%d: %s cmd failed\n", vm->um_ctlr,
+                   vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
+               splx(s);
+               return (0);
+       }
+       if (vd->vd_type == VDTYPE_SMDE) {
+               vd->vd_dcb.trail.idtrail.date = 0;
+               if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
+                       uncache(&vd->vd_dcb.trail.idtrail.date);
+                       if (vd->vd_dcb.trail.idtrail.date != 0)
+                               vd->vd_flags |= VD_SCATGATH;
+               }
+       }
+       splx(s);
        /*
         * Allocate page tables and i/o buffer.
         */
        /*
         * Allocate page tables and i/o buffer.
         */
-       vbmapalloc(btoc(VDMAXIO)+1, &ci->map, &ci->utl);
-       ci->rawbuf = calloc(VDMAXIO);
-       /*
-        * Initialize all the drives to be of an unknown type.
-        */
-       for (i = 0; i < 15; i++)
-               ci->unit_type[i] = UNKNOWN;
+       if (vbainit(&vd->vd_rbuf, MAXPHYS,
+           vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
+               printf("vd%d: vbainit failed\n", vm->um_ctlr);
+               return (0);
+       }
        br = 0x17, cvec = 0xe0 + vm->um_ctlr;   /* XXX */
        br = 0x17, cvec = 0xe0 + vm->um_ctlr;   /* XXX */
-       return (sizeof (*addr));
+       return (sizeof (struct vddevice));
 }
 
 /*
 }
 
 /*
- * See if a drive is really there
- * Try to reset/configure the drive, then test its status.
+ * See if a drive is really there.
+ *
+ * Can't read pack label here as various data structures
+ * aren't setup for doing a read in a straightforward
+ * manner.  Instead just probe for the drive and leave
+ * the pack label stuff to the attach routine.
  */
  */
-vdslave(vi, addr)
+/* ARGSUSED */
+vdslave(vi, vdaddr)
        register struct vba_device *vi;
        register struct vba_device *vi;
-       register cdr *addr;
+       struct vddevice *vdaddr;
 {
 {
-       register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
-       register unit_tab *ui = &vdunit_info[vi->ui_unit];
-       register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
-       register fmt_dcb *dcb = &ci->ctlr_dcb;
-       register int type;
-
-       if (!ci->initdone) {
-               printf("vd%d: %s controller\n", vi->ui_ctlr,
-                   ci->ctlr_type == SMDCTLR ? "smd" : "smde");
-               if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, INIT, 10) &
-                   HRDERR) {
-                       printf("vd%d: init error\n", vi->ui_ctlr);
-                       return (0);
-               }
-               if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, DIAG, 10) &
-                   HRDERR) {
-                       printf("vd%d: diagnostic error\n", vi->ui_ctlr);
-                       return (0);
+       register struct disklabel *lp = &dklabel[vi->ui_unit];
+       register struct dksoftc *dk = &dksoftc[vi->ui_unit];
+       struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
+
+       if ((vd->vd_flags&VD_INIT) == 0) {
+               printf("vd%d: %s controller", vi->ui_ctlr,
+                   vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
+               if (vd->vd_flags & VD_SCATGATH) {
+                       char rev[5];
+
+                       bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
+                           sizeof(vd->vd_dcb.trail.idtrail.rev));
+                       printf(" firmware rev %s (%d-%d-%d)", rev,
+                           (vd->vd_dcb.trail.idtrail.date >> 8) & 0xff,
+                           vd->vd_dcb.trail.idtrail.date & 0xff,
+                           (vd->vd_dcb.trail.idtrail.date >> 16) & 0xffff);
                }
                }
-               ci->initdone = 1;
+               printf("\n");
+               vd->vd_flags |= VD_INIT;
        }
        }
+
        /*
        /*
-        * Seek on all drive types starting from the largest one.
-        * a successful seek to the last sector/cylinder/track verifies 
-        * the drive type connected to this port. 
+        * Initialize label enough to do a reset on
+        * the drive.  The remainder of the default
+        * label values will be filled in in vdinit
+        * at attach time.
         */
         */
-       for (type = 0; type < nvddrv; type++) { 
-               /* XXX */
-               if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
-                       continue;
-               /* XXX */
-               if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type,0))
-                       return (0);
-               dcb->opcode = (short)RD;
-               dcb->intflg = NOINT;
-               dcb->nxtdcb = (fmt_dcb *)0;     /* end of chain */
-               dcb->operrsta = 0;
-               dcb->devselect = (char)(vi->ui_slave);
-               dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
-               dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf); 
-               dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
-               dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
-               dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
-               dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
-               mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
-               mdcb->vddcstat = 0;
-               VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
-               if (!vdpoll(ci, addr, 60))
-                       printf(" during probe\n");
-               if ((dcb->operrsta&HRDERR) == 0)
-                       break;
-       }
-       if (type >= nvddrv) {
-               /*
-                * If reached here, a drive which is not defined in the 
-                * 'vdst' tables is connected. Cannot set its type.
-                */
-               printf("dk%d: unknown drive type\n", vi->ui_unit);
-               return (0);
+       if (vd->vd_type == VDTYPE_SMDE)
+               lp->d_secsize = VD_MAXSECSIZE;
+       else
+               lp->d_secsize = VDDC_SECSIZE;
+       lp->d_nsectors = 66;            /* only used on smd-e */
+       lp->d_ntracks = 23;
+       lp->d_ncylinders = 850;
+       lp->d_secpercyl = 66*23;
+       lp->d_rpm = 3600;
+       lp->d_npartitions = 1;
+       lp->d_partitions[0].p_offset = 0;
+       lp->d_partitions[0].p_size = LABELSECTOR + 1;
+
+       /*
+        * Initialize invariant portion of
+        * dcb used for overlapped seeks.
+        */
+       dk->dk_dcb.opcode = VDOP_SEEK;
+       dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
+       dk->dk_dcb.devselect = vi->ui_slave;
+       dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
+       dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
+       dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
+#ifndef SECSIZE
+       vd_setsecsize(dk, lp);
+#endif
+       return (vdreset_drive(vi));
+}
+
+vdattach(vi)
+       register struct vba_device *vi;
+{
+       register int unit = vi->ui_unit;
+       register struct disklabel *lp = &dklabel[unit];
+
+       /*
+        * Try to initialize device and read pack label.
+        */
+       if (vdinit(vdminor(unit, 0), 0) != 0) {
+               printf(": unknown drive type");
+               return;
        }
        }
-       ui->drive_type = type;
-       ui->info = vdst[type];
-       ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
-       vi->ui_type = type;
-       vi->ui_dk = 1;
-       return (1);
+       if (dksoftc[unit].dk_state == OPEN)
+               printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
+                   lp->d_typename, lp->d_secsize,
+                   lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
+       /*
+        * (60 / rpm) / (sectors per track * (bytes per sector / 2))
+        */
+       if (vi->ui_dk >= 0)
+               dk_mspw[vi->ui_dk] = 120.0 /
+                   (lp->d_rpm * lp->d_nsectors * lp->d_secsize);
+#ifdef notyet
+       addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
+#endif
 }
 
 }
 
-vdconfigure_drive(addr, ctlr, slave, type, pass)
-       register cdr *addr;
-       int ctlr, slave, type, pass;
+vdopen(dev, flags, fmt)
+       dev_t dev;
+       int flags, fmt;
 {
 {
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
-
-       ci->ctlr_dcb.opcode = RSTCFG;           /* command */
-       ci->ctlr_dcb.intflg = NOINT;
-       ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0;     /* end of chain */
-       ci->ctlr_dcb.operrsta = 0;
-       ci->ctlr_dcb.devselect = (char)slave;
-       ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
-       ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
-       if (ci->ctlr_type == SMD_ECTLR) {
-               ci->ctlr_dcb.trailcnt = (char)5;
-               ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
-               ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
-               ci->ctlr_dcb.trail.rstrail.recovery = 0x18f;
-       } else
-               ci->ctlr_dcb.trailcnt = (char)2;
-       ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
-       ci->ctlr_mdcb.vddcstat = 0;
-       VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
-       if (!vdpoll(ci, addr, 5)) {
-               printf(" during config\n");
-               return (0);
+       register unit = vdunit(dev);
+       register struct disklabel *lp;
+       register struct dksoftc *dk;
+       register struct partition *pp;
+       struct vba_device *vi;
+       int s, error, part = vdpart(dev), mask = 1 << part;
+       daddr_t start, end;
+
+       if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
+               return (ENXIO);
+       lp = &dklabel[unit];
+       dk = &dksoftc[unit];
+
+       s = spl7();
+       while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
+           dk->dk_state != CLOSED)
+               sleep((caddr_t)dk, PZERO+1);
+       splx(s);
+       if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
+               if (error = vdinit(dev, flags))
+                       return (error);
+
+       if (vdwstart == 0) {
+               timeout(vdwatch, (caddr_t)0, hz);
+               vdwstart++;
        }
        }
-       if (ci->ctlr_dcb.operrsta & HRDERR) {
-               if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
-                       printf("vd%d: drive %d: config error\n", ctlr, slave);
-               else if (pass == 0) {
-                       vdstart_drive(addr, ctlr, slave);
-                       return (vdconfigure_drive(addr, ctlr, slave, type, 1));
-               } else if (pass == 2)
-                       return (vdconfigure_drive(addr, ctlr, slave, type, 3));
-               return (0);
+       /*
+        * Warn if a partion is opened
+        * that overlaps another partition which is open
+        * unless one is the "raw" partition (whole disk).
+        */
+#define        RAWPART         8               /* 'x' partition */     /* XXX */
+       if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
+               pp = &lp->d_partitions[part];
+               start = pp->p_offset;
+               end = pp->p_offset + pp->p_size;
+               for (pp = lp->d_partitions;
+                    pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
+                       if (pp->p_offset + pp->p_size <= start ||
+                           pp->p_offset >= end)
+                               continue;
+                       if (pp - lp->d_partitions == RAWPART)
+                               continue;
+                       if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
+                               log(LOG_WARNING,
+                                   "dk%d%c: overlaps open partition (%c)\n",
+                                   unit, part + 'a',
+                                   pp - lp->d_partitions + 'a');
+               }
        }
        }
-       return (1);
+       if (part >= lp->d_npartitions)
+               return (ENXIO);
+       dk->dk_openpart |= mask;
+       switch (fmt) {
+       case S_IFCHR:
+               dk->dk_copenpart |= mask;
+               break;
+       case S_IFBLK:
+               dk->dk_bopenpart |= mask;
+               break;
+       }
+       return (0);
 }
 
 }
 
-vdstart_drive(addr, ctlr, slave)
-       cdr *addr;
-       register int ctlr, slave;
+/* ARGSUSED */
+vdclose(dev, flags, fmt)
+       dev_t dev;
+       int flags, fmt;
 {
 {
-       int error = 0;
+       register int unit = vdunit(dev);
+       register struct dksoftc *dk = &dksoftc[unit];
+       int part = vdpart(dev), mask = 1 << part;
 
 
-       printf("vd%d: starting drive %d, wait...", ctlr, slave);
-       if (vdctlr_info[ctlr].ctlr_started) {
-#ifdef notdef
-printf("DELAY(5500000)...");
-               DELAY(5500000);
-#endif
-               goto done;
+       switch (fmt) {
+       case S_IFCHR:
+               dk->dk_copenpart &= ~mask;
+               break;
+       case S_IFBLK:
+               dk->dk_bopenpart &= ~mask;
+               break;
        }
        }
-       vdctlr_info[ctlr].ctlr_started = 1;
-       error = vdnotrailer(addr, ctlr, 0, VDSTART, (slave*6)+62) & HRDERR;
-       if (!error) {
-#ifdef notdef
-               DELAY((slave * 5500000) + 62000000);
-#endif
+       if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
+               dk->dk_openpart &= ~mask;
+       /*
+        * Should wait for i/o to complete on this partition
+        * even if others are open, but wait for work on blkflush().
+        */
+       if (dk->dk_openpart == 0) {
+               int s = spl7();
+               while (dkutab[unit].b_actf)
+                       sleep((caddr_t)dk, PZERO-1);
+               splx(s);
+               dk->dk_state = CLOSED;
+               dk->dk_wlabel = 0;
        }
        }
-done:
-       printf("\n");
-       return (error == 0);
+       return (0);
 }
 
 }
 
-vdnotrailer(addr, ctlr, unit, function, time)
-       register cdr *addr;
-       int ctlr, unit, function, time;
+vdinit(dev, flags)
+       dev_t dev;
+       int flags;
 {
 {
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
-       fmt_mdcb *mdcb = &ci->ctlr_mdcb;
-       fmt_dcb *dcb = &ci->ctlr_dcb;
-
-       dcb->opcode = function;         /* command */
-       dcb->intflg = NOINT;
-       dcb->nxtdcb = (fmt_dcb *)0;     /* end of chain */
-       dcb->operrsta = 0;
-       dcb->devselect = (char)unit;
-       dcb->trailcnt = (char)0;
-       mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
-       mdcb->vddcstat = 0;
-       VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
-       if (!vdpoll(ci, addr, time)) {
-               printf(" during init\n");
-               return (DCBCMP|ANYERR|HRDERR|OPABRT);
+       register struct disklabel *lp;
+       register struct dksoftc *dk;
+       struct vba_device *vi;
+       int unit = vdunit(dev), error = 0;
+       char *msg, *readdisklabel();
+       extern int cold;
+
+       dk = &dksoftc[unit];
+       if (flags & O_NDELAY) {
+               dk->dk_state = OPENRAW;
+               return (0);
        }
        }
-       return (dcb->operrsta);
+       dk->dk_state = RDLABEL;
+       lp = &dklabel[unit];
+       vi = vddinfo[unit];
+       if (msg = readdisklabel(dev, vdstrategy, lp)) {
+               if (cold) {
+                       printf(": %s", msg);
+                       dk->dk_state = CLOSED;
+               } else {
+                       log(LOG_ERR, "dk%d: %s\n", unit, msg);
+                       dk->dk_state = OPENRAW;
+               }
+#ifdef COMPAT_42
+               vdlock(vi->ui_ctlr);
+               if (vdmaptype(vi, lp))
+                       dk->dk_state = OPEN;
+               vdunlock(vi->ui_ctlr);
+#endif
+       } else {
+               /*
+                * Now that we have the label, configure
+                * the correct drive parameters.
+                */
+               vdlock(vi->ui_ctlr);
+               if (vdreset_drive(vi))
+                       dk->dk_state = OPEN;
+               else {
+                       dk->dk_state = CLOSED;
+                       error = ENXIO;
+               }
+               vdunlock(vi->ui_ctlr);
+       }
+#ifndef SECSIZE
+       vd_setsecsize(dk, lp);
+#endif
+       wakeup((caddr_t)dk);
+       return (error);
 }
 
 }
 
-vdattach(vi)
-       register struct vba_device *vi;
+#ifndef SECSIZE
+vd_setsecsize(dk, lp)
+       register struct dksoftc *dk;
+       register struct disklabel *lp;
 {
 {
-       register unit_tab *ui = &vdunit_info[vi->ui_unit];
-       register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
-       register struct buf *cq = &vi->ui_mi->um_tab;
-       register struct buf *uq = cq->b_forw;
-       register struct buf *start_queue = uq;
-       register fs_tab *fs = &ui->info;
-
-       ui->info = vdst[vi->ui_type];
-       ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
-       ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
-       ui->xfer_queue.b_dev = vi->ui_slave;
-       ci->unit_type[vi->ui_slave] = vi->ui_type;
-       /* load unit into controller's active unit list */
-       if (uq == NULL) {
-               cq->b_forw = &ui->xfer_queue;
-               ui->xfer_queue.b_forw = &ui->xfer_queue;
-               ui->xfer_queue.b_back = &ui->xfer_queue;
-       } else {
-               while (uq->b_forw != start_queue)
-                       uq = uq->b_forw;
-               ui->xfer_queue.b_forw = start_queue;
-               ui->xfer_queue.b_back = uq;
-               uq->b_forw = &ui->xfer_queue;
-               start_queue->b_back = &ui->xfer_queue;
-       }
-       printf("dk%d: %s <ntrak %d, ncyl %d, nsec %d>\n",
-           vi->ui_unit, fs->type_name,
-           ui->info.ntrak, ui->info.ncyl, ui->info.nsec);
+       int mul;
+
        /*
        /*
-        * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
+        * Calculate scaling shift for mapping
+        * DEV_BSIZE blocks to drive sectors.
         */
         */
-       dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
+       mul = DEV_BSIZE / lp->d_secsize;
+       dk->dk_bshift = 0;
+       while ((mul >>= 1) > 0)
+               dk->dk_bshift++;
 }
 }
+#endif SECSIZE
 
 /*ARGSUSED*/
 
 /*ARGSUSED*/
-vddgo(um)
-       struct vba_ctlr *um;
+vddgo(vm)
+       struct vba_device *vm;
 {
 
 }
 {
 
 }
@@ -354,601 +480,1029 @@ vddgo(um)
 vdstrategy(bp)
        register struct buf *bp;
 {
 vdstrategy(bp)
        register struct buf *bp;
 {
-       register int unit = VDUNIT(bp->b_dev);
-       register struct vba_device *vi = vddinfo[unit];
-       register par_tab *par;
-       register unit_tab *ui;
-       register fs_tab *fs;
-       register int blks, bn, s;
-
-       if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0)
+       register struct vba_device *vi;
+       register struct disklabel *lp;
+       register struct dksoftc *dk;
+       register int unit;
+       register daddr_t sn;
+       struct buf *dp;
+       daddr_t sz, maxsz;
+       int part, s;
+
+       unit = vdunit(bp->b_dev);
+       if (unit >= NDK) {
+               bp->b_error = ENXIO;
                goto bad;
                goto bad;
-       ui = &vdunit_info[unit];
-       fs = &ui->info;
-       par = &fs->partition[FILSYS(bp->b_dev)];
-       blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
-       if (bp->b_blkno + blks >= par->par_len) {
-               blks = par->par_len - bp->b_blkno;
-               if (blks <= 0)
+       }
+       vi = vddinfo[unit];
+       lp = &dklabel[unit];
+       if (vi == 0 || vi->ui_alive == 0) {
+               bp->b_error = ENXIO;
+               goto bad;
+       }
+       dk = &dksoftc[unit];
+       if (dk->dk_state < OPEN)
+               goto q;
+       if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
+               bp->b_error = EROFS;
+               goto bad;
+       }
+       part = vdpart(bp->b_dev);
+       if ((dk->dk_openpart & (1 << part)) == 0) {
+               bp->b_error = ENODEV;
+               goto bad;
+       }
+       sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
+       maxsz = lp->d_partitions[part].p_size;
+#ifndef SECSIZE
+       sn = bp->b_blkno << dk->dk_bshift;
+#else SECSIZE
+       sn = bp->b_blkno;
+#endif SECSIZE
+       if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
+#if LABELSECTOR != 0
+           sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
+#endif
+           (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
+               bp->b_error = EROFS;
+               goto bad;
+       }
+       if (sn < 0 || sn + sz > maxsz) {
+               if (sn == maxsz) {
+                       bp->b_resid = bp->b_bcount;
+                       goto done;
+               }
+               sz = maxsz - sn;
+               if (sz <= 0) {
+                       bp->b_error = EINVAL;
                        goto bad;
                        goto bad;
-               bp->b_bcount = blks * DEV_BSIZE;
+               }
+               bp->b_bcount = sz * lp->d_secsize;
        }
        }
-       bn = bp->b_blkno + par->par_start;
-       bn *= ui->sec_per_blk;
-       bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
-       bp->b_cylin = bn / ui->sec_per_cyl;
-       vbasetup(bp, ui->info.secsize);
+       bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
+#ifdef SECSIZE
+if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
+panic("vdstrat blksize");
+#endif SECSIZE
+q:
        s = spl7();
        s = spl7();
-       if (ui->xfer_queue.av_forw == NULL) {
-               register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
-               int slave = vi->ui_slave;
-
-               if (bp->b_cylin != ci->cur_cyl[slave] ||
-                   bp->b_daddr != ci->cur_trk[slave])
-                       ci->off_cylinder |= 1 << slave;
+       dp = &dkutab[vi->ui_unit];
+       disksort(dp, bp);
+       if (!dp->b_active) {
+               (void) vdustart(vi);
+               if (!vi->ui_mi->um_tab.b_active)
+                       vdstart(vi->ui_mi);
        }
        }
-       bp->b_daddr |= (bn % fs->nsec) << 8;
-       disksort(&ui->xfer_queue, bp);
-       if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
-               splx(s);
-               vdstart(vddinfo[unit]->ui_mi);
-       } else
-               splx(s);
+       splx(s);
        return;
 bad:   
        return;
 bad:   
-       bp->b_flags |= B_ERROR, bp->b_error = ENXIO;
-       bp->b_resid = bp->b_bcount;
-       iodone(bp);
+       bp->b_flags |= B_ERROR;
+done:
+       biodone(bp);
+       return;
 }
 
 }
 
-/*
- * Start up a transfer on a drive.
- */
-vdstart(ci)
-       register struct vba_ctlr *ci;
+vdustart(vi)
+       register struct vba_device *vi;
 {
 {
-       register struct buf *cq = &ci->um_tab;
-       register struct buf *uq = cq->b_forw;
-
-       /* search for next ready unit */
-       cq->b_forw = cq->b_forw->b_forw;
-       uq = cq->b_forw;
-       do {
-               if (uq->av_forw != NULL) {
-                       cq->b_forw = uq;
-                       vdexecute(ci, uq);
-                       return;
-               }
-               uq = uq->b_forw;
-       } while (uq != cq->b_forw);
+       register struct buf *bp, *dp;
+       register struct vba_ctlr *vm;
+       register int unit = vi->ui_unit;
+       register struct dksoftc *dk;
+       register struct vdsoftc *vd;
+       struct disklabel *lp;
+
+       dp = &dkutab[unit];
+       /*
+        * If queue empty, nothing to do.
+        */
+       if ((bp = dp->b_actf) == NULL)
+               return;
+       /*
+        * If drive is off-cylinder and controller supports seeks,
+        * place drive on seek queue for controller.
+        * Otherwise, place on transfer queue.
+        */
+       vd = &vdsoftc[vi->ui_ctlr];
+       dk = &dksoftc[unit];
+       vm = vi->ui_mi;
+       if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
+               lp = &dklabel[unit];
+               bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
+               if (vm->um_tab.b_seekf == NULL)
+                       vm->um_tab.b_seekf = dp;
+               else
+                       vm->um_tab.b_seekl->b_forw = dp;
+               vm->um_tab.b_seekl = dp;
+       } else {
+               if (vm->um_tab.b_actf == NULL)
+                       vm->um_tab.b_actf = dp;
+               else
+                       vm->um_tab.b_actl->b_forw = dp;
+               vm->um_tab.b_actl = dp;
+       }
+       dp->b_forw = NULL;
+       dp->b_active++;
 }
 
 /*
 }
 
 /*
- * Initiate seeks for all drives off-cylinder.
+ * Start next transfer on a controller.
+ * There are two queues of drives, the first on-cylinder
+ * and the second off-cylinder from their next transfers.
+ * Perform the first transfer for the first drive on the on-cylinder
+ * queue, if any, otherwise the first transfer for the first drive
+ * on the second queue.  Initiate seeks on remaining drives on the
+ * off-cylinder queue, then move them all to the on-cylinder queue.
  */
  */
-vdload_seeks(ci, uq)
-       register ctlr_tab *ci;
-       register struct buf *uq;
+vdstart(vm)
+       register struct vba_ctlr *vm;
 {
 {
-       register int unit, slave, nseeks;
-       register fmt_dcb *dcb;
        register struct buf *bp;
        register struct buf *bp;
-       register struct buf *start_queue = uq;
-
-       nseeks = 0;
-       do {
-               bp = uq->av_forw;
-               if (bp != NULL) {
-                       unit = VDUNIT(bp->b_dev);
-                       slave = vddinfo[unit]->ui_slave;
-                       if (ci->off_cylinder & (1 << slave)) {
-                               ci->off_cylinder &= ~(1 << slave);
-                               if (ci->cur_cyl[slave] != bp->b_cylin) {
-                                       ci->cur_cyl[slave] = bp->b_cylin;
-                                       dk_seek[unit]++;
-                               }
-                               ci->cur_trk[slave] = bp->b_daddr&0xff;
-                               dcb = &ci->seek_dcb[nseeks++];
-                               dcb->opcode = SEEK;
-                               dcb->intflg = NOINT | INT_PBA;
-                               dcb->operrsta = 0;
-                               dcb->devselect = (char)slave;
-                               dcb->trailcnt = (char)1;
-                               dcb->trail.sktrail.skaddr.cylinder =
-                                   bp->b_cylin;
-                               dcb->trail.sktrail.skaddr.track =
-                                   bp->b_daddr & 0xff;
-                               dcb->trail.sktrail.skaddr.sector = 0;
-                       }
-               }
-               uq = uq->b_forw;
-       } while (uq != start_queue && nseeks < 4);
-       return (nseeks);
-}
+       register struct vba_device *vi;
+       register struct vdsoftc *vd;
+       register struct dksoftc *dk;
+       register struct disklabel *lp;
+       register struct dcb **dcbp;
+       struct buf *dp;
+       int sn, tn;
+
+loop:
+       /*
+        * Pull a request off the controller queue.
+        */
+       if ((dp = vm->um_tab.b_actf) == NULL &&
+           (dp = vm->um_tab.b_seekf) == NULL)
+               return;
+       if ((bp = dp->b_actf) == NULL) {
+               if (dp == vm->um_tab.b_actf)
+                       vm->um_tab.b_actf = dp->b_forw;
+               else
+                       vm->um_tab.b_seekf = dp->b_forw;
+               goto loop;
+       }
 
 
-extern vd_int_timeout();
-/*
- * Execute the next command on the unit queue uq.
- */
-vdexecute(controller_info, uq)
-       register struct vba_ctlr *controller_info;
-       register struct buf *uq;
-{
-       register struct buf *bp = uq->av_forw;
-       register int ctlr = controller_info->um_ctlr;
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
-       register int unit = VDUNIT(bp->b_dev);
-       register int slave = vddinfo[unit]->ui_slave;
-       register fmt_mdcb *mdcb = &ci->ctlr_mdcb; 
-       register fmt_dcb *dcb = &ci->ctlr_dcb; 
-       
        /*
        /*
-        * If there are overlapped seeks to perform, shuffle
-        * them to the front of the queue and get them started
-        * before any data transfers (to get some parallelism).
+        * Mark controller busy, and determine
+        * destination of this request.
         */
         */
-       if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
-               register int i, nseeks;
-               
-               /* setup seek requests in seek-q */
-               nseeks = vdload_seeks(ci, uq);
-               /* place at the front of the master q */
-               mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
-               /* shuffle any remaining seeks up in the seek-q */
-               for (i = 1; i < nseeks; i++)
-                       ci->seek_dcb[i-1].nxtdcb = 
-                           (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
-               ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
-       } else {
-               if (bp->b_cylin != ci->cur_cyl[slave]) {
-                       ci->cur_cyl[slave] = bp->b_cylin;
-                       dk_seek[unit]++;
-               }
-               ci->cur_trk[slave] = bp->b_daddr & 0xff;
-               ci->off_cylinder = 0;
-               mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
-       }
-       dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
-       dcb->intflg = INTDONE;
-       dcb->nxtdcb = (fmt_dcb *)0;     /* end of chain */
-       dcb->operrsta = 0;
-       dcb->devselect = (char)slave;
-       dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
-       dcb->trail.rwtrail.memadr = (char *)
-           vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
-       dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
-       dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
-       dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
-       dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
-       mdcb->vddcstat = 0;
-       dk_wds[unit] += bp->b_bcount / 32;
-       ci->int_expected = 1;
-       timeout(vd_int_timeout, (caddr_t)ctlr, 20*60);
-       dk_busy |= 1 << unit;
-       scope_out(1);
-       VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
-           (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
+       vm->um_tab.b_active++;
+       vi = vddinfo[vdunit(bp->b_dev)];
+       dk = &dksoftc[vi->ui_unit];
+#ifndef SECSIZE
+       sn = bp->b_blkno << dk->dk_bshift;
+#else SECSIZE
+       sn = bp->b_blkno;
+#endif SECSIZE
+       lp = &dklabel[vi->ui_unit];
+       sn %= lp->d_secpercyl;
+       tn = sn / lp->d_nsectors;
+       sn %= lp->d_nsectors;
+
+       /*
+        * Construct dcb for read/write command.
+        */
+       vd = &vdsoftc[vm->um_ctlr];
+       vd->vd_dcb.intflg = DCBINT_DONE;
+       vd->vd_dcb.devselect = dk->dk_dcb.devselect;
+       vd->vd_dcb.operrsta = 0;
+       vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
+       vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
+       vd->vd_dcb.trail.rwtrail.disk.track = tn;
+       vd->vd_dcb.trail.rwtrail.disk.sector = sn;
+       dk->dk_curcyl = bp->b_cylin;
+       bp->b_track = 0;                /* init overloaded field */
+       vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
+       if (bp->b_flags & B_FORMAT)
+               vd->vd_dcb.opcode = dk->dk_op;
+       else if (vd->vd_flags & VD_SCATGATH &&
+           ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
+               vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
+       else
+               vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
+
+       switch (vd->vd_dcb.opcode) {
+       case VDOP_FSECT:
+               vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
+               vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
+                   lp->d_secsize;
+               vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
+               vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
+               goto setupaddr;
+
+       case VDOP_RDRAW:
+       case VDOP_RD:
+       case VDOP_WD:
+               vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
+setupaddr:
+               vd->vd_dcb.trail.rwtrail.memadr =
+                       vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
+               break;
+
+       case VDOP_RAS:
+       case VDOP_GAW:
+               vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
+                   &vd->vd_dcb.trail.sgtrail);
+               break;
+       }
+       if (vi->ui_dk >= 0) {
+               dk_busy |= 1<<vi->ui_dk;
+               dk_xfer[vi->ui_dk]++;
+               dk_wds[vi->ui_dk] += bp->b_bcount>>6;
+       }
+
+       /*
+        * Look for any seeks to be performed on other drives on this
+        * controller.  If overlapped seeks exist, insert seek commands
+        * on the controller's command queue before the transfer.
+        */
+       dcbp = &vd->vd_mdcb.mdcb_head;
+
+       if (dp == vm->um_tab.b_seekf)
+               dp = dp->b_forw;
+       else
+               dp = vm->um_tab.b_seekf;
+       for (; dp != NULL; dp = dp->b_forw) {
+               if ((bp = dp->b_actf) == NULL)
+                       continue;
+               vi = vddinfo[vdunit(bp->b_dev)];
+               dk = &dksoftc[vi->ui_unit];
+               dk->dk_curcyl = bp->b_cylin;
+               if (vi->ui_dk >= 0)
+                       dk_seek[vi->ui_dk]++;
+               dk->dk_dcb.operrsta = 0;
+               dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
+               dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
+               *dcbp = (struct dcb *)dk->dk_dcbphys;
+               dcbp = &dk->dk_dcb.nxtdcb;
+       }
+       *dcbp = (struct dcb *)vd->vd_dcbphys;
+       if (vm->um_tab.b_actf)
+               vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
+       else
+               vm->um_tab.b_actf = vm->um_tab.b_seekf;
+       if (vm->um_tab.b_seekf)
+               vm->um_tab.b_actl = vm->um_tab.b_seekl;
+       vm->um_tab.b_seekf = 0;
+
+       /*
+        * Initiate operation.
+        */
+       vd->vd_mdcb.mdcb_status = 0;
+       VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
 }
 
 /*
 }
 
 /*
- * Watch for lost interrupts.
+ * Wait for controller to finish current operation
+ * so that direct controller accesses can be done.
  */
  */
-vd_int_timeout(ctlr)
-       register int ctlr;
+vdlock(ctlr)
 {
 {
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
-       register fmt_dcb *dcb = &ci->ctlr_dcb;
+       register struct vba_ctlr *vm = vdminfo[ctlr];
+       register struct vdsoftc *vd = &vdsoftc[ctlr];
+       int s;
 
 
-       uncache(&dcb->operrsta);
-       printf("vd%d: lost interrupt, status %b", ctlr, dcb->operrsta, ERRBITS);
-       if (ci->ctlr_type == SMD_ECTLR) {
-               uncache(&dcb->err_code);
-               printf(", error code %x", dcb->err_code);
-       }
-       printf("\n");
-       if ((dcb->operrsta&DCBCMP) == 0) { 
-               VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
-               dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
+       s = spl7();
+       while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
+               vd->vd_flags |= VD_WAIT;
+               sleep((caddr_t)vd, PRIBIO);
        }
        }
-       vdintr(ctlr);
+       vd->vd_flags |= VD_LOCKED;
+       splx(s);
 }
 
 }
 
+/*
+ * Continue normal operations after pausing for 
+ * munging the controller directly.
+ */
+vdunlock(ctlr)
+{
+       register struct vba_ctlr *vm = vdminfo[ctlr];
+       register struct vdsoftc *vd = &vdsoftc[ctlr];
+
+       vd->vd_flags &= ~VD_LOCKED;
+       if (vd->vd_flags & VD_WAIT) {
+               vd->vd_flags &= ~VD_WAIT;
+               wakeup((caddr_t)vd);
+       } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
+               vdstart(vm);
+}
+
+#define        DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
 /*
  * Handle a disk interrupt.
  */
 vdintr(ctlr)
 /*
  * Handle a disk interrupt.
  */
 vdintr(ctlr)
-       register int ctlr;
+       register ctlr;
 {
 {
-       register ctlr_tab *ci;
-       register struct buf *cq, *uq, *bp;
-       register int slave, unit;
-       register fmt_mdcb  *mdcb;
-       register fmt_dcb *dcb;
-       int code, s;
-
-       untimeout(vd_int_timeout, (caddr_t)ctlr);
-       scope_out(2);
-       ci = &vdctlr_info[ctlr];
-       if (!ci->int_expected) {
+       register struct buf *bp, *dp;
+       register struct vba_ctlr *vm = vdminfo[ctlr];
+       register struct vba_device *vi;
+       register struct vdsoftc *vd = &vdsoftc[ctlr];
+       register status;
+       int timedout;
+       struct dksoftc *dk;
+
+       if (!vm->um_tab.b_active) {
                printf("vd%d: stray interrupt\n", ctlr);
                return;
        }
        /*
                printf("vd%d: stray interrupt\n", ctlr);
                return;
        }
        /*
-        * Take first request off controller's queue.
+        * Get device and block structures, and a pointer
+        * to the vba_device for the drive.
         */
         */
-       cq = &vdminfo[ctlr]->um_tab;
-       uq = cq->b_forw;
-       bp = uq->av_forw;
-       unit = VDUNIT(bp->b_dev);
-       dk_busy &= ~(1 << unit);
-       dk_xfer[unit]++;
-       ci->int_expected = 0;
-       /* find associated control blocks */
-       mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
-       dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
-       if (ci->ctlr_type == SMD_ECTLR)
-               uncache(&dcb->err_code);
-       slave = uq->b_dev;
-       switch (code = vddecode_error(dcb)) {
-
-       case CTLR_ERROR:
-       case DRIVE_ERROR:
-               if (cq->b_errcnt >= 2)
-                       vdhard_error(ci, bp, dcb);
-               if (code == CTLR_ERROR)
-                       vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
-               else
-                       reset_drive((cdr *)vdminfo[ctlr]->um_addr, ctlr,
-                           slave, 2);
-               if (cq->b_errcnt++ < 2) {       /* retry error */
-                       cq->b_forw = uq->b_back;
-                       vdstart(vdminfo[ctlr]);
-                       return;
-               }
-               bp->b_resid = bp->b_bcount;
-               break;
-
-       case HARD_DATA_ERROR:
-       case WRITE_PROTECT:
-               vdhard_error(ci, bp, dcb);
-               bp->b_resid = 0;
-               break;
-
-       case SOFT_DATA_ERROR:
-               vdsoft_error(ci, bp, dcb);
-               /* fall thru... */
+       dp = vm->um_tab.b_actf;
+       bp = dp->b_actf;
+       vi = vddinfo[vdunit(bp->b_dev)];
+       dk = &dksoftc[vi->ui_unit];
+       if (vi->ui_dk >= 0)
+               dk_busy &= ~(1<<vi->ui_dk);
+       timedout = (vd->vd_wticks >= VDMAXTIME);
+       /*
+        * Check for and process errors on
+        * either the drive or the controller.
+        */
+       uncache(&vd->vd_dcb.operrsta);
+       status = vd->vd_dcb.operrsta;
+       if (bp->b_flags & B_FORMAT) {
+               dk->dk_operrsta = status;
+               uncache(&vd->vd_dcb.err_code);
+               dk->dk_ecode = vd->vd_dcb.err_code;
+       }
+       if (status & VDERR_HARD || timedout) {
+               if (vd->vd_type == VDTYPE_SMDE)
+                       uncache(&vd->vd_dcb.err_code);
+               if (status & DCBS_WPT) {
+                       /*
+                        * Give up on write locked devices immediately.
+                        */
+                       printf("dk%d: write locked\n", vi->ui_unit);
+                       bp->b_flags |= B_ERROR;
+               } else if (status & VDERR_RETRY || timedout) {
+                       int endline = 1;
+
+                       if (status & VDERR_CTLR || timedout) {
+                               vdharderr("controller err",
+                                   vd, bp, &vd->vd_dcb);
+                               printf("; resetting controller...");
+                               vdreset_ctlr(vm);
+                       } else if (status & VDERR_DRIVE) {
+                               vdharderr("drive err", vd, bp, &vd->vd_dcb);
+                               printf("; resetting drive...");
+                               if (!vdreset_drive(vi))
+                                       vi->ui_alive = 0;
+                       } else
+                               endline = 0;
+                       /*
+                        * Retry transfer once, unless reset failed.
+                        */
+                       if (!vi->ui_alive || dp->b_errcnt++ >= 2 ||
+                           bp->b_flags & B_FORMAT) {
+                               if (endline)
+                                       printf("\n");
+                               goto hard;
+                       }
 
 
-       default:                        /* operation completed */
-               bp->b_error = 0;
+                       if (endline)
+                               printf(" retrying\n");
+                       vm->um_tab.b_active = 0;        /* force retry */
+               } else  {
+       hard:
+                       bp->b_flags |= B_ERROR;
+                       vdharderr("hard error", vd, bp, &vd->vd_dcb);
+                       printf("\n");
+               }
+       } else if (status & DCBS_SOFT)
+               vdsofterr(bp, &vd->vd_dcb);
+       vd->vd_wticks = 0;
+       if (vm->um_tab.b_active) {
+               vm->um_tab.b_active = 0;
+               vm->um_tab.b_actf = dp->b_forw;
+               dp->b_active = 0;
+               dp->b_errcnt = 0;
+               dp->b_actf = bp->av_forw;
                bp->b_resid = 0;
                bp->b_resid = 0;
-               break;
+               vbadone(bp, &vd->vd_rbuf);
+               biodone(bp);
+               /*
+                * If this unit has more work to do,
+                * then start it up right away.
+                */
+               if (dp->b_actf)
+                       vdustart(vi);
+               else if (dk->dk_openpart == 0)
+                       wakeup((caddr_t)dk);
        }
        }
-       vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
        /*
        /*
-        * Take next request on this unit q, or, if none,
-        * the next request on the next active unit q.
+        * If there are devices ready to
+        * transfer, start the controller.
         */
         */
-       s = spl7();
-       uq->av_forw = bp->av_forw;
-       if (uq->av_back != bp) {
-               register struct buf *next;
-
-               unit = VDUNIT(uq->av_forw->b_dev);
-               slave = vddinfo[unit]->ui_slave;
-               next = uq->av_forw;
-               if (next->b_cylin != ci->cur_cyl[slave] ||
-                   (next->b_daddr & 0xff) != ci->cur_trk[slave])
-                       ci->off_cylinder |= 1 << slave;
-       } else
-               uq->av_back = NULL;
-       splx(s);
-       /* reset controller state */
-       cq->b_errcnt = 0;
-       cq->b_active--;
-       scope_out(3);
-       if (bp->b_flags & B_ERROR)
-               bp->b_error = EIO;
-       iodone(bp);
-       vdstart(vdminfo[ctlr]);
+       if (vd->vd_flags & VD_WAIT) {
+               vd->vd_flags &= ~VD_WAIT;
+               wakeup((caddr_t)vd);
+       } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
+               vdstart(vm);
 }
 
 }
 
-/*
- * Convert controller status to internal operation/error code.
- */
-vddecode_error(dcb)
-       register fmt_dcb *dcb;
-{
-
-       if (dcb->operrsta & HRDERR) {
-               if (dcb->operrsta & WPTERR)
-                       return (WRITE_PROTECT);
-               if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR |
-                   DSEEKERR | NOTCYLERR |DRVNRDY | INVDADR))
-                       return (DRIVE_ERROR);
-               if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
-                       return (CTLR_ERROR);
-               return (HARD_DATA_ERROR);
-       }
-       if (dcb->operrsta & SFTERR)
-               return (SOFT_DATA_ERROR);
-       return (0);
-}
-
-/*
- * Report a hard error.
- */
-vdhard_error(ci, bp, dcb)
-       ctlr_tab *ci; 
+vdharderr(what, vd, bp, dcb)
+       char *what;
+       struct vdsoftc *vd;
        register struct buf *bp;
        register struct buf *bp;
-       register fmt_dcb *dcb;
+       register struct dcb *dcb;
 {
 {
-       unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
-
-       bp->b_flags |= B_ERROR;
-       harderr(bp, ui->info.type_name);
-       if (dcb->operrsta & WPTERR)
-               printf("write protected");
-       else {
-               printf("status %b", dcb->operrsta, ERRBITS);
-               if (ci->ctlr_type == SMD_ECTLR)
-                       printf(" ecode %x", dcb->err_code);
-       }
-       printf("\n");
+       int unit = vdunit(bp->b_dev), status = dcb->operrsta;
+       register struct disklabel *lp = &dklabel[unit];
+       int blkdone;
+
+       if (vd->vd_wticks < VDMAXTIME)
+               status &= ~DONTCARE;
+       blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
+           lp->d_nsectors + dcb->err_sec -
+           lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
+           dksoftc[unit].dk_bshift) - bp->b_blkno;
+       diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
+       printf(", status %b", status, VDERRBITS);
+       if (vd->vd_type == VDTYPE_SMDE)
+               printf(" ecode %x", dcb->err_code);
 }
 
 }
 
-/*
- * Report a soft error.
- */
-vdsoft_error(ci, bp, dcb)
-       ctlr_tab *ci; 
+vdsofterr(bp, dcb)
        register struct buf *bp;
        register struct buf *bp;
-       register fmt_dcb *dcb;
+       register struct dcb *dcb;
 {
 {
-       unit_tab *ui = &vdunit_info[VDUNIT(bp->b_dev)];
-
-       printf("dk%d%c: soft error sn%d status %b", minor(bp->b_dev) >> 3,
-           'a'+(minor(bp->b_dev)&07), bp->b_blkno, dcb->operrsta, ERRBITS);
-       if (ci->ctlr_type == SMD_ECTLR)
-               printf(" ecode %x", dcb->err_code);
-       printf("\n");
+       int unit = vdunit(bp->b_dev);
+       struct disklabel *lp = &dklabel[unit];
+       int status = dcb->operrsta;
+       int blkdone;
+
+       blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
+           lp->d_nsectors + dcb->err_sec -
+           lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
+           dksoftc[unit].dk_bshift) - bp->b_blkno;
+
+       if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
+               diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
+               addlog(", status %b ecode %x\n", status, VDERRBITS,
+                   dcb->err_code);
+       } else {
+               diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
+               addlog("\n");
+       }
 }
 
 }
 
-/*ARGSUSED*/
-vdopen(dev, flag)
+vdioctl(dev, cmd, data, flag)
        dev_t dev;
        dev_t dev;
+       int cmd;
+       caddr_t data;
        int flag;
 {
        int flag;
 {
-       register unit = VDUNIT(dev);
-       register struct vba_device *vi = vddinfo[unit];
+       register int unit = vdunit(dev);
+       register struct disklabel *lp = &dklabel[unit];
+       register struct dksoftc *dk = &dksoftc[unit];
+       int error = 0, vdformat();
 
 
-       if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
-               return (ENXIO);
-       if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
-               return (ENXIO);
-       return (0);
+       switch (cmd) {
+
+       case DIOCGDINFO:
+               *(struct disklabel *)data = *lp;
+               break;
+
+       case DIOCGPART:
+               ((struct partinfo *)data)->disklab = lp;
+               ((struct partinfo *)data)->part =
+                   &lp->d_partitions[vdpart(dev)];
+               break;
+
+       case DIOCSDINFO:
+               if ((flag & FWRITE) == 0)
+                       error = EBADF;
+               else
+                       error = setdisklabel(lp, (struct disklabel *)data,
+                           (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
+               if (error == 0 && dk->dk_state == OPENRAW &&
+                   vdreset_drive(vddinfo[unit]))
+                       dk->dk_state = OPEN;
+               break;
+
+       case DIOCWLABEL:
+               if ((flag & FWRITE) == 0)
+                       error = EBADF;
+               else
+                       dk->dk_wlabel = *(int *)data;
+               break;
+
+       case DIOCWDINFO:
+               if ((flag & FWRITE) == 0)
+                       error = EBADF;
+               else if ((error = setdisklabel(lp, (struct disklabel *)data,
+                   (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
+                       int wlab;
+
+                       if (error == 0 && dk->dk_state == OPENRAW &&
+                           vdreset_drive(vddinfo[unit]))
+                               dk->dk_state = OPEN;
+                       /* simulate opening partition 0 so write succeeds */
+                       dk->dk_openpart |= (1 << 0);            /* XXX */
+                       wlab = dk->dk_wlabel;
+                       dk->dk_wlabel = 1;
+                       error = writedisklabel(dev, vdstrategy, lp);
+                       dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
+                       dk->dk_wlabel = wlab;
+               }
+               break;
+
+       case DIOCWFORMAT:
+           {
+               register struct format_op *fop;
+               struct uio auio;
+               struct iovec aiov;
+
+               if ((flag & FWRITE) == 0) {
+                       error = EBADF;
+                       break;
+               }
+               fop = (struct format_op *)data;
+               aiov.iov_base = fop->df_buf;
+               aiov.iov_len = fop->df_count;
+               auio.uio_iov = &aiov;
+               auio.uio_iovcnt = 1;
+               auio.uio_resid = fop->df_count;
+               auio.uio_segflg = UIO_USERSPACE;
+               auio.uio_offset = fop->df_startblk * lp->d_secsize;
+               dk->dk_operrsta = fop->dk_operrsta;
+               dk->dk_ecode = fop->dk_ecode;
+               /*
+                * Don't return errors, as the format op won't get copied
+                * out if we return nonzero.  Callers must check the returned
+                * count.
+                */
+               (void) physio(vdformat, (struct buf *)NULL, dev,
+                   (cmd == DIOCWFORMAT ? B_WRITE : B_READ), minphys, &auio);
+               fop->df_count -= auio.uio_resid;
+               fop->dk_operrsta = dk->dk_operrsta;
+               fop->dk_ecode = dk->dk_ecode;
+               break;
+           }
+
+       default:
+               error = ENOTTY;
+               break;
+       }
+       return (error);
 }
 
 }
 
-vdread(dev, uio)
-       dev_t dev;
-       struct uio *uio;
+vdformat(bp)
+       struct buf *bp;
 {
 {
-       register int unit = VDUNIT(dev);
-       register unit_tab *ui = &vdunit_info[unit];
-
-       if (unit >= NDK)
-               return (ENXIO);
-       return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
-           minphys, uio));
+       bp->b_flags |= B_FORMAT;
+       vdstrategy(bp);
 }
 
 }
 
-vdwrite(dev, uio)
-       dev_t dev;
-       struct uio *uio;
+/*
+ * Watch for lost interrupts.
+ */
+vdwatch()
 {
 {
-       register int unit = VDUNIT(dev);
-       register unit_tab *ui = &vdunit_info[unit];
+       register struct vdsoftc *vd;
+       register struct vba_ctlr *vm;
+       register int ctlr;
+       int s;
 
 
-       if (unit >= NDK)
-               return (ENXIO);
-       return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
-           minphys, uio));
+       timeout(vdwatch, (caddr_t)0, hz);
+       for (ctlr = 0; ctlr < NVD; ctlr++) {
+               vm = vdminfo[ctlr];
+               if (vm == 0 || vm->um_alive == 0)
+                       continue;
+               vd = &vdsoftc[ctlr];
+               s = spl7();
+               if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
+                       printf("vd%d: lost interrupt\n", ctlr);
+#ifdef maybe
+                       VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
+#endif
+                       vdintr(ctlr);
+               }
+               splx(s);
+       }
 }
 
 }
 
+#define        DBSIZE  64      /* controller limit with 1K sectors */
 /*
  * Crash dump.
  */
 vddump(dev)
        dev_t dev;
 {
 /*
  * Crash dump.
  */
 vddump(dev)
        dev_t dev;
 {
-       register int unit = VDUNIT(dev);
-       register unit_tab *ui = &vdunit_info[unit];
-       register fs_tab *fs = &ui->info;
-       register int ctlr = vddinfo[unit]->ui_ctlr;
-       register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
-       register int filsys = FILSYS(dev);
-       register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
-       register int cur_blk, blkcount, blocks;
-       caddr_t memaddr;
-
-       vdreset_ctlr(addr, ctlr);
-       blkcount = maxfree - 2;         /* In 1k byte pages */
-       if (dumplo + blkcount > fs->partition[filsys].par_len) {
-               blkcount = fs->partition[filsys].par_len - dumplo;
-               printf("vd%d: Dump truncated to %dMB\n", unit, blkcount/1024);
-       }
-       cur_blk = fs->partition[filsys].par_start + dumplo;
-       memaddr = 0;
-       while (blkcount > 0) {
-               blocks = MIN(blkcount, DUMPSIZE);
-               if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
+       register struct vba_device *vi;
+       register struct vba_ctlr *vm;
+       register struct disklabel *lp;
+       register struct vdsoftc *vd;
+       struct dksoftc *dk;
+       int part, unit, num;
+       u_long start;
+
+       start = 0;
+       unit = vdunit(dev);
+       if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
+               return (ENXIO);
+       dk = &dksoftc[unit];
+       if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
+           vdinit(vdminor(unit, 0), 0) != 0)
+               return (ENXIO);
+       lp = &dklabel[unit];
+       part = vdpart(dev);
+       if (part >= lp->d_npartitions)
+               return (ENXIO);
+       vm = vi->ui_mi;
+       vdreset_ctlr(vm);
+       if (dumplo < 0)
+               return (EINVAL);
+       /*
+        * Maxfree is in pages, dumplo is in DEV_BSIZE units.
+        */
+       num = maxfree * (NBPG / lp->d_secsize);
+       dumplo *= DEV_BSIZE / lp->d_secsize;
+       if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
+               num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
+       vd = &vdsoftc[vm->um_ctlr];
+       vd->vd_dcb.intflg = DCBINT_NONE;
+       vd->vd_dcb.opcode = VDOP_WD;
+       vd->vd_dcb.devselect = dk->dk_dcb.devselect;
+       vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
+       while (num > 0) {
+               int nsec, cn, sn, tn;
+
+               nsec = MIN(num, DBSIZE);
+               sn = dumplo + start / lp->d_secsize;
+               cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
+                   lp->d_secpercyl;
+               sn %= lp->d_secpercyl;
+               tn = sn / lp->d_nsectors;
+               sn %= lp->d_nsectors;
+               vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
+               vd->vd_dcb.trail.rwtrail.memadr = start;
+               vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
+               vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
+               vd->vd_dcb.trail.rwtrail.disk.track = tn;
+               vd->vd_dcb.trail.rwtrail.disk.sector = sn;
+               vd->vd_dcb.operrsta = 0;
+               VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
+               if (!vdpoll(vm, 5)) {
+                       printf(" during dump\n");
+                       return (EIO);
+               }
+               if (vd->vd_dcb.operrsta & VDERR_HARD) {
+                       printf("dk%d: hard error, status=%b\n", unit,
+                           vd->vd_dcb.operrsta, VDERRBITS);
                        return (EIO);
                        return (EIO);
-               blkcount -= blocks;
-               memaddr += blocks * NBPG;
-               cur_blk += blocks;
+               }
+               start += nsec * lp->d_secsize;
+               num -= nsec;
        }
        return (0);
 }
 
        }
        return (0);
 }
 
-/*
- * Write a block to disk during a crash dump.
- */
-vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
-       register cdr *caddr;
-       register int ctlr, unit;
-       register caddr_t addr;
-       register int block, blocks;
-{
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
-       register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
-       register fmt_dcb *dcb = &ci->ctlr_dcb;
-       register unit_tab *ui = &vdunit_info[unit];
-       register fs_tab  *fs = &ui->info;
-
-       block *= (int)ui->sec_per_blk;
-       blocks *= (int)ui->sec_per_blk;
-       mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
-       dcb->intflg = NOINT;
-       dcb->opcode = WD;
-       dcb->operrsta = 0;
-       dcb->devselect = (char)(vddinfo[unit])->ui_slave;
-       dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
-       dcb->trail.rwtrail.memadr = addr;
-       dcb->trail.rwtrail.wcount = (short)
-           ((blocks * fs->secsize)/ sizeof (short));
-       dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
-       dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
-       dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
-       VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
-       if (!vdpoll(ci, caddr, 5)) {
-               printf(" during dump\n");
-               return (0);
-       }
-       if (dcb->operrsta & HRDERR) {
-               printf("dk%d: hard error, status=%b\n", unit,
-                   dcb->operrsta, ERRBITS);
-               return (0);
-       }
-       return (1);
-}
-
 vdsize(dev)
        dev_t dev;
 {
 vdsize(dev)
        dev_t dev;
 {
-       struct vba_device *vi = vddinfo[VDUNIT(dev)];
+       register int unit = vdunit(dev);
+       register struct dksoftc *dk;
+       struct vba_device *vi;
+       struct disklabel *lp;
 
 
-       if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
+       if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
+           (dk = &dksoftc[unit])->dk_state != OPEN)
                return (-1);
                return (-1);
-       return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
+       lp = &dklabel[unit];
+#ifdef SECSIZE
+       return ((int)lp->d_partitions[vdpart(dev)].p_size);
+#else SECSIZE
+       return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
+#endif SECSIZE
 }
 
 /*
  * Perform a controller reset.
  */
 }
 
 /*
  * Perform a controller reset.
  */
-vdreset_ctlr(addr, ctlr)
-       register cdr *addr;
-       register int ctlr;
+vdreset_ctlr(vm)
+       register struct vba_ctlr *vm;
 {
 {
-       register struct buf *cq = &vdminfo[ctlr]->um_tab;
-       register struct buf *uq = cq->b_forw;
-       register ctlr_tab *ci = &vdctlr_info[ctlr];
+       register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
+       register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
+       register int unit;
+       struct vba_device *vi;
        
        
-       VDDC_RESET(addr, ci->ctlr_type);
-       ci->ctlr_started = 0;
-       if (ci->ctlr_type == SMD_ECTLR) {
-               addr->cdr_csr = 0;
-               addr->mdcb_tcf = AM_ENPDA;
-               addr->dcb_tcf = AM_ENPDA;
-               addr->trail_tcf = AM_ENPDA;
-               addr->data_tcf = AM_ENPDA;
-               addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
+       VDRESET(vdaddr, vd->vd_type);
+       if (vd->vd_type == VDTYPE_SMDE) {
+               vdaddr->vdcsr = 0;
+               vdaddr->vdtcf_mdcb = AM_ENPDA;
+               vdaddr->vdtcf_dcb = AM_ENPDA;
+               vdaddr->vdtcf_trail = AM_ENPDA;
+               vdaddr->vdtcf_data = AM_ENPDA;
+               vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
                    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
        }
                    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
        }
-       if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
-               printf("failed to init\n");
+       if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
+               printf("%s cmd failed\n",
+                   vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
+               return;
+       }
+       for (unit = 0; unit < NDK; unit++)
+               if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
+                       (void) vdreset_drive(vi);
+}
+
+vdreset_drive(vi)
+       register struct vba_device *vi;
+{
+       register struct disklabel *lp = &dklabel[vi->ui_unit];
+       struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
+       struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
+       register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
+       register struct dksoftc *dk = &dksoftc[vi->ui_unit];
+
+top:
+       vd->vd_dcb.opcode = VDOP_CONFIG;                /* command */
+       vd->vd_dcb.intflg = DCBINT_NONE;
+       vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
+       vd->vd_dcb.operrsta = 0;
+       vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
+       vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
+       vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
+       if (vd->vd_type == VDTYPE_SMDE) {
+               vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
+               vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
+               vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
+               vd->vd_dcb.trail.rstrail.recovery = VDRF_NORMAL;
+       } else
+               vd->vd_dcb.trailcnt = 2;                /* XXX */
+       vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
+       vd->vd_mdcb.mdcb_status = 0;
+       VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
+       if (!vdpoll(vm, 5)) {
+               printf(" during config\n");
                return (0);
        }
                return (0);
        }
-       if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
-               printf("diagnostic error\n");
+/*
+uncache(&vd->vd_dcb.err_code);
+printf("vdreset_drive %d, error %b, ecode %x, status %x => ",
+   vi->ui_unit, vd->vd_dcb.operrsta, VDERRBITS, vd->vd_dcb.err_code,
+   vdaddr->vdstatus[vi->ui_slave]);
+uncache(&vdaddr->vdstatus[vi->ui_slave]);
+printf("%x =>", vdaddr->vdstatus[vi->ui_slave]);
+{ int status = vd->vd_dcb.operrsta;
+vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
+vd->vd_dcb.operrsta = status;
+}
+uncache(&vdaddr->vdstatus[vi->ui_slave]);
+printf("%x\n", vdaddr->vdstatus[vi->ui_slave]);
+*/
+       if (vd->vd_dcb.operrsta & VDERR_HARD) {
+               if (vd->vd_type == VDTYPE_SMDE) {
+                       if (lp->d_devflags == 0) {
+                               lp->d_devflags = VD_ESDI;
+                               goto top;
+                       }
+#ifdef notdef
+                       /* this doesn't work, STA_US isn't set(?) */
+                       if ((vdaddr->vdstatus[vi->ui_slave] & STA_US) == 0)
+                               return (0);
+#endif
+               }
+               if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
+                       printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
+                          vd->vd_dcb.operrsta, VDERRBITS,
+                          (u_char) vd->vd_dcb.err_code);
+               else if ((vd->vd_flags & VD_STARTED) == 0) {
+                       int started;
+
+                       printf(" starting drives, wait ... ");
+                       vd->vd_flags |= VD_STARTED;
+                       started = (vdcmd(vm, VDOP_START, 10) == 1);
+                       DELAY(62000000);
+                       printf("done\n");
+                       lp->d_devflags = 0;
+                       if (started)
+                               goto top;
+               }
                return (0);
        }
                return (0);
        }
-       /*  reset all units attached to controller */
-       uq = cq->b_forw;
-       do {
-               reset_drive(addr, ctlr, uq->b_dev, 0);
-               uq = uq->b_forw;
-       } while (uq != cq->b_forw);
+       dk->dk_dcb.devselect |= lp->d_devflags;
        return (1);
 }
 
 /*
        return (1);
 }
 
 /*
- * Perform a reset on a drive.
+ * Perform a command w/o trailer.
  */
  */
-reset_drive(addr, ctlr, slave, start)
-       register cdr *addr;
-       register int ctlr, slave, start;
+vdcmd(vm, cmd, t, slave)
+       register struct vba_ctlr *vm;
 {
 {
-       register int type = vdctlr_info[ctlr].unit_type[slave];
-
-       if (type == UNKNOWN)
-               return;
-       if (!vdconfigure_drive(addr, ctlr, slave, type, start))
-               printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
+       register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
+
+       vd->vd_dcb.opcode = cmd;                /* command */
+       vd->vd_dcb.intflg = DCBINT_NONE;
+       vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
+       vd->vd_dcb.operrsta = 0;
+       vd->vd_dcb.devselect = slave;
+       vd->vd_dcb.trailcnt = 0;
+       vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
+       vd->vd_mdcb.mdcb_status = 0;
+       VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
+       if (!vdpoll(vm, t)) {
+               printf(" during init\n");
+               return (0);
+       }
+       return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
 }
 
 /*
 }
 
 /*
- * Poll controller until operation completes
- * or timeout expires.
+ * Poll controller until operation
+ * completes or timeout expires.
  */
  */
-vdpoll(ci, addr, t)
-       register ctlr_tab *ci;
-       register cdr *addr;
+vdpoll(vm, t)
+       register struct vba_ctlr *vm;
        register int t;
 {
        register int t;
 {
-       register fmt_dcb *dcb = &ci->ctlr_dcb;
+       register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
+       register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
 
        t *= 1000;
 
        t *= 1000;
-       uncache(&dcb->operrsta);
-       while ((dcb->operrsta&(DCBCMP|DCBABT)) == 0) {
-               DELAY(1000);
-               uncache(&dcb->operrsta);
+       for (;;) {
+               uncache(&vd->vd_dcb.operrsta);
+               if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
+                       break;
                if (--t <= 0) {
                if (--t <= 0) {
-                       printf("vd%d: controller timeout", ci-vdctlr_info);
-                       VDDC_ABORT(addr, ci->ctlr_type);
-                       DELAY(30000);
-                       uncache(&dcb->operrsta);
+                       printf("vd%d: controller timeout", vm->um_ctlr);
+                       VDABORT(vdaddr, vd->vd_type);
                        return (0);
                }
                        return (0);
                }
+               DELAY(1000);
        }
        }
-       if (ci->ctlr_type == SMD_ECTLR) {
-               uncache(&addr->cdr_csr);
-               while (addr->cdr_csr&CS_GO) {
+       if (vd->vd_type == VDTYPE_SMDE) {
+               do {
                        DELAY(50);
                        DELAY(50);
-                       uncache(&addr->cdr_csr);
-               }
-               DELAY(300);
+                       uncache(&vdaddr->vdcsr);
+               } while (vdaddr->vdcsr & CS_GO);
+               DELAY(300);
+               uncache(&vd->vd_dcb.err_code);
        }
        DELAY(200);
        }
        DELAY(200);
-       uncache(&dcb->operrsta);
+       uncache(&vd->vd_dcb.operrsta);
        return (1);
 }
 
        return (1);
 }
 
-#ifdef notdef
+#ifdef COMPAT_42
+struct vdst {
+       int     nsec;           /* sectors/track */
+       int     ntrack;         /* tracks/cylinder */
+       int     ncyl;           /* cylinders */
+       int     secsize;        /* sector size */
+       char    *name;          /* type name */
+       struct {
+               int     off;    /* partition offset in sectors */
+               int     size;   /* partition size in sectors */
+       } parts[8];
+} vdst[] = {
+       { 66, 23, 850, 512, "NEC 800",
+               {0,      1290300},      /* a cyl   0 - 849 */
+       },
+       { 64, 20, 842, 512, "2361a",
+               {0,      61440},        /* a cyl   0 - 47 */
+               {61440,  67840},        /* b cyl  48 - 100 */
+               {129280, 942080},       /* c cyl 101 - 836 */
+               {0,      1071360},      /* d cyl   0 - 836 */
+               {449280, 311040},       /* e cyl 351 - 593 */
+               {760320, 311040},       /* f cyl 594 - 836 */
+               {449280, 622080},       /* g cyl 351 - 836 */
+               {129280, 320000}        /* h cyl 101 - 350 */
+       },
+       { 48, 24, 711, 512, "xsd",
+               {0,      61056},        /* a cyl   0 - 52 */
+               {61056,  61056},        /* b cyl  53 - 105 */
+               {122112, 691200},       /* c cyl 106 - 705 */
+               {237312, 576000},       /* d cyl 206 - 705 */
+               {352512, 460800},       /* e cyl 306 - 705 */
+               {467712, 345600},       /* f cyl 406 - 705 */
+               {582912, 230400},       /* g cyl 506 - 705 */
+               {698112, 115200}        /* h cyl 606 - 705 */
+       },
+       { 44, 20, 842, 512, "eagle",
+               {0,      52800},        /* egl0a cyl   0 - 59 */
+               {52800,  66000},        /* egl0b cyl  60 - 134 */
+               {118800, 617760},       /* egl0c cyl 135 - 836 */
+               {736560, 4400},         /* egl0d cyl 837 - 841 */
+               {0,      736560},       /* egl0e cyl   0 - 836 */
+               {0,      740960},       /* egl0f cyl   0 - 841 */
+               {118800, 310640},       /* egl0g cyl 135 - 487 */
+               {429440, 307120}        /* egl0h cyl 488 - 836 */
+       },
+       { 64, 10, 823, 512, "fuj",
+               {0,      38400},        /* fuj0a cyl   0 - 59 */
+               {38400,  48000},        /* fuj0b cyl  60 - 134 */
+               {86400,  437120},       /* fuj0c cyl 135 - 817 */
+               {159360, 364160},       /* fuj0d cyl 249 - 817 */
+               {232320, 291200},       /* fuj0e cyl 363 - 817 */
+               {305280, 218240},       /* fuj0f cyl 477 - 817 */
+               {378240, 145280},       /* fuj0g cyl 591 - 817 */
+               {451200, 72320}         /* fug0h cyl 705 - 817 */
+       },
+       { 32, 24, 711, 512, "xfd",
+               { 0,     40704 },       /* a cyl   0 - 52 */
+               { 40704, 40704 },       /* b cyl  53 - 105 */
+               { 81408, 460800 },      /* c cyl 106 - 705 */
+               { 0,     81408 },       /* d cyl 709 - 710 (a & b) */
+               { 0,     542208 },      /* e cyl   0 - 705 */
+               { 40704, 501504 },      /* f cyl  53 - 705 (b & c) */
+               { 81408, 230400 },      /* g cyl 106 - 405 (1/2 of c) */
+               { 311808,230400 }       /* h cyl 406 - 705 (1/2 of c) */
+       },
+       { 32, 19, 823, 512, "smd",
+               {0,      40128},        /* a cyl   0-65 */
+               {40128,  27360},        /* b cyl  66-110 */
+               {67488,  429856},       /* c cyl 111-817 */
+               {139232, 358112},       /* d cyl 229 - 817 */
+               {210976, 286368},       /* e cyl 347 - 817 */
+               {282720, 214624},       /* f cyl 465 - 817 */
+               {354464, 142880},       /* g cyl 583 - 817 */
+               {426208, 71136}         /* h cyl 701 - 817 */
+       },
+       { 18, 15, 1224, 1024, "mxd",
+               {0,      21600},        /* a cyl   0-79 */
+               {21600,  22410},        /* b cyl  80-162 */
+               {44010,  285120},       /* c cyl 163-1217 */
+#ifdef notyet
+               {x, 237600},    /* d cyl y - 1217 */
+               {x, 190080},    /* e cyl y - 1217 */
+               {x, 142560},    /* f cyl y - 1217 */
+               {x, 95040},     /* g cyl y - 1217 */
+               {x, 47520}              /* h cyl 701 - 817 */
+#endif
+       },
+       { 32, 10, 823, 512, "fsd",
+               {0,      19200},        /* a cyl   0 -  59 */
+               {19200,  24000},        /* b cyl  60 - 134 */
+               {43200,  218560},       /* c cyl 135 - 817 */
+       }
+};
+#define        NVDST   (sizeof (vdst) / sizeof (vdst[0]))
+
 /*
 /*
- * Dump the mdcb and DCB for diagnostic purposes.
+ * Construct a label for an unlabeled pack.  We
+ * deduce the drive type by reading from the last
+ * track on successively smaller drives until we
+ * don't get an error.
  */
  */
-vdprintdcb(lp)
-       register long *lp;
+vdmaptype(vi, lp)
+       register struct vba_device *vi;
+       register struct disklabel *lp;
 {
 {
-       register int i, dcb, tc;
+       register struct vdsoftc *vd;
+       register struct vdst *p;
+       struct vba_ctlr *vm = vi->ui_mi;
+       int i;
 
 
-       for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
-               lp = (long *)((long)lp | 0xc0000000);
-               printf("\nDump of dcb%d@%x:", dcb, lp);
-               for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
-                       printf(" %lx", lp[i]);
-               printf("\n");
+       vd = &vdsoftc[vi->ui_ctlr];
+       for (p = vdst; p < &vdst[NVDST]; p++) {
+               if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
+                       continue;
+               lp->d_nsectors = p->nsec;
+               lp->d_ntracks = p->ntrack;
+               lp->d_ncylinders = p->ncyl;
+               lp->d_secsize = p->secsize;
+               DELAY(100000);
+               if (!vdreset_drive(vi))
+                       return (0);
+               DELAY(100000);
+               vd->vd_dcb.opcode = VDOP_RD;
+               vd->vd_dcb.intflg = DCBINT_NONE;
+               vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
+               vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
+               vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
+               vd->vd_dcb.trail.rwtrail.memadr =
+                   vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
+               vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
+               vd->vd_dcb.operrsta = 0;
+               vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
+               vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
+               vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
+               vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
+               vd->vd_mdcb.mdcb_status = 0;
+               VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
+               if (!vdpoll(vm, 60))
+                       printf(" during probe\n");
+               if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
+                       break;
        }
        }
-       DELAY(1750000);
+       if (p >= &vdst[NVDST])
+               return (0);
+
+       for (i = 0; i < 8; i++) {
+               lp->d_partitions[i].p_offset = p->parts[i].off;
+               lp->d_partitions[i].p_size = p->parts[i].size;
+       }
+       lp->d_npartitions = 8;
+       lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
+       bcopy(p->name, lp->d_typename, 4);
+       return (1);
 }
 }
-#endif
+#endif COMPAT_42
 #endif
 #endif