cleanup, time is a struct timeval you know
[unix-history] / usr / src / sys / vax / uba / up.c
index 3af2b36..7d544e8 100644 (file)
@@ -1,36 +1,37 @@
-/*     up.c    4.32    81/03/09        */
+/*     up.c    4.74    83/05/27        */
 
 #include "up.h"
 #if NSC > 0
 /*
 
 #include "up.h"
 #if NSC > 0
 /*
- * UNIBUS disk driver with overlapped seeks and ECC recovery.
+ * UNIBUS disk driver with:
+ *     overlapped seeks,
+ *     ECC recovery, and
+ *     bad sector forwarding.
  *
  * TODO:
  *
  * TODO:
- *     Add reading of bad sector information and disk layout from sector 1
- *     Add bad sector forwarding code
- *     Check multiple drive handling
- *     Check unibus reset code
- *     Check that offset recovery code, etc works
+ *     Check that offset recovery code works
  */
  */
+#include "../machine/pte.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
-#include "../h/cpu.h"
-#include "../h/nexus.h"
 #include "../h/dk.h"
 #include "../h/dk.h"
+#include "../h/dkbad.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/map.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/map.h"
-#include "../h/pte.h"
-#include "../h/mtpr.h"
 #include "../h/vm.h"
 #include "../h/vm.h"
-#include "../h/ubavar.h"
-#include "../h/ubareg.h"
 #include "../h/cmap.h"
 #include "../h/cmap.h"
-
-#include "../h/upreg.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+#include "../h/dkbad.h"
+#include "../vax/cpu.h"
+#include "../vax/nexus.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/upreg.h"
 
 struct up_softc {
        int     sc_softas;
 
 struct up_softc {
        int     sc_softas;
@@ -40,32 +41,57 @@ struct      up_softc {
 } up_softc[NSC];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
 } up_softc[NSC];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
-struct size
-{
+struct size {
        daddr_t nblocks;
        int     cyloff;
        daddr_t nblocks;
        int     cyloff;
-} up_sizes[8] = {
+} up9300_sizes[8] = {
+#ifdef ERNIE
+       49324,  0,              /* A=cyl 0 thru 26 */
+#else
        15884,  0,              /* A=cyl 0 thru 26 */
        15884,  0,              /* A=cyl 0 thru 26 */
+#endif
        33440,  27,             /* B=cyl 27 thru 81 */
        495520, 0,              /* C=cyl 0 thru 814 */
        15884,  562,            /* D=cyl 562 thru 588 */
        55936,  589,            /* E=cyl 589 thru 680 */
        33440,  27,             /* B=cyl 27 thru 81 */
        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 */
+       81376,  681,            /* F=cyl 681 thru 814 */
+       153728, 562,            /* G=cyl 562 thru 814 */
+       291346, 82,             /* H=cyl 82 thru 561 */
+}, up9766_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 26 */
+       33440,  27,             /* B=cyl 27 thru 81 */
+       500384, 0,              /* C=cyl 0 thru 822 */
+       15884,  562,            /* D=cyl 562 thru 588 */
+       55936,  589,            /* E=cyl 589 thru 680 */
+       86240,  681,            /* F=cyl 681 thru 822 */
+       158592, 562,            /* G=cyl 562 thru 822 */
        291346, 82,             /* H=cyl 82 thru 561 */
        291346, 82,             /* H=cyl 82 thru 561 */
-}, fj_sizes[8] = {
+}, up160_sizes[8] = {
        15884,  0,              /* A=cyl 0 thru 49 */
        33440,  50,             /* B=cyl 50 thru 154 */
        263360, 0,              /* C=cyl 0 thru 822 */
        15884,  0,              /* A=cyl 0 thru 49 */
        33440,  50,             /* B=cyl 50 thru 154 */
        263360, 0,              /* C=cyl 0 thru 822 */
+       15884,  155,            /* D=cyl 155 thru 204 */
+       55936,  205,            /* E=cyl 205 thru 379 */
+       141664, 380,            /* F=cyl 380 thru 822 */
+       213664, 155,            /* G=cyl 155 thru 822 */
        0,      0,
        0,      0,
-       0,      0,
-       0,      0,
-       0,      0,
-       213760, 155,            /* H=cyl 155 thru 822 */
+}, upam_sizes[8] = {
+       15884,  0,              /* A=cyl 0 thru 31 */
+       33440,  32,             /* B=cyl 32 thru 97 */
+       524288, 0,              /* C=cyl 0 thru 1023 */
+       15884,  668,            /* D=cyl 668 thru 699 */
+       55936,  700,            /* E=cyl 700 thru 809 */
+       109472, 810,            /* F=cyl 810 thru 1023 */
+       182176, 668,            /* G=cyl 668 thru 1023 */
+       291346, 98,             /* H=cyl 98 thru 667 */
 };
 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
 
 };
 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
 
