new formats... new !RDY code... no more FLAKEY up
[unix-history] / usr / src / sys / vax / uba / up.c
index 95bc4ad..4e88914 100644 (file)
@@ -1,9 +1,17 @@
-/*     up.c    4.17    81/02/19        */
+/*     up.c    4.29    81/03/06        */
 
 #include "up.h"
 
 #include "up.h"
-#if NSC21 > 0
+#if NSC > 0
 /*
  * UNIBUS disk driver with overlapped seeks and ECC recovery.
 /*
  * UNIBUS disk driver with overlapped seeks and ECC recovery.
+ *
+ * TODO:
+ *     Check out handling of spun-down drives and write lock
+ *     Add reading of bad sector information and disk layout from sector 1
+ *     Add bad sector forwarding code
+ *     Check multiple drive handling
+ *     Check dump code
+ *     Check unibus reset code
  */
 #define        DELAY(N)                { register int d; d = N; while (--d > 0); }
 
  */
 #define        DELAY(N)                { register int d; d = N; while (--d > 0); }
 
@@ -18,7 +26,6 @@
 #include "../h/user.h"
 #include "../h/map.h"
 #include "../h/pte.h"
 #include "../h/user.h"
 #include "../h/map.h"
 #include "../h/pte.h"
-#include "../h/mba.h"
 #include "../h/mtpr.h"
 #include "../h/vm.h"
 #include "../h/uba.h"
 #include "../h/mtpr.h"
 #include "../h/vm.h"
 #include "../h/uba.h"
 
 struct up_softc {
        int     sc_softas;
 
 struct up_softc {
        int     sc_softas;
-       int     sc_seek;
+       int     sc_ndrive;
        int     sc_wticks;
        int     sc_wticks;
-       /* struct uba_minfo sc_minfo; */
-} up_softc[NSC21];
+       int     sc_recal;
+} up_softc[NSC];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
 struct size
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
 struct size
@@ -65,13 +72,14 @@ struct      size
 int    upSDIST = _upSDIST;
 int    upRDIST = _upRDIST;
 
 int    upSDIST = _upSDIST;
 int    upRDIST = _upRDIST;
 
-int    upcntrlr(), upslave(), updgo(), upintr();
-struct uba_minfo *upminfo[NSC21];
+int    upprobe(), upslave(), upattach(), updgo(), upintr();
+struct uba_minfo *upminfo[NSC];
 struct uba_dinfo *updinfo[NUP];
 struct uba_dinfo *updinfo[NUP];
+struct uba_dinfo *upip[NSC][4];
 
 
-u_short        upstd[] = { 0776700, 0774400, 0776300 };
-struct uba_driver updriver =
-       { upcntrlr, upslave, updgo, 0, upstd, "up", updinfo, "sc", upminfo };
+u_short        upstd[] = { 0776700, 0774400, 0776300, 0 };
+struct uba_driver scdriver =
+    { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
 struct buf     uputab[NUP];
 
 struct upst {
 struct buf     uputab[NUP];
 
 struct upst {
@@ -81,20 +89,17 @@ struct      upst {
        short   ncyl;
        struct  size *sizes;
 } upst[] = {
        short   ncyl;
        struct  size *sizes;
 } upst[] = {
-       32,     19,     32*19,  815,    up_sizes,       /* 9300 */
-       32,     19,     32*19,  823,    up_sizes,       /* so cdc will boot */
+       32,     19,     32*19,  823,    up_sizes,       /* 9300/cdc */
+/* 9300 actually has 815 cylinders... */
        32,     10,     32*10,  823,    fj_sizes,       /* fujitsu 160m */
 };
 
        32,     10,     32*10,  823,    fj_sizes,       /* fujitsu 160m */
 };
 
-int    up_offset[16] =
-{
-       P400, M400, P400, M400,
-       P800, M800, P800, M800,
-       P1200, M1200, P1200, M1200,
-       0, 0, 0, 0,
+u_char up_offset[16] = {
+    UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 
+    UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0
 };
 
 };
 
-struct buf     rupbuf;                 /* GROT */
+struct buf     rupbuf[NUP];
 
 #define        b_cylin b_resid
 
 
 #define        b_cylin b_resid
 
@@ -104,37 +109,62 @@ daddr_t dkblock();
 
 int    upwstart, upwatch();            /* Have started guardian */
 int    upseek;
 
 int    upwstart, upwatch();            /* Have started guardian */
 int    upseek;
+int    upwaitdry;
 
 /*ARGSUSED*/
 
 /*ARGSUSED*/
-upcntrlr(um, reg)
-       struct uba_minfo *um;
+upprobe(reg)
        caddr_t reg;
 {
        register int br, cvec;
 
        caddr_t reg;
 {
        register int br, cvec;
 
-       ((struct device *)reg)->upcs1 |= (IE|RDY);
+#ifdef lint    
+       br = 0; cvec = br; br = cvec;
+#endif
+       ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
+       DELAY(10);
+       ((struct updevice *)reg)->upcs1 = 0;
        return (1);
 }
 
        return (1);
 }
 
-upslave(ui, reg, slaveno)
+upslave(ui, reg)
        struct uba_dinfo *ui;
        caddr_t reg;
 {
        struct uba_dinfo *ui;
        caddr_t reg;
 {
-       register struct device *upaddr = (struct device *)reg;
+       register struct updevice *upaddr = (struct updevice *)reg;
 
        upaddr->upcs1 = 0;              /* conservative */
 
        upaddr->upcs1 = 0;              /* conservative */
-       upaddr->upcs2 = slaveno;
-       if (upaddr->upcs2&NED) {
-               upaddr->upcs1 = DCLR|GO;
+       upaddr->upcs2 = ui->ui_slave;
+       if (upaddr->upcs2&UP_NED) {
+               upaddr->upcs1 = UP_DCLR|UP_GO;
                return (0);
        }
                return (0);
        }
+       return (1);
+}
+
+upattach(ui)
+       register struct uba_dinfo *ui;
+{
+#ifdef notdef
+       register struct updevice *upaddr;
+#endif
+
        if (upwstart == 0) {
        if (upwstart == 0) {
-               timeout(upwatch, (caddr_t)0, HZ);
+               timeout(upwatch, (caddr_t)0, hz);
                upwstart++;
        }
        if (ui->ui_dk >= 0)
                dk_mspw[ui->ui_dk] = .0000020345;
                upwstart++;
        }
        if (ui->ui_dk >= 0)
                dk_mspw[ui->ui_dk] = .0000020345;
-       return (1);
+       upip[ui->ui_ctlr][ui->ui_slave] = ui;
+       up_softc[ui->ui_ctlr].sc_ndrive++;
+#ifdef notdef
+       upaddr = (struct updevice *)ui->ui_addr;
+       upaddr->upcs1 = 0;
+       upaddr->upcs2 = ui->ui_slave;
+       upaddr->uphr = -1;
+       /* ... */
+       if (upaddr-> ... == 10)
+               ui->ui_type = 1;
+#endif
 }
  
 upstrategy(bp)
 }
  
 upstrategy(bp)
@@ -177,48 +207,90 @@ bad:
        return;
 }
 
        return;
 }
 
