add appropriate copyright notice
[unix-history] / usr / src / sys / tahoe / vba / vd.c
index e164ca2..6de9137 100644 (file)
@@ -1,4 +1,24 @@
-/*     vd.c    1.23    88/04/23        */
+/*
+ * 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
 
 #include "dk.h"
 #if NVD > 0
@@ -34,6 +54,7 @@
 #ifndef        COMPAT_42
 #define        COMPAT_42
 #endif
 #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 vdunit(dev)    (minor(dev) >> 3)
 #define vdpart(dev)    (minor(dev) & 0x07)
@@ -42,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.
@@ -64,6 +85,8 @@ struct vdsoftc {
        struct  vb_buf vd_rbuf; /* vba resources */
 } vdsoftc[NVD];
 
        struct  vb_buf vd_rbuf; /* vba resources */
 } vdsoftc[NVD];
 
+#define        VDMAXTIME       20      /* max time for operation, sec. */
+
 /*
  * Per-drive state.
  */
 /*
  * Per-drive state.
  */
@@ -79,6 +102,7 @@ struct       dksoftc {
        u_int   dk_curcyl;      /* last selected cylinder */
        struct  skdcb dk_dcb;   /* seek command block */
        u_long  dk_dcbphys;     /* physical address of dk_dcb */
        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];
 
 /*
 } dksoftc[NDK];
 
 /*
@@ -93,7 +117,6 @@ struct       dksoftc {
 #define        OPEN            4               /* intialized and ready */
 #define        OPENRAW         5               /* open, no label */
 
 #define        OPEN            4               /* intialized and ready */
 #define        OPENRAW         5               /* open, no label */
 
-struct buf rdkbuf[NDK];        /* raw i/o buffer headers */
 struct buf dkutab[NDK];        /* i/o queue headers */
 struct disklabel dklabel[NDK]; /* pack labels */
 
 struct buf dkutab[NDK];        /* i/o queue headers */
 struct disklabel dklabel[NDK]; /* pack labels */
 
@@ -208,10 +231,13 @@ vdslave(vi, vdaddr)
                lp->d_secsize = VD_MAXSECSIZE;
        else
                lp->d_secsize = VDDC_SECSIZE;
                lp->d_secsize = VD_MAXSECSIZE;
        else
                lp->d_secsize = VDDC_SECSIZE;
-       lp->d_nsectors = 68;            /* only used on smd-e */
+       lp->d_nsectors = 66;            /* only used on smd-e */
        lp->d_ntracks = 23;
        lp->d_ntracks = 23;
-       lp->d_ncylinders = 842;
-       lp->d_secpercyl = 68*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
 
        /*
         * Initialize invariant portion of
@@ -325,6 +351,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;
@@ -372,7 +399,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];
@@ -579,7 +606,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;
 
@@ -629,16 +655,37 @@ loop:
        dk->dk_curcyl = bp->b_cylin;
        bp->b_track = 0;                /* init overloaded field */
        vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
        dk->dk_curcyl = bp->b_cylin;
        bp->b_track = 0;                /* init overloaded field */
        vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