-#define        _upSDIST        2               /* 1.0 msec */
+/*
+ * On a 780 upSDIST could be 2, but
+ * in the interest of 750's...
+ */
+#define        _upSDIST        3               /* 1.5 msec */
 #define        _upRDIST        4               /* 2.0 msec */
 
 int    upSDIST = _upSDIST;
 #define        _upRDIST        4               /* 2.0 msec */
 
 int    upSDIST = _upSDIST;
@@ -74,12 +100,15 @@ int        upRDIST = _upRDIST;
 int    upprobe(), upslave(), upattach(), updgo(), upintr();
 struct uba_ctlr *upminfo[NSC];
 struct uba_device *updinfo[NUP];
 int    upprobe(), upslave(), upattach(), updgo(), upintr();
 struct uba_ctlr *upminfo[NSC];
 struct uba_device *updinfo[NUP];
-struct uba_device *upip[NSC][4];
+#define        UPIPUNITS       8
+struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */
 
 u_short        upstd[] = { 0776700, 0774400, 0776300, 0 };
 struct uba_driver scdriver =
     { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
 struct buf     uputab[NUP];
 
 u_short        upstd[] = { 0776700, 0774400, 0776300, 0 };
 struct uba_driver scdriver =
     { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo };
 struct buf     uputab[NUP];
+char upinit[NUP];
+char upinit[NUP];
 
 struct upst {
        short   nsect;
 
 struct upst {
        short   nsect;
@@ -88,17 +117,27 @@ struct     upst {
        short   ncyl;
        struct  size *sizes;
 } upst[] = {
        short   ncyl;
        struct  size *sizes;
 } upst[] = {
-       32,     19,     32*19,  823,    up_sizes,       /* 9300/cdc */
-/* 9300 actually has 815 cylinders... */
-       32,     10,     32*10,  823,    fj_sizes,       /* fujitsu 160m */
+       32,     19,     32*19,  815,    up9300_sizes,   /* 9300 */
+       32,     19,     32*19,  823,    up9766_sizes,   /* 9766 */
+       32,     10,     32*10,  823,    up160_sizes,    /* fujitsu 160m */
+       32,     16,     32*16,  1024,   upam_sizes,     /* ampex capricorn */
+       0,      0,      0,      0,      0
 };
 
 u_char up_offset[16] = {
 };
 
 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
+       UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400,
+       UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 
+       UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200,
+       0, 0, 0, 0
 };
 
 struct buf     rupbuf[NUP];
 };
 
 struct buf     rupbuf[NUP];
+struct         buf     bupbuf[NUP];
+struct dkbad   upbad[NUP];
+#ifndef NOBADSECT
+struct         buf     bupbuf[NUP];
+struct dkbad   upbad[NUP];
+#endif
 
 #define        b_cylin b_resid
 
 
 #define        b_cylin b_resid
 
@@ -117,12 +156,12 @@ upprobe(reg)
        register int br, cvec;
 
 #ifdef lint    
        register int br, cvec;
 
 #ifdef lint    
-       br = 0; cvec = br; br = cvec;
+       br = 0; cvec = br; br = cvec; upintr(0);
 #endif
        ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
        DELAY(10);
        ((struct updevice *)reg)->upcs1 = 0;
 #endif
        ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY;
        DELAY(10);
        ((struct updevice *)reg)->upcs1 = 0;
-       return (1);
+       return (sizeof (struct updevice));
 }
 
 upslave(ui, reg)
 }
 
 upslave(ui, reg)