+/*
+ * Unit start routine.
+ * Seek the drive to be where the data is
+ * and then generate another interrupt
+ * to actually start the transfer.
+ * If there is only one drive on the controller,
+ * or we are very close to the data, don't
+ * bother with the search.  If called after
+ * searching once, don't bother to look where
+ * we are, just queue for transfer (to avoid
+ * positioning forever without transferrring.)
+ */
 upustart(ui)
        register struct uba_dinfo *ui;
 {
        register struct buf *bp, *dp;
 upustart(ui)
        register struct uba_dinfo *ui;
 {
        register struct buf *bp, *dp;
-       register struct uba_minfo *um;
-       register struct device *upaddr;
+       register struct uba_minfo *um = ui->ui_mi;
+       register struct updevice *upaddr;
        register struct upst *st;
        daddr_t bn;
        register struct upst *st;
        daddr_t bn;
-       int sn, cn, csn;
+       int sn, csn;
+       /*
+        * The SC21 cancels commands if you just say
+        *      cs1 = UP_IE
+        * so we are cautious about handling of cs1.
+        * Also don't bother to clear as bits other than in upintr().
+        */
        int didie = 0;
 
        int didie = 0;
 
-       /* SC21 cancels commands if you say cs1 = IE, so dont */
-       /* being ultra-cautious, we clear as bits only in upintr() */
+       if (ui == 0)
+               return (0);
        dk_busy &= ~(1<<ui->ui_dk);
        dp = &uputab[ui->ui_unit];
        if ((bp = dp->b_actf) == NULL)
                goto out;
        dk_busy &= ~(1<<ui->ui_dk);
        dp = &uputab[ui->ui_unit];
        if ((bp = dp->b_actf) == NULL)
                goto out;
-       /* dont confuse controller by giving SEARCH while dt in progress */
-       um = ui->ui_mi;
+       /*
+        * If the controller is active, just remember
+        * that this device would like to be positioned...
+        * if we tried to position now we would confuse the SC21.
+        */
        if (um->um_tab.b_active) {
                up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
                return (0);
        }
        if (um->um_tab.b_active) {
                up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
                return (0);
        }
+       /*
+        * If we have already positioned this drive,
+        * then just put it on the ready queue.
+        */
        if (dp->b_active)
                goto done;
        dp->b_active = 1;
        if (dp->b_active)
                goto done;
        dp->b_active = 1;
-       upaddr = (struct device *)um->um_addr;
+       upaddr = (struct updevice *)um->um_addr;
        upaddr->upcs2 = ui->ui_slave;
        upaddr->upcs2 = ui->ui_slave;
-       if ((upaddr->upds & VV) == 0) {
-               upaddr->upcs1 = IE|DCLR|GO;
-               upaddr->upcs1 = IE|PRESET|GO;
-               upaddr->upof = FMT22;
+       /*
+        * If drive has just come up,
+        * setup the pack.
+        */
+       if ((upaddr->upds & UP_VV) == 0) {
+               /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
+               upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
+               upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
+               upaddr->upof = UP_FMT22;
                didie = 1;
        }
                didie = 1;
        }
-       if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL))
+       /*
+        * If drive is offline, forget about positioning.
+        */
+       if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL))
+               goto done;
+       /*
+        * If there is only one drive,
+        * dont bother searching.
+        */
+       if (up_softc[um->um_ctlr].sc_ndrive == 1)
                goto done;
                goto done;
