(no message)
[unix-history] / usr / src / sys / vax / uba / up.c
index 9421ac5..519fb16 100644 (file)
@@ -1,38 +1,11 @@
-/*     %H%     3.15    %G%     */
+/*     up.c    4.12    %G%     */
 
 
-#define        spl5    spl6            /* block clock, for delay loop's sake */
+#include "up.h"
+#if NUP > 0
 /*
 /*
- * Emulex UNIBUS disk driver with overlapped seeks and ECC recovery.
- *
- * NB: This device is very sensitive: be aware that the code is the way
- *     it is for good reason and that there are delay loops here which may
- *     have to be lengthened if your processor is faster and which should
- *     probably be shortened if your processor is slower.
- *
- * This driver has been tested on a SC-11B Controller, configured
- * with the following internal switch settings:
- *     SW1-1   5/19 surfaces   (off, 19 surfaces on Ampex 9300)
- *     SW1-2   chksum enable   (off, checksum disabled)
- *     SW1-3   volume select   (off, 815 cylinders)
- *     SW1-4   sector select   (on, 32 sectors)
- *     SW1-5   unused          (off)
- *     SW1-6   port select     (on, single port)
- *     SW1-7   npr delay       (off, disable)
- *     SW1-8   ecc test mode   (off, disable)
- * and top mounted switches:
- *     SW2-1   extend opcodes  (off=open, disable)
- *     SW2-2   extend diag     (off=open, disable)
- *     SW2-3   4 wd dma burst  (off=open, disable)
- *     SW2-4   unused          (off=open)
- *
- * The controller transfers data much more rapidly with SW2-3 set,
- * but we have previously experienced problems with it set this way.
- * We intend to try this again in the near future.
- *
- * NB: OUR SYSTEM CURRENTLY GETS UBA ERRORS WHEN RUNNING THIS DRIVER
- *     AND THE BUS OCCASIONALLY HANGS, NECESSITATING THE DEVIE RESET
- *     CODE WHICH RE-INITS THE UNIBUS.  YECHHH.
+ * UNIBUS disk driver with overlapped seeks and ECC recovery.
  */
  */
+#define        DELAY(N)                { register int d; d = N; while (--d > 0); }
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/map.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/map.h"
+#include "../h/pte.h"
 #include "../h/mba.h"
 #include "../h/mtpr.h"
 #include "../h/mba.h"
 #include "../h/mtpr.h"
-#include "../h/pte.h"
 #include "../h/uba.h"
 #include "../h/vm.h"
 #include "../h/uba.h"
 #include "../h/vm.h"
+#include "../h/cmap.h"
 
 
-/*
- * Define number of drives, and range of sampling information to be used.
- *
- * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats,
- * and DK_N+NUP gathers controller transferring stats.
- *
- * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive.
- * If DK_NMAX is yet smaller, some drives are not monitored.
- */
-#define        DK_N    2
-#define        DK_NMAX 3
-
-#define        ushort  unsigned short
-
-struct device
-{
-       ushort  upcs1;          /* control and status register 1 */
-       short   upwc;           /* word count register */
-       ushort  upba;           /* UNIBUS address register */
-       ushort  upda;           /* desired address register */
-       ushort  upcs2;          /* control and status register 2 */
-       ushort  upds;           /* drive Status */
-       ushort  uper1;          /* error register 1 */
-       ushort  upas;           /* attention summary */
-       ushort  upla;           /* look ahead */
-       ushort  updb;           /* data buffer */
-       ushort  upmr;           /* maintenance */ 
-       ushort  updt;           /* drive type */
-       ushort  upsn;           /* serial number */
-       ushort  upof;           /* offset register */
-       ushort  updc;           /* desired cylinder address register */
-       ushort  upcc;           /* current cylinder */
-       ushort  uper2;          /* error register 2 */
-       ushort  uper3;          /* error register 3 */
-       ushort  upec1;          /* burst error bit position */
-       ushort  upec2;          /* burst error bit pattern */
-};
+#include "../h/upreg.h"
 
 /*
  * Software extension to the upas register, so we can
  * postpone starting SEARCH commands until the controller
  * is not transferring.
  */
 
 /*
  * Software extension to the upas register, so we can
  * postpone starting SEARCH commands until the controller
  * is not transferring.
  */