@@ -133,7 +172,9 @@ upslave(ui, reg)
 
        upaddr->upcs1 = 0;              /* conservative */
        upaddr->upcs2 = ui->ui_slave;
 
        upaddr->upcs1 = 0;              /* conservative */
        upaddr->upcs2 = ui->ui_slave;
-       if (upaddr->upcs2&UP_NED) {
+       upaddr->upcs1 = UP_NOP|UP_GO;
+       upaddr->upcs1 = UP_NOP|UP_GO;
+       if (upaddr->upcs2&UPCS2_NED) {
                upaddr->upcs1 = UP_DCLR|UP_GO;
                return (0);
        }
                upaddr->upcs1 = UP_DCLR|UP_GO;
                return (0);
        }
@@ -143,9 +184,6 @@ upslave(ui, reg)
 upattach(ui)
        register struct uba_device *ui;
 {
 upattach(ui)
        register struct uba_device *ui;
 {
-#ifdef notdef
-       register struct updevice *upaddr;
-#endif
 
        if (upwstart == 0) {
                timeout(upwatch, (caddr_t)0, hz);
 
        if (upwstart == 0) {
                timeout(upwatch, (caddr_t)0, hz);
@@ -155,17 +193,46 @@ upattach(ui)
                dk_mspw[ui->ui_dk] = .0000020345;
        upip[ui->ui_ctlr][ui->ui_slave] = ui;
        up_softc[ui->ui_ctlr].sc_ndrive++;
                dk_mspw[ui->ui_dk] = .0000020345;
        upip[ui->ui_ctlr][ui->ui_slave] = ui;
        up_softc[ui->ui_ctlr].sc_ndrive++;
-#ifdef notdef
-       upaddr = (struct updevice *)ui->ui_addr;
+       ui->ui_type = upmaptype(ui);
+}
+
+upmaptype(ui)
+       register struct uba_device *ui;
+{
+       register struct updevice *upaddr = (struct updevice *)ui->ui_addr;
+       int type = ui->ui_type;
+       register struct upst *st;
+
        upaddr->upcs1 = 0;
        upaddr->upcs2 = ui->ui_slave;
        upaddr->upcs1 = 0;
        upaddr->upcs2 = ui->ui_slave;
-       upaddr->uphr = -1;
-       /* ... */
-       if (upaddr-> ... == 10)
-               ui->ui_type = 1;
-#endif
+       upaddr->uphr = UPHR_MAXTRAK;
+       for (st = upst; st->nsect != 0; st++)
+               if (upaddr->uphr == st->ntrak - 1) {
+                       type = st - upst;
+                       break;
+               }
+       if (st->nsect == 0)
+               printf("up%d: uphr=%x\n", ui->ui_slave, upaddr->uphr);
+       if (type == 0) {
+               upaddr->uphr = UPHR_MAXCYL;
+               if (upaddr->uphr == 822)
+                       type++;
+       }
+       upaddr->upcs2 = UPCS2_CLR;
+       return (type);
 }
  
 }
  
+upopen(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       return (0);
+}
+
 upstrategy(bp)
        register struct buf *bp;
 {
 upstrategy(bp)
        register struct buf *bp;
 {
@@ -264,17 +331,44 @@ upustart(ui)
         * If drive has just come up,
         * setup the pack.
         */
         * If drive has just come up,
         * setup the pack.
         */
-       if ((upaddr->upds & UP_VV) == 0) {
+       if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) {
+#ifndef NOBADSECT
+               struct buf *bbp = &bupbuf[ui->ui_unit];
+#endif
                /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
                /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
+               upinit[ui->ui_unit] = 1;
+               upinit[ui->ui_unit] = 1;
                upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
                upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
                upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO;
                upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO;
-               upaddr->upof = UP_FMT22;
+               upaddr->upof = UPOF_FMT22;
                didie = 1;
                didie = 1;
+               st = &upst[ui->ui_type];
+               bbp->b_flags = B_READ|B_BUSY;
+               bbp->b_dev = bp->b_dev;
+               bbp->b_bcount = 512;
+               bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit];
+               bbp->b_blkno = st->ncyl * st->nspc - st->nsect;
+               bbp->b_cylin = st->ncyl - 1;
+               dp->b_actf = bbp;
+               bbp->av_forw = bp;
+               bp = bbp;
+#ifndef NOBADSECT
+               st = &upst[ui->ui_type];
+               bbp->b_flags = B_READ|B_BUSY;
+               bbp->b_dev = bp->b_dev;
+               bbp->b_bcount = 512;
+               bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit];
+               bbp->b_blkno = st->ncyl * st->nspc - st->nsect;
+               bbp->b_cylin = st->ncyl - 1;
+               dp->b_actf = bbp;
+               bbp->av_forw = bp;
+               bp = bbp;
+#endif
        }
        /*
         * If drive is offline, forget about positioning.
         */
        }
        /*
         * If drive is offline, forget about positioning.
         */
-       if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL))
+       if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL))
                goto done;
        /*
         * If there is only one drive,
                goto done;
        /*
         * If there is only one drive,
@@ -384,14 +478,16 @@ loop:
         * Check that it is ready and online
         */
        waitdry = 0;
         * Check that it is ready and online
         */
        waitdry = 0;