+       /*
+        * Figure out where this transfer is going to
+        * and see if we are close enough to justify not searching.
+        */
        st = &upst[ui->ui_type];
        bn = dkblock(bp);
        st = &upst[ui->ui_type];
        bn = dkblock(bp);
-       cn = bp->b_cylin;
        sn = bn%st->nspc;
        sn = (sn + st->nsect - upSDIST) % st->nsect;
        sn = bn%st->nspc;
        sn = (sn + st->nsect - upSDIST) % st->nsect;
-       if (cn - upaddr->updc)
+       if (bp->b_cylin - upaddr->updc)
                goto search;            /* Not on-cylinder */
        else if (upseek)
                goto done;              /* Ok just to be on-cylinder */
                goto search;            /* Not on-cylinder */
        else if (upseek)
                goto done;              /* Ok just to be on-cylinder */
@@ -228,43 +300,62 @@ upustart(ui)
        if (csn > st->nsect - upRDIST)
                goto done;
 search:
        if (csn > st->nsect - upRDIST)
                goto done;
 search:
-       upaddr->updc = cn;
+       upaddr->updc = bp->b_cylin;
+       /*
+        * Not on cylinder at correct position,
+        * seek/search.
+        */
        if (upseek)
        if (upseek)
-               upaddr->upcs1 = IE|SEEK|GO;
+               upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
        else {
                upaddr->upda = sn;
        else {
                upaddr->upda = sn;
-               upaddr->upcs1 = IE|SEARCH|GO;
+               upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
        }
        didie = 1;
        }
        didie = 1;
+       /*
+        * Mark unit busy for iostat.
+        */
        if (ui->ui_dk >= 0) {
                dk_busy |= 1<<ui->ui_dk;
                dk_seek[ui->ui_dk]++;
        }
        goto out;
 done:
        if (ui->ui_dk >= 0) {
                dk_busy |= 1<<ui->ui_dk;
                dk_seek[ui->ui_dk]++;
        }
        goto out;
 done:
-       dp->b_forw = NULL;
-       if (um->um_tab.b_actf == NULL)
-               um->um_tab.b_actf = dp;
-       else
-               um->um_tab.b_actl->b_forw = dp;
-       um->um_tab.b_actl = dp;
+       /*
+        * Device is ready to go.
+        * Put it on the ready queue for the controller
+        * (unless its already there.)
+        */
+       if (dp->b_active != 2) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_active = 2;
+       }
 out:
        return (didie);
 }
 
 out:
        return (didie);
 }
 