-       if (vd->vd_flags & VD_SCATGATH &&
-           ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0) {
+       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;
                vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
-               vd->vd_dcb.trailcnt += vba_sgsetup(bp, &vd->vd_rbuf,
-                   &vd->vd_dcb.trail.sgtrail);
-       } else {
+       else
                vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
                vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
-               vd->vd_dcb.trail.rwtrail.memadr =
-                       vbasetup(bp, &vd->vd_rbuf, lp->d_secsize);
+
+       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;
                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;
        }
        if (vi->ui_dk >= 0) {
                dk_busy |= 1<<vi->ui_dk;
@@ -699,10 +746,9 @@ 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;
+       int timedout;
        struct dksoftc *dk;
 
        struct dksoftc *dk;
 
-       vd->vd_wticks = 0;
        if (!vm->um_tab.b_active) {
                printf("vd%d: stray interrupt\n", ctlr);
                return;
        if (!vm->um_tab.b_active) {
                printf("vd%d: stray interrupt\n", ctlr);
                return;
@@ -714,51 +760,50 @@ 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);
        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;
        /*
         * Check for and process errors on
         * either the drive or the controller.
         */
        uncache(&vd->vd_dcb.operrsta);
        status = vd->vd_dcb.operrsta;
-       if (status & VDERR_HARD) {
-               if (vd->vd_type == VDTYPE_SMDE) {
+       if (bp->b_flags & B_FORMAT) {
+               dk->dk_operrsta = status;
+               uncache(&vd->vd_dcb.err_code);
+               dk->dk_ecode = vd->vd_dcb.err_code;
+       }
+       if (status & VDERR_HARD || timedout) {
+               if (vd->vd_type == VDTYPE_SMDE)
                        uncache(&vd->vd_dcb.err_code);
                        uncache(&vd->vd_dcb.err_code);
-                       ecode = 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;
                if (status & DCBS_WPT) {
                        /*
                         * Give up on write locked devices immediately.
                         */
                        printf("dk%d: write locked\n", vi->ui_unit);
                        bp->b_flags |= B_ERROR;
-               } else if (status & VDERR_RETRY) {
+               } else if (status & VDERR_RETRY || timedout) {
                        int endline = 1;
 
                        int endline = 1;
 
-                       if (status & VDERR_DRIVE) {
-                               printf("dk%d%c: drive err %b, bn %d,",
-                                   vi->ui_unit, 'a' + vdpart(bp->b_dev),
-                                   status &~ DONTCARE, VDERRBITS, bp->b_blkno);
-                               if (vd->vd_type == VDTYPE_SMDE)
-                                       printf(" ecode %x,", ecode);
-                               printf(" resetting drive...");
+                       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;
                                if (!vdreset_drive(vi))
                                        vi->ui_alive = 0;
-                       } else if (status & VDERR_CTLR) {
-                               printf("dk%d%c: controller err %b, bn %d,",
-                                   vi->ui_unit, 'a' + vdpart(bp->b_dev),
-                                   status &~ DONTCARE, VDERRBITS, bp->b_blkno);
-                               if (vd->vd_type == VDTYPE_SMDE)
-                                       printf(" ecode %x,", ecode);
-                               printf("resetting controller...");
-                               vdreset_ctlr(vm);
                        } else
                                endline = 0;
                        /*
                         * Retry transfer once, unless reset failed.
                         */
                        } else
                                endline = 0;
                        /*
                         * Retry transfer once, unless reset failed.
                         */
-                       if (!vi->ui_alive || dp->b_errcnt++ >= 2) {
+                       if (!vi->ui_alive || dp->b_errcnt++ >= 2 ||
+                           bp->b_flags & B_FORMAT) {
                                if (endline)
                                        printf("\n");
                                goto hard;
                                if (endline)
                                        printf("\n");
                                goto hard;
@@ -770,16 +815,12 @@ vdintr(ctlr)
                } else  {
        hard:
                        bp->b_flags |= B_ERROR;
                } else  {
        hard:
                        bp->b_flags |= B_ERROR;
-                       /* NEED TO ADJUST b_blkno to failed sector */
-                       harderr(bp, "dk");
-                       printf("status %x (%b)", status,
-                          status &~ DONTCARE, VDERRBITS);
-                       if (vd->vd_type == VDTYPE_SMDE)
-                               printf(" ecode %x", ecode);
+                       vdharderr("hard error", vd, bp, &vd->vd_dcb);
                        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;
                vm->um_tab.b_actf = dp->b_forw;
        if (vm->um_tab.b_active) {
                vm->um_tab.b_active = 0;
                vm->um_tab.b_actf = dp->b_forw;
@@ -795,7 +836,7 @@ 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);
        }
        /*
                        wakeup((caddr_t)dk);
        }
        /*
@@ -806,42 +847,50 @@ vdintr(ctlr)
                vdstart(vm);
 }
 
                vdstart(vm);
 }
 
-vdsofterr(vd, bp, dcb)
+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;
        struct vdsoftc *vd;
        register struct buf *bp;
        register struct dcb *dcb;
 {
        int unit = vdunit(bp->b_dev), status = dcb->operrsta;
-       char part = 'a' + vdpart(bp->b_dev);
-
-       if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE))
-               log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
-                   unit, part, bp->b_blkno, status, VDERRBITS, dcb->err_code);
-       else
-               log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
-                   unit, part, bp->b_blkno);
-}
-
-vdread(dev, uio)
-       dev_t dev;
-       struct uio *uio;
-{
-       register int unit = vdunit(dev);
-
-       if (unit >= NDK)
-               return (ENXIO);
-       return (physio(vdstrategy, &rdkbuf[unit], dev, B_READ, minphys, uio));
+       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);
 }
 
 }
 
-vdwrite(dev, uio)
-       dev_t dev;
-       struct uio *uio;
+vdsofterr(bp, dcb)
+       register struct buf *bp;
+       register struct dcb *dcb;
 {
 {
-       register int unit = vdunit(dev);
-
-       if (unit >= NDK)
-               return (ENXIO);
-       return (physio(vdstrategy, &rdkbuf[unit], dev, B_WRITE, minphys, uio));
+       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");
+       }
 }
 
 vdioctl(dev, cmd, data, flag)
 }
 
 vdioctl(dev, cmd, data, flag)
@@ -853,7 +902,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;
+       int error = 0, vdformat();
 
        switch (cmd) {
 
 
        switch (cmd) {
 
@@ -873,7 +922,8 @@ vdioctl(dev, cmd, data, flag)
                else
                        error = setdisklabel(lp, (struct disklabel *)data,
                            (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
                else
                        error = setdisklabel(lp, (struct disklabel *)data,
                            (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
-               if (error == 0)
+               if (error == 0 && dk->dk_state == OPENRAW &&
+                   vdreset_drive(vddinfo[unit]))
                        dk->dk_state = OPEN;
                break;
 
                        dk->dk_state = OPEN;
                break;
 
@@ -885,20 +935,55 @@ 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) {
+                       int wlab;
+
                        dk->dk_state = OPEN;
                        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;
+               }
+               break;
+
+       case DIOCWFORMAT:
+           {
+               register struct format_op *fop;
+               struct uio auio;
+               struct iovec aiov;
+
+               if ((flag & FWRITE) == 0) {
+                       error = EBADF;
+                       break;
                }
                }
-               dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
-               dk->dk_wlabel = wlab;
+               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;
                break;
+           }
 
        default:
                error = ENOTTY;
 
        default:
                error = ENOTTY;
@@ -907,6 +992,13 @@ vdioctl(dev, cmd, data, flag)
        return (error);
 }
 
        return (error);
 }
 
+vdformat(bp)
+       struct buf *bp;
+{
+       bp->b_flags |= B_FORMAT;
+       vdstrategy(bp);
+}
+
 /*
  * Watch for lost interrupts.
  */
 /*
  * Watch for lost interrupts.
  */
@@ -914,7 +1006,8 @@ 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);
        for (ctlr = 0; ctlr < NVD; ctlr++) {
 
        timeout(vdwatch, (caddr_t)0, hz);
        for (ctlr = 0; ctlr < NVD; ctlr++) {
@@ -922,11 +1015,15 @@ vdwatch()
                if (vm == 0 || vm->um_alive == 0)
                        continue;
                vd = &vdsoftc[ctlr];
                if (vm == 0 || vm->um_alive == 0)
                        continue;
                vd = &vdsoftc[ctlr];
-               if (vm->um_tab.b_active && vd->vd_wticks++ >= 20) {
-                       vd->vd_wticks = 0;
+               s = spl7();
+               if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
                        printf("vd%d: lost interrupt\n", ctlr);
                        printf("vd%d: lost interrupt\n", ctlr);
-                       /* abort pending dcb's and restart controller */
+#ifdef maybe
+                       VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
+#endif
+                       vdintr(ctlr);
                }
                }
+               splx(s);
        }
 }
 
        }
 }
 
@@ -1101,7 +1198,8 @@ top:
                }
                if ((vd->vd_dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0)
                        printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
                }
                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, vd->vd_dcb.err_code);
+                          vd->vd_dcb.operrsta, VDERRBITS,
+                          (u_char) vd->vd_dcb.err_code);
                else if ((vd->vd_flags & VD_STARTED) == 0) {
                        int started;
 
                else if ((vd->vd_flags & VD_STARTED) == 0) {
                        int started;
 
@@ -1163,7 +1261,6 @@ vdpoll(vm, t)
                if (--t <= 0) {
                        printf("vd%d: controller timeout", vm->um_ctlr);
                        VDABORT(vdaddr, vd->vd_type);
                if (--t <= 0) {
                        printf("vd%d: controller timeout", vm->um_ctlr);
                        VDABORT(vdaddr, vd->vd_type);
-                       DELAY(30000);
                        return (0);
                }
                DELAY(1000);
                        return (0);
                }
                DELAY(1000);
@@ -1196,6 +1293,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 */