-       while ((upaddr->upds&UP_DRY) == 0) {
+       while ((upaddr->upds&UPDS_DRY) == 0) {
+               printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds);
+               printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds);
                if (++waitdry > 512)
                        break;
                upwaitdry++;
        }
                if (++waitdry > 512)
                        break;
                upwaitdry++;
        }
-       if ((upaddr->upds & UP_DREADY) != UP_DREADY) {
+       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
                printf("up%d: not ready", dkunit(bp));
                printf("up%d: not ready", dkunit(bp));
-               if ((upaddr->upds & UP_DREADY) != UP_DREADY) {
+               if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
                        printf("\n");
                        um->um_tab.b_active = 0;
                        um->um_tab.b_errcnt = 0;
                        printf("\n");
                        um->um_tab.b_active = 0;
                        um->um_tab.b_errcnt = 0;
@@ -407,15 +503,6 @@ loop:
                 */
                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);
-       }
        /*
         * Setup for the transfer, and get in the
         * UNIBUS adaptor queue.
        /*
         * Setup for the transfer, and get in the
         * UNIBUS adaptor queue.
@@ -440,6 +527,7 @@ updgo(um)
 {
        register struct updevice *upaddr = (struct updevice *)um->um_addr;
 
 {
        register struct updevice *upaddr = (struct updevice *)um->um_addr;
 
+       um->um_tab.b_active = 2;        /* should now be 2 */
        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);
 }
@@ -466,11 +554,13 @@ upintr(sc21)
         * interrupt for attention status on seeking drives.
         * Just service them.
         */
         * interrupt for attention status on seeking drives.
         * Just service them.
         */
-       if (um->um_tab.b_active == 0) {
+       if (um->um_tab.b_active != 2 && !sc->sc_recal) {
                if (upaddr->upcs1 & UP_TRE)
                        upaddr->upcs1 = UP_TRE;
                goto doattn;
        }
                if (upaddr->upcs1 & UP_TRE)
                        upaddr->upcs1 = UP_TRE;
                goto doattn;
        }
+       um->um_tab.b_active = 1;
+       um->um_tab.b_active = 1;
        /*
         * Get device and block structures, and a pointer
         * to the uba_device for the drive.  Select the drive.
        /*
         * Get device and block structures, and a pointer
         * to the uba_device for the drive.  Select the drive.
@@ -481,18 +571,28 @@ upintr(sc21)
        dk_busy &= ~(1 << ui->ui_dk);
        if ((upaddr->upcs2&07) != ui->ui_slave)
                upaddr->upcs2 = ui->ui_slave;
        dk_busy &= ~(1 << ui->ui_dk);
        if ((upaddr->upcs2&07) != ui->ui_slave)
                upaddr->upcs2 = ui->ui_slave;
+       if (bp->b_flags&B_BAD) {
+               if (upecc(ui, CONT))
+                       return;
+       }
+#ifndef NOBADSECT
+       if (bp->b_flags&B_BAD) {
+               if (upecc(ui, CONT))
+                       return;
+       }
+#endif
        /*
         * Check for and process errors on
         * either the drive or the controller.
         */
        /*
         * Check for and process errors on
         * either the drive or the controller.
         */
