sun merge
[unix-history] / usr / src / sys / vax / uba / rk.c
index 6f8bb13..7f17005 100644 (file)
@@ -1,29 +1,42 @@
-/*     rk.c    4.10    %G%     */
+/*     rk.c    4.51    82/12/17        */
 
 #include "rk.h"
 #if NHK > 0
 
 #include "rk.h"
 #if NHK > 0
-int    rkflags,rkerrs;         /* GROT */
+int    rkpip;          /* DEBUG */
+int    rknosval;       /* DEBUG */
+#ifdef RKDEBUG
+int    rkdebug;
+#endif
+#ifdef RKBDEBUG
+int    rkbdebug;
+#endif
 /*
 /*
- * RK11/RK07 disk driver
+ * RK611/RK0[67] disk driver
  *
  * This driver mimics up.c; see it for an explanation of common code.
  *
  * This driver mimics up.c; see it for an explanation of common code.
+ *
+ * TODO:
+ *     Learn why we lose an interrupt sometime when spinning drives down
  */
  */
-#define        DELAY(i)                { register int j; j = i; while (--j > 0); }
+#include "../machine/pte.h"
+
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/buf.h"
 #include "../h/conf.h"
 #include "../h/dir.h"
 #include "../h/user.h"
-#include "../h/pte.h"
 #include "../h/map.h"
 #include "../h/vm.h"
 #include "../h/map.h"
 #include "../h/vm.h"
-#include "../h/uba.h"
 #include "../h/dk.h"
 #include "../h/dk.h"
-#include "../h/cpu.h"
 #include "../h/cmap.h"
 #include "../h/cmap.h"
+#include "../h/dkbad.h"
+#include "../h/uio.h"
 
 
-#include "../h/rkreg.h"
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/rkreg.h"
 
 struct rk_softc {
        int     sc_softas;
 
 struct rk_softc {
        int     sc_softas;
@@ -33,11 +46,10 @@ struct      rk_softc {
 } rk_softc[NHK];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
 } rk_softc[NHK];
 
 /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
-struct size
-{
+struct size {
        daddr_t nblocks;
        int     cyloff;
        daddr_t nblocks;
        int     cyloff;
-} rk7_sizes[] ={
+} rk7_sizes[8] ={
        15884,  0,              /* A=cyl 0 thru 240 */
        10032,  241,            /* B=cyl 241 thru 392 */
        53790,  0,              /* C=cyl 0 thru 814 */
        15884,  0,              /* A=cyl 0 thru 240 */
        10032,  241,            /* B=cyl 241 thru 392 */
        53790,  0,              /* C=cyl 0 thru 814 */
@@ -46,19 +58,34 @@ struct      size
        0,      0,
        27786,  393,            /* G=cyl 393 thru 813 */
        0,      0,
        0,      0,
        27786,  393,            /* G=cyl 393 thru 813 */
        0,      0,
+}, rk6_sizes[8] ={
+       15884,  0,              /* A=cyl 0 thru 240 */
+       11154,  241,            /* B=cyl 241 thru 409 */
+       27126,  0,              /* C=cyl 0 thru 410 */
+       0,      0,
+       0,      0,
+       0,      0,
+       0,      0,
+       0,      0,
 };
 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
 
 };
 /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
 
+short  rktypes[] = { RK_CDT, 0 };
+
 int    rkprobe(), rkslave(), rkattach(), rkdgo(), rkintr();
 int    rkprobe(), rkslave(), rkattach(), rkdgo(), rkintr();
-struct uba_minfo *rkminfo[NHK];
-struct uba_dinfo *rkdinfo[NRK];
-struct uba_dinfo *rkip[NHK][4];
+struct uba_ctlr *rkminfo[NHK];
+struct uba_device *rkdinfo[NRK];
+struct uba_device *rkip[NHK][4];
 
 u_short        rkstd[] = { 0777440, 0 };
 struct uba_driver hkdriver =
  { rkprobe, rkslave, rkattach, rkdgo, rkstd, "rk", rkdinfo, "hk", rkminfo, 1 };
 struct buf rkutab[NRK];
 short  rkcyl[NRK];
 
 u_short        rkstd[] = { 0777440, 0 };
 struct uba_driver hkdriver =
  { rkprobe, rkslave, rkattach, rkdgo, rkstd, "rk", rkdinfo, "hk", rkminfo, 1 };
 struct buf rkutab[NRK];
 short  rkcyl[NRK];
+#ifndef NOBADSECT
+struct dkbad rkbad[NRK];
+struct buf brkbuf[NRK];
+#endif
 
 struct rkst {
        short   nsect;
 
 struct rkst {
        short   nsect;
@@ -68,10 +95,13 @@ struct      rkst {
        struct  size *sizes;
 } rkst[] = {
        NRKSECT, NRKTRK, NRKSECT*NRKTRK,        NRK7CYL,        rk7_sizes,
        struct  size *sizes;
 } rkst[] = {
        NRKSECT, NRKTRK, NRKSECT*NRKTRK,        NRK7CYL,        rk7_sizes,
+       NRKSECT, NRKTRK, NRKSECT*NRKTRK,        NRK6CYL,        rk6_sizes,
 };
 
 u_char         rk_offset[16] =
 };
 
 u_char         rk_offset[16] =
-  { P400,M400,P400,M400,P800,M800,P800,M800,P1200,M1200,P1200,M1200,0,0,0,0 };
+  { RKAS_P400,RKAS_M400,RKAS_P400,RKAS_M400,RKAS_P800,RKAS_M800,RKAS_P800,
+    RKAS_M800,RKAS_P1200,RKAS_M1200,RKAS_P1200,RKAS_M1200,0,0,0,0
+  };
 
 struct buf rrkbuf[NRK];
 
 
 struct buf rrkbuf[NRK];
 
@@ -90,55 +120,74 @@ rkprobe(reg)
 
 #ifdef lint    
        br = 0; cvec = br; br = cvec;
 
 #ifdef lint    
        br = 0; cvec = br; br = cvec;
+       rkintr(0);
 #endif
        ((struct rkdevice *)reg)->rkcs1 = RK_CDT|RK_IE|RK_CRDY;
        DELAY(10);
        ((struct rkdevice *)reg)->rkcs1 = RK_CDT;
 #endif
        ((struct rkdevice *)reg)->rkcs1 = RK_CDT|RK_IE|RK_CRDY;
        DELAY(10);
        ((struct rkdevice *)reg)->rkcs1 = RK_CDT;
-       return (1);
+       return (sizeof (struct rkdevice));
 }
 
 rkslave(ui, reg)
 }
 
 rkslave(ui, reg)
-       struct uba_dinfo *ui;
+       struct uba_device *ui;
        caddr_t reg;
 {
        register struct rkdevice *rkaddr = (struct rkdevice *)reg;
 
        caddr_t reg;
 {
        register struct rkdevice *rkaddr = (struct rkdevice *)reg;
 
-       rkaddr->rkcs1 = RK_CDT;
+       ui->ui_type = 0;
+       rkaddr->rkcs1 = RK_CCLR;
        rkaddr->rkcs2 = ui->ui_slave;
        rkaddr->rkcs2 = ui->ui_slave;
+       rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
        rkwait(rkaddr);
        rkwait(rkaddr);
-/* SHOULD TRY THIS BY PULLING A PLUG */
-/* A DELAY OR SOMETHING MAY BE NEEDED */
-       if (rkaddr->rkcs2&RK_NED) {
-               rkaddr->rkcs1 = RK_CDT|RK_CCLR;
+       DELAY(50);
+       if (rkaddr->rkcs2&RKCS2_NED || (rkaddr->rkds&RKDS_SVAL) == 0) {
+               rkaddr->rkcs1 = RK_CCLR;
                return (0);
        }
                return (0);
        }
+       if (rkaddr->rkcs1&RK_CERR && rkaddr->rker&RKER_DTYE) {
+               ui->ui_type = 1;
+               rkaddr->rkcs1 = RK_CCLR;
+       }
        return (1);
 }
 
 rkattach(ui)
        return (1);
 }
 
 rkattach(ui)
-       register struct uba_dinfo *ui;
+       register struct uba_device *ui;
 {
 
        if (rkwstart == 0) {
 {
 
        if (rkwstart == 0) {
-               timeout(rkwatch, (caddr_t)0, HZ);
+               timeout(rkwatch, (caddr_t)0, hz);
                rkwstart++;
        }
        if (ui->ui_dk >= 0)
                rkwstart++;
        }
        if (ui->ui_dk >= 0)
-               dk_mspw[ui->ui_dk] = 1.0 / (HZ * NRKSECT * 256);
+               dk_mspw[ui->ui_dk] = 1.0 / (60 * NRKSECT * 256);
        rkip[ui->ui_ctlr][ui->ui_slave] = ui;
        rk_softc[ui->ui_ctlr].sc_ndrive++;
        rkcyl[ui->ui_unit] = -1;
        rkip[ui->ui_ctlr][ui->ui_slave] = ui;
        rk_softc[ui->ui_ctlr].sc_ndrive++;
        rkcyl[ui->ui_unit] = -1;
+       ui->ui_flags = 0;
 }
  
 }
  
+rkopen(dev)
+       dev_t dev;
+{
+       register int unit = minor(dev) >> 3;
+       register struct uba_device *ui;
+
+       if (unit >= NRK || (ui = rkdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
+       return (0);
+}
+
 rkstrategy(bp)
        register struct buf *bp;
 {
 rkstrategy(bp)
        register struct buf *bp;
 {
-       register struct uba_dinfo *ui;
+       register struct uba_device *ui;
        register struct rkst *st;
        register int unit;
        register struct buf *dp;
        int xunit = minor(bp->b_dev) & 07;
        long bn, sz;
        register struct rkst *st;
        register int unit;
        register struct buf *dp;
        int xunit = minor(bp->b_dev) & 07;
        long bn, sz;
+       int s;
 
        sz = (bp->b_bcount+511) >> 9;
        unit = dkunit(bp);
 
        sz = (bp->b_bcount+511) >> 9;
        unit = dkunit(bp);
@@ -152,7 +201,7 @@ rkstrategy(bp)
            (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
                goto bad;
        bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
            (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
                goto bad;
        bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
-       (void) spl5();
+       s = spl5();
        dp = &rkutab[ui->ui_unit];
        disksort(dp, bp);
        if (dp->b_active == 0) {
        dp = &rkutab[ui->ui_unit];
        disksort(dp, bp);
        if (dp->b_active == 0) {
@@ -161,7 +210,7 @@ rkstrategy(bp)
                if (bp->b_actf && bp->b_active == 0)
                        (void) rkstart(ui->ui_mi);
        }
                if (bp->b_actf && bp->b_active == 0)
                        (void) rkstart(ui->ui_mi);
        }
-       (void) spl0();
+       splx(s);
        return;
 
 bad:
        return;
 
 bad:
@@ -171,49 +220,62 @@ bad:
 }
 
 rkustart(ui)
 }
 
 rkustart(ui)
-       register struct uba_dinfo *ui;
+       register struct uba_device *ui;
 {
        register struct buf *bp, *dp;
 {
        register struct buf *bp, *dp;
-       register struct uba_minfo *um;
+       register struct uba_ctlr *um;
        register struct rkdevice *rkaddr;
        register struct rkdevice *rkaddr;
-       register struct rkst *st;
-       daddr_t bn;
-       int sn, csn;
-       int didie = 0;
 
        if (ui == 0)
 
        if (ui == 0)
-               return (0);
+               return;
        dk_busy &= ~(1<<ui->ui_dk);
        dp = &rkutab[ui->ui_unit];
        dk_busy &= ~(1<<ui->ui_dk);
        dp = &rkutab[ui->ui_unit];
-       if ((bp = dp->b_actf) == NULL)
-               goto out;
        um = ui->ui_mi;
        um = ui->ui_mi;
+       rkaddr = (struct rkdevice *)um->um_addr;
        if (um->um_tab.b_active) {
                rk_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
        if (um->um_tab.b_active) {
                rk_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave;
-               return (0);
+               return;
        }
        }
-       rkaddr = (struct rkdevice *)um->um_addr;
-       rkaddr->rkcs1 = RK_CDT|RK_CERR;
+       if ((bp = dp->b_actf) == NULL)
+               return;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_CERR;
        rkaddr->rkcs2 = ui->ui_slave;
        rkaddr->rkcs2 = ui->ui_slave;
-       rkaddr->rkcs1 = RK_CDT|RK_SELECT|RK_GO;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
        rkwait(rkaddr);
        rkwait(rkaddr);
-       if (dp->b_active)
-               goto done;
-       dp->b_active = 1;
-       if ((rkaddr->rkds & RK_VV) == 0) {
+       if ((rkaddr->rkds & RKDS_VV) == 0 || ui->ui_flags == 0) {
                /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
                /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
-               rkaddr->rkcs1 = RK_CDT|RK_IE|RK_PACK|RK_GO;
+#ifndef NOBADSECT
+               struct rkst *st = &rkst[ui->ui_type];
+               struct buf *bbp = &brkbuf[ui->ui_unit];
+#endif
+
+               rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_PACK|RK_GO;
+               ui->ui_flags = 1;
+#ifndef NOBADSECT
+               bbp->b_flags = B_READ|B_BUSY;
+               bbp->b_dev = bp->b_dev;
+               bbp->b_bcount = 512;
+               bbp->b_un.b_addr = (caddr_t)&rkbad[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
                rkwait(rkaddr);
                rkwait(rkaddr);
-               didie = 1;
        }
        }
+       if (dp->b_active)
+               goto done;
+       dp->b_active = 1;
+       if ((rkaddr->rkds & RKDS_DREADY) != RKDS_DREADY)
+               goto done;
        if (rk_softc[um->um_ctlr].sc_ndrive == 1)
                goto done;
        if (bp->b_cylin == rkcyl[ui->ui_unit])
                goto done;
        rkaddr->rkcyl = bp->b_cylin;
        rkcyl[ui->ui_unit] = bp->b_cylin;
        if (rk_softc[um->um_ctlr].sc_ndrive == 1)
                goto done;
        if (bp->b_cylin == rkcyl[ui->ui_unit])
                goto done;
        rkaddr->rkcyl = bp->b_cylin;
        rkcyl[ui->ui_unit] = bp->b_cylin;
-       rkaddr->rkcs1 = RK_CDT|RK_IE|RK_SEEK|RK_GO;
-       didie = 1;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_SEEK|RK_GO;
        if (ui->ui_dk >= 0) {
                dk_busy |= 1<<ui->ui_dk;
                dk_seek[ui->ui_dk]++;
        if (ui->ui_dk >= 0) {
                dk_busy |= 1<<ui->ui_dk;
                dk_seek[ui->ui_dk]++;
@@ -230,14 +292,14 @@ done:
                dp->b_active = 2;
        }
 out:
                dp->b_active = 2;
        }
 out:
-       return (didie);
+       return;
 }
 
 rkstart(um)
 }
 
 rkstart(um)
-       register struct uba_minfo *um;
+       register struct uba_ctlr *um;
 {
        register struct buf *bp, *dp;
 {
        register struct buf *bp, *dp;
-       register struct uba_dinfo *ui;
+       register struct uba_device *ui;
        register struct rkdevice *rkaddr;
        struct rkst *st;
        daddr_t bn;
        register struct rkdevice *rkaddr;
        struct rkst *st;
        daddr_t bn;
@@ -245,7 +307,7 @@ rkstart(um)
 
 loop:
        if ((dp = um->um_tab.b_actf) == NULL)
 
 loop:
        if ((dp = um->um_tab.b_actf) == NULL)
-               return (0);
+               return;
        if ((bp = dp->b_actf) == NULL) {
                um->um_tab.b_actf = dp->b_forw;
                goto loop;
        if ((bp = dp->b_actf) == NULL) {
                um->um_tab.b_actf = dp->b_forw;
                goto loop;
@@ -258,109 +320,166 @@ loop:
        tn = sn/st->nsect;
        sn %= st->nsect;
        rkaddr = (struct rkdevice *)ui->ui_addr;
        tn = sn/st->nsect;
        sn %= st->nsect;
        rkaddr = (struct rkdevice *)ui->ui_addr;
-       rkaddr->rkcs1 = RK_CDT|RK_CERR;
+retry:
+       rkaddr->rkcs1 = RK_CCLR;
        rkaddr->rkcs2 = ui->ui_slave;
        rkaddr->rkcs2 = ui->ui_slave;
-       rkaddr->rkcs1 = RK_CDT|RK_SELECT|RK_GO;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
        rkwait(rkaddr);
        rkwait(rkaddr);
-       if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) {
-               rkaddr->rkatt = rk_offset[um->um_tab.b_errcnt & 017];
-               rkaddr->rkcs1 = RK_CDT|RK_OFFSET|RK_GO;
-               rkwait(rkaddr);
+       if ((rkaddr->rkds&RKDS_SVAL) == 0) {
+               rknosval++;
+               goto nosval;
+       }
+       if (rkaddr->rkds&RKDS_PIP) {
+               rkpip++;
+               goto retry;
+       }
+       if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) {
+               printf("rk%d: not ready", dkunit(bp));
+               if ((rkaddr->rkds&RKDS_DREADY) != RKDS_DREADY) {
+                       printf("\n");
+                       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
+                       rkwait(rkaddr);
+                       rkaddr->rkcs1 = RK_CCLR;
+                       rkwait(rkaddr);
+                       um->um_tab.b_active = 0;
+                       um->um_tab.b_errcnt = 0;
+                       dp->b_actf = bp->av_forw;
+                       dp->b_active = 0;
+                       bp->b_flags |= B_ERROR;
+                       iodone(bp);
+                       goto loop;
+               }
+               printf(" (came back!)\n");
        }
        }
+nosval:
        rkaddr->rkcyl = bp->b_cylin;
        rkcyl[ui->ui_unit] = bp->b_cylin;
        rkaddr->rkda = (tn << 8) + sn;
        rkaddr->rkwc = -bp->b_bcount / sizeof (short);
        if (bp->b_flags & B_READ)
        rkaddr->rkcyl = bp->b_cylin;
        rkcyl[ui->ui_unit] = bp->b_cylin;
        rkaddr->rkda = (tn << 8) + sn;
        rkaddr->rkwc = -bp->b_bcount / sizeof (short);
        if (bp->b_flags & B_READ)
-               cmd = RK_CDT|RK_IE|RK_READ|RK_GO;
+               cmd = rktypes[ui->ui_type]|RK_IE|RK_READ|RK_GO;
        else
        else
-               cmd = RK_CDT|RK_IE|RK_WRITE|RK_GO;
+               cmd = rktypes[ui->ui_type]|RK_IE|RK_WRITE|RK_GO;
        um->um_cmd = cmd;
        um->um_cmd = cmd;
-       ubago(ui);
-       return (1);
+       (void) ubago(ui);
 }
 
 rkdgo(um)
 }
 
 rkdgo(um)
-       register struct uba_minfo *um;
+       register struct uba_ctlr *um;
 {
        register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
 
 {
        register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
 
+       um->um_tab.b_active = 2;        /* should now be 2 */
        rkaddr->rkba = um->um_ubinfo;
        rkaddr->rkcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
        rkaddr->rkba = um->um_ubinfo;
        rkaddr->rkcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300);
 }
 
-hkintr(rk11)
+rkintr(rk11)
        int rk11;
 {
        int rk11;
 {
-       register struct uba_minfo *um = rkminfo[rk11];
-       register struct uba_dinfo *ui;
+       register struct uba_ctlr *um = rkminfo[rk11];
+       register struct uba_device *ui;
        register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
        register struct buf *bp, *dp;
        int unit;
        struct rk_softc *sc = &rk_softc[um->um_ctlr];
        int as = (rkaddr->rkatt >> 8) | sc->sc_softas;
        register struct rkdevice *rkaddr = (struct rkdevice *)um->um_addr;
        register struct buf *bp, *dp;
        int unit;
        struct rk_softc *sc = &rk_softc[um->um_ctlr];
        int as = (rkaddr->rkatt >> 8) | sc->sc_softas;
-       int needie = 1;
 
        sc->sc_wticks = 0;
        sc->sc_softas = 0;
 
        sc->sc_wticks = 0;
        sc->sc_softas = 0;
-       if (um->um_tab.b_active) {
+       if (um->um_tab.b_active == 2 || sc->sc_recal) {
+               um->um_tab.b_active = 1;
                dp = um->um_tab.b_actf;
                bp = dp->b_actf;
                ui = rkdinfo[dkunit(bp)];
                dk_busy &= ~(1 << ui->ui_dk);
                dp = um->um_tab.b_actf;
                bp = dp->b_actf;
                ui = rkdinfo[dkunit(bp)];
                dk_busy &= ~(1 << ui->ui_dk);
+#ifndef NOBADSECT
+               if (bp->b_flags&B_BAD)
+                       if (rkecc(ui, CONT))
+                               return;
+#endif
                if (rkaddr->rkcs1 & RK_CERR) {
                        int recal;
                        u_short ds = rkaddr->rkds;
                        u_short cs2 = rkaddr->rkcs2;
                        u_short er = rkaddr->rker;
                if (rkaddr->rkcs1 & RK_CERR) {
                        int recal;
                        u_short ds = rkaddr->rkds;
                        u_short cs2 = rkaddr->rkcs2;
                        u_short er = rkaddr->rker;
-                       if (sc->sc_recal)
-                               printf("recal CERR\n");
-                       rkerrs++;                               /* GROT */
-                       if (rkflags&1)                          /* GROT */
-                       printf("%d ds %o cs2 %o er %o\n",       /* GROT */
-                           um->um_tab.b_errcnt, ds, cs2, er);  /* GROT */
-                       if (er & RK_WLE)        
-                               printf("rk%d is write locked\n", dkunit(bp));
-/* THIS DOESN'T SEEM TO HAPPEN */
-/* OR WAS SOMETHING BROKEN WHEN WE TRIED */
-/* SPINNING A DRIVE DOWN ? */
-                       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)
+#ifdef RKDEBUG
+                       if (rkdebug) {
+                               printf("cs2=%b ds=%b er=%b\n",
+                                   cs2, RKCS2_BITS, ds, 
+                                   RKDS_BITS, er, RKER_BITS);
+                       }
+#endif
+                       if (er & RKER_WLE) {
+                               printf("rk%d: write locked\n", dkunit(bp));
+                               bp->b_flags |= B_ERROR;
+                       } else if (++um->um_tab.b_errcnt > 28 ||
+                           ds&RKDS_HARD || er&RKER_HARD || cs2&RKCS2_HARD) {
+hard:
+                               harderr(bp, "rk");
+                               printf("cs2=%b ds=%b er=%b\n",
+                                   cs2, RKCS2_BITS, ds, 
+                                   RKDS_BITS, er, RKER_BITS);
                                bp->b_flags |= B_ERROR;
                                bp->b_flags |= B_ERROR;
-                       else
-                               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;
+                               sc->sc_recal = 0;
+                       } else if (er & RKER_BSE) {
+#ifndef NOBADSECT
+                               if (rkecc(ui, BSE))
+                                       return;
+                               else
+#endif
+                                       goto hard;
+                       } else {
+                               if ((er & (RKER_DCK|RKER_ECH)) == RKER_DCK) {
+                                       if (rkecc(ui, ECC))
+                                               return;
+                               } else
+                                       um->um_tab.b_active = 0;
+                       }
+                       if (cs2&RKCS2_MDS) {
+                               rkaddr->rkcs2 = RKCS2_SCLR;
                                goto retry;
                        }
                        recal = 0;
                                goto retry;
                        }
                        recal = 0;
-                       if (ds&RK_DROT || er&(RK_OPI|RK_SKI|RK_UNS) ||
+                       if (ds&RKDS_DROT || er&(RKER_OPI|RKER_SKI|RKER_UNS) ||
                            (um->um_tab.b_errcnt&07) == 4)
                                recal = 1;
                            (um->um_tab.b_errcnt&07) == 4)
                                recal = 1;
-                       if ((er & (RK_DCK|RK_ECH)) == RK_DCK)
-                               if (rkecc(ui))
-                                       return;
-                       rkaddr->rkcs1 = RK_CDT|RK_CCLR;
+                       rkaddr->rkcs1 = RK_CCLR;
                        rkaddr->rkcs2 = ui->ui_slave;
                        rkaddr->rkcs2 = ui->ui_slave;
-                       rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
+                       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
                        rkwait(rkaddr);
                        if (recal && um->um_tab.b_active == 0) {
                        rkwait(rkaddr);
                        if (recal && um->um_tab.b_active == 0) {
-                               rkaddr->rkcs1 = RK_CDT|RK_IE|RK_RECAL|RK_GO;
+                               rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_RECAL|RK_GO;
                                rkcyl[ui->ui_unit] = -1;
                                rkcyl[ui->ui_unit] = -1;
-                               rkwait(rkaddr);
-                               um->um_tab.b_active = 1;
-                               sc->sc_recal = 1;
-                               return;
+                               sc->sc_recal = 0;
+                               goto nextrecal;
                        }
                }
 retry:
                        }
                }
 retry:
-               if (sc->sc_recal) {
+               switch (sc->sc_recal) {
+
+               case 1:
+                       rkaddr->rkcyl = bp->b_cylin;
+                       rkcyl[ui->ui_unit] = bp->b_cylin;
+                       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_SEEK|RK_GO;
+                       goto nextrecal;
+               case 2:
+                       if (um->um_tab.b_errcnt < 16 ||
+                           (bp->b_flags&B_READ) == 0)
+                               goto donerecal;
+                       rkaddr->rkatt = rk_offset[um->um_tab.b_errcnt & 017];
+                       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_OFFSET|RK_GO;
+                       /* fall into ... */
+               nextrecal:
+                       sc->sc_recal++;
+                       rkwait(rkaddr);
+                       um->um_tab.b_active = 1;
+                       return;
+               donerecal:
+               case 3:
                        sc->sc_recal = 0;
                        um->um_tab.b_active = 0;
                        sc->sc_recal = 0;
                        um->um_tab.b_active = 0;
+                       break;
                }
                ubadone(um);
                if (um->um_tab.b_active) {
                }
                ubadone(um);
                if (um->um_tab.b_active) {
@@ -373,20 +492,27 @@ retry:
                        bp->b_resid = -rkaddr->rkwc * sizeof(short);
                        iodone(bp);
                        if (dp->b_actf)
                        bp->b_resid = -rkaddr->rkwc * sizeof(short);
                        iodone(bp);
                        if (dp->b_actf)
-                               if (rkustart(ui))
-                                       needie = 0;
+                               rkustart(ui);
                }
                as &= ~(1<<ui->ui_slave);
        }
        for (unit = 0; as; as >>= 1, unit++)
                }
                as &= ~(1<<ui->ui_slave);
        }
        for (unit = 0; as; as >>= 1, unit++)
-               if (as & 1)
-                       if (rkustart(rkip[rk11][unit]))
-                               needie = 0;
+               if (as & 1) {
+                       ui = rkip[rk11][unit];
+                       if (ui) {
+                               rkustart(rkip[rk11][unit]);
+                       } else {
+                               rkaddr->rkcs1 = RK_CCLR;
+                               rkaddr->rkcs2 = unit;
+                               rkaddr->rkcs1 = RK_DCLR|RK_GO;
+                               rkwait(rkaddr);
+                               rkaddr->rkcs1 = RK_CCLR;
+                       }
+               }
        if (um->um_tab.b_actf && um->um_tab.b_active == 0)
        if (um->um_tab.b_actf && um->um_tab.b_active == 0)
-               if (rkstart(um))
-                       needie = 0;
-       if (needie)
-               rkaddr->rkcs1 = RK_CDT|RK_IE;
+               rkstart(um);
+       if (((rkaddr->rkcs1) & RK_IE) == 0)
+               rkaddr->rkcs1 = RK_IE;
 }
 
 rkwait(addr)
 }
 
 rkwait(addr)
@@ -397,120 +523,166 @@ rkwait(addr)
                ;
 }
 
                ;
 }
 
-rkread(dev)
+rkread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NRK)
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NRK)
-               u.u_error = ENXIO;
-       else
-               physio(rkstrategy, &rrkbuf[unit], dev, B_READ, minphys);
+               return (ENXIO);
+       return (physio(rkstrategy, &rrkbuf[unit], dev, B_READ, minphys, uio));
 }
 
 }
 
-rkwrite(dev)
+rkwrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NRK)
 {
        register int unit = minor(dev) >> 3;
 
        if (unit >= NRK)
-               u.u_error = ENXIO;
-       else
-               physio(rkstrategy, &rrkbuf[unit], dev, B_WRITE, minphys);
+               return (ENXIO);
+       return (physio(rkstrategy, &rrkbuf[unit], dev, B_WRITE, minphys, uio));
 }
 
 }
 
-rkecc(ui)
-       register struct uba_dinfo *ui;
+rkecc(ui, flag)
+       register struct uba_device *ui;
 {
        register struct rkdevice *rk = (struct rkdevice *)ui->ui_addr;
        register struct buf *bp = rkutab[ui->ui_unit].b_actf;
 {
        register struct rkdevice *rk = (struct rkdevice *)ui->ui_addr;
        register struct buf *bp = rkutab[ui->ui_unit].b_actf;
-       register struct uba_minfo *um = ui->ui_mi;
+       register struct uba_ctlr *um = ui->ui_mi;
        register struct rkst *st;
        struct uba_regs *ubp = ui->ui_hd->uh_uba;
        register struct rkst *st;
        struct uba_regs *ubp = ui->ui_hd->uh_uba;
-       register int i;
        caddr_t addr;
        caddr_t addr;
-       int reg, bit, byte, npf, mask, o, cmd, ubaddr;
+       int reg, npf, o, cmd, ubaddr;
        int bn, cn, tn, sn;
 
        int bn, cn, tn, sn;
 
-       npf = btop((rk->rkwc * sizeof(short)) + bp->b_bcount) - 1;
+#ifndef NOBADSECT
+       if (flag == CONT)
+               npf = bp->b_error;
+       else
+#endif
+               npf = btop((rk->rkwc * 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("%D ", bp->b_blkno+npf);
-       prdev("ECC", bp->b_dev);
-       mask = rk->rkec2;
-       if (mask == 0) {
-               rk->rkatt = 0;
-               return (0);
-       }
-       ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE;
-       i = rk->rkec1 - 1;              /* -1 makes 0 origin */
-       printf("mask %x pos %x\n", mask, i+1);
-       bit = i&07;
-       i = (i&~07)>>3;
-       byte = i + o;
-       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;
-       }
-       um->um_tab.b_active++;  /* Either complete or continuing... */
-       if (rk->rkwc == 0)
-               return (0);
-#ifdef notdef
-       rk->rkcs1 |= RK_GO;
-#else
-       rk->rkcs1 = RK_CDT|RK_CCLR;
-       rk->rkcs2 = ui->ui_slave;
-       rk->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
-       rkwait(rk);
        bn = dkblock(bp);
        st = &rkst[ui->ui_type];
        cn = bp->b_cylin;
        bn = dkblock(bp);
        st = &rkst[ui->ui_type];
        cn = bp->b_cylin;
-       sn = bn%st->nspc + npf + 1;
+       sn = bn%st->nspc + npf;
        tn = sn/st->nsect;
        sn %= st->nsect;
        cn += tn/st->ntrak;
        tn %= st->ntrak;
        tn = sn/st->nsect;
        sn %= st->nsect;
        cn += tn/st->ntrak;
        tn %= st->ntrak;
+       ubapurge(um);
+       switch (flag) {
+       case ECC:
+               {
+               register int i;
+               int bit, byte, mask;
+
+               npf--;
+               reg--;
+               printf("rk%d%c: soft ecc sn%d\n", dkunit(bp),
+                   'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf);
+               mask = rk->rkec2;
+               i = rk->rkec1 - 1;              /* -1 makes 0 origin */
+               bit = i&07;
+               i = (i&~07)>>3;
+               byte = i + o;
+               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;
+               }
+               if (rk->rkwc == 0) {
+                       um->um_tab.b_active = 0;
+                       return (0);
+               }
+               npf++;
+               reg++;
+               break;
+               }
+
+#ifndef NOBADSECT
+       case BSE:
+#ifdef RKBDEBUG
+               if (rkbdebug)
+       printf("rkecc, BSE: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn);
+#endif
+               if ((bn = isbad(&rkbad[ui->ui_unit], cn, tn, sn)) < 0)
+                       return(0);
+               bp->b_flags |= B_BAD;
+               bp->b_error = npf + 1;
+               bn = st->ncyl*st->nspc - st->nsect - 1 - bn;
+               cn = bn/st->nspc;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn %= st->nsect;
+#ifdef RKBDEBUG
+               if (rkbdebug)
+       printf("revector to cn %d tn %d sn %d\n", cn, tn, sn);
+#endif
+               rk->rkwc = -(512 / sizeof (short));
+               break;
+
+       case CONT:
+#ifdef RKBDEBUG
+               if (rkbdebug)
+       printf("rkecc, CONT: bn %d cn %d tn %d sn %d\n", bn,cn,tn,sn);
+#endif
+               bp->b_flags &= ~B_BAD;
+               rk->rkwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof (short));
+               if (rk->rkwc == 0) {
+                       um->um_tab.b_active = 0;
+                       return (0);
+               }
+               break;
+#endif
+       }
+       rk->rkcs1 = RK_CCLR;
+       rk->rkcs2 = ui->ui_slave;
+       rk->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
+       rkwait(rk);
        rk->rkcyl = cn;
        rk->rkda = (tn << 8) | sn;
        rk->rkcyl = cn;
        rk->rkda = (tn << 8) | sn;
-       ubaddr = (int)ptob(reg+1) + o;
+       ubaddr = (int)ptob(reg) + o;
        rk->rkba = ubaddr;
        rk->rkba = ubaddr;
-       cmd = (ubaddr >> 8) & 0x300;
-       cmd |= RK_CDT|RK_IE|RK_GO|RK_READ;
+       cmd = (bp->b_flags&B_READ ? RK_READ : RK_WRITE)|RK_IE|RK_GO;
+       cmd |= (ubaddr >> 8) & 0x300;
+       cmd |= rktypes[ui->ui_type];
        rk->rkcs1 = cmd;
        rk->rkcs1 = cmd;
-#endif
+       um->um_tab.b_active = 2;        /* continuing */
+       um->um_tab.b_errcnt = 0;        /* error has been corrected */
        return (1);
 }
 
 rkreset(uban)
        return (1);
 }
 
 rkreset(uban)
+       int uban;
 {
 {
-       register struct uba_minfo *um;
-       register struct uba_dinfo *ui;
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
        register rk11, unit;
        register rk11, unit;
-       int any = 0;
 
        for (rk11 = 0; rk11 < NHK; rk11++) {
                if ((um = rkminfo[rk11]) == 0 || um->um_ubanum != uban ||
                    um->um_alive == 0)
                        continue;
 
        for (rk11 = 0; rk11 < NHK; rk11++) {
                if ((um = rkminfo[rk11]) == 0 || um->um_ubanum != uban ||
                    um->um_alive == 0)
                        continue;
-               if (any == 0) {
-                       printf(" rk");
-                       any++;
-               }
+               printf(" hk%d", rk11);
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
                rk_softc[um->um_ctlr].sc_recal = 0;
                um->um_tab.b_active = 0;
                um->um_tab.b_actf = um->um_tab.b_actl = 0;
                rk_softc[um->um_ctlr].sc_recal = 0;
+               rk_softc[um->um_ctlr].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;
                }
                }
-               for (unit = 0; unit < NHK; unit++) {
+               for (unit = 0; unit < NRK; unit++) {
                        if ((ui = rkdinfo[unit]) == 0)
                                continue;
                        if ((ui = rkdinfo[unit]) == 0)
                                continue;
-                       if (ui->ui_alive == 0)
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
                                continue;
                        rkutab[unit].b_active = 0;
                        (void) rkustart(ui);
                                continue;
                        rkutab[unit].b_active = 0;
                        (void) rkustart(ui);
@@ -521,11 +693,11 @@ rkreset(uban)
 
 rkwatch()
 {
 
 rkwatch()
 {
-       register struct uba_minfo *um;
+       register struct uba_ctlr *um;
        register rk11, unit;
        register struct rk_softc *sc;
 
        register rk11, unit;
        register struct rk_softc *sc;
 
-       timeout(rkwatch, (caddr_t)0, HZ);
+       timeout(rkwatch, (caddr_t)0, hz);
        for (rk11 = 0; rk11 < NHK; rk11++) {
                um = rkminfo[rk11];
                if (um == 0 || um->um_alive == 0)
        for (rk11 = 0; rk11 < NHK; rk11++) {
                um = rkminfo[rk11];
                if (um == 0 || um->um_alive == 0)
@@ -543,7 +715,7 @@ 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 rkintr ");
+                       printf("hk%d: lost interrupt\n", rk11);
                        ubareset(um->um_ubanum);
                }
        }
                        ubareset(um->um_ubanum);
                }
        }
@@ -559,43 +731,34 @@ rkdump(dev)
        int num, blk, unit;
        struct size *sizes;
        register struct uba_regs *uba;
        int num, blk, unit;
        struct size *sizes;
        register struct uba_regs *uba;
-       register struct uba_dinfo *ui;
+       register struct uba_device *ui;
        register short *rp;
        struct rkst *st;
 
        unit = minor(dev) >> 3;
        register short *rp;
        struct rkst *st;
 
        unit = minor(dev) >> 3;
-       if (unit >= NRK) {
-               printf("bad unit\n");
-               return (-1);
-       }
+       if (unit >= NRK)
+               return (ENXIO);
 #define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
 #define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
-       ui = phys(struct uba_dinfo *, rkdinfo[unit]);
-       if (ui->ui_alive == 0) {
-               printf("dna\n");
-               return(-1);
-       }
+       ui = phys(struct uba_device *, rkdinfo[unit]);
+       if (ui->ui_alive == 0)
+               return (ENXIO);
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
        uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
-#if VAX780
-       if (cpu == VAX_780)
-               ubainit(uba);
-#endif
+       ubainit(uba);
        rkaddr = (struct rkdevice *)ui->ui_physaddr;
        num = maxfree;
        start = 0;
        rkaddr = (struct rkdevice *)ui->ui_physaddr;
        num = maxfree;
        start = 0;
-       rkaddr->rkcs1 = RK_CDT|RK_CERR;
+       rkaddr->rkcs1 = RK_CCLR;
        rkaddr->rkcs2 = unit;
        rkaddr->rkcs2 = unit;
-       rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
        rkwait(rkaddr);
        rkwait(rkaddr);
-       if ((rkaddr->rkds & RK_VV) == 0) {
-               rkaddr->rkcs1 = RK_CDT|RK_IE|RK_PACK|RK_GO;
+       if ((rkaddr->rkds & RKDS_VV) == 0) {
+               rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_PACK|RK_GO;
                rkwait(rkaddr);
        }
        st = &rkst[ui->ui_type];
        sizes = phys(struct size *, st->sizes);
                rkwait(rkaddr);
        }
        st = &rkst[ui->ui_type];
        sizes = phys(struct size *, st->sizes);
-       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) {
-               printf("oor\n");
-               return (-1);
-       }
+       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;
@@ -605,7 +768,7 @@ rkdump(dev)
                blk = num > DBSIZE ? DBSIZE : num;
                io = uba->uba_map;
                for (i = 0; i < blk; i++)
                blk = num > DBSIZE ? DBSIZE : num;
                io = uba->uba_map;
                for (i = 0; i < blk; i++)
-                       *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV;
+                       *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
                *(int *)io = 0;
                bn = dumplo + btop(start);
                cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
                *(int *)io = 0;
                bn = dumplo + btop(start);
                cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
@@ -617,15 +780,10 @@ rkdump(dev)
                *rp = (tn << 8) + sn;
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
                *rp = (tn << 8) + sn;
                *--rp = 0;
                *--rp = -blk*NBPG / sizeof (short);
-               *--rp = RK_CDT|RK_GO|RK_WRITE;
+               *--rp = rktypes[ui->ui_type]|RK_GO|RK_WRITE;
                rkwait(rkaddr);
                rkwait(rkaddr);
-               if (rkaddr->rkcs1 & RK_CERR) {
-       printf("rk dump dsk err: (%d,%d,%d) cs1=%x, ds=%x, er1=%x\n",
-                           cn, tn, sn,
-                           rkaddr->rkcs1&0xffff, rkaddr->rkds&0xffff,
-                           rkaddr->rker&0xffff);
-                       return (-1);
-               }
+               if (rkaddr->rkcs1 & RK_CERR)
+                       return (EIO);
                start += blk*NBPG;
                num -= blk;
        }
                start += blk*NBPG;
                num -= blk;
        }