+/*
+ * Start up a transfer on a drive.
+ */
 upstart(um)
        register struct uba_minfo *um;
 {
        register struct buf *bp, *dp;
        register struct uba_dinfo *ui;
 upstart(um)
        register struct uba_minfo *um;
 {
        register struct buf *bp, *dp;
        register struct uba_dinfo *ui;
-       register unit;
-       register struct device *upaddr;
+       register struct updevice *upaddr;
        struct upst *st;
        struct upst *st;
-       struct up_softc *sc = &up_softc[um->um_ctlr];
        daddr_t bn;
        daddr_t bn;
-       int dn, sn, tn, cmd;
+       int dn, sn, tn, cmd, waitdry;
 
 loop:
 
 loop:
+       /*
+        * Pull a request off the controller queue
+        */
        if ((dp = um->um_tab.b_actf) == NULL)
                return (0);
        if ((bp = dp->b_actf) == NULL) {
        if ((dp = um->um_tab.b_actf) == NULL)
                return (0);
        if ((bp = dp->b_actf) == NULL) {
@@ -272,8 +363,8 @@ loop:
                goto loop;
        }
        /*
                goto loop;
        }
        /*
-        * Mark the controller busy, and multi-part disk address.
-        * Select the unit on which the i/o is to take place.
+        * Mark controller busy, and
+        * determine destination of this request.
         */
        um->um_tab.b_active++;
        ui = updinfo[dkunit(bp)];
         */
        um->um_tab.b_active++;
        ui = updinfo[dkunit(bp)];
@@ -283,19 +374,25 @@ loop:
        sn = bn%st->nspc;
        tn = sn/st->nsect;
        sn %= st->nsect;
        sn = bn%st->nspc;
        tn = sn/st->nsect;
        sn %= st->nsect;
-       upaddr = (struct device *)ui->ui_addr;
-       if ((upaddr->upcs2 & 07) != dn)
+       upaddr = (struct updevice *)ui->ui_addr;
+       /*
+        * Select drive if not selected already.
+        */
+       if ((upaddr->upcs2&07) != dn)
                upaddr->upcs2 = dn;
        /*
                upaddr->upcs2 = dn;
        /*
-        * If drive is not present and on-line, then
-        * get rid of this with an error and loop to get
-        * rid of the rest of its queued requests.
-        * (Then on to any other ready drives.)
+        * Check that it is ready and online
         */
         */
-       if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
-               printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds);
-               if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) {
-                       printf("-- hard\n");
+       waitdry = 0;
+       while ((upaddr->upds&UP_DRY) == 0) {
+               if (++waitdry > 512)
+                       break;
+               upwaitdry++;
+       }
+       if ((upaddr->upds & UP_DREADY) != UP_DREADY) {
+               printf("up%d: not ready", dkunit(bp));
+               if ((upaddr->upds & UP_DREADY) != UP_DREADY) {
+                       printf("\n");
                        um->um_tab.b_active = 0;
                        um->um_tab.b_errcnt = 0;
                        dp->b_actf = bp->av_forw;
                        um->um_tab.b_active = 0;
                        um->um_tab.b_errcnt = 0;
                        dp->b_actf = bp->av_forw;
@@ -304,52 +401,51 @@ loop:
                        iodone(bp);
                        goto loop;
                }
                        iodone(bp);
                        goto loop;
                }
-               printf("-- came back\n");
+               /*
+                * Oh, well, sometimes this
+                * happens, for reasons unknown.
+                */
+               printf(" (flakey)\n");
        }
        /*
        }
        /*
-        * If this is a retry, then with the 16'th retry we
-        * begin to try offsetting the heads to recover the data.
+        * After 16th retry, do offset positioning
         */
        if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
         */
        if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
-               upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22;
-               upaddr->upcs1 = IE|OFFSET|GO;
-               while (upaddr->upds & PIP)
+               upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22;
+               upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
+               while (upaddr->upds & UP_PIP)
                        DELAY(25);
        }
        /*
                        DELAY(25);
        }
        /*
-        * Now set up the transfer, retrieving the high
-        * 2 bits of the UNIBUS address from the information
-        * returned by ubasetup() for the cs1 register bits 8 and 9.
+        * Setup for the transfer, and get in the
+        * UNIBUS adaptor queue.
         */
        upaddr->updc = bp->b_cylin;
        upaddr->upda = (tn << 8) + sn;
        upaddr->upwc = -bp->b_bcount / sizeof (short);
        if (bp->b_flags & B_READ)
         */
        upaddr->updc = bp->b_cylin;
        upaddr->upda = (tn << 8) + sn;
        upaddr->upwc = -bp->b_bcount / sizeof (short);
        if (bp->b_flags & B_READ)
-               cmd = IE|RCOM|GO;
+               cmd = UP_IE|UP_RCOM|UP_GO;
        else
        else
-               cmd = IE|WCOM|GO;
+               cmd = UP_IE|UP_WCOM|UP_GO;
        um->um_cmd = cmd;
        ubago(ui);
        return (1);
 }
 
        um->um_cmd = cmd;
        ubago(ui);
        return (1);
 }
 