-int    softas;
+int    upsoftas;
 
 /*
  * If upseek then we don't issue SEARCH commands but rather just
 
 /*
  * If upseek then we don't issue SEARCH commands but rather just
@@ -99,10 +37,6 @@ int  softas;
  */
 int    upseek;
 
  */
 int    upseek;
 
-#define        UPADDR  ((struct device *)(UBA0_DEV + 0176700))
-
-#define        NUP     2               /* Number of drives this installation */
-
 #define        NSECT   32
 #define        NTRAC   19
 
 #define        NSECT   32
 #define        NTRAC   19
 
@@ -116,8 +50,8 @@ int  upseek;
  * and in the driver then we take it as it is.  Otherwise we do a SEARCH
  * requesting an interrupt upSDIST sectors in advance.
  */
  * and in the driver then we take it as it is.  Otherwise we do a SEARCH
  * requesting an interrupt upSDIST sectors in advance.
  */
-#define        _upSDIST        6               /* 3.0 msec */
-#define        _upRDIST        6               /* 3.0 msec */
+#define        _upSDIST        2               /* 1.0 msec */
+#define        _upRDIST        4               /* 2.0 msec */
 
 int    upSDIST = _upSDIST;
 int    upRDIST = _upRDIST;
 
 int    upSDIST = _upSDIST;
 int    upRDIST = _upRDIST;
@@ -130,6 +64,9 @@ int  upRDIST = _upRDIST;
  * On systems with RP06'es, we normally use only 291346 blocks of the H
  * area, and use DEF or G to cover the rest of the drive.  The C system
  * covers the whole drive and can be used for pack-pack copying.
  * On systems with RP06'es, we normally use only 291346 blocks of the H
  * area, and use DEF or G to cover the rest of the drive.  The C system
  * covers the whole drive and can be used for pack-pack copying.
+ *
+ * Note: sizes here are for AMPEX drives with 815 cylinders.
+ * CDC drives can make the F,G, and H areas larger as they have 823 cylinders.
  */
 struct size
 {
  */
 struct size
 {
@@ -138,13 +75,11 @@ struct     size
 } up_sizes[8] = {
        15884,  0,              /* A=cyl 0 thru 26 */
        33440,  27,             /* B=cyl 27 thru 81 */
 } up_sizes[8] = {
        15884,  0,              /* A=cyl 0 thru 26 */
        33440,  27,             /* B=cyl 27 thru 81 */
-       494912, 0,              /* C=cyl 0 thru 814 */
+       495520, 0,              /* C=cyl 0 thru 814 */
        15884,  562,            /* D=cyl 562 thru 588 */
        55936,  589,            /* E=cyl 589 thru 680 */
        81472,  681,            /* F=cyl 681 thru 814 */
        153824, 562,            /* G=cyl 562 thru 814 */
        15884,  562,            /* D=cyl 562 thru 588 */
        55936,  589,            /* E=cyl 589 thru 680 */
        81472,  681,            /* F=cyl 681 thru 814 */
        153824, 562,            /* G=cyl 562 thru 814 */
-       445664, 82,             /* H=cyl 82 thru 814 */
-/* Later, and more safely for H area...
        291346, 82,             /* H=cyl 82 thru 561 */
 };
 
        291346, 82,             /* H=cyl 82 thru 561 */
 };
 
@@ -154,7 +89,7 @@ struct       size
  * +/- microinches.  Note that header compare inhibit (HCI) is not
  * tried (this makes sense only during read, in any case.)
  *
  * +/- microinches.  Note that header compare inhibit (HCI) is not
  * tried (this makes sense only during read, in any case.)
  *
- * ARE ALL THESE IMPLEMENTED ON 9300?
+ * NB: Not all drives/controllers emulate all of these.
  */
 #define        P400    020
 #define        M400    0220
  */
 #define        P400    020
 #define        M400    0220
@@ -187,63 +122,9 @@ struct     buf     uputab[NUP];
 
 struct buf     rupbuf;                 /* Buffer for raw i/o */
 
 
 struct buf     rupbuf;                 /* Buffer for raw i/o */
 
