add appropriate copyright notice
[unix-history] / usr / src / sys / tahoe / vba / vd.c
index 19b41f2..6de9137 100644 (file)
-/*     vd.c    1.1     85/07/21        */
-
-#include "fsd.h"
-#if NVD > 0
 /*
 /*
-**     VDDC Driver - Versabus to SMD direct interface version.
-**             Written for TAHOE vmunix, CCI-WDC 9/1/83.               
-*/
-
-#include "../h/param.h"
-#include "../h/buf.h"
-#include "../h/cmap.h"
-#include "../h/conf.h"
-#include "../h/dir.h"
-#include "../h/dk.h"
-#include "../h/map.h"
-#include "../machine/mtpr.h"
-#include "../machine/pte.h"
-#include "../h/systm.h"
-#include "../vba/vbavar.h"
-#include "../h/user.h"
-#include "../h/vmmac.h"
-#include "../h/proc.h"
-#include "../h/uio.h"
-#include "../vba/vddc.h"
-
-int    vddebug = 1;    /* if = 1, error messages are printed on the console */
-int    vdintflg = 0;   /* if = 1, interrupts are handled by the driver, 
-                        * otherwise they are just ignored. (during setup) */
-
-static struct size FSD[] = {
-    9600,       0,     /* minor 0/ 8/16/24 = fsd0a - fsd3a - cyl   0 -  59*/
-   12000,    9600,     /* minor 1/ 9/17/25 = fsd0b - fsd3b - cyl  60 - 134*/
-  108480,   21600,     /* minor 2/10/18/26 = fsd0c - fsd3c - cyl 135 - 812*/
-    1600,  130080,     /* minor 3/11/19/27 = fsd0d - fsd3d - cyl 813 - 822*/
-  130080,       0,     /* minor 4/12/20/28 = fsd0e - fsd3e - cyl   0 - 812*/
-  131680,       0,     /* minor 5/13/21/29 = fsd0f - fsd3f - cyl   0 - 822*/
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-};
-
-static struct size     SMD[]= {
-    20064,     0,      /* minor 32/40/48/56 = smd0a - smd3a cyl 0- 65 */
-    13680,  20064,     /* minor 33/41/49/57 = smd0b - smd3b cyl 66- 110 */
-   214928,  33744,     /* minor 34/42/50/58 = smd0c - smd3c cyl 111-817 */
-     1520, 248672,     /* minor 35/43/51/59 = smd0d - smd3d cyl 818-822 */
-   248672,     0,      /* minor 36/44/52/60 = smd0e - smd3e cyl 0-817 */
-   250192,     0,      /* minor 37/45/53/61 = smd0f - smd3f cyl 0-822 */
-       0,      0,      /* minor 38/46/54/62 = smd0g - smd3g */
-       0,      0,      /* minor 39/47/55/63 = smd0h - smd3h */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-};
-
-static struct size XFSD[] = {
-    20352,     0,      /* minor 64/72/80/88 = xfsd0a - xfsd3a cyl 0- 52 */
-    20352,  20352,     /* minor 65/73/81/89 = xfsd0b - xfsd3b cyl 53- 105 */
-   230400,  40704,     /* minor 66/74/82/90 = xfsd0c - xfsd3c cyl 106-705 */
-     1920, 271104,     /* minor 67/75/83/91 = xfsd0d - xfsd3d cyl 706-710 */
-   271104,     0,      /* minor 68/76/84/92 = xfsd0e - xfsd3e cyl 0-705 */
-   273024,     0,      /* minor 69/77/85/93 = xfsd0f - xfsd3f cyl 0-710 */
-       0,      0,      /* minor 70/78/86/94 = xfsd0g - xfsd3g */
-       0,      0,      /* minor 71/79/87/95 = xfsd0h - xfsd3h */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-       0,      0,      /* Non existent minor device */
-};
+ * 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.6 (Berkeley) %G%
+ */
 
 
+#include "dk.h"
+#if NVD > 0
 /*
 /*
-/*
-/* Layout of minor number assignments for the VDDC devices.
-/*
-/*       1
-/*       5                         3 2   0
-/*      +---------------------------+-----+
-/*      |               Unit number | FLS |
-/*      +---------------------------+-----+
-/*                                |    |_____ File system # ( 0-7 )
-/*                                |__________ Unit # in the system
-/*
-/********************************************************/
-
-#define VDUNIT(x)      (minor(x) >> 3)
-#define FLSYS(x)       (minor(x) & 0x07)
-#define PHYS(x)                ( vtoph( 0, (int) (x) ) )
-
-
-/* Drive types should be in order of drive capacity for auto-configuration */
-/* e.g: smallest capacity = drive type 0, highest capacity = type NXPDRV-1 */
-
-struct vdst {
-       short nsect;
-       short ntrak;
-       short nspc;
-       short ncyl;
-       struct size *sizes;
-       short dtype;            /* type as in byte 5 (drive) of iopb */
-       char    *name;          /* drive name for autoconf */
-} vdst[] = {
-
-16,    10,     16*10,  823,    FSD,    0,      "fsd",
-16,    19,     16*19,  823,    SMD,    1,      "smd",
-16,    24,     16*24,  711,   XFSD,    2,      "xfd"
-};
+ * Versabus VDDC/SMDE driver.
+ */
+#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 "file.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/vdreg.h"
+
+#ifndef        COMPAT_42
+#define        COMPAT_42
+#endif
+#define        B_FORMAT        B_XXX           /* XXX */
 
 
+#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_ctlr *vdminfo[NVD];
-struct  vba_device *vddinfo[NFSD];
-
-/*
-**     Internal Functions
-*/
-int    vdopen();
-int    vdclose();
-int    vdprobe();              /* See if VDDC is really there */
-int    vd_setup();             /* Called from vdprobe */
-int    vdslave();              /* See if drive is really there */
-int    vdattach();
-int    vddgo();
-int    vdstrategy();           /* VDDC strategy routine */
-int    vdstart();              /* Top level interface to device queue */
-int    vdintr();               /* Top Level ISR */
-int    vdread();               /* raw i/o read routine */
-int    vdwrite();              /* raw i/o write routine */
-int    vddump();               /* dump routine */
-int    vdsize();               /* sizes for swapconfig */
-int    dskrst();               /* reset a drive after hard error */
-
-long   vdstd[] = {
-               0x0f2000 };
-
-struct vba_driver vddriver = {
-       vdprobe, vdslave, vdattach, vddgo, vdstd, 
-       "smd/fsd", vddinfo, "vd", vdminfo
-};
-
-struct buf     vdutab[NFSD];
-struct         buf     rvdbuf[NFSD];
-char   vdbuf[NVD][MAXBPTE * NBPG];     /* internal buffer for raw/swap i/o */
-long   vdbufused[NVD];
-extern char    vd0utl[],vd1utl[],vd2utl[],vd3utl[];
-
-/*
-**     Disk Address
-*/
-struct dskadr  {
-       char    track;          /* all 8 bits */
-       char    sector;         /* low order 5 bits */
-       short   cylinder;       /* low order 12 bits */
-};
-
-/*
-**     DCB Trailer Formats
-**********************************/
+struct  vba_device *vddinfo[NDK];
+int    vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
+long   vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
+struct vba_driver vddriver =
+  { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
 
 /*
 
 /*
-**     Read / Write Trailer
-*/
-struct trrw    {
-       char    *memadr;                        /* memory address */
-       long    wcount;                         /* 16 bit word count */
-       struct  dskadr  disk;                   /* disk address */
-};
+ * 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) */
+       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. */
 
 /*
 
 /*
-**     Format Trailer
-*/
-struct trfmt   {
-       char    *addr;                  /* data buffer to be filled on sector*/
-       long    nsectors;               /* # of sectors to be formatted */
-       struct  dskadr  disk;
-       struct  dskadr  hdr;
-};
+ * Per-drive state.
+ */
+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];
 
 /*
 
 /*
-**     Reset / Configure Trailer
-*/
-struct treset  {
-       long    ncyl;           /* # cylinders */
-       long    nsurfaces;      /* # surfaces */
-};                             /* # of sectors is defined by VDDC */
-                               /* to be 32/track of 512 data bytes each */
+ * 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.
+ */
+#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 */
 
 
-/*
-**     Seek Trailer
-*/
-struct trseek  {
-       struct  dskadr  disk;
-};
+struct buf dkutab[NDK];        /* i/o queue headers */
+struct disklabel dklabel[NDK]; /* pack labels */
 
 
-/*
-**     DCB Format
-*/
-struct fmt_dcb {
-       struct  fmt_dcb *nxtdcb;        /* next dcb in chain or End of Chain */
-       short   intflg;                 /* interrupt settings and flags */
-       short   opcode;                 /* DCB Command code etc... */
-       long    operrsta;               /* Error & Status info */
-       short   fill;                   /* not used */
-       char    devselect;              /* Drive selection */
-       char    trailcnt;               /* Trailer Word Count */
-       long    err_memadr;             /* Error memory address */
-       short   fill2;
-       short   err_wcount;             /* Error word count */
-       short   err_track;              /* Error track/sector */
-       short   err_cyl;                /* Error cylinder adr */
-       union   {
-               struct  trrw    rwtrail;        /* read/write trailer */
-               struct  trfmt   fmtrail;        /* format trailer */
-               struct  treset  resetrail;      /* reset/configure trailer */
-               struct  trseek  seektrail;      /* seek trailer */
-       } trail;
-};
+#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 */
 
 
-/*
-**     MDCB Format
-*/
-struct fmt_mdcb        {
-       struct  fmt_dcb *firstdcb;      /* first dcb in chain */
-       struct  fmt_dcb *procdcb;       /* dcb being processed */
-       struct  fmt_dcb *intdcb;        /* dcb causing interrupt */
-       long    vddcstat;               /* VDDC status */
-}mdcbx[NVD];
+int    vdwstart, vdwatch();
 
 /*
 
 /*
-**     DCB
-*/
-
-struct fmt_dcb         dcbx[NVD];
-
-int vdtimeout; 
-#define        POLLTILLDONE(x, name) { \
-       vdtimeout = 1000*(x); \
-       uncache((char *)&dcb->operrsta); \
-       while (! (dcb->operrsta & DCBCMP)) { \
-               DELAY(1000); \
-               vdtimeout--; \
-               uncache((char *)&dcb->operrsta); \
-               if (vdtimeout <=0) { \
-                       printf("vd: timeout on %s\n", name);\
-                       return(0); \
-               } \
-       } \
+ * See if the controller is really there; if so, initialize it.
+ */
+vdprobe(reg, vm)
+       caddr_t reg;
+       struct vba_ctlr *vm;
+{
+       register br, cvec;              /* must be r12, r11 */
+       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);
+       vd = &vdsoftc[vm->um_ctlr];
+       vdaddr->vdreset = 0xffffffff;
+       DELAY(1000000);
+       if (vdaddr->vdreset != (unsigned)0xffffffff) {
+               vd->vd_type = VDTYPE_VDDC;
+               vd->vd_flags &= ~VD_DOSEEKS;
+               DELAY(1000000);
+       } else {
+               vd->vd_type = VDTYPE_SMDE;
+               vd->vd_flags |= VD_DOSEEKS;
+               vdaddr->vdrstclr = 0;
+               DELAY(3000000);
+               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_DER | CCF_STS |
+                   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) || !vdcmd(vm, VDOP_DIAG, 10)) {
+               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)) {
+                       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.
+        */
+       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 */
+       return (sizeof (struct vddevice));
 }
 
 /*
 }
 
 /*
-**     See if the controller is really there. 
-**     if TRUE - initialize the controller.
-*/
-vdprobe(cntrl_vaddr)
-caddr_t cntrl_vaddr;
+ * 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.
+ */
+/* ARGSUSED */
+vdslave(vi, vdaddr)
+       register struct vba_device *vi;
+       struct vddevice *vdaddr;
 {
 {
-       if ( badaddr(cntrl_vaddr,2) ) return(0); /* no controller */
-       else 
-               if (vd_setup(cntrl_vaddr))      /* initialize the controller */
-                       return(1);
-               else return(0);         /* initialization error */      
+       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%s\n", vi->ui_ctlr,
+                   vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE",
+                   (vd->vd_flags & VD_SCATGATH) ? " with scatter-gather" : "");
+               vd->vd_flags |= VD_INIT;
+       }
+
+       /*
+        * 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.
+        */
+       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_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));
 }
 
 }
 