+/*
+ * Now all ready to go, stuff the registers.
+ */
 updgo(um)
        struct uba_minfo *um;
 {
 updgo(um)
        struct uba_minfo *um;
 {
-       register struct device *upaddr = (struct device *)um->um_addr;
+       register struct updevice *upaddr = (struct updevice *)um->um_addr;
 
        upaddr->upba = um->um_ubinfo;
        upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
 /*
 
        upaddr->upba = um->um_ubinfo;
        upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
 /*
- * Handle a device interrupt.
- *
- * If the transferring drive needs attention, service it
- * retrying on error or beginning next transfer.
- * Service all other ready drives, calling ustart to transfer
- * their blocks to the ready queue in um->um_tab, and then restart
- * the controller if there is anything to do.
+ * Handle a disk interrupt.
  */
 upintr(sc21)
        register sc21;
  */
 upintr(sc21)
        register sc21;
@@ -357,106 +453,177 @@ upintr(sc21)
        register struct buf *bp, *dp;
        register struct uba_minfo *um = upminfo[sc21];
        register struct uba_dinfo *ui;
        register struct buf *bp, *dp;
        register struct uba_minfo *um = upminfo[sc21];
        register struct uba_dinfo *ui;
-       register struct device *upaddr = (struct device *)um->um_addr;
+       register struct updevice *upaddr = (struct updevice *)um->um_addr;
        register unit;
        struct up_softc *sc = &up_softc[um->um_ctlr];
        register unit;
        struct up_softc *sc = &up_softc[um->um_ctlr];
-       int as = upaddr->upas & 0377;
-       int needie = 1;
+       int as = (upaddr->upas & 0377) | sc->sc_softas;
+       int needie = 1, waitdry;
 
        sc->sc_wticks = 0;
 
        sc->sc_wticks = 0;
-       if (um->um_tab.b_active) {
-               if ((upaddr->upcs1 & RDY) == 0)
-                       printf("upintr !RDY\n");
-               dp = um->um_tab.b_actf;
-               bp = dp->b_actf;
-               ui = updinfo[dkunit(bp)];
-               dk_busy &= ~(1 << ui->ui_dk);
+       sc->sc_softas = 0;
+       /*
+        * If controller wasn't transferring, then this is an
+        * interrupt for attention status on seeking drives.
+        * Just service them.
+        */
+       if (um->um_tab.b_active == 0) {
+               if (upaddr->upcs1 & UP_TRE)
+                       upaddr->upcs1 = UP_TRE;
+               goto doattn;
+       }
+       /*
+        * Get device and block structures, and a pointer
+        * to the uba_dinfo for the drive.  Select the drive.
+        */
+       dp = um->um_tab.b_actf;
+       bp = dp->b_actf;
+       ui = updinfo[dkunit(bp)];
+       dk_busy &= ~(1 << ui->ui_dk);
+       if ((upaddr->upcs2&07) != ui->ui_slave)
                upaddr->upcs2 = ui->ui_slave;
                upaddr->upcs2 = ui->ui_slave;
-               if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) {
-                       int cs2;
-                       while ((upaddr->upds & DRY) == 0)
+       /*
+        * Check for and process errors on
+        * either the drive or the controller.
+        */
+       if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) {
+               waitdry = 0;
+               while ((upaddr->upds & UP_DRY) == 0) {
+                       if (++waitdry > 512)
+                               break;
+                       upwaitdry++;
+               }
+               if (upaddr->uper1&UP_WLE) {
+                       /*
+                        * Give up on write locked devices
+                        * immediately.
+                        */
+                       printf("up%d: write locked\n", dkunit(bp));
+                       bp->b_flags |= B_ERROR;
+               } else if (++um->um_tab.b_errcnt > 27) {
+                       /*
+                        * After 28 retries (16 without offset, and
+                        * 12 with offset positioning) give up.
+                        */
+                       harderr(bp, "up");
+                       printf("cs2=%b er1=%b er2=%b\n",
+                           upaddr->upcs2, UPCS2_BITS,
+                           upaddr->uper1, UPER1_BITS,
+                           upaddr->uper2, UPER2_BITS);
+                       bp->b_flags |= B_ERROR;
+               } else {
+                       /*
+                        * Retriable error.
+                        * If a soft ecc, correct it (continuing
+                        * by returning if necessary.
+                        * Otherwise fall through and retry the transfer
+                        */
+                       um->um_tab.b_active = 0;         /* force retry */
+                       if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK)
+                               if (upecc(ui))
+                                       return;
+               }
+               /*
+                * Clear drive error and, every eight attempts,
+                * (starting with the fourth)
+                * recalibrate to clear the slate.
+                */
+               upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
+               needie = 0;
+               if ((um->um_tab.b_errcnt&07) == 4) {
+                       upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
+                       um->um_tab.b_active = 1;
+                       sc->sc_recal = 1;
+                       return;
+               }
+       }
+       /*
+        * Done retrying transfer... release
+        * resources... if we were recalibrating,
+        * then retry the transfer.
+        * Mathematical note: 28%8 != 4.
+        */
+       ubadone(um);
+       if (sc->sc_recal) {
+               sc->sc_recal = 0;
+               um->um_tab.b_active = 0;        /* force retry */
+       }
+       /*
+        * If still ``active'', then don't need any more retries.
+        */
+       if (um->um_tab.b_active) {
+               /*
+                * If we were offset positioning,
+                * return to centerline.
+                */
+               if (um->um_tab.b_errcnt >= 16) {
+                       upaddr->upof = UP_FMT22;
+                       upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
+                       while (upaddr->upds & UP_PIP)
                                DELAY(25);
                                DELAY(25);
-                       if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE)
-                               bp->b_flags |= B_ERROR;
-                       else
-                               um->um_tab.b_active = 0; /* force retry */
-                       if (um->um_tab.b_errcnt > 27) {
-                               cs2 = (int)upaddr->upcs2;
-                               deverror(bp, cs2, (int)upaddr->uper1);
-                       }
-                       if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui))
-                               return;
-                       upaddr->upcs1 = TRE|IE|DCLR|GO;
                        needie = 0;
                        needie = 0;
-                       if ((um->um_tab.b_errcnt&07) == 4) {
-                               upaddr->upcs1 = RECAL|GO|IE;
-                               while(upaddr->upds & PIP)
-                                       DELAY(25);
-                       }
-                       if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) {
-                               printf("FLAKEY UP ");
-                               ubareset(um->um_ubanum);
-                               return;
-                       }
                }
                }