-/* Drive commands, placed in upcs1 */
-#define        GO      01              /* Go bit, set in all commands */
-#define        PRESET  020             /* Preset drive at init or after errors */
-#define        OFFSET  014             /* Offset heads to try to recover error */
-#define        RTC     016             /* Return to center-line after OFFSET */
-#define        SEARCH  030             /* Search for cylinder+sector */
-#define        SEEK    04              /* Seek to cylinder */
-#define        RECAL   06              /* Recalibrate, needed after seek error */
-#define        DCLR    010             /* Drive clear, after error */
-#define        WCOM    060             /* Write */
-#define        RCOM    070             /* Read */
-
-/* Other bits of upcs1 */
-#define        IE      0100            /* Controller wide interrupt enable */
-#define        TRE     040000          /* Transfer error */
-#define        RDY     020             /* Transfer terminated */
-
-/* Drive status bits of upds */
-#define        PIP     020000          /* Positioning in progress */
-#define        ERR     040000          /* Error has occurred, DCLR necessary */
-#define        VV      0100            /* Volume is valid, set by PRESET */
-#define        DPR     0400            /* Drive has been preset */
-#define        MOL     010000          /* Drive is online, heads loaded, etc */
-#define        DRY     0200            /* Drive ready */
-
-/* Bits of upcs2 */
-#define        CLR     040             /* Controller clear */
-/* Bits of uper1 */
-#define        DCK     0100000         /* Ecc error occurred */
-#define        ECH     0100            /* Ecc error was unrecoverable */
-#define        WLE     04000           /* Attempt to write read-only drive */
-
-/* Bits of upof; the offset bits above are also in this register */
-#define        FMT22   010000          /* 16 bits/word, must be always set */
-
 #define        b_cylin b_resid
 
 int    up_ubinfo;              /* Information about UBA usage saved here */
 #define        b_cylin b_resid
 
 int    up_ubinfo;              /* Information about UBA usage saved here */
-/*
- * The EMULEX controller balks if accessed quickly after
- * certain operations.  The exact timing has not yet been
- * determined, but delays are known to be needed when changing
- * the selected drive (by writing in upcs2), and thought to be
- * needed after operations like PRESET and DCLR.  The following
- * variables control the delay, DELAY(n) is approximately n usec.
- */
-int    idelay = 500;           /* Delay after PRESET or DCLR */
-int    sdelay = 150;           /* Delay after selecting drive in upcs2 */
-int    rdelay = 100;           /* Delay after SEARCH */
-int    asdel = 100;            /* Delay after clearing bit in upas */
-
-int    csdel2 = 0;             /* ??? Delay in upstart ??? */
-
-#define        DELAY(N)                { register int d; d = N; while (--d > 0); }
-int    nwaitcs2;               /* How many sdelay loops ? */
-int    neasycs2;               /* How many sdelay loops not needed ? */
 
 int    up_wticks;              /* Ticks waiting for interrupt */
 int    upwstart;               /* Have started guardian */
 
 int    up_wticks;              /* Ticks waiting for interrupt */
 int    upwstart;               /* Have started guardian */
@@ -269,7 +150,7 @@ register struct buf *bp;
        long sz, bn;
 
        if (upwstart == 0) {
        long sz, bn;
 
        if (upwstart == 0) {
-               timeout((caddr_t)upwatch, 0, HZ);
+               timeout(upwatch, (caddr_t)0, HZ);
                upwstart++;
        }
        xunit = minor(bp->b_dev) & 077;
                upwstart++;
        }
        xunit = minor(bp->b_dev) & 077;
@@ -283,6 +164,8 @@ register struct buf *bp;
                iodone(bp);
                return;
        }
                iodone(bp);
                return;
        }
+       if (UPDK_N+unit <= UPDK_NMAX)
+               dk_mspw[UPDK_N+unit] = .0000020345;
        bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff;
        dp = &uputab[unit];
        (void) spl5();
        bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff;
        dp = &uputab[unit];
        (void) spl5();
@@ -313,12 +196,9 @@ register unit;
         * Other drivers tend to say something like
         *      upaddr->upcs1 = IE;
         *      upaddr->upas = 1<<unit;
         * Other drivers tend to say something like
         *      upaddr->upcs1 = IE;
         *      upaddr->upas = 1<<unit;
-        * here, but the SC-11B will cancel a command which
+        * here, but some controllers will cancel a command
         * happens to be sitting in the cs1 if you clear the go
         * happens to be sitting in the cs1 if you clear the go