-vd_setup(cntrl_vaddr)
-caddr_t cntrl_vaddr;
+vdattach(vi)
+       register struct vba_device *vi;
 {
 {
-       register struct fmt_dcb *dcb = &dcbx[0];
-       register struct fmt_mdcb *mdcb = &mdcbx[0];
-       int j;
-
-       VDDC_RESET(cntrl_vaddr);                /* Reset the controller */
-               /* Burn some time ...... needed after accessing reset port */
-       for (j=0; j<20; j++)
-               DELAY(1000);
+       register int unit = vi->ui_unit;
+       register struct disklabel *lp = &dklabel[unit];
 
 
-       /* setup & issue INIT to initialize VDDC */
-
-       dcb->opcode = INIT;
-       dcb->nxtdcb = (struct fmt_dcb *)0;
-       dcb->intflg = NOINT;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       dcb->operrsta  = 0;
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) );        /* do it */
-       POLLTILLDONE(1,"INIT");         /* poll till done */
-       if (dcb->operrsta & HRDERR) {
-               if (vddebug)
-                       printf("vd: init error, err=%b\n",
-                           dcb->operrsta, ERRBITS);
-               return(0);
-       }
-       /* setup & issue DIAGNOSE */
-
-       dcb->opcode = DIAG;
-       dcb->nxtdcb = (struct fmt_dcb *)0;
-       dcb->intflg = NOINT;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       dcb->operrsta  = 0;
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-       POLLTILLDONE(1,"DIAG")          /* poll till done */
-       if (dcb->operrsta & HRDERR) {
-               if (vddebug)
-                       printf("vd: diagnose error, err=%b\n",
-                           dcb->operrsta, ERRBITS);
-               return(0);
-       }
-       /* Start drives command */
-#ifdef notdef
-       dcb->opcode = VDSTART;
-       dcb->nxtdcb = (struct fmt_dcb *)0;
-       dcb->intflg = NOINT;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       dcb->operrsta  = 0;
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-       POLLTILLDONE(20,"VDSTART")              /* poll till done */
-       if (dcb->operrsta & HRDERR) {
-               if (vddebug)
-                       printf("vd: start error, err=%b\n",
-                           dcb->operrsta, ERRBITS);
-               return(0);
+       /*
+        * Try to initialize device and read pack label.
+        */
+       if (vdinit(vdminor(unit, 0), 0) != 0) {
+               printf(": unknown drive type");
+               return;
        }
        }