-       if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) {
+       if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) {
                waitdry = 0;
                waitdry = 0;
-               while ((upaddr->upds & UP_DRY) == 0) {
+               while ((upaddr->upds & UPDS_DRY) == 0) {
                        if (++waitdry > 512)
                                break;
                        upwaitdry++;
                }
                        if (++waitdry > 512)
                                break;
                        upwaitdry++;
                }
-               if (upaddr->uper1&UP_WLE) {
+               if (upaddr->uper1&UPER1_WLE) {
                        /*
                         * Give up on write locked devices
                         * immediately.
                        /*
                         * Give up on write locked devices
                         * immediately.
@@ -503,13 +603,36 @@ upintr(sc21)
                        /*
                         * After 28 retries (16 without offset, and
                         * 12 with offset positioning) give up.
                        /*
                         * After 28 retries (16 without offset, and
                         * 12 with offset positioning) give up.
+                        * If the error was header CRC, the header is 
+                        * screwed up, and the sector may in fact exist
+                        * in the bad sector table, better check...
                         */
                         */
+                       if (upaddr->uper1&UPER1_HCRC) {
+                               if (upecc(ui, BSE))
+                                       return;
+                       }
+       hard:
+       hard:
                        harderr(bp, "up");
                        harderr(bp, "up");
-                       printf("cs2=%b er1=%b er2=%b\n",
-                           upaddr->upcs2, UPCS2_BITS,
-                           upaddr->uper1, UPER1_BITS,
-                           upaddr->uper2, UPER2_BITS);
+                       printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n",
+                               upaddr->updc, ((upaddr->upda)>>8)&077,
+                               (upaddr->upda)&037,
+                               upaddr->upcs2, UPCS2_BITS,
+                               upaddr->uper1, UPER1_BITS,
+                               upaddr->uper2, UPER2_BITS);
                        bp->b_flags |= B_ERROR;
                        bp->b_flags |= B_ERROR;
+               } else if (upaddr->uper2 & UPER2_BSE) {
+                       if (upecc(ui, BSE))
+                               return;
+                       else
+                               goto hard;
+               } else if (upaddr->uper2 & UPER2_BSE) {
+#ifndef NOBADSECT
+                       if (upecc(ui, BSE))
+                               return;
+                       else
+#endif
+                               goto hard;
                } else {
                        /*
                         * Retriable error.
                } else {
                        /*
                         * Retriable error.
@@ -517,10 +640,13 @@ upintr(sc21)
                         * by returning if necessary.
                         * Otherwise fall through and retry the transfer
                         */
                         * 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))
+                       if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) {
+                               if (upecc(ui, ECC))
                                        return;
                                        return;
+                       } else
+                               um->um_tab.b_active = 0; /* force retry */
+                       } else
+                               um->um_tab.b_active = 0; /* force retry */
                }
                /*
                 * Clear drive error and, every eight attempts,
                }
                /*
                 * Clear drive error and, every eight attempts,
@@ -529,23 +655,41 @@ upintr(sc21)
                 */
                upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
                needie = 0;
                 */
                upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
                needie = 0;
-               if ((um->um_tab.b_errcnt&07) == 4) {
+               if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) {
                        upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
                        upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO;
-                       um->um_tab.b_active = 1;
-                       sc->sc_recal = 1;
-                       return;
+                       sc->sc_recal = 0;
+                       goto nextrecal;
                }
        }
        /*
                }
        }
        /*
-        * Done retrying transfer... release
-        * resources... if we were recalibrating,
-        * then retry the transfer.
-        * Mathematical note: 28%8 != 4.
+        * Advance recalibration finite state machine
+        * if recalibrate in progress, through
+        *      RECAL
+        *      SEEK
+        *      OFFSET (optional)
+        *      RETRY
         */
         */