-        * bit by storing there (so the first is not safe),
-        * and it also does not like being bothered with operations
-        * such as clearing upas when a transfer is active (as
-        * it may well be.)
+        * bit by storing there (so the first is not safe).
         *
         * Thus we keep careful track of when we re-enable IE
         * after an interrupt and do it only if we didn't issue
         *
         * Thus we keep careful track of when we re-enable IE
         * after an interrupt and do it only if we didn't issue
@@ -328,31 +208,27 @@ register unit;
         */
        if (unit >= NUP)
                goto out;
         */
        if (unit >= NUP)
                goto out;
-       if (unit+DK_N <= DK_NMAX)
-               dk_busy &= ~(1<<(unit+DK_N));
+       if (unit+UPDK_N <= UPDK_NMAX)
+               dk_busy &= ~(1<<(unit+UPDK_N));
        dp = &uputab[unit];
        if ((bp = dp->b_actf) == NULL)
                goto out;
        /*
        dp = &uputab[unit];
        if ((bp = dp->b_actf) == NULL)
                goto out;
        /*
-        * The SC-11B doesn't start SEARCH commands when transfers are
-        * in progress.  In fact, it tends to get confused when given
+        * Most controllers don't start SEARCH commands when transfers are
+        * in progress.  In fact, some tend to get confused when given
         * SEARCH'es during transfers, generating interrupts with neither
         * RDY nor a bit in the upas register.  Thus we defer
         * until an interrupt when a transfer is pending.
         */
        if (uptab.b_active) {
         * SEARCH'es during transfers, generating interrupts with neither
         * RDY nor a bit in the upas register.  Thus we defer
         * until an interrupt when a transfer is pending.
         */
        if (uptab.b_active) {
-               softas |= 1<<unit;
+               upsoftas |= 1<<unit;
                return (0);
        }
        if (dp->b_active)
                goto done;
        dp->b_active = 1;
                return (0);
        }
        if (dp->b_active)
                goto done;
        dp->b_active = 1;
-       if ((upaddr->upcs2 & 07) != unit) {
+       if ((upaddr->upcs2 & 07) != unit)
                upaddr->upcs2 = unit;
                upaddr->upcs2 = unit;
-               DELAY(sdelay);
-               nwaitcs2++;
-       } else
-               neasycs2++;
        /*
         * If we have changed packs or just initialized,
         * then the volume will not be valid; if so, clear
        /*
         * If we have changed packs or just initialized,
         * then the volume will not be valid; if so, clear
@@ -360,15 +236,14 @@ register unit;
         */
        if ((upaddr->upds & VV) == 0) {
                upaddr->upcs1 = IE|DCLR|GO;
         */
        if ((upaddr->upds & VV) == 0) {
                upaddr->upcs1 = IE|DCLR|GO;
-               DELAY(idelay);
                upaddr->upcs1 = IE|PRESET|GO;
                upaddr->upcs1 = IE|PRESET|GO;
-               DELAY(idelay);
                upaddr->upof = FMT22;
                upaddr->upof = FMT22;
-               printf("VV done ds %o, er? %o %o %o\n", upaddr->upds, upaddr->uper1, upaddr->uper2, upaddr->uper3);
                didie = 1;
        }
        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
                goto done;
                didie = 1;
        }
        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
                goto done;
+
+#if NUP > 1
        /*
         * Do enough of the disk address decoding to determine
         * which cylinder and sector the request is on.
        /*
         * Do enough of the disk address decoding to determine
         * which cylinder and sector the request is on.
@@ -404,13 +279,13 @@ search:
        /*
         * Mark this unit busy.
         */
        /*
         * Mark this unit busy.
         */
-       unit += DK_N;
-       if (unit <= DK_NMAX) {
+       unit += UPDK_N;
+       if (unit <= UPDK_NMAX) {
                dk_busy |= 1<<unit;
                dk_busy |= 1<<unit;
-               dk_numb[unit]++;
+               dk_seek[unit]++;
        }
        }
-       DELAY(rdelay);
        goto out;
        goto out;