+       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
 #endif
-       return(1);
-   }
+}
 
 
-/*
- * See if a drive is really there
- * Try to Reset/Configure the drive, then test its status.
-*/
-vdslave(ui,cntrl_vaddr)
-register struct vba_device *ui;
-register caddr_t cntrl_vaddr;
+vdopen(dev, flags, fmt)
+       dev_t dev;
+       int flags, fmt;
 {
 {
-       register struct fmt_dcb *dcb = &dcbx[0];
-       register struct fmt_mdcb *mdcb = &mdcbx[ui->ui_ctlr];
-       register struct vdst *st;
-       int dsktype;
+       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++;
+       }
        /*
        /*
-       **  check drive status - see if drive exists. 
-       */
-       dcb->opcode = VDSTATUS;
-       dcb->intflg = NOINT;
-       dcb->operrsta  = 0;
-       dcb->devselect = (char)ui->ui_slave;
-       dcb->trailcnt = (char)0;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       mdcb->vddcstat = 0;
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb))  /* do it */
-       POLLTILLDONE(5,"VDSTATUS")
-#ifdef notdef
-       if (dcb->operrsta & HRDERR) {
-               if (vddebug) 
-                 printf("vd%d: status error, err=%b\n", ui->ui_unit,
-                     dcb->operrsta, ERRBITS);
-               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');
+               }
        }
        }
