almost working versions
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Thu, 26 Feb 1981 13:03:44 +0000 (05:03 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Thu, 26 Feb 1981 13:03:44 +0000 (05:03 -0800)
SCCS-vsn: sys/vax/mba/hp.c 4.14
SCCS-vsn: sys/vax/mba/mba.c 4.9
SCCS-vsn: sys/vax/uba/up.c 4.22
SCCS-vsn: sys/vax/uba/tm.c 4.18
SCCS-vsn: sys/vax/uba/rk.c 4.11

usr/src/sys/vax/mba/hp.c
usr/src/sys/vax/mba/mba.c
usr/src/sys/vax/uba/rk.c
usr/src/sys/vax/uba/tm.c
usr/src/sys/vax/uba/up.c

index e69f6c7..615462f 100644 (file)
@@ -1,4 +1,4 @@
-/*     hp.c    4.13    81/02/25        */
+/*     hp.c    4.14    81/02/25        */
 
 #include "hp.h"
 #if NHP > 0
 
 #include "hp.h"
 #if NHP > 0
@@ -217,16 +217,16 @@ hpstart(mi)
        hpaddr->hpda = (tn << 8) + sn;
 }
 
        hpaddr->hpda = (tn << 8) + sn;
 }
 
-hpdtint(mi, mbastat)
+hpdtint(mi, mbasr)
        register struct mba_info *mi;
        register struct mba_info *mi;