+#endif
 
 done:
        /*
 
 done:
        /*
@@ -440,7 +315,6 @@ upstart()
        int dn, sn, tn, cn, cmd;
 
 loop:
        int dn, sn, tn, cn, cmd;
 
 loop:
-       if (csdel2) DELAY(csdel2);
        /*
         * Pick a drive off the queue of ready drives, and
         * perform the first transfer on its queue.
        /*
         * Pick a drive off the queue of ready drives, and
         * perform the first transfer on its queue.
@@ -469,13 +343,9 @@ loop:
        tn = sn/NSECT;
        sn %= NSECT;
        upaddr = UPADDR;
        tn = sn/NSECT;
        sn %= NSECT;
        upaddr = UPADDR;
-       if ((upaddr->upcs2 & 07) != dn) {
+       if ((upaddr->upcs2 & 07) != dn)
                upaddr->upcs2 = dn;
                upaddr->upcs2 = dn;
-               /* DELAY(sdelay);               Provided by ubasetup() */
-               nwaitcs2++;
-       } else
-               neasycs2++;
-       up_ubinfo = ubasetup(bp, 1);    /* Providing delay */
+       up_ubinfo = ubasetup(bp, 1);
        /*
         * If drive is not present and on-line, then
         * get rid of this with an error and loop to get
        /*
         * If drive is not present and on-line, then
         * get rid of this with an error and loop to get
@@ -483,24 +353,28 @@ loop:
         * (Then on to any other ready drives.)
         */
        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
         * (Then on to any other ready drives.)
         */
        if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
-               printf("!DPR || !MOL, unit %d, ds %o\n", dn, upaddr->upds);
-               uptab.b_active = 0;
-               uptab.b_errcnt = 0;
-               dp->b_actf = bp->av_forw;
-               dp->b_active = 0;
-               bp->b_flags |= B_ERROR;
-               iodone(bp);
-               ubafree(up_ubinfo), up_ubinfo = 0;      /* A funny place ... */
-               goto loop;
+               printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds);
+               if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
+                       printf("-- hard\n");
+                       uptab.b_active = 0;
+                       uptab.b_errcnt = 0;
+                       dp->b_actf = bp->av_forw;
+                       dp->b_active = 0;
+                       bp->b_flags |= B_ERROR;
+                       iodone(bp);
+                       /* A funny place to do this ... */
+                       ubarelse(&up_ubinfo);
+                       goto loop;
+               }
+               printf("-- came back\n");
        }
        /*
         * If this is a retry, then with the 16'th retry we
         * begin to try offsetting the heads to recover the data.
         */
        }
        /*
         * If this is a retry, then with the 16'th retry we
         * begin to try offsetting the heads to recover the data.
         */
-       if (uptab.b_errcnt >= 16) {
+       if (uptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
                upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
                upaddr->upcs1 = IE|OFFSET|GO;
                upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22;
                upaddr->upcs1 = IE|OFFSET|GO;
-               DELAY(idelay);
                while (upaddr->upds & PIP)
                        DELAY(25);
        }
                while (upaddr->upds & PIP)
                        DELAY(25);
        }
@@ -521,17 +395,15 @@ loop:
        upaddr->upcs1 = cmd;
        /*
         * This is a controller busy situation.
        upaddr->upcs1 = cmd;
        /*
         * This is a controller busy situation.
-        * Record in dk slot NUP+DK_N (after last drive)
+        * Record in dk slot NUP+UPDK_N (after last drive)
         * unless there aren't that many slots reserved for
         * us in which case we record this as a drive busy
         * (if there is room for that).
         */
         * unless there aren't that many slots reserved for
         * us in which case we record this as a drive busy
         * (if there is room for that).
         */
-       unit = dn+DK_N;
-       if (NUP+DK_N == DK_NMAX)
-               unit = NUP+DK_N;
-       if (unit <= DK_NMAX) {
+       unit = dn+UPDK_N;
+       if (unit <= UPDK_NMAX) {
                dk_busy |= 1<<unit;
                dk_busy |= 1<<unit;
-               dk_numb[unit]++;
+               dk_xfer[unit]++;
                dk_wds[unit] += bp->b_bcount>>6;
        }
        return (1);
                dk_wds[unit] += bp->b_bcount>>6;
        }
        return (1);
@@ -552,7 +424,7 @@ upintr()
        register unit;
        register struct device *upaddr = UPADDR;
        int as = upaddr->upas & 0377;
        register unit;
        register struct device *upaddr = UPADDR;
        int as = upaddr->upas & 0377;
-       int osoftas;
+       int oupsoftas;
        int needie = 1;
 
        (void) spl6();
        int needie = 1;
 
        (void) spl6();