-               ubarelse(ui->ui_ubanum, &um->um_ubinfo);
-               if (um->um_tab.b_active) {
-                       if (um->um_tab.b_errcnt >= 16) {
-                               upaddr->upcs1 = RTC|GO|IE;
-                               while (upaddr->upds & PIP)
-                                       DELAY(25);
+               um->um_tab.b_active = 0;
+               um->um_tab.b_errcnt = 0;
+               um->um_tab.b_actf = dp->b_forw;
+               dp->b_active = 0;
+               dp->b_errcnt = 0;
+               dp->b_actf = bp->av_forw;
+               bp->b_resid = (-upaddr->upwc * sizeof(short));
+               iodone(bp);
+               /*
+                * If this unit has more work to do,
+                * then start it up right away.
+                */
+               if (dp->b_actf)
+                       if (upustart(ui))
                                needie = 0;
                                needie = 0;
-                       }
-                       um->um_tab.b_active = 0;
-                       um->um_tab.b_errcnt = 0;
-                       um->um_tab.b_actf = dp->b_forw;
-                       dp->b_active = 0;
-                       dp->b_errcnt = 0;
-                       dp->b_actf = bp->av_forw;
-                       bp->b_resid = (-upaddr->upwc * sizeof(short));
-                       /* CHECK FOR WRITE LOCK HERE... */
-                       if (bp->b_resid)
-                               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)
-                               if (upustart(ui))
-                                       needie = 0;
-               }
-               sc->sc_softas &= ~(1<<ui->ui_slave);
-       } else {
-               if (upaddr->upcs1 & TRE)
-                       upaddr->upcs1 = TRE;
        }
        }
-       as |= sc->sc_softas;
-       sc->sc_softas = 0;
-       for (unit = 0; unit < NUP; unit++) {
-               if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um)
-                       continue;
-               if (as & (1<<unit)) {
+       as &= ~(1<<ui->ui_slave);
+doattn:
+       /*
+        * Process other units which need attention.
+        * For each unit which needs attention, call
+        * the unit start routine to place the slave
+        * on the controller device queue.
+        */
+       for (unit = 0; as; as >>= 1, unit++)
+               if (as & 1) {
                        upaddr->upas = 1<<unit;
                        upaddr->upas = 1<<unit;
-                       if (upustart(ui))
+                       if (upustart(upip[sc21][unit]))
                                needie = 0;
                }
                                needie = 0;
                }
-       }
+       /*
+        * If the controller is not transferring, but
+        * there are devices ready to transfer, start
+        * the controller.
+        */
        if (um->um_tab.b_actf && um->um_tab.b_active == 0)
                if (upstart(um))
                        needie = 0;
        if (needie)
        if (um->um_tab.b_actf && um->um_tab.b_active == 0)
                if (upstart(um))
                        needie = 0;
        if (needie)
-               upaddr->upcs1 = IE;
+               upaddr->upcs1 = UP_IE;
 }
 
 upread(dev)
 }
 
 upread(dev)
+       dev_t dev;
 {
 {
+       register int unit = minor(dev) >> 3;
 
 
-       physio(upstrategy, &rupbuf, dev, B_READ, minphys);
+       if (unit >= NUP)
+               u.u_error = ENXIO;
+       else
+               physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys);
 }
 
 upwrite(dev)
 }
 
 upwrite(dev)
+       dev_t dev;
 {
 {
+       register int unit = minor(dev) >> 3;
 
 
-       physio(upstrategy, &rupbuf, dev, B_WRITE, minphys);
+       if (unit >= NUP)
+               u.u_error = ENXIO;
+       else
+               physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys);
 }
 
 /*
 }
 
 /*
@@ -468,11 +635,10 @@ upwrite(dev)
 upecc(ui)
        register struct uba_dinfo *ui;
 {
 upecc(ui)
        register struct uba_dinfo *ui;
 {
-       register struct device *up = (struct device *)ui->ui_addr;
+       register struct updevice *up = (struct updevice *)ui->ui_addr;
        register struct buf *bp = uputab[ui->ui_unit].b_actf;
        register struct uba_minfo *um = ui->ui_mi;
        register struct upst *st;
        register struct buf *bp = uputab[ui->ui_unit].b_actf;
        register struct uba_minfo *um = ui->ui_mi;
        register struct upst *st;
-       struct up_softc *sc = &up_softc[um->um_ctlr];
        struct uba_regs *ubp = ui->ui_hd->uh_uba;
        register int i;
        caddr_t addr;
        struct uba_regs *ubp = ui->ui_hd->uh_uba;
        register int i;
        caddr_t addr;
@@ -488,20 +654,16 @@ upecc(ui)
        npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
        reg = btop(um->um_ubinfo&0x3ffff) + npf;
        o = (int)bp->b_un.b_addr & PGOFSET;
        npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
        reg = btop(um->um_ubinfo&0x3ffff) + npf;
        o = (int)bp->b_un.b_addr & PGOFSET;
-       printf("%D ", bp->b_blkno+npf);
-       prdev("ECC", bp->b_dev);
+       printf("up%d%c: soft ecc bn%d\n", dkunit(bp),
+           'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
        mask = up->upec2;
        mask = up->upec2;
-       if (mask == 0) {
-               up->upof = FMT22;               /* == RTC ???? */
-               return (0);
-       }
        /*
         * Flush the buffered data path, and compute the
         * byte and bit position of the error.  The variable i
         * is the byte offset in the transfer, the variable byte
         * is the offset from a page boundary in main memory.
         */
        /*
         * Flush the buffered data path, and compute the
         * byte and bit position of the error.  The variable i
         * is the byte offset in the transfer, the variable byte
         * is the offset from a page boundary in main memory.
         */