-#endif
-       uncache((char *)&mdcb->vddcstat);
-       if (mdcb->vddcstat & DRVNRDY) return(0); /* not ready-> non existent */
+       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);
+}
 
 
+/* ARGSUSED */
+vdclose(dev, flags, fmt)
+       dev_t dev;
+       int flags, fmt;
+{
+       register int unit = vdunit(dev);
+       register struct dksoftc *dk = &dksoftc[unit];
+       int part = vdpart(dev), mask = 1 << part;
+
+       switch (fmt) {
+       case S_IFCHR:
+               dk->dk_copenpart &= ~mask;
+               break;
+       case S_IFBLK:
+               dk->dk_bopenpart &= ~mask;
+               break;
+       }
+       if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
+               dk->dk_openpart &= ~mask;
        /*
        /*
-        * drive is alive, now get its type!
-        * Seek on all drive types starting from the largest one.
-        * a sucessful seek to the last sector/cylinder/track verifies 
-        * the drive type connected to this port. 
+        * Should wait for i/o to complete on this partition
+        * even if others are open, but wait for work on blkflush().
         */
         */
-       for (dsktype = NVDDRV-1; dsktype >= 0; dsktype--) {     
-               st = &vdst[dsktype];
-               dcb->opcode = RSTCFG;           /* configure drive command */
-               dcb->intflg = NOINT;
-               dcb->operrsta  = 0;
-               dcb->trail.resetrail.ncyl = st->ncyl;
-               dcb->trail.resetrail.nsurfaces = st->ntrak;
-               dcb->devselect = (char)ui->ui_slave;
-               dcb->trailcnt = (char)2;
-               mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-               VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-               POLLTILLDONE(3,"RSTCFG")
-               if (dcb->operrsta & HRDERR) {
-                       if (vddebug) 
-                               printf("vd%d: reset error, err=%b\n", 
-                                   ui->ui_unit, dcb->operrsta, ERRBITS);
-                       return(0);
-               }
-               mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-               dcb->intflg = NOINT;
-               dcb->opcode =  RD;
-               dcb->operrsta = 0;
-               dcb->devselect = (char)ui->ui_slave;
-               dcb->trailcnt = (char)3;
-               dcb->trail.rwtrail.memadr = (char *)PHYS(vdbuf);
-               dcb->trail.rwtrail.wcount = 256;
-               dcb->trail.rwtrail.disk.cylinder = st->ncyl -4;
-               dcb->trail.rwtrail.disk.track = st->ntrak -1;
-               dcb->trail.rwtrail.disk.sector = 0;
-               VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-               POLLTILLDONE(5,"RD")
-if (vddebug) 
-       printf("vd%d: cyl %d, trk %d, sec %d, operrsta err=%b\n", 
-          ui->ui_unit, 
-          dcb->trail.rwtrail.disk.cylinder,
-          dcb->trail.rwtrail.disk.track,
-          dcb->trail.rwtrail.disk.sector,
-          dcb->operrsta, ERRBITS);
-               if ( (dcb->operrsta & HRDERR) == 0) 
-               /* found the drive type! */
-                       break;
+       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;
+       }
+       return (0);
+}
+
+vdinit(dev, flags)
+       dev_t dev;
+       int flags;
+{
+       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);
        }
        }
-       if (dsktype < 0) {
-               /* If reached here, a drive which is not defined in the 
-                * 'vdst' tables is connected. Cannot set it's type.
+       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
+               if (vdmaptype(vi, lp))
+                       dk->dk_state = OPEN;
+#endif
+       } else {
+               /*
+                * Now that we have the label, configure
+                * the correct drive parameters.
                 */
                 */
-               printf("vd%d: unrecognized drive type\n", ui->ui_unit);
-               return(0);
+               if (vdreset_drive(vi))
+                       dk->dk_state = OPEN;
+               else {
+                       dk->dk_state = CLOSED;
+                       error = ENXIO;
+               }
        }
        }
-       ui->ui_type = dsktype;
-       vddriver.ud_dname = st->name;
-       return(1);
+#ifndef SECSIZE
+       vd_setsecsize(dk, lp);
+#endif
+       wakeup((caddr_t)dk);
+       return (error);
 }
 
 }
 
-vdattach(ui)
-struct vba_device *ui;
+#ifndef SECSIZE
+vd_setsecsize(dk, lp)
+       register struct dksoftc *dk;
+       register struct disklabel *lp;
 {
 {
-       if (ui->ui_dk >= 0)
-               dk_mspw[ui->ui_dk] = .0000020345;       /* BAD VALUE */
+       int mul;
+
+       /*
+        * Calculate scaling shift for mapping
+        * DEV_BSIZE blocks to drive sectors.
+        */
+       mul = DEV_BSIZE / lp->d_secsize;
+       dk->dk_bshift = 0;
+       while ((mul >>= 1) > 0)
+               dk->dk_bshift++;
 }
 }
+#endif SECSIZE
 
 
-vddgo(um)
-struct vba_ctlr *um;
+/*ARGSUSED*/
+vddgo(vm)
+       struct vba_device *vm;
 {
 {
+
 }
 
 vdstrategy(bp)
 }
 
 vdstrategy(bp)