@@ -566,26 +438,22 @@ upintr()
                if ((upaddr->upcs1 & RDY) == 0) {
                        printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
                            upaddr->upds, upaddr->upwc);
                if ((upaddr->upcs1 & RDY) == 0) {
                        printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1,
                            upaddr->upds, upaddr->upwc);
-printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1].b_active);
+                       printf("as=%d act %d %d %d\n", as, uptab.b_active,
+                           uputab[0].b_active, uputab[1].b_active);
                }
                /*
                }
                /*
-                * Mark controller or drive not busy, and check for an
+                * Mark drive not busy, and check for an
                 * error condition which may have resulted from the transfer.
                 */
                dp = uptab.b_actf;
                bp = dp->b_actf;
                unit = dkunit(bp);
                 * error condition which may have resulted from the transfer.
                 */
                dp = uptab.b_actf;
                bp = dp->b_actf;
                unit = dkunit(bp);
-               if (DK_N+NUP == DK_NMAX)
-                       dk_busy &= ~(1<<(DK_N+NUP));
-               else if (DK_N+unit <= DK_NMAX)
-                       dk_busy &= ~(1<<(DK_N+unit));
-               if ((upaddr->upcs2 & 07) != unit) {
+               if (UPDK_N+unit <= UPDK_NMAX)
+                       dk_busy &= ~(1<<(UPDK_N+unit));
+               if ((upaddr->upcs2 & 07) != unit)
                        upaddr->upcs2 = unit;
                        upaddr->upcs2 = unit;
-                       DELAY(sdelay);
-                       nwaitcs2++;
-               } else
-                       neasycs2++;
-               if (upaddr->upds & ERR) {
+               if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
+                       int cs2;
                        /*
                         * An error occurred, indeed.  Select this unit
                         * to get at the drive status (a SEARCH may have
                        /*
                         * An error occurred, indeed.  Select this unit
                         * to get at the drive status (a SEARCH may have
@@ -607,7 +475,9 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
                        else
                                uptab.b_active = 0;     /* To force retry */
                        if (uptab.b_errcnt > 27)
                        else
                                uptab.b_active = 0;     /* To force retry */
                        if (uptab.b_errcnt > 27)
-                               deverror(bp, upaddr->upcs2, upaddr->uper1);
+                               cs2 = (int)upaddr->upcs2;
+                               deverror(bp, (int)upaddr->upcs2,
+                                   (int)upaddr->uper1);
                        /*
                         * If this was a correctible ECC error, let upecc
                         * do the dirty work to correct it.  If upecc
                        /*
                         * If this was a correctible ECC error, let upecc
                         * do the dirty work to correct it.  If upecc
@@ -623,14 +493,17 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
                         * to hopefully help clear up seek positioning problems.
                         */
                        upaddr->upcs1 = TRE|IE|DCLR|GO;
                         * to hopefully help clear up seek positioning problems.
                         */
                        upaddr->upcs1 = TRE|IE|DCLR|GO;
-                       DELAY(idelay);
                        needie = 0;
                        if ((uptab.b_errcnt&07) == 4) {
                                upaddr->upcs1 = RECAL|GO|IE;
                        needie = 0;
                        if ((uptab.b_errcnt&07) == 4) {
                                upaddr->upcs1 = RECAL|GO|IE;
-                               DELAY(idelay);
                                while(upaddr->upds & PIP)
                                        DELAY(25);
                        }
                                while(upaddr->upds & PIP)
                                        DELAY(25);
                        }
+                       if (uptab.b_errcnt == 28 && cs2&(NEM|MXF)) {
+                               printf("FLAKEY UP ");
+                               ubareset();
+                               return;
+                       }
                }
                /*
                 * If we are still noted as active, then no
                }
                /*
                 * If we are still noted as active, then no
@@ -644,7 +517,6 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
                if (uptab.b_active) {
                        if (uptab.b_errcnt >= 16) {
                                upaddr->upcs1 = RTC|GO|IE;
                if (uptab.b_active) {
                        if (uptab.b_errcnt >= 16) {
                                upaddr->upcs1 = RTC|GO|IE;
-                               DELAY(idelay);
                                while (upaddr->upds & PIP)
                                        DELAY(25);
                                needie = 0;
                                while (upaddr->upds & PIP)
                                        DELAY(25);
                                needie = 0;
@@ -657,7 +529,8 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
                        dp->b_actf = bp->av_forw;
                        bp->b_resid = (-upaddr->upwc * sizeof(short));
                        if (bp->b_resid)
                        dp->b_actf = bp->av_forw;
                        bp->b_resid = (-upaddr->upwc * sizeof(short));
                        if (bp->b_resid)
-                               printf("resid %d ds %o er? %o %o %o\n", bp->b_resid, upaddr->upds,
+                               printf("resid %d ds %o er? %o %o %o\n",
+                                   bp->b_resid, upaddr->upds,
                                    upaddr->uper1, upaddr->uper2, upaddr->uper3);
                        iodone(bp);
                        if(dp->b_actf)
                                    upaddr->uper1, upaddr->uper2, upaddr->uper3);
                        iodone(bp);
                        if(dp->b_actf)
@@ -665,13 +538,11 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
                                        needie = 0;
                }
                as &= ~(1<<unit);
                                        needie = 0;
                }
                as &= ~(1<<unit);
-               softas &= ~(1<<unit);
-               ubafree(up_ubinfo), up_ubinfo = 0;
+               upsoftas &= ~(1<<unit);
+               ubarelse(&up_ubinfo);
        } else {
        } else {
-               if (upaddr->upcs1 & TRE) {
+               if (upaddr->upcs1 & TRE)
                        upaddr->upcs1 = TRE;
                        upaddr->upcs1 = TRE;
-                       DELAY(idelay);
-               }
        }
        /*
         * If we have a unit with an outstanding SEARCH,
        }
        /*
         * If we have a unit with an outstanding SEARCH,
@@ -680,22 +551,19 @@ printf("as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1]
         * Finally, if the controller is not transferring
         * start it if any drives are now ready to transfer.
         */
         * Finally, if the controller is not transferring
         * start it if any drives are now ready to transfer.
         */