-       ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE;
+       ubapurge(um);
        i = up->upec1 - 1;              /* -1 makes 0 origin */
        bit = i&07;
        i = (i&~07)>>3;
        i = up->upec1 - 1;              /* -1 makes 0 origin */
        bit = i&07;
        i = (i&~07)>>3;
@@ -529,7 +691,11 @@ upecc(ui)
         * We have completed npf+1 sectors of the transfer already;
         * restart at offset o of next sector (i.e. in UBA register reg+1).
         */
         * We have completed npf+1 sectors of the transfer already;
         * restart at offset o of next sector (i.e. in UBA register reg+1).
         */
-       up->upcs1 = TRE|IE|DCLR|GO;
+#ifdef notdef
+       up->uper1 = 0;
+       up->upcs1 |= UP_GO;
+#else
+       up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
        bn = dkblock(bp);
        st = &upst[ui->ui_type];
        cn = bp->b_cylin;
        bn = dkblock(bp);
        st = &upst[ui->ui_type];
        cn = bp->b_cylin;
@@ -543,8 +709,9 @@ upecc(ui)
        ubaddr = (int)ptob(reg+1) + o;
        up->upba = ubaddr;
        cmd = (ubaddr >> 8) & 0x300;
        ubaddr = (int)ptob(reg+1) + o;
        up->upba = ubaddr;
        cmd = (ubaddr >> 8) & 0x300;
-       cmd |= IE|GO|RCOM;
+       cmd |= UP_IE|UP_GO|UP_RCOM;
        up->upcs1 = cmd;
        up->upcs1 = cmd;
+#endif
        return (1);
 }
 
        return (1);
 }
 
@@ -554,34 +721,29 @@ upecc(ui)
  * and restart all units and the controller.
  */
 upreset(uban)
  * and restart all units and the controller.
  */
 upreset(uban)
+       int uban;
 {
        register struct uba_minfo *um;
        register struct uba_dinfo *ui;
        register sc21, unit;
 {
        register struct uba_minfo *um;
        register struct uba_dinfo *ui;
        register sc21, unit;
-       struct up_softc *sc;
-       int any = 0;
 
 
-       for (sc21 = 0; sc21 < NSC21; sc21++) {
+       for (sc21 = 0; sc21 < NSC; sc21++) {
                if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
                    um->um_alive == 0)
                        continue;
                if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban ||
                    um->um_alive == 0)
                        continue;
-               sc = &up_softc[um->um_ctlr];
-               if (any == 0) {
-                       printf(" up");
-                       DELAY(10000000);        /* give it time to self-test */
-                       any++;
-               }
+               printf(" sc%d", sc21);
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
+               up_softc[sc21].sc_recal = 0;
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
-                       ubarelse(um->um_ubanum, &um->um_ubinfo);
+                       ubadone(um);
                }
                }
-               ((struct device *)(um->um_addr))->upcs2 = CLR;
+               ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR;
                for (unit = 0; unit < NUP; unit++) {
                        if ((ui = updinfo[unit]) == 0)
                                continue;
                for (unit = 0; unit < NUP; unit++) {
                        if ((ui = updinfo[unit]) == 0)
                                continue;
-                       if (ui->ui_alive == 0)
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
                                continue;
                        uputab[unit].b_active = 0;
                        (void) upustart(ui);
                                continue;
                        uputab[unit].b_active = 0;
                        (void) upustart(ui);
@@ -593,7 +755,7 @@ upreset(uban)
 /*
  * Wake up every second and if an interrupt is pending
  * but nothing has happened increment a counter.
 /*
  * Wake up every second and if an interrupt is pending
  * but nothing has happened increment a counter.
- * If nothing happens for 20 seconds, reset the controller
+ * If nothing happens for 20 seconds, reset the UNIBUS
  * and begin anew.
  */
 upwatch()
  * and begin anew.
  */
 upwatch()
@@ -602,28 +764,26 @@ upwatch()
        register sc21, unit;
        register struct up_softc *sc;
 
        register sc21, unit;
        register struct up_softc *sc;
 
-       timeout(upwatch, (caddr_t)0, HZ);
-       for (sc21 = 0; sc21 < NSC21; sc21++) {
+       timeout(upwatch, (caddr_t)0, hz);
+       for (sc21 = 0; sc21 < NSC; sc21++) {
                um = upminfo[sc21];
                if (um == 0 || um->um_alive == 0)
                        continue;
                sc = &up_softc[sc21];
                if (um->um_tab.b_active == 0) {
                        for (unit = 0; unit < NUP; unit++)
                um = upminfo[sc21];
                if (um == 0 || um->um_alive == 0)
                        continue;
                sc = &up_softc[sc21];
                if (um->um_tab.b_active == 0) {
                        for (unit = 0; unit < NUP; unit++)
-                               if (updinfo[unit]->ui_mi == um &&
-                                   uputab[unit].b_active)
+                               if (uputab[unit].b_active &&
+                                   updinfo[unit]->ui_mi == um)
                                        goto active;
                        sc->sc_wticks = 0;
                        continue;
                }
                                        goto active;
                        sc->sc_wticks = 0;
                        continue;
                }
-    active:
+active:
                sc->sc_wticks++;
                if (sc->sc_wticks >= 20) {
                        sc->sc_wticks = 0;
                sc->sc_wticks++;
                if (sc->sc_wticks >= 20) {
                        sc->sc_wticks = 0;
-                       printf("LOST INTERRUPT RESET");
-                       /* SHOULD JUST RESET ONE CTLR, NOT ALL ON UBA */
-                       upreset(um->um_ubanum);
-                       printf("\n");
+                       printf("sc%d: lost interrupt\n", sc21);
+                       ubareset(um->um_ubanum);
                }
        }
 }
                }
        }
 }