-       ubadone(um);
-       if (sc->sc_recal) {
+       switch (sc->sc_recal) {
+
+       case 1:
+               upaddr->updc = bp->b_cylin;
+               upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO;
+               goto nextrecal;
+       case 2:
+               if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0)
+                       goto donerecal;
+               upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22;
+               upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO;
+               goto nextrecal;
+       nextrecal:
+               sc->sc_recal++;
+               um->um_tab.b_active = 1;
+               return;
+       donerecal:
+       case 3:
                sc->sc_recal = 0;
                sc->sc_recal = 0;
-               um->um_tab.b_active = 0;        /* force retry */
+               um->um_tab.b_active = 0;
+               break;
        }
        /*
         * If still ``active'', then don't need any more retries.
        }
        /*
         * If still ``active'', then don't need any more retries.
@@ -556,9 +700,9 @@ upintr(sc21)
                 * return to centerline.
                 */
                if (um->um_tab.b_errcnt >= 16) {
                 * return to centerline.
                 */
                if (um->um_tab.b_errcnt >= 16) {
-                       upaddr->upof = UP_FMT22;
+                       upaddr->upof = UPOF_FMT22;
                        upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
                        upaddr->upcs1 = UP_RTC|UP_GO|UP_IE;
-                       while (upaddr->upds & UP_PIP)
+                       while (upaddr->upds & UPDS_PIP)
                                DELAY(25);
                        needie = 0;
                }
                                DELAY(25);
                        needie = 0;
                }
@@ -579,6 +723,10 @@ upintr(sc21)
                                needie = 0;
        }
        as &= ~(1<<ui->ui_slave);
                                needie = 0;
        }
        as &= ~(1<<ui->ui_slave);
+       /*
+        * Release unibus resources and flush data paths.
+        */
+       ubadone(um);
 doattn:
        /*
         * Process other units which need attention.
 doattn:
        /*
         * Process other units which need attention.
@@ -586,12 +734,13 @@ doattn:
         * the unit start routine to place the slave
         * on the controller device queue.
         */
         * 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;
-               }
+       while (unit = ffs(as)) {
+               unit--;         /* was 1 origin */
+               as &= ~(1<<unit);
+               upaddr->upas = 1<<unit;
+               if (unit < UPIPUNITS && upustart(upip[sc21][unit]))
+                       needie = 0;
+       }
        /*
         * If the controller is not transferring, but
         * there are devices ready to transfer, start
        /*
         * If the controller is not transferring, but
         * there are devices ready to transfer, start
@@ -604,26 +753,26 @@ doattn:
                upaddr->upcs1 = UP_IE;
 }
 
                upaddr->upcs1 = UP_IE;
 }
 
-upread(dev)
+upread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NUP)
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NUP)
-               u.u_error = ENXIO;
-       else
-               physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys);
+               return (ENXIO);
+       return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio));
 }
 
 }
 
-upwrite(dev)
+upwrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NUP)
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NUP)
-               u.u_error = ENXIO;
-       else
-               physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys);
+               return (ENXIO);
+       return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio));
 }
 
 /*
 }
 
 /*
@@ -632,8 +781,10 @@ upwrite(dev)
  * the transfer may be going to an odd memory address base and/or
  * across a page boundary.
  */
  * the transfer may be going to an odd memory address base and/or
  * across a page boundary.
  */
-upecc(ui)
+upecc(ui, flag)
        register struct uba_device *ui;
        register struct uba_device *ui;