-register struct buf *bp;
+       register struct buf *bp;
 {
 {
-       register struct vba_device *ui;
-       register struct vba_ctlr *um;
+       register struct vba_device *vi;
+       register struct disklabel *lp;
+       register struct dksoftc *dk;
        register int unit;
        register int unit;
-       register struct buf *dp;
-       register struct size *sizep;
-       int index, blocks, s;
-
-       vdintflg = 1;           /* enable interrupts handling by the driver */
-       blocks = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
-       unit = VDUNIT(bp->b_dev);
-       ui = vddinfo[unit];
-       if (ui == 0 || ui->ui_alive == 0) goto bad1;
-       index = FLSYS(bp->b_dev); /* get file system index */
-       sizep = vdst[ui->ui_type].sizes;
-       if (bp->b_blkno < 0 ||
-        (dkblock(bp)+blocks > sizep[index].nblocks))   /* disk overflow */
-               goto bad1;
-       s = spl8();
-       dp = &vdutab[ui->ui_unit];
-       bp->b_resid = bp->b_blkno + sizep[index].block0; 
-                                       /* block # plays same role as
-                                          cylinder # for disksort, as long
-                                          as increasing blocks correspond to
-                                          increasing cylinders on disk */
-
-       buf_setup (bp, SECTSIZ);
-
+       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;
+       }
+       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;
+               }
+               bp->b_bcount = sz * lp->d_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();
+       dp = &dkutab[vi->ui_unit];
        disksort(dp, bp);
        disksort(dp, bp);
-       if (dp->b_active == 0) {        /* unit is on controller queue */
-               /* put the device on the controller queue */
-               dp->b_forw = NULL;              /* end of queue indicator */
-               um = ui->ui_mi;         /* get controller structure !! */
-               if (um->um_tab.b_actf == NULL)  /* controller queue is empty */
-                       um->um_tab.b_actf = dp; 
-               else
-                       um->um_tab.b_actl->b_forw = dp; /* add into queue */
-               um->um_tab.b_actl = dp;         /* update queue tail */
-               dp->b_active ++;
-       }
-       bp = &ui->ui_mi->um_tab;        /* controller structure addr */
-       if (bp->b_actf &&               /* cntrl queue not empty */
-               bp->b_active == 0)      /* controller not active */
-               (void) vdstart(ui->ui_mi);/* go start I/O */
+       if (!dp->b_active) {
+               (void) vdustart(vi);
+               if (!vi->ui_mi->um_tab.b_active)
+                       vdstart(vi->ui_mi);
+       }
        splx(s);
        return;
        splx(s);
        return;
-
-bad1:
+bad:   
        bp->b_flags |= B_ERROR;
        bp->b_flags |= B_ERROR;
-       iodone(bp);
+done:
+       biodone(bp);
        return;
 }
 
        return;
 }
 
+vdustart(vi)
+       register struct vba_device *vi;
+{
+       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++;
+}
 
 /*
 
 /*
- * Start up a transfer on a drive.
+ * 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.
  */
  */
-vdstart(um)
-register struct vba_ctlr *um;
+vdstart(vm)
+       register struct vba_ctlr *vm;
 {
 {
-       register struct buf *bp, *dp;
-       register struct fmt_dcb *dcb = &dcbx[um->um_ctlr];
-       register struct fmt_mdcb *mdcb;
-       register struct size *sizep;    /* Pointer to one of the tables */
-       register struct vdst *st;
-       register int index ;            /* Index in the relevant table */
-       register int phadr;             /* Buffer's physical address */
-       register caddr_t cntrl_vaddr = um->um_addr;
-       int     sblock, unit;
-       int ct;
+       register struct buf *bp;
+       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:
        /*
 
 loop:
        /*
-        * Pull a request off the controller queue
+        * Pull a request off the controller queue.
         */
         */
-       if ((dp = um->um_tab.b_actf) == NULL)
-               return ;
+       if ((dp = vm->um_tab.b_actf) == NULL &&
+           (dp = vm->um_tab.b_seekf) == NULL)
+               return;
        if ((bp = dp->b_actf) == NULL) {
        if ((bp = dp->b_actf) == NULL) {
-               dp->b_active = 0;       /* device removed from ctlr queue */
-               um->um_tab.b_actf = dp->b_forw;
+               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;
        }
                goto loop;
        }
+
        /*
        /*
-                * Mark controller busy, and
-                * prepare a command packet for the controller.
-                */
-       um->um_tab.b_active++;
-       unit = VDUNIT(bp->b_dev);
-       st = &vdst[vddinfo[unit]->ui_type];
-       mdcb = &mdcbx[vddinfo[unit]->ui_ctlr];
-       index = FLSYS(bp->b_dev);
-       sizep = st->sizes;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       dcb->intflg = INTDUN;           /* interrupt on completion */
-       dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
-       dcb->operrsta = 0;
-       dcb->devselect = (char)(vddinfo[unit])->ui_slave;
-       dcb->trailcnt = (char)3;
-       ct = vddinfo[unit]->ui_ctlr;
-
-       switch (ct) {
-               case 0:
-                       phadr = get_ioadr(bp, vdbuf[0], VD0map, (caddr_t)vd0utl);
-                       break;
-               case 1:
-                       phadr = get_ioadr(bp, vdbuf[1], VD1map, (caddr_t)vd1utl);
-                       break;
-               case 2:
-                       phadr = get_ioadr(bp, vdbuf[2], VD2map, (caddr_t)vd2utl);
-                       break;
-               case 3:
-                       phadr = get_ioadr(bp, vdbuf[3], VD3map, (caddr_t)vd3utl);
-                       break;
+        * Mark controller busy, and determine
+        * destination of this request.
+        */
+       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 += vba_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;
        }
        }
-/*
-       phadr = get_ioadr(bp, vdbuf, IOmap, (caddr_t)ioutl);
-*/
-
-       if (vddinfo[unit]->ui_dk >= 0) {
-               int dku = vddinfo[unit]->ui_dk;
-               dk_busy |= 1<<dku;
-               dk_xfer[dku]++;
-               dk_wds[dku] += bp->b_bcount>>6;
-       }
-       dcb->trail.rwtrail.memadr = (char *)phadr;
-       dcb->trail.rwtrail.wcount = (bp->b_bcount + 1) / 2;
-       sblock = sizep[index].block0 + bp->b_blkno;
-       dcb->trail.rwtrail.disk.cylinder = (short)(sblock / st->nspc);
-       dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc) / st->nsect);
-       dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2));
-
-#ifdef VDDCPERF
-       scope_out(1);
-#endif
 
 
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb))  /* do it */
-}
+       /*
+        * 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);
+}
 
 
+#define        DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
 /*
  * Handle a disk interrupt.
  */
 /*
  * Handle a disk interrupt.
  */