@@ -633,9 +793,9 @@ upwatch()
 updump(dev)
        dev_t dev;
 {
 updump(dev)
        dev_t dev;
 {
-       struct device *upaddr;
+       struct updevice *upaddr;
        char *start;
        char *start;
-       int num, blk, unit, nsect, ntrak, nspc;
+       int num, blk, unit, i;
        struct size *sizes;
        register struct uba_regs *uba;
        register struct uba_dinfo *ui;
        struct size *sizes;
        register struct uba_regs *uba;
        register struct uba_dinfo *ui;
@@ -643,46 +803,34 @@ updump(dev)
        struct upst *st;
 
        unit = minor(dev) >> 3;
        struct upst *st;
 
        unit = minor(dev) >> 3;
-       if (unit >= NUP) {
-               printf("bad unit\n");
-               return (-1);
-       }
+       if (unit >= NUP)
+               return (ENXIO);
 #define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
        ui = phys(struct uba_dinfo *, updinfo[unit]);
 #define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
        ui = phys(struct uba_dinfo *, updinfo[unit]);
-       if (ui->ui_alive == 0) {
-               printf("dna\n");
-               return(-1);
-       }
+       if (ui->ui_alive == 0)
+               return (ENXIO);
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
 #if VAX780
        if (cpu == VAX_780)
                ubainit(uba);
 #endif
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
 #if VAX780
        if (cpu == VAX_780)
                ubainit(uba);
 #endif
-       DELAY(1000000);
-       upaddr = (struct device *)ui->ui_physaddr;
-       while ((upaddr->upcs1&DVA) == 0)
-               ;
+       upaddr = (struct updevice *)ui->ui_physaddr;
+       if ((upaddr->upcs1&UP_DVA) == 0)
+               return (EFAULT);
        num = maxfree;
        start = 0;
        upaddr->upcs2 = unit;
        num = maxfree;
        start = 0;
        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);
+       if ((upaddr->upds & UP_VV) == 0) {
+               upaddr->upcs1 = UP_DCLR|UP_GO;
+               upaddr->upcs1 = UP_PRESET|UP_GO;
+               upaddr->upof = UP_FMT22;
        }
        }
+       if ((upaddr->upds & UP_DREADY) != UP_DREADY)
+               return (EFAULT);
        st = &upst[ui->ui_type];
        st = &upst[ui->ui_type];
-       nsect = st->nsect;
-       ntrak = st->ntrak;
        sizes = phys(struct size *, st->sizes);
        sizes = phys(struct size *, st->sizes);
-       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) {
-               printf("oor\n");
-               return (-1);
-       }
-       nspc = st->nspc;
+       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
+               return (EINVAL);
        while (num > 0) {
                register struct pte *io;
                register int i;
        while (num > 0) {
                register struct pte *io;
                register int i;
@@ -695,24 +843,21 @@ updump(dev)
                        *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV;
                *(int *)io = 0;
                bn = dumplo + btop(start);
                        *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_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;
+               cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
                upaddr->updc = cn;
                rp = (short *) &upaddr->upda;
                *rp = (tn << 8) + sn;
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
                upaddr->updc = cn;
                rp = (short *) &upaddr->upda;
                *rp = (tn << 8) + sn;
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
-               *--rp = GO|WCOM;
+               *--rp = UP_GO|UP_WCOM;
                do {
                        DELAY(25);
                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);
-               }
+               } while ((upaddr->upcs1 & UP_RDY) == 0);
+               if (upaddr->upcs1&UP_ERR)
+                       return (EIO);
                start += blk*NBPG;
                num -= blk;
        }
                start += blk*NBPG;
                num -= blk;
        }