-       int mbastat;
+       int mbasr;
 {
        register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
        register struct buf *bp = mi->mi_tab.b_actf;
 
        while ((hpaddr->hpds & HP_DRY) == 0)    /* shouldn't happen */
                printf("hp dry not set\n");
 {
        register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv;
        register struct buf *bp = mi->mi_tab.b_actf;
 
        while ((hpaddr->hpds & HP_DRY) == 0)    /* shouldn't happen */
                printf("hp dry not set\n");
-       if (hpaddr->hpds & HP_ERR || mbastat & MBAEBITS)
+       if (hpaddr->hpds & HP_ERR || mbasr & MBAEBITS)
                if (++mi->mi_tab.b_errcnt < 28 && (hpaddr->hper1&HP_WLE) == 0) {
                        if ((hpaddr->hper1&0xffff) != HP_DCK) {
                                hpaddr->hpcs1 = HP_DCLR|HP_GO;
                if (++mi->mi_tab.b_errcnt < 28 && (hpaddr->hper1&HP_WLE) == 0) {
                        if ((hpaddr->hper1&0xffff) != HP_DCK) {
                                hpaddr->hpcs1 = HP_DCLR|HP_GO;
@@ -243,7 +243,12 @@ hpdtint(mi, mbastat)
                        if (hpaddr->hper1&HP_WLE)       
                                printf("hp%d is write locked\n", dkunit(bp));
                        else
                        if (hpaddr->hper1&HP_WLE)       
                                printf("hp%d is write locked\n", dkunit(bp));
                        else
-                               deverror(bp, mbastat, hpaddr->hper1);
+               harderr(bp);
+               printf("hp%d mbasr %b er1 %b er2 %b\n",
+                                   dkunit(bp), mbasr, mbasr_bits,
+                                   hpaddr->hper1, HPER1_BITS,
+                                   hpaddr->hper2, HPER2_BITS);
+                       hpaddr->hpcs1 = HP_DCLR|HP_GO;
                        bp->b_flags |= B_ERROR;
                }
        bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff;
                        bp->b_flags |= B_ERROR;
                }
        bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff;
index 39df6ef..bc64c1d 100644 (file)
@@ -1,4 +1,4 @@
-/*     mba.c   4.8     81/02/21        */
+/*     mba.c   4.9     81/02/25        */
 
 /*
  * Massbus driver; arbitrates massbusses through device driver routines
 
 /*
  * Massbus driver; arbitrates massbusses through device driver routines
@@ -21,6 +21,7 @@ int   mbadebug = 0;
 #include "../h/mtpr.h"
 #include "../h/vm.h"
 
 #include "../h/mtpr.h"
 #include "../h/vm.h"
 
+char   mbasr_bits[] = MBASR_BITS;
 /*
  * Start activity on a massbus device.
  * We are given the device's mba_info structure and activate
 /*
  * Start activity on a massbus device.
  * We are given the device's mba_info structure and activate
index 6f8bb13..2a98e83 100644 (file)
@@ -1,4 +1,4 @@
-/*     rk.c    4.10    %G%     */
+/*     rk.c    4.11    %G%     */
 
 #include "rk.h"
 #if NHK > 0
 
 #include "rk.h"
 #if NHK > 0
@@ -327,12 +327,14 @@ hkintr(rk11)
                        if (ds & RKDS_HARD)
                                printf("rk%d is down\n", dkunit(bp));
                        if (++um->um_tab.b_errcnt > 28 ||
                        if (ds & RKDS_HARD)
                                printf("rk%d is down\n", dkunit(bp));
                        if (++um->um_tab.b_errcnt > 28 ||
-                           ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD)
+                           ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD) {
                                bp->b_flags |= B_ERROR;
                                bp->b_flags |= B_ERROR;
-                       else
+                               harderr(bp);
+                               printf("rk%d cs2 %b ds %b er %b\n",
+                                   dkunit(bp), cs2, RKCS2_BITS, ds, 
+                                   RKDS_BITS, er, RKER_BITS);
+                       } else
                                um->um_tab.b_active = 0;
                                um->um_tab.b_active = 0;
-                       if (um->um_tab.b_errcnt > 27)
-                               deverror(bp, cs2, (ds<<16)|er);
                        if (cs2&RK_MDS) {
                                rkaddr->rkcs2 = RK_SCLR;
                                goto retry;
                        if (cs2&RK_MDS) {
                                rkaddr->rkcs2 = RK_SCLR;
                                goto retry;
index 9311997..50d6592 100644 (file)
@@ -1,4 +1,4 @@
-/*     tm.c    4.17    %G%     */
+/*     tm.c    4.18    %G%     */
 
 #include "tm.h"
 #if NTM > 0
 
 #include "tm.h"
 #if NTM > 0
@@ -518,7 +518,9 @@ tmintr(tm11)
                /*
                 * Couldn't recover error
                 */
                /*
                 * Couldn't recover error
                 */
-               deverror(bp, sc->sc_erreg, sc->sc_dsreg);
+               harderr(bp);
+               printf("tm%d er %b\n", dkunit(bp),
+                   sc->sc_erreg, TMEREG_BITS);
                bp->b_flags |= B_ERROR;
                goto opdone;
        }
                bp->b_flags |= B_ERROR;
                goto opdone;
        }
index 8d4c658..e25d94e 100644 (file)
@@ -1,4 +1,4 @@
-/*     up.c    4.21    81/02/23        */
+/*     up.c    4.22    81/02/25        */
 
 #include "up.h"
 #if NSC > 0
 
 #include "up.h"
 #if NSC > 0
@@ -30,6 +30,7 @@ struct        up_softc {
        int     sc_softas;
        int     sc_ndrive;
        int     sc_wticks;
        int     sc_softas;
        int     sc_ndrive;
        int     sc_wticks;
+       int     sc_recal;
 } up_softc[NSC];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
 } up_softc[NSC];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
@@ -101,6 +102,7 @@ daddr_t dkblock();
 
 int    upwstart, upwatch();            /* Have started guardian */
 int    upseek;
 
 int    upwstart, upwatch();            /* Have started guardian */
 int    upseek;
+int    updrydel;
 
 /*ARGSUSED*/
 upprobe(reg)
 
 /*ARGSUSED*/
 upprobe(reg)
@@ -198,40 +200,63 @@ 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 uba_minfo *um = ui->ui_mi;
        register struct updevice *upaddr;
        register struct upst *st;
        daddr_t bn;
        register struct updevice *upaddr;
        register struct upst *st;
        daddr_t bn;
-       int sn, cn, csn;
-       int didie = 0;
-
-       if (ui == 0)
-               return (0);
+       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().
         */
        /*
         * 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;
+
+       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;
        upaddr = (struct updevice *)um->um_addr;
        upaddr->upcs2 = ui->ui_slave;
        if (dp->b_active)
                goto done;
        dp->b_active = 1;
        upaddr = (struct updevice *)um->um_addr;
        upaddr->upcs2 = ui->ui_slave;
+       /*
+        * 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;
        if ((upaddr->upds & UP_VV) == 0) {
                /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
                upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
@@ -239,16 +264,26 @@ upustart(ui)
                upaddr->upof = UP_FMT22;
                didie = 1;
        }
                upaddr->upof = UP_FMT22;
                didie = 1;
        }
+       /*
+        * If drive is offline, forget about positioning.
+        */
        if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL))
                goto done;
        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;
        if (up_softc[um->um_ctlr].sc_ndrive == 1)
                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 */
@@ -258,7 +293,11 @@ 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)
                upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
        else {
        if (upseek)
                upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO;
        else {
@@ -266,12 +305,20 @@ search:
                upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
        }
        didie = 1;
                upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO;
        }
        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:
+       /*
+        * 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)
        if (dp->b_active != 2) {
                dp->b_forw = NULL;
                if (um->um_tab.b_actf == NULL)
@@ -285,6 +332,9 @@ out:
        return (didie);
 }
 
        return (didie);
 }
 
+/*
+ * Start up a transfer on a drive.
+ */
 upstart(um)
        register struct uba_minfo *um;
 {
 upstart(um)
        register struct uba_minfo *um;
 {
@@ -296,12 +346,19 @@ upstart(um)
        int dn, sn, tn, cmd;
 
 loop:
        int dn, sn, tn, cmd;
 
 loop:
+       /*
+        * Pull a request off the controller queue
+        */
        if ((dp = um->um_tab.b_actf) == NULL)
                return (0);
        if ((bp = dp->b_actf) == NULL) {
                um->um_tab.b_actf = dp->b_forw;
                goto loop;
        }
        if ((dp = um->um_tab.b_actf) == NULL)
                return (0);
        if ((bp = dp->b_actf) == NULL) {
                um->um_tab.b_actf = dp->b_forw;
                goto loop;
        }
+       /*
+        * Mark controller busy, and
+        * determine destination of this request.
+        */
        um->um_tab.b_active++;
        ui = updinfo[dkunit(bp)];
        bn = dkblock(bp);
        um->um_tab.b_active++;
        ui = updinfo[dkunit(bp)];
        bn = dkblock(bp);
@@ -311,7 +368,14 @@ loop:
        tn = sn/st->nsect;
        sn %= st->nsect;
        upaddr = (struct updevice *)ui->ui_addr;
        tn = sn/st->nsect;
        sn %= st->nsect;
        upaddr = (struct updevice *)ui->ui_addr;
-       upaddr->upcs2 = dn;
+       /*
+        * Select drive if not selected already.
+        */
+       if ((upaddr->upcs2&07) != dn)
+               upaddr->upcs2 = dn;
+       /*
+        * Check that it is ready and online
+        */
        if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) {
                printf("up%d not ready", dkunit(bp));
                if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) {
        if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) {
                printf("up%d not ready", dkunit(bp));
                if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) {
@@ -324,14 +388,25 @@ loop:
                        iodone(bp);
                        goto loop;
                }
                        iodone(bp);
                        goto loop;
                }
+               /*
+                * Oh, well, sometimes this
+                * happens, for reasons unknown.
+                */
                printf(" (flakey)\n");
        }
                printf(" (flakey)\n");
        }