-       as |= softas;
-       osoftas = softas;
-       softas = 0;
+       as |= upsoftas;
+       oupsoftas = upsoftas;
+       upsoftas = 0;
        for (unit = 0; unit < NUP; unit++)
        for (unit = 0; unit < NUP; unit++)
-               if ((as|osoftas) & (1<<unit)) {
-                       if (as & (1<<unit)) {
+               if ((as|oupsoftas) & (1<<unit)) {
+                       if (as & (1<<unit))
                                upaddr->upas = 1<<unit;
                                upaddr->upas = 1<<unit;
-                               if (asdel) DELAY(asdel);
-                       }
                        if (upustart(unit))
                                needie = 0;
                }
        if (uptab.b_actf && uptab.b_active == 0)
                if (upstart())
                        needie = 0;
                        if (upustart(unit))
                                needie = 0;
                }
        if (uptab.b_actf && uptab.b_active == 0)
                if (upstart())
                        needie = 0;
-out:
        if (needie)
                upaddr->upcs1 = IE;
 }
        if (needie)
                upaddr->upcs1 = IE;
 }
@@ -742,7 +610,6 @@ register struct buf *bp;
        mask = up->upec2;
        if (mask == 0) {
                up->upof = FMT22;               /* == RTC ???? */
        mask = up->upec2;
        if (mask == 0) {
                up->upof = FMT22;               /* == RTC ???? */
-               DELAY(idelay);
                return (0);
        }
        /*
                return (0);
        }
        /*
@@ -780,7 +647,6 @@ register struct buf *bp;
         * restart at offset o of next sector (i.e. in UBA register reg+1).
         */
        up->upcs1 = TRE|IE|DCLR|GO;
         * restart at offset o of next sector (i.e. in UBA register reg+1).
         */
        up->upcs1 = TRE|IE|DCLR|GO;
-       DELAY(idelay);
        bn = dkblock(bp);
        cn = bp->b_cylin;
        sn = bn%(NSECT*NTRAC) + npf + 1;
        bn = dkblock(bp);
        cn = bp->b_cylin;
        sn = bn%(NSECT*NTRAC) + npf + 1;
@@ -808,16 +674,14 @@ upreset()
        int unit;
 
        printf(" up");
        int unit;
 
        printf(" up");
+       DELAY(15000000);                /* give it time to self-test */
        uptab.b_active = 0;
        uptab.b_actf = uptab.b_actl = 0;
        uptab.b_active = 0;
        uptab.b_actf = uptab.b_actl = 0;
-       if (DK_N+NUP == DK_NMAX)
-               dk_busy &= ~(1<<(DK_N+NUP));
        if (up_ubinfo) {
                printf("<%d>", (up_ubinfo>>28)&0xf);
        if (up_ubinfo) {
                printf("<%d>", (up_ubinfo>>28)&0xf);
-               ubafree(up_ubinfo), up_ubinfo = 0;
+               ubarelse(&up_ubinfo);
        }
        UPADDR->upcs2 = CLR;            /* clear controller */
        }
        UPADDR->upcs2 = CLR;            /* clear controller */
-       DELAY(idelay);
        for (unit = 0; unit < NUP; unit++) {
                uputab[unit].b_active = 0;
                (void) upustart(unit);
        for (unit = 0; unit < NUP; unit++) {
                uputab[unit].b_active = 0;
                (void) upustart(unit);
@@ -835,7 +699,7 @@ upwatch()
 {
        int i;
 
 {
        int i;
 
-       timeout((caddr_t)upwatch, 0, HZ);
+       timeout(upwatch, (caddr_t)0, HZ);
        if (uptab.b_active == 0) {
                for (i = 0; i < NUP; i++)
                        if (uputab[i].b_active)
        if (uptab.b_active == 0) {
                for (i = 0; i < NUP; i++)
                        if (uputab[i].b_active)
@@ -852,3 +716,90 @@ active:
                printf("\n");
        }
 }
                printf("\n");
        }
 }
+
+#define        DBSIZE  20
+
+updump(dev)
+       dev_t dev;
+{
+       struct device *upaddr;
+       char *start;
+       int num, blk, unit, nsect, ntrak, nspc;
+       struct size *sizes;
+#if VAX==780
+       register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
+       register short *rp;
+       int bdp;
+
+       up->uba_cr = ADINIT;
+       up->uba_cr = IFS|BRIE|USEFIE|SUEFIE;
+       while ((up->uba_cnfgr & UBIC) == 0)
+               ;
+#endif
+       DELAY(1000000);
+       while ((UPADDR->upcs1&DVA) == 0)
+               ;
+       num = maxfree;
+       start = 0;
+       unit = minor(dev) >> 3;
+       if (unit >= NUP) {
+               printf("bad unit\n");
+               return (-1);
+       }
+       upaddr = UPPHYS;
+       upaddr->upcs2 = unit;
+       if ((upaddr->upds & VV) == 0) {
+               upaddr->upcs1 = DCLR|GO;
+               upaddr->upcs1 = PRESET|GO;
+               upaddr->upof = FMT22;
+       }
+       if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
+               printf("up !DPR || !MOL\n");
+               return (-1);
+       }
+       nsect = NSECT; ntrak = NTRAC; sizes = up_sizes;
+       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) {
+               printf("dumplo+num, sizes %d %d\n", dumplo+num, sizes[minor(dev)&07].nblocks);
+               return (-1);
+       }
+       nspc = nsect * ntrak;
+       while (num > 0) {
+               register struct pte *io;
+               register int i;
+               int cn, sn, tn;
+               daddr_t bn;
+
+               blk = num > DBSIZE ? DBSIZE : num;
+               bdp = 1;                /* trick pcc */
+               ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE;
+               io = ((struct uba_regs *)PHYSUBA0)->uba_map;
+               for (i = 0; i < blk; i++)
+                       *(int *)io++ = (btop(start)+i) | (1<<21) | MRV;
+               *(int *)io = 0;
+               bn = dumplo + btop(start);
+               cn = bn/nspc + sizes[minor(dev)&07].cyloff;
+               sn = bn%nspc;
+               tn = sn/nsect;
+               sn = sn%nsect;
+               upaddr->updc = cn;
+               rp = (short *) &upaddr->upda;
+               *rp = (tn << 8) + sn;
+               *--rp = 0;
+               *--rp = -blk*NBPG / sizeof (short);
+               *--rp = GO|WCOM;
+               do {
+                       DELAY(25);
+               } while ((upaddr->upcs1 & RDY) == 0);
+               if (upaddr->upcs1&ERR) {
+                       printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n",
+                           cn, tn, sn, upaddr->upcs1, upaddr->uper1);
+                       return (-1);
+               }
+               start += blk*NBPG;
+               num -= blk;
+       }
+       bdp = 1;                /* crud to fool c compiler */
+       ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE;
+       return (0);
+}
+#endif