+       int flag;
+       int flag;
 {
        register struct updevice *up = (struct updevice *)ui->ui_addr;
        register struct buf *bp = uputab[ui->ui_unit].b_actf;
 {
        register struct updevice *up = (struct updevice *)ui->ui_addr;
        register struct buf *bp = uputab[ui->ui_unit].b_actf;
@@ -651,40 +802,116 @@ upecc(ui)
         * mapping (the first part of) the transfer.
         * O is offset within a memory page of the first byte transferred.
         */
         * mapping (the first part of) the transfer.
         * O is offset within a memory page of the first byte transferred.
         */
-       npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1;
+#ifndef NOBADSECT
+       if (flag == CONT)
+               npf = bp->b_error;
+       else
+#endif
+       npf = btop((up->upwc * sizeof(short)) + bp->b_bcount);
        reg = btop(um->um_ubinfo&0x3ffff) + npf;
        o = (int)bp->b_un.b_addr & PGOFSET;
        reg = btop(um->um_ubinfo&0x3ffff) + npf;
        o = (int)bp->b_un.b_addr & PGOFSET;
-       printf("up%d%c: soft ecc sn%d\n", dkunit(bp),
-           'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
        mask = up->upec2;
        mask = up->upec2;
-       /*
-        * 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.
-        */
+#ifdef UPECCDEBUG
+       printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask,
+           up->upec1);
+#endif
+       bn = dkblock(bp);
+       st = &upst[ui->ui_type];
+       cn = bp->b_cylin;
+       sn = bn%st->nspc + npf;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       cn += tn/st->ntrak;
+       tn %= st->ntrak;
        ubapurge(um);
        ubapurge(um);
-       i = up->upec1 - 1;              /* -1 makes 0 origin */
-       bit = i&07;
-       i = (i&~07)>>3;
-       byte = i + o;
+       um->um_tab.b_active=2;
        /*
        /*
-        * Correct while possible bits remain of mask.  Since mask
-        * contains 11 bits, we continue while the bit offset is > -11.
-        * Also watch out for end of this block and the end of the whole
-        * transfer.
+        * action taken depends on the flag
         */
         */
-       while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
-               addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
-                   (byte & PGOFSET);
-               putmemc(addr, getmemc(addr)^(mask<<bit));
-               byte++;
-               i++;
-               bit -= 8;
+       switch(flag){
+       case ECC:
+               npf--;
+               reg--;
+               mask = up->upec2;
+               printf("up%d%c: soft ecc sn%d\n", dkunit(bp),
+                       'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
+               /*
+                * 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.
+                */
+               i = up->upec1 - 1;              /* -1 makes 0 origin */
+               bit = i&07;
+               i = (i&~07)>>3;
+               byte = i + o;
+               /*
+                * Correct while possible bits remain of mask.  Since mask
+                * contains 11 bits, we continue while the bit offset is > -11.
+                * Also watch out for end of this block and the end of the whole
+                * transfer.
+                */
+               while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) {
+                       addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
+                               (byte & PGOFSET);
+#ifdef UPECCDEBUG
+                       printf("addr %x map reg %x\n",
+                               addr, *(int *)(&ubp->uba_map[reg+btop(byte)]));
+                       printf("old: %x, ", getmemc(addr));
+#endif
+                       putmemc(addr, getmemc(addr)^(mask<<bit));
+#ifdef UPECCDEBUG
+                       printf("new: %x\n", getmemc(addr));
+#endif
+                       byte++;
+                       i++;
+               }
+               if (up->upwc == 0)
+                       return (0);
+               npf++;
+               reg++;
+               break;
+#ifndef NOBADSECT
+       case BSE:
+               /*
+                * if not in bad sector table, return 0
+                */
+               if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0)
+                       return(0);
+               /*
+                * flag this one as bad
+                */
+               bp->b_flags |= B_BAD;
+               bp->b_error = npf + 1;
+#ifdef UPECCDEBUG
+               printf("BSE: restart at %d\n",npf+1);
+#endif
+               bn = st->ncyl * st->nspc -st->nsect - 1 - bn;
+               cn = bn / st->nspc;
+               sn = bn % st->nspc;
+               tn = sn / st->nsect;
+               sn %= st->nsect;
+               up->upwc = -(512 / sizeof (short));
+#ifdef UPECCDEBUG
+               printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
+#endif
+               break;
+       case CONT:
+#ifdef UPECCDEBUG
+               printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
+#endif
+               bp->b_flags &= ~B_BAD;
+               up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short));
+               if (up->upwc == 0)
+                       return(0);
+               break;
+#endif
        }
        }
-       um->um_tab.b_active++;  /* Either complete or continuing... */
-       if (up->upwc == 0)
+       if (up->upwc == 0) {
+               um->um_tab.b_active = 0;
                return (0);
                return (0);
+       }
+       }
        /*
         * Have to continue the transfer... clear the drive,
         * and compute the position where the transfer is to continue.
        /*
         * Have to continue the transfer... clear the drive,
         * and compute the position where the transfer is to continue.
@@ -696,20 +923,13 @@ upecc(ui)
        up->upcs1 |= UP_GO;
 #else
        up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO;
        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;
-       sn = bn%st->nspc + npf + 1;
-       tn = sn/st->nsect;
-       sn %= st->nsect;
-       cn += tn/st->ntrak;
-       tn %= st->ntrak;
        up->updc = cn;
        up->upda = (tn << 8) | sn;
        up->updc = cn;
        up->upda = (tn << 8) | sn;
-       ubaddr = (int)ptob(reg+1) + o;
+       ubaddr = (int)ptob(reg) + o;
        up->upba = ubaddr;
        cmd = (ubaddr >> 8) & 0x300;
        up->upba = ubaddr;
        cmd = (ubaddr >> 8) & 0x300;
-       cmd |= UP_IE|UP_GO|UP_RCOM;
+       cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO;
+       um->um_tab.b_errcnt = 0;
        up->upcs1 = cmd;
 #endif
        return (1);
        up->upcs1 = cmd;
 #endif
        return (1);
@@ -735,11 +955,12 @@ upreset(uban)
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
                up_softc[sc21].sc_recal = 0;
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
                up_softc[sc21].sc_recal = 0;
+               up_softc[sc21].sc_wticks = 0;
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
-                       ubadone(um);
+                       um->um_ubinfo = 0;
                }
                }
-               ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR;
+               ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_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;
@@ -801,6 +1022,8 @@ updump(dev)
        register struct uba_device *ui;
        register short *rp;
        struct upst *st;
        register struct uba_device *ui;
        register short *rp;
        struct upst *st;
+       register int retry;
+       register int retry;
 
        unit = minor(dev) >> 3;
        if (unit >= NUP)
 
        unit = minor(dev) >> 3;
        if (unit >= NUP)
@@ -812,21 +1035,24 @@ updump(dev)
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
        ubainit(uba);
        upaddr = (struct updevice *)ui->ui_physaddr;
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
        ubainit(uba);
        upaddr = (struct updevice *)ui->ui_physaddr;
-       DELAY(2000000);
+       DELAY(5000000);
        num = maxfree;
        num = maxfree;
-       start = 0;
        upaddr->upcs2 = unit;
        DELAY(100);
        upaddr->upcs2 = unit;
        DELAY(100);
-       if ((upaddr->upcs1&UP_DVA) == 0)
-               return (EFAULT);
-       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)
+       upaddr->upcs1 = UP_DCLR|UP_GO;
+       upaddr->upcs1 = UP_PRESET|UP_GO;
+       upaddr->upof = UPOF_FMT22;
+       retry = 0;
+       do {
+               DELAY(25);
+               if (++retry > 527)
+                       break;
+       } while ((upaddr->upds & UP_RDY) == 0);
+       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY)
                return (EFAULT);
                return (EFAULT);
+       start = 0;
        st = &upst[ui->ui_type];
        st = &upst[ui->ui_type];
+       start = 0;
        sizes = phys(struct size *, st->sizes);
        if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
                return (EINVAL);
        sizes = phys(struct size *, st->sizes);
        if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
                return (EINVAL);
@@ -852,14 +1078,49 @@ updump(dev)
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
                *--rp = UP_GO|UP_WCOM;
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
                *--rp = UP_GO|UP_WCOM;
+               retry = 0;
+               retry = 0;
                do {
                        DELAY(25);
                do {
                        DELAY(25);
+                       if (++retry > 527)
+                               break;
+                       if (++retry > 527)
+                               break;
                } while ((upaddr->upcs1 & UP_RDY) == 0);
                } while ((upaddr->upcs1 & UP_RDY) == 0);
-               if (upaddr->upcs1&UP_ERR)
+               if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                       printf("up%d: not ready", unit);
+                       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                               printf("\n");
+                               return (EIO);
+                       }
+                       printf(" (flakey)\n");
+               }
+               if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                       printf("up%d: not ready", unit);
+                       if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) {
+                               printf("\n");
+                               return (EIO);
+                       }
+                       printf(" (flakey)\n");
+               }
+               if (upaddr->upds&UPDS_ERR)
                        return (EIO);
                start += blk*NBPG;
                num -= blk;
        }
        return (0);
 }
                        return (EIO);
                start += blk*NBPG;
                num -= blk;
        }
        return (0);
 }
+
+upsize(dev)
+       dev_t dev;
+{
+       int unit = minor(dev) >> 3;
+       struct uba_device *ui;
+       struct upst *st;
+
+       if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       st = &upst[ui->ui_type];
+       return (st->sizes[minor(dev) & 07].nblocks);
+}
 #endif
 #endif