-vdintr(vdnum)
-register vdnum;
+vdintr(ctlr)
+       register ctlr;
 {
        register struct buf *bp, *dp;
 {
        register struct buf *bp, *dp;
-       register struct vba_ctlr *um = vdminfo[vdnum];  
-       register struct fmt_dcb *dcb = &dcbx[vdnum];
-       register struct fmt_mdcb *mdcb = &mdcbx[vdnum];
-       register struct vdst *st;
-       int unit;
-       struct vba_device *ui;
-
-#ifdef VDDCPERF
-       scope_out(2);
-#endif
-       if (intenable == 0 || vdintflg == 0)    /* ignore all interrupts */
-               return;
-       if (um->um_tab.b_active == NULL) return;/* unexpected interrupt */
-       uncache((char *)&mdcb->intdcb);
-       uncache((char *)&dcb->operrsta);
-       if ( mdcb->intdcb != (struct fmt_dcb *)PHYS(dcb)) {     /* dcb causing interrupt */
-               printf("vd%d: bad dcb=%x (phys=%x)\n",
-                   vdnum, mdcb->intdcb, PHYS(dcb));
+       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;
        }
                return;
        }
-       if (! (dcb->operrsta & DCBCMP)) { /* unexpected interrupt */
-               printf("vd%d: unexpected interrupt, err=%b\n", vdnum,
-                   dcb->operrsta, ERRBITS);
-               return;
+       /*
+        * Get device and block structures, and a pointer
+        * to the vba_device for the drive.
+        */
+       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;
        }
        }
-       dp = um->um_tab.b_actf;         /* device queue head in ctlr queue */
-       bp = dp->b_actf;                /* first buffer in device queue */
-       unit = VDUNIT(bp->b_dev);
-       ui = vddinfo[unit];
-       if (ui->ui_dk >= 0)
-               dk_busy &= ~(1 << ui->ui_dk);
-       if (dcb->operrsta & (HRDERR|SFTERR)) {
-               st = &vdst[ui->ui_type];
-               if (dcb->operrsta & HRDERR) {
-                       harderr(bp, &st->name[7]);
-                       printf("status=%b\n", dcb->operrsta, ERRBITS);
-                       dskrst(bp);
+       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;
                        bp->b_flags |= B_ERROR;
-               } else
-#define        SECTOR(x)       ((x)*2)
-                       printf("%s%d: soft error sn%d status=%b\n", &st->name[7], unit,
-                          SECTOR(bp->b_blkno + st->sizes[FLSYS(bp->b_dev)].block0),
-                          dcb->operrsta, ERRBITS);
-       }
-       switch (vdnum) {
-               case 0:
-                       end_transfer(bp, vdbuf[0], VD0map, (caddr_t)vd0utl);
-                       break;
-               case 1:
-                       end_transfer(bp, vdbuf[1], VD1map, (caddr_t)vd1utl);
-                       break;
-               case 2:
-                       end_transfer(bp, vdbuf[2], VD2map, (caddr_t)vd2utl);
-                       break;
-               case 3:
-                       end_transfer(bp, vdbuf[3], VD3map, (caddr_t)vd3utl);
-                       break;
+               } 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;
+                       }
+
+                       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;
+               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);
        }
        }
+       /*
+        * If there are devices ready to
+        * transfer, start the controller.
+        */
+       if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
+               vdstart(vm);
+}
+
+vdharderr(what, vd, bp, dcb)
+       char *what;
+       struct vdsoftc *vd;
+       register struct buf *bp;
+       register struct dcb *dcb;
+{
+       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);
+}
 
 
-       um->um_tab.b_active = 0;
-       um->um_tab.b_errcnt = 0;
-       if (dp->b_forw != NULL) {               /* more than 1 unit on queue */
-               um->um_tab.b_actf = dp->b_forw; /* next device on ctlr queue */
-               dp->b_forw = um->um_tab.b_actl->b_forw; /* be last in queue */
-               um->um_tab.b_actl->b_forw = dp; /* last points now to dp */
-               um->um_tab.b_actl = dp;         /* pointer in ctlr structure */
+vdsofterr(bp, dcb)
+       register struct buf *bp;
+       register struct dcb *dcb;
+{
+       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");
        }
        }
-       dp->b_errcnt = 0;
-       dp->b_actf = bp->av_forw;               /* remove first from queue */
-       bp->b_resid = 0;        /* All data read here */
+}
 
 
-#ifdef VDDCPERF
-       scope_out(3);
-#endif
+vdioctl(dev, cmd, data, flag)
+       dev_t dev;
+       int cmd;
+       caddr_t data;
+       int flag;
+{
+       register int unit = vdunit(dev);
+       register struct disklabel *lp = &dklabel[unit];
+       register struct dksoftc *dk = &dksoftc[unit];
+       int error = 0, vdformat();
+
+       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;
+
+                       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;
 
 
-       iodone(bp);
-       vdstart(um);            /* start requests for next device on queue */
+               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);
 }
 
 }
 
+vdformat(bp)
+       struct buf *bp;
+{
+       bp->b_flags |= B_FORMAT;
+       vdstrategy(bp);
+}
 
 
-vdread(dev, uio)
-dev_t dev;
-struct uio *uio;
+/*
+ * Watch for lost interrupts.
+ */
+vdwatch()
 {
 {
-       register int unit = VDUNIT(dev);
-       register int error;
-       register int ct;
-       register int s;
-
-       if (unit >= NFSD)
-               error = ENXIO;
-       else {
-               ct = vddinfo[unit]->ui_ctlr;
-               s = spl8();
-               while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1);
-               vdbufused[ct] = 1;
+       register struct vdsoftc *vd;
+       register struct vba_ctlr *vm;
+       register int ctlr;
+       int s;
+
+       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);
                splx(s);
-               error = physio(vdstrategy, &rvdbuf[unit], dev, B_READ, minphys, uio);
-               vdbufused[ct] = 0;
-               wakeup (&vdbufused[ct]);
        }
        }
-       return error;
 }
 
 }
 
-vdwrite(dev, uio)
-dev_t dev;
-struct uio *uio;
+#define        DBSIZE  64      /* controller limit with 1K sectors */
+/*
+ * Crash dump.
+ */
+vddump(dev)
+       dev_t dev;
 {
 {
-       register int unit = VDUNIT(dev);
-       register int error;
-       register int ct;
-       register int s;
-
-       if (unit >= NFSD)
-               error = ENXIO;
-       else {
-               ct = vddinfo[unit]->ui_ctlr;
-               s = spl8();
-               while (vdbufused[ct]) sleep (&vdbufused[ct],PRIBIO+1);
-               vdbufused[ct] = 1;
-               splx(s);
-               error = physio(vdstrategy, &rvdbuf[unit], dev, B_WRITE, minphys, uio);
-               vdbufused[ct] = 0;
-               wakeup (&vdbufused[ct]);
+       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);
+               }
+               start += nsec * lp->d_secsize;
+               num -= nsec;
        }
        }
-       return error;
+       return (0);
 }
 
 }
 
-#define        DUMPSIZE        32      /* Up to 32k at a time - controller limit */
+vdsize(dev)
+       dev_t dev;
+{
+       register int unit = vdunit(dev);
+       register struct dksoftc *dk;
+       struct vba_device *vi;
+       struct disklabel *lp;
+
+       if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
+           (dk = &dksoftc[unit])->dk_state != OPEN)
+               return (-1);
+       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
+}
 
 
-vddump(dev)
-dev_t  dev;
 /*
 /*
- * Dump the main memory to the given device.
+ * Perform a controller reset.
  */
  */
+vdreset_ctlr(vm)
+       register struct vba_ctlr *vm;
 {
 {
-       register struct vba_ctlr *um;
-       register struct fmt_dcb *dcb = &dcbx[0];
-       register struct fmt_mdcb *mdcb = &mdcbx[0];
-       register struct vdst *st;
+       register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
+       register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
        register int unit;
        register int unit;
-       register caddr_t cntrl_vaddr ;
-       register struct size *sizep;    /* Pointer to one of the tables */
-       int index,sblock,blkcount,thiscount;
-       int     memaddr;
-
-       unit = VDUNIT(dev);
-       um = (vddinfo[unit])->ui_mi;
-       st = &vdst[(vddinfo[unit])->ui_type];
-       dcb = &dcbx[um->um_ctlr];
-       cntrl_vaddr = um->um_addr;
-       memaddr = 0x0;
-       index = FLSYS(dev);
-       sizep = st->sizes;
-       blkcount = maxfree - 2;         /* In 1k byte pages */
-       if (dumplo + blkcount > sizep[index].nblocks) return(EINVAL);
-       sblock = sizep[index].block0 + dumplo;
-       while (blkcount > 0) {
-               thiscount = MIN (blkcount, DUMPSIZE);
-               mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-               dcb->intflg = NOINT;
-               dcb->opcode = WD;
-               dcb->operrsta = 0;
-               dcb->devselect = (char)(vddinfo[unit])->ui_slave;
-               dcb->trailcnt = (char)3;
-               dcb->trail.rwtrail.memadr = (char *)memaddr;
-               dcb->trail.rwtrail.wcount = thiscount*512;
-               dcb->trail.rwtrail.disk.cylinder= (short)(sblock/st->nspc);
-               dcb->trail.rwtrail.disk.track = (char)((sblock % st->nspc) 
-                       / st->nsect);
-               dcb->trail.rwtrail.disk.sector = (char)(sblock*2 % (st->nsect*2));
-               VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-               POLLTILLDONE(5,"WD");
-               if (dcb->operrsta & HRDERR) {
-                       if (vddebug)
-                               printf("vd%d: i/o error, err=%b\n", unit,
-                                   dcb->operrsta, ERRBITS);
-                       return(EIO);
-               };
-               blkcount -= thiscount;
-               memaddr += thiscount*NBPG;
-               sblock += thiscount;
-       }
-       return(0);
+       struct vba_device *vi;
+       
+       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;
+       }
+       if (!vdcmd(vm, VDOP_INIT, 10) || !vdcmd(vm, VDOP_DIAG, 10)) {
+               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);
 }
 
 }
 
-vdopen(dev, flag)
-register dev_t dev;
-int flag;
+vdreset_drive(vi)
+       register struct vba_device *vi;
 {
 {
-       register struct vba_device *ui;
-       register unit = VDUNIT(dev);
+       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);
+       }
+       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");
+                       lp->d_devflags = 0;
+                       if (started)
+                               goto top;
+               }
+               return (0);
+       }
+       dk->dk_dcb.devselect |= lp->d_devflags;
+       return (1);
+}
 
 
-       ui = vddinfo[unit];
-       if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV)
-               return ENXIO;
-       return 0;
+/*
+ * Perform a command w/o trailer.
+ */
+vdcmd(vm, cmd, t)
+       register struct vba_ctlr *vm;
+{
+       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 = 0;
+       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);
 }
 
 }
 
-vdsize(dev)
-register dev_t dev;
+/*
+ * Poll controller until operation
+ * completes or timeout expires.
+ */
+vdpoll(vm, t)
+       register struct vba_ctlr *vm;
+       register int t;
 {
 {
-       register struct vba_device *ui;
-       register unit = VDUNIT(dev);
+       register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
+       register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
 
 
-       ui = vddinfo[unit];
-       if (ui == 0 || ui->ui_alive == 0 || ui->ui_type >= NVDDRV)
-               return -1;
-       return vdst[ui->ui_type].sizes[FLSYS(dev)].nblocks;
+       t *= 1000;
+       for (;;) {
+               uncache(&vd->vd_dcb.operrsta);
+               if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
+                       break;
+               if (--t <= 0) {
+                       printf("vd%d: controller timeout", vm->um_ctlr);
+                       VDABORT(vdaddr, vd->vd_type);
+                       return (0);
+               }
+               DELAY(1000);
+       }
+       if (vd->vd_type == VDTYPE_SMDE) {
+               do {
+                       DELAY(50);
+                       uncache(&vdaddr->vdcsr);
+               } while (vdaddr->vdcsr & CS_GO);
+               DELAY(300);
+               uncache(&vd->vd_dcb.err_code);
+       }
+       DELAY(200);
+       uncache(&vd->vd_dcb.operrsta);
+       return (1);
 }
 
 }
 
-/* reset a drive after a hard error */
-dskrst(bp)
-       register struct buf *bp;
+#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]))
+
+/*
+ * 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.
+ */
+vdmaptype(vi, lp)
+       register struct vba_device *vi;
+       register struct disklabel *lp;
 {
 {
-       register struct vdst *st;
-       register struct fmt_dcb *dcb;
-       register struct fmt_mdcb *mdcb;
-       register struct vba_device *ui;
-       register caddr_t cntrl_vaddr ;
-       int unit;
-
-       unit = VDUNIT(bp->b_dev);
-       ui = vddinfo[unit];
-       mdcb = &mdcbx[ui->ui_ctlr];
-       dcb = &dcbx[ui->ui_ctlr];
-       cntrl_vaddr = (ui->ui_mi)->um_addr;
-       st = &vdst[vddinfo[unit]->ui_type];
-       dcb->opcode = RSTCFG;           /* configure drive command */
-       dcb->intflg = NOINT;
-       dcb->operrsta  = 0;
-       dcb->trail.resetrail.ncyl = st->ncyl;
-       dcb->trail.resetrail.nsurfaces = st->ntrak;
-       dcb->devselect = (char)ui->ui_slave;
-       dcb->trailcnt = (char)2;
-       mdcb->firstdcb = (struct fmt_dcb *)PHYS(dcb);
-       VDDC_ATTENTION(cntrl_vaddr,PHYS(mdcb) ) /* do it */
-       POLLTILLDONE(3,"reset")
-       if (dcb->operrsta & HRDERR) {
-               if (vddebug) {
-                       harderr(bp, &st->name[7]);
-                       printf("reset failed, err=%b\n", dcb->operrsta,ERRBITS);
-               }
+       register struct vdsoftc *vd;
+       register struct vdst *p;
+       struct vba_ctlr *vm = vi->ui_mi;
+       int i;
+
+       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;
+               if (!vdreset_drive(vi))
+                       return (0);
+               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;
+       }
+       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;
+       lp->d_rpm = 3600;
+       bcopy(p->name, lp->d_typename, 4);
+       return (1);
 }
 }
+#endif COMPAT_42
 #endif
 #endif