+       /*
+        * After 16th retry, do offset positioning
+        */
        if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
                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);
        }
        if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
                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);
        }
+       /*
+        * 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);
        upaddr->updc = bp->b_cylin;
        upaddr->upda = (tn << 8) + sn;
        upaddr->upwc = -bp->b_bcount / sizeof (short);
@@ -344,6 +419,9 @@ loop:
        return (1);
 }
 
        return (1);
 }
 
+/*
+ * Now all ready to go, stuff the registers.
+ */
 updgo(um)
        struct uba_minfo *um;
 {
 updgo(um)
        struct uba_minfo *um;
 {
@@ -353,6 +431,9 @@ updgo(um)
        upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
        upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
+/*
+ * Handle a disk interrupt.
+ */
 scintr(sc21)
        register sc21;
 {
 scintr(sc21)
        register sc21;
 {
@@ -367,75 +448,144 @@ scintr(sc21)
 
        sc->sc_wticks = 0;
        sc->sc_softas = 0;
 
        sc->sc_wticks = 0;
        sc->sc_softas = 0;
-       if (um->um_tab.b_active) {
-               if ((upaddr->upcs1 & UP_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);
+       /*
+        * 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;
+       }
+       if ((upaddr->upcs1 & UP_RDY) == 0)
+               printf("upintr !RDY\n");                /* shouldn't happen */
+       /*
+        * 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&UP_ERR) || (upaddr->upcs1&UP_TRE)) {
-                       int cs2;
-                       while ((upaddr->upds & UP_DRY) == 0)
-                               DELAY(25);
-                       if (upaddr->uper1&UP_WLE)       
-                               printf("up%d is write locked\n", dkunit(bp));
-                       if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&UP_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);
+       /*
+        * Check for and process errors on
+        * either the drive or the controller.
+        */
+       if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) {
+               while ((upaddr->upds & UP_DRY) == 0)
+                       updrydel++;
+               if (upaddr->uper1&UP_WLE) {
+                       /*
+                        * Give up on write locked devices
+                        * immediately.
+                        */
+                       printf("up%d is 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.
+                        */
+                       if (upaddr->upcs2&(UP_NEM|UP_MXF)) {
+                               printf("FLAKEY UP ");
+                               ubareset(um->um_ubanum);
+                               return;
                        }
                        }
+                       harderr(bp);
+                       printf("up%d cs2 %b er1 %b er2 %b\n",
+                           dkunit(bp), 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;
                        if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK)
                                if (upecc(ui))
                                        return;
-                       upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
+               }
+               /*
+                * 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);
                        needie = 0;
                        needie = 0;
-                       if ((um->um_tab.b_errcnt&07) == 4) {
-                               upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
-                               while(upaddr->upds & UP_PIP)
-                                       DELAY(25);
-                       }
-                       if (um->um_tab.b_errcnt == 28 && cs2&(UP_NEM|UP_MXF)) {
-                               printf("FLAKEY UP ");
-                               ubareset(um->um_ubanum);
-                               return;
-                       }
                }
                }
-               ubadone(um);
-               if (um->um_tab.b_active) {
-                       if (um->um_tab.b_errcnt >= 16) {
-                               upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
-                               while (upaddr->upds & UP_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));
-                       iodone(bp);
-                       if (dp->b_actf)
-                               if (upustart(ui))
-                                       needie = 0;
-               }
-               as &= ~(1<<ui->ui_slave);
-       } else {
-               if (upaddr->upcs1 & UP_TRE)
-                       upaddr->upcs1 = UP_TRE;
        }
        }
+       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;
                        if (upustart(upip[sc21][unit]))
                                needie = 0;
                }
        for (unit = 0; as; as >>= 1, unit++)
                if (as & 1) {
                        upaddr->upas = 1<<unit;
                        if (upustart(upip[sc21][unit]))
                                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 (um->um_tab.b_actf && um->um_tab.b_active == 0)
                if (upstart(um))
                        needie = 0;