from Keith Muller;
[unix-history] / usr / src / sys / tahoe / vba / vd.c
index 61f772b..31f9597 100644 (file)
@@ -1,4 +1,24 @@
-/*     vd.c    7.1     88/05/21        */
+/*
+ * 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
@@ -43,9 +63,9 @@
 struct vba_ctlr *vdminfo[NVD];
 struct  vba_device *vddinfo[NDK];
 int    vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
 struct vba_ctlr *vdminfo[NVD];
 struct  vba_device *vddinfo[NDK];
 int    vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
-long   vdaddr[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
+long   vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
 struct vba_driver vddriver =
 struct vba_driver vddriver =
-  { vdprobe, vdslave, vdattach, vddgo, vdaddr, "dk", vddinfo, "vd", vdminfo };
+  { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
 
 /*
  * Per-controller state.
 
 /*
  * Per-controller state.
@@ -56,6 +76,8 @@ struct vdsoftc {
 #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_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_short vd_type;        /* controller type */
        u_short vd_wticks;      /* timeout */
        struct  mdcb vd_mdcb;   /* master command block */
@@ -142,7 +164,7 @@ vdprobe(reg, vm)
                vdaddr->vdtcf_dcb = AM_ENPDA;
                vdaddr->vdtcf_trail = AM_ENPDA;
                vdaddr->vdtcf_data = 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 |
+               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;
        }
@@ -150,7 +172,7 @@ vdprobe(reg, vm)
        vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
        vm->um_addr = reg;              /* XXX */
        s = spl7();
        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)) {
+       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);
                printf("vd%d: %s cmd failed\n", vm->um_ctlr,
                    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
                splx(s);
@@ -158,7 +180,7 @@ vdprobe(reg, vm)
        }
        if (vd->vd_type == VDTYPE_SMDE) {
                vd->vd_dcb.trail.idtrail.date = 0;
        }
        if (vd->vd_type == VDTYPE_SMDE) {
                vd->vd_dcb.trail.idtrail.date = 0;
-               if (vdcmd(vm, VDOP_IDENT, 10)) {
+               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;
                        uncache(&vd->vd_dcb.trail.idtrail.date);
                        if (vd->vd_dcb.trail.idtrail.date != 0)
                                vd->vd_flags |= VD_SCATGATH;
@@ -195,9 +217,19 @@ vdslave(vi, vdaddr)
        struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
 
        if ((vd->vd_flags&VD_INIT) == 0) {
        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" : "");
+               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);
+               }
+               printf("\n");
                vd->vd_flags |= VD_INIT;
        }
 
                vd->vd_flags |= VD_INIT;
        }
 
@@ -215,6 +247,10 @@ vdslave(vi, vdaddr)
        lp->d_ntracks = 23;
        lp->d_ncylinders = 850;
        lp->d_secpercyl = 66*23;
        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
 
        /*
         * Initialize invariant portion of
@@ -328,6 +364,7 @@ vdopen(dev, flags, fmt)
        return (0);
 }
 
        return (0);
 }
 
+/* ARGSUSED */
 vdclose(dev, flags, fmt)
        dev_t dev;
        int flags, fmt;
 vdclose(dev, flags, fmt)
        dev_t dev;
        int flags, fmt;
@@ -375,7 +412,7 @@ vdinit(dev, flags)
        dk = &dksoftc[unit];
        if (flags & O_NDELAY) {
                dk->dk_state = OPENRAW;
        dk = &dksoftc[unit];
        if (flags & O_NDELAY) {
                dk->dk_state = OPENRAW;
-               return;
+               return (0);
        }
        dk->dk_state = RDLABEL;
        lp = &dklabel[unit];
        }
        dk->dk_state = RDLABEL;
        lp = &dklabel[unit];
@@ -389,20 +426,24 @@ vdinit(dev, flags)
                        dk->dk_state = OPENRAW;
                }
 #ifdef COMPAT_42
                        dk->dk_state = OPENRAW;
                }
 #ifdef COMPAT_42
+               vdlock(vi->ui_ctlr);
                if (vdmaptype(vi, lp))
                        dk->dk_state = OPEN;
                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.
                 */
 #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;
                }
                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);
        }
 #ifndef SECSIZE
        vd_setsecsize(dk, lp);
@@ -582,7 +623,6 @@ vdstart(vm)
        register struct dksoftc *dk;
        register struct disklabel *lp;
        register struct dcb **dcbp;
        register struct dksoftc *dk;
        register struct disklabel *lp;
        register struct dcb **dcbp;
-       struct mdcb *mdcb;
        struct buf *dp;
        int sn, tn;
 
        struct buf *dp;
        int sn, tn;
 
@@ -655,12 +695,12 @@ loop:
                vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
 setupaddr:
                vd->vd_dcb.trail.rwtrail.memadr =
                vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
 setupaddr:
                vd->vd_dcb.trail.rwtrail.memadr =
-                       vbasetup(bp, &vd->vd_rbuf, lp->d_secsize);
+                       vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
                break;
 
        case VDOP_RAS:
        case VDOP_GAW:
                break;
 
        case VDOP_RAS:
        case VDOP_GAW:
-               vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
+               vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
                    &vd->vd_dcb.trail.sgtrail);
                break;
        }
                    &vd->vd_dcb.trail.sgtrail);
                break;
        }
@@ -711,6 +751,42 @@ setupaddr:
        VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
 }
 
        VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
 }
 
+/*
+ * Wait for controller to finish current operation
+ * so that direct controller accesses can be done.
+ */
+vdlock(ctlr)
+{
+       register struct vba_ctlr *vm = vdminfo[ctlr];
+       register struct vdsoftc *vd = &vdsoftc[ctlr];
+       int s;
+
+       s = spl7();
+       while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
+               vd->vd_flags |= VD_WAIT;
+               sleep((caddr_t)vd, PRIBIO);
+       }
+       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.
 #define        DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
 /*
  * Handle a disk interrupt.
@@ -723,7 +799,7 @@ vdintr(ctlr)
        register struct vba_device *vi;
        register struct vdsoftc *vd = &vdsoftc[ctlr];
        register status;
        register struct vba_device *vi;
        register struct vdsoftc *vd = &vdsoftc[ctlr];
        register status;
-       int ecode, timedout;
+       int timedout;
        struct dksoftc *dk;
 
        if (!vm->um_tab.b_active) {
        struct dksoftc *dk;
 
        if (!vm->um_tab.b_active) {
@@ -737,6 +813,7 @@ vdintr(ctlr)
        dp = vm->um_tab.b_actf;
        bp = dp->b_actf;
        vi = vddinfo[vdunit(bp->b_dev)];
        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);
        if (vi->ui_dk >= 0)
                dk_busy &= ~(1<<vi->ui_dk);
        timedout = (vd->vd_wticks >= VDMAXTIME);
@@ -752,10 +829,8 @@ vdintr(ctlr)
                dk->dk_ecode = vd->vd_dcb.err_code;
        }
        if (status & VDERR_HARD || timedout) {
                dk->dk_ecode = vd->vd_dcb.err_code;
        }
        if (status & VDERR_HARD || timedout) {
-               if (vd->vd_type == VDTYPE_SMDE) {
+               if (vd->vd_type == VDTYPE_SMDE)
                        uncache(&vd->vd_dcb.err_code);
                        uncache(&vd->vd_dcb.err_code);
-                       ecode = vd->vd_dcb.err_code;
-               }
                if (status & DCBS_WPT) {
                        /*
                         * Give up on write locked devices immediately.
                if (status & DCBS_WPT) {
                        /*
                         * Give up on write locked devices immediately.
@@ -797,7 +872,7 @@ vdintr(ctlr)
                        printf("\n");
                }
        } else if (status & DCBS_SOFT)
                        printf("\n");
                }
        } else if (status & DCBS_SOFT)
-               vdsofterr(vd, bp, &vd->vd_dcb);
+               vdsofterr(bp, &vd->vd_dcb);
        vd->vd_wticks = 0;
        if (vm->um_tab.b_active) {
                vm->um_tab.b_active = 0;
        vd->vd_wticks = 0;
        if (vm->um_tab.b_active) {
                vm->um_tab.b_active = 0;
@@ -814,14 +889,17 @@ vdintr(ctlr)
                 */
                if (dp->b_actf)
                        vdustart(vi);
                 */
                if (dp->b_actf)
                        vdustart(vi);
-               else if ((dk = &dksoftc[vi->ui_unit])->dk_openpart == 0)
+               else if (dk->dk_openpart == 0)
                        wakeup((caddr_t)dk);
        }
        /*
         * If there are devices ready to
         * transfer, start the controller.
         */
                        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)
+       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);
 }
 
                vdstart(vm);
 }
 
@@ -832,46 +910,43 @@ vdharderr(what, vd, bp, dcb)
        register struct dcb *dcb;
 {
        int unit = vdunit(bp->b_dev), status = dcb->operrsta;
        register struct dcb *dcb;
 {
        int unit = vdunit(bp->b_dev), status = dcb->operrsta;
-       int part = vdpart(bp->b_dev);
        register struct disklabel *lp = &dklabel[unit];
        register struct disklabel *lp = &dklabel[unit];
-       char partname = 'a' + part;
-       int sn;
+       int blkdone;
 
        if (vd->vd_wticks < VDMAXTIME)
                status &= ~DONTCARE;
 
        if (vd->vd_wticks < VDMAXTIME)
                status &= ~DONTCARE;
-/* generic
-       sn = bp->b_blkno + lp->d_partitions[part].p_offset;
-*/
-       sn = ((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk)
-           * lp->d_nsectors + dcb->err_sec;
-       printf("dk%d%c: %s bn [%d-%d) (sn %d), status %b",
-           unit, partname, what, bp->b_blkno,
-           bp->b_blkno + (bp->b_bcount - 1)/DEV_BSIZE, sn, status, VDERRBITS);
+       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);
        if (vd->vd_type == VDTYPE_SMDE)
                printf(" ecode %x", dcb->err_code);
-       printf("\n(error sec %d trk %d cyl %d wcount %d)", dcb->err_sec,
-           dcb->err_trk, dcb->err_cyl, dcb->err_wcount);
 }
 
 }
 
-vdsofterr(vd, bp, dcb)
-       struct vdsoftc *vd;
+vdsofterr(bp, dcb)
        register struct buf *bp;
        register struct dcb *dcb;
 {
        register struct buf *bp;
        register struct dcb *dcb;
 {
-       int unit = vdunit(bp->b_dev), status = dcb->operrsta;
-       int part = vdpart(bp->b_dev);
-       char partname = 'a' + part;
-       int sn = (bp->b_blkno << dksoftc[unit].dk_bshift) +
-           dklabel[unit].d_partitions[part].p_offset;
-
-       if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE))
-               log(LOG_WARNING,
-                   "dk%d%c: soft error sn %d bn %d, status %b ecode %x\n",
-                   unit, partname, sn, bp->b_blkno, status, VDERRBITS,
+       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);
                    dcb->err_code);
-       else
-               log(LOG_WARNING, "dk%d%c: soft ecc sn %d bn %d\n",
-                   unit, part, sn, bp->b_blkno);
+       } else {
+               diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
+               addlog("\n");
+       }
 }
 
 vdioctl(dev, cmd, data, flag)
 }
 
 vdioctl(dev, cmd, data, flag)
@@ -883,7 +958,7 @@ vdioctl(dev, cmd, data, flag)
        register int unit = vdunit(dev);
        register struct disklabel *lp = &dklabel[unit];
        register struct dksoftc *dk = &dksoftc[unit];
        register int unit = vdunit(dev);
        register struct disklabel *lp = &dklabel[unit];
        register struct dksoftc *dk = &dksoftc[unit];
-       int error = 0, wlab, vdformat();
+       int error = 0, vdformat();
 
        switch (cmd) {
 
 
        switch (cmd) {
 
@@ -916,19 +991,23 @@ vdioctl(dev, cmd, data, flag)
                break;
 
        case DIOCWDINFO:
                break;
 
        case DIOCWDINFO:
-               /* simulate opening partition 0 so write succeeds */
-               dk->dk_openpart |= (1 << 0);            /* XXX */
-               wlab = dk->dk_wlabel;
-               dk->dk_wlabel = 1;
                if ((flag & FWRITE) == 0)
                        error = EBADF;
                else if ((error = setdisklabel(lp, (struct disklabel *)data,
                    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
                if ((flag & FWRITE) == 0)
                        error = EBADF;
                else if ((error = setdisklabel(lp, (struct disklabel *)data,
                    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
-                       dk->dk_state = OPEN;
+                       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);
                        error = writedisklabel(dev, vdstrategy, lp);
+                       dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
+                       dk->dk_wlabel = wlab;
                }
                }
-               dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
-               dk->dk_wlabel = wlab;
                break;
 
        case DIOCWFORMAT:
                break;
 
        case DIOCWFORMAT:
@@ -985,7 +1064,7 @@ vdwatch()
 {
        register struct vdsoftc *vd;
        register struct vba_ctlr *vm;
 {
        register struct vdsoftc *vd;
        register struct vba_ctlr *vm;
-       register int ctlr, unit;
+       register int ctlr;
        int s;
 
        timeout(vdwatch, (caddr_t)0, hz);
        int s;
 
        timeout(vdwatch, (caddr_t)0, hz);
@@ -1122,7 +1201,7 @@ vdreset_ctlr(vm)
                vdaddr->vdccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
                    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
        }
                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)) {
+       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;
                printf("%s cmd failed\n",
                    vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
                return;
@@ -1163,6 +1242,20 @@ top:
                printf(" during config\n");
                return (0);
        }
                printf(" during config\n");
                return (0);
        }
+/*
+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) {
        if (vd->vd_dcb.operrsta & VDERR_HARD) {
                if (vd->vd_type == VDTYPE_SMDE) {
                        if (lp->d_devflags == 0) {
@@ -1186,7 +1279,7 @@ top:
                        vd->vd_flags |= VD_STARTED;
                        started = (vdcmd(vm, VDOP_START, 10) == 1);
                        DELAY(62000000);
                        vd->vd_flags |= VD_STARTED;
                        started = (vdcmd(vm, VDOP_START, 10) == 1);
                        DELAY(62000000);
-                       printf("done");
+                       printf("done\n");
                        lp->d_devflags = 0;
                        if (started)
                                goto top;
                        lp->d_devflags = 0;
                        if (started)
                                goto top;
@@ -1200,7 +1293,7 @@ top:
 /*
  * Perform a command w/o trailer.
  */
 /*
  * Perform a command w/o trailer.
  */
-vdcmd(vm, cmd, t)
+vdcmd(vm, cmd, t, slave)
        register struct vba_ctlr *vm;
 {
        register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
        register struct vba_ctlr *vm;
 {
        register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
@@ -1209,7 +1302,7 @@ vdcmd(vm, cmd, t)
        vd->vd_dcb.intflg = DCBINT_NONE;
        vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
        vd->vd_dcb.operrsta = 0;
        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.devselect = slave;
        vd->vd_dcb.trailcnt = 0;
        vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
        vd->vd_mdcb.mdcb_status = 0;
        vd->vd_dcb.trailcnt = 0;
        vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
        vd->vd_mdcb.mdcb_status = 0;
@@ -1272,6 +1365,16 @@ struct   vdst {
        { 66, 23, 850, 512, "NEC 800",
                {0,      1290300},      /* a cyl   0 - 849 */
        },
        { 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 */
        { 48, 24, 711, 512, "xsd",
                {0,      61056},        /* a cyl   0 - 52 */
                {61056,  61056},        /* b cyl  53 - 105 */
@@ -1365,8 +1468,10 @@ vdmaptype(vi, lp)
                lp->d_ntracks = p->ntrack;
                lp->d_ncylinders = p->ncyl;
                lp->d_secsize = p->secsize;
                lp->d_ntracks = p->ntrack;
                lp->d_ncylinders = p->ncyl;
                lp->d_secsize = p->secsize;
+               DELAY(100000);
                if (!vdreset_drive(vi))
                        return (0);
                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.opcode = VDOP_RD;
                vd->vd_dcb.intflg = DCBINT_NONE;
                vd->vd_dcb.nxtdcb = (struct dcb *)0;    /* end of chain */
@@ -1396,7 +1501,6 @@ vdmaptype(vi, lp)
        }
        lp->d_npartitions = 8;
        lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
        }
        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);
 }
        bcopy(p->name, lp->d_typename, 4);
        return (1);
 }