BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 2 Nov 1983 08:51:35 +0000 (00:51 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 2 Nov 1983 08:51:35 +0000 (00:51 -0800)
Work on file usr/src/sys/vaxuba/rk.c
Work on file usr/src/sys/vax/tu.c
Work on file usr/src/new/new/spms/bin/pinstall

Synthesized-from: CSRG/cd1/4.2

usr/src/new/new/spms/bin/pinstall [new file with mode: 0755]
usr/src/sys/vax/tu.c [new file with mode: 0644]
usr/src/sys/vaxuba/rk.c [new file with mode: 0644]

diff --git a/usr/src/new/new/spms/bin/pinstall b/usr/src/new/new/spms/bin/pinstall
new file mode 100755 (executable)
index 0000000..22f3960
--- /dev/null
@@ -0,0 +1,60 @@
+#! /bin/csh -f
+#
+# Install SPMS Software Project Management System
+#
+
+if (!(-d /usr/new)) then
+       echo "/usr/new: No such directory"
+       exit(1)
+endif
+if (!(-d /usr/new/lib)) then
+       echo "/usr/new/lib: No such directory"
+       exit(1)
+endif
+
+# pexec relies upon the PROJECT environment variable
+# which MUST be set to the root directory of the project.
+cd ..
+setenv PROJECT $cwd
+
+set PATH = (/usr/new /usr/ucb /bin /usr/bin)
+
+#install libraries
+foreach p (libhash libpdb libslist libspms libtree)
+       cd $PROJECT/src/lib/$p/src
+       sed -e '/###/,$d' < Makefile > $$Mf
+       mv $$Mf Makefile
+       make install
+end
+
+#install programs in /usr/new
+cd $PROJECT/src/bin
+foreach p (*)
+       cd $PROJECT/src/bin/$p
+       sed -e '/###/,$d' < Makefile > $$Mf
+       mv $$Mf Makefile
+       make install
+end
+rehash
+
+# reconstruct Makefile dependencies and update
+pexec -Tupdate "mkmf; make update"
+
+# clean up
+pexec -Tclean "make clean"
+
+#install manual pages in /usr/man/mann
+cp $PROJECT/man/mann/*.n /usr/man/mann
+
+# create ~root^ and ~root^usr projects
+cd /
+mkproject -d -Tproject ~root^
+cd /usr/src
+mkproject -Nusr -Tproject ~root^.../usr/src > /dev/null << 'EOF'
+/usr source
+'EOF'
+
+# connect spms project to ~root^usr
+mkproject -d ~root^usr/new/spms
+
+exit(0)
diff --git a/usr/src/sys/vax/tu.c b/usr/src/sys/vax/tu.c
new file mode 100644 (file)
index 0000000..3b6df41
--- /dev/null
@@ -0,0 +1,725 @@
+/*     %M      6.2     83/10/12        */
+
+#if defined(VAX750) || defined(VAX730)
+/*
+ * TU58 DECtape II device driver
+ *
+ * TU58 console cassette driver (for VAX-11/750 or VAX-11/730).
+ * The TU58 is treated as a block device (only).  Error detection and
+ * recovery is not extensive, but sufficient for most situations. It is 
+ * assumed that the TU58 will follow the RSP (or MRSP) protocol exactly,
+ * very few protocol errors are checked for.  It is also assumed that
+ * the 730 uses Modified RSP (MRSP), while the 750 may use either RSP
+ * or MRSP depending on whether defined(MRSP) is true or not.
+ * In the case of a 750 without MRSP, the only way for the CPU to
+ * keep up with the tu58 is to lock out virtually everything else.
+ *
+ * NOTE: Reading large amounts of data from the tu58 is likely
+ *      to crash your system if you are running multiuser.
+ *             ******FOR SINGLE USER USE ONLY*****
+ */
+#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/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vax/rsp.h"
+
+#define        printd  if(tudebug) printf
+#ifdef printd
+int    tudebug;        /* printd */
+#endif printd
+
+#define        NTU     ((cpu == VAX_750) ? 1 : 2)
+#define DNUM    01             /* mask for drive number (should match NTU) */
+#define        NTUBLK  512             /* number of blocks on a TU58 cassette */
+#define WRV     02              /* bit in minor dev => write w. read verify */
+#define NTUQ    2               /* # of blocks which can be queued up */
+#define        TUIPL   ((cpu == VAX_750) ? 0x17 : 0x14)
+
+#ifndef MRSP
+#define MRSP (cpu != VAX_750)
+#endif
+
+/*
+ * State information 
+ */
+struct tu {
+       u_char  *tu_rbptr;      /* pointer to buffer for read */
+       int     tu_rcnt;        /* how much to read */
+       u_char  *tu_wbptr;      /* pointer to buffer for write */
+       int     tu_wcnt;        /* how much to write */
+       int     tu_state;       /* current state of tansfer operation */
+       int     tu_flag;        /* read in progress flag */
+       char    *tu_addr;       /* real buffer data address */
+       int     tu_count;       /* real requested count */
+       int     tu_serrs;       /* count of soft errors */
+       int     tu_cerrs;       /* count of checksum errors */
+       int     tu_herrs;       /* count of hard errors */
+       char    tu_dopen[2];    /* drive is open */
+} tu;
+
+
+/*
+ * Device register bits
+ */
+#define        READY   0200            /* transmitter ready */
+#define        DONE    0200            /* receiver done */
+#define        IE      0100            /* interrupt enable */
+#define        BREAK   1               /* send break */
+
+struct packet tucmd;           /* a command sent to the TU58 */
+struct packet tudata;          /* a command or data returned from TU58 */
+
+char *tustates[TUS_NSTATES] = {
+       "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
+       "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
+};
+
+u_char tunull[2] = { 0, 0 };   /* nulls to send for initialization */
+u_char tuinit[2] = { TUF_INITF, TUF_INITF };   /* inits to send */
+static char tu_pcnt[2];                        /* pee/vee counters */
+int    tutimer = 0;
+int    tuwake();
+struct buf tutab;                              /* I/O queue header */
+
+/*
+ * Open the TU58
+ */
+/*ARGSUSED*/
+tuopen(dev, flag)
+{
+       extern int tuwatch();
+       register s;
+
+#ifdef lint
+       turintr(); tuwintr();
+#endif
+       if ((minor(dev)&DNUM) >= NTU)
+               return (ENXIO);
+       if (tu.tu_dopen[minor(dev)&DNUM])
+               return (EBUSY);
+       if (tutimer++ == 0)
+               timeout(tuwatch, (caddr_t)0, hz);
+
+       s = splx(TUIPL);
+       tu.tu_dopen[minor(dev)&DNUM]++;
+       /*
+        * If the cassette's already initialized,
+        * just enable interrupts and return.
+        */
+       if (tu.tu_state == TUS_IDLE) {
+               mtpr(CSRS, IE);
+               goto ok;
+       }
+
+       /* 
+        * Must initialize, reset the cassette
+        * and wait for things to settle down.
+        */
+       tureset();
+       sleep((caddr_t)&tu, PZERO+1);
+       tutab.b_active = NULL;
+       if (tu.tu_state != TUS_IDLE) {
+               tu.tu_state = TUS_INIT1;
+               tu.tu_dopen[minor(dev)&DNUM] = 0;
+               tu.tu_rcnt = tu.tu_wcnt = 0;
+               mtpr(CSTS, 0);
+               mtpr(CSRS, 0);
+               splx(s);
+               return (EIO);
+       }
+ok:
+       splx(s);
+       return (0);
+}
+
+/*
+ * Close the TU58, but make sure all
+ * outstanding i/o is complete first..
+ */
+tuclose(dev, flag)
+       dev_t dev;
+       int flag;
+{
+       int s, unit = minor(dev);
+       struct buf *bp, *last = NULL;
+
+       s = splx(TUIPL);
+       while (tu_pcnt[unit])
+               sleep(&tu_pcnt[unit], PRIBIO);
+       /*
+        * No more writes are pending, scan the 
+        * buffer queue for oustanding reads from
+        * this unit.
+        */
+       for (bp = tutab.b_actf; bp; bp = bp->b_actf) {
+               if (bp->b_dev == dev)
+                       last = bp;
+       }
+       if (last) {
+               last->b_flags |= B_CALL;
+               last->b_iodone = tuwake;
+               sleep((caddr_t)last, PRIBIO);
+       }
+       tu.tu_dopen[unit&DNUM] = 0;
+       if (!tu.tu_dopen[0] && !tu.tu_dopen[1]) {
+               tutimer = 0;
+               mtpr(CSRS, 0);
+               tu.tu_flag = 0;
+       }
+       splx(s);
+}
+
+tuwake(bp)
+       struct buf *bp;
+{
+       wakeup(bp);
+}
+
+/*
+ * Reset the TU58
+ */
+tureset()
+{
+
+       mtpr(CSRS, 0);
+       tu.tu_state = TUS_INIT1;
+       tu.tu_wbptr = tunull;
+       tu.tu_wcnt = sizeof (tunull);
+       tucmd.pk_flag = TUF_CMD;
+       tucmd.pk_mcount = sizeof (tucmd) - 4;
+       tucmd.pk_mod = 0;
+       tucmd.pk_seq = 0;
+       tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
+       tutab.b_active++;
+       mtpr(CSTS, IE | BREAK);
+       tuxintr();                      /* start output */
+}
+
+/*
+ * Strategy routine for block I/O
+ */
+tustrategy(bp)
+       register struct buf *bp;
+{
+       register int s;
+
+       if (bp->b_blkno >= NTUBLK) {
+               bp->b_flags |= B_ERROR;
+               iodone(bp);
+               return;
+       }
+       if ((bp->b_flags&B_READ) == 0)
+               tu_pee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
+       bp->av_forw = NULL;
+       s = splx(TUIPL);
+       if (tutab.b_actf == NULL)
+               tutab.b_actf = bp;
+       else
+               tutab.b_actl->av_forw = bp;
+       tutab.b_actl = bp;
+       if (tutab.b_active == NULL)
+               tustart();
+       splx(s);
+}
+
+/*
+ * Start the transfer
+ */
+tustart()
+{
+       register struct buf *bp;
+       int s;
+
+       if ((bp = tutab.b_actf) == NULL)
+               return;
+       s = splx(TUIPL);
+       if (tu.tu_state != TUS_IDLE) {
+               tureset();
+               splx(s);
+               return;
+       }
+       tutab.b_active++;
+       tutab.b_errcnt = 0;
+       tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
+       tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
+           TUMD_WRV : 0;
+       tucmd.pk_unit = (minor(bp->b_dev)&DNUM);
+       tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
+       tucmd.pk_count = tu.tu_count = bp->b_bcount;
+       tucmd.pk_block = bp->b_blkno;
+       tucmd.pk_chksum =
+           tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
+               (int)tucmd.pk_mcount);
+       tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
+       tu.tu_addr = bp->b_un.b_addr;
+       tu.tu_wbptr = (u_char *)&tucmd;
+       tu.tu_wcnt = sizeof (tucmd);
+       tuxintr();
+       splx(s);
+}
+
+/*
+ * TU58 receiver interrupt
+ */
+turintr()
+{
+       register struct buf *bp;
+       register int c;
+
+       c = mfpr(CSRD)&0xff;
+       if (MRSP) {
+               while ((mfpr(CSTS)&READY) == 0)
+                       ;
+               mtpr(CSTD, TUF_CONT);                   /* ACK */
+               if (tu.tu_rcnt) {
+                       *tu.tu_rbptr++ = c;
+                       if (--tu.tu_rcnt)
+                               return;
+               }
+       }
+
+       /*
+        * Switch on the state of the transfer.
+        */
+       switch(tu.tu_state) {
+
+       /*
+        * Probably an overrun error,
+        * cannot happen if MRSP is used
+        */
+       case TUS_RCVERR:
+               mtpr(CSRS, 0);                                  /* flush */
+               printf("overrun error, transfer restarted\n");  /* DEBUG */
+               tu.tu_serrs++;
+               tu_restart();
+               break;
+
+       /*
+        * If we get an unexpected "continue",
+        * start all over again...
+        */
+       case TUS_INIT2:
+               tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
+               tu.tu_flag = 0;
+               wakeup((caddr_t)&tu);
+               tustart();
+               break;
+
+       /*
+        * Only transition from this state
+        * is on a "continue", so if we don't
+        * get it, reset the world.
+        */
+       case TUS_WAIT:                  /* waiting for continue */
+               switch(c) {
+               case TUF_CONT:  /* got the expected continue */
+                       tu.tu_flag = 0;
+                       tudata.pk_flag = TUF_DATA;
+                       tudata.pk_mcount = MIN(128, tu.tu_count);
+                       tudata.pk_chksum =
+                           tuchk(*((short *)&tudata), (caddr_t)tu.tu_addr,
+                               (int)tudata.pk_mcount);
+                       tu.tu_state = TUS_SENDH;
+                       tu.tu_wbptr = (u_char *)&tudata;
+                       tu.tu_wcnt = 2;
+                       tuxintr();
+                       break;
+
+               case TUF_CMD:   /* sending us an END packet...error */
+                       tu.tu_state = TUS_GET;
+                       tu.tu_rbptr = (u_char *) &tudata;
+                       tu.tu_rcnt = sizeof (tudata) - 1;
+                       tu.tu_flag = 1;
+                       mtpr (CSTS, 0);
+                       *tu.tu_rbptr = c;
+                       break;
+
+               case TUF_INITF:
+                       tureset();
+                       break;
+
+               default:        /* something random...bad news */
+                       tu.tu_state = TUS_INIT1;
+                       break;
+               }
+               break;
+
+       case TUS_SENDW:
+               if (c != TUF_CONT && c != TUF_INITF) 
+                       goto bad;
+               tureset();
+               break;
+
+       /*
+        * Got header, now get data; amount to
+        * fetch is included in packet.
+        */
+       case TUS_GETH:
+               if (MRSP && (tudata.pk_flag == TUF_DATA))
+                       tu.tu_rbptr = (u_char *)tu.tu_addr;
+               tu.tu_rcnt = tudata.pk_mcount;
+               tu.tu_state = TUS_GETD;
+               break;
+
+       /*
+        * Got the data, now fetch the checksum.
+        */
+       case TUS_GETD:
+               tu.tu_rbptr = (u_char *)&tudata.pk_chksum;
+               tu.tu_rcnt = sizeof (tudata.pk_chksum);
+               tu.tu_state = TUS_GETC;
+               break;
+
+       case TUS_CHKERR:                /* from tudma only */
+               tu.tu_cerrs++;
+               goto tus_get;
+
+       case TUS_GET:
+               if (MRSP)
+                       /* 
+                        * The checksum has already been calculated and
+                        * verified in the pseudo DMA routine
+                        */
+                       goto tus_get;
+
+       case TUS_GETC:
+               /* got entire packet */
+               if (tudata.pk_chksum !=
+                   tuchk(*((short *)&tudata), (u_short *)
+                    (tudata.pk_flag == TUF_DATA ? 
+                    (u_short *) tu.tu_addr : (u_short *)&tudata.pk_op),
+                    (int)tudata.pk_mcount))
+                       tu.tu_cerrs++;
+tus_get:
+               if (tudata.pk_flag == TUF_DATA) {
+                       /* data packet, advance to next */
+                       tu.tu_addr += tudata.pk_mcount;
+                       tu.tu_count -= tudata.pk_mcount;
+                       tu.tu_state = TUS_GETH;
+                       tu.tu_rbptr = (u_char *)&tudata; /* next packet */
+                       tu.tu_rcnt = 2;
+               } else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
+                       /* end packet, idle and reenable transmitter */
+                       tu.tu_state = TUS_IDLE;
+                       tu.tu_flag = 0;
+                       mtpr(CSTS, IE);
+                       printd("ON ");
+                       if ((bp = tutab.b_actf) == NULL) {
+                               printf("tu%d: no bp, active %d\n",
+                                       tudata.pk_unit, tutab.b_active);
+                               tustart();
+                               return;
+                       }
+                       if (tudata.pk_mod > 1) {        /* hard error */
+                               bp->b_flags |= B_ERROR;
+                               tu.tu_herrs++;
+                               printf("tu%d: hard error bn%d,", 
+                                       minor(bp->b_dev)&DNUM, bp->b_blkno);
+                               printf("  pk_mod %o\n", tudata.pk_mod&0377);
+                       } else if (tudata.pk_mod != 0)  /* soft error */
+                               tu.tu_serrs++;
+                       tutab.b_active = NULL;
+                       tutab.b_actf = bp->av_forw;
+                       bp->b_resid = tu.tu_count;
+                       if ((bp->b_flags&B_READ) == 0)
+                               tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
+                       iodone(bp);
+                       tustart();
+               } else {
+                       /*
+                        * Neither data nor end: data was lost
+                        * somehow, restart the transfer
+                        */
+                       mtpr(CSRS, 0);          /* flush the rest */
+                       tu_restart();
+                       tu.tu_serrs++;
+               }
+               break;
+
+       case TUS_IDLE:
+       case TUS_INIT1:
+               break;
+
+       default:
+bad:
+               if (c == TUF_INITF) {
+                       printf("tu%d protocol error, state=", 
+                                                       (int)tudata.pk_unit);
+                       printstate(tu.tu_state);
+                       printf(", op=%x, cnt=%d, block=%d\n",
+                           tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
+                       tutab.b_active = NULL;
+                       if (bp = tutab.b_actf) {
+                               bp->b_flags |= B_ERROR;
+                               tutab.b_actf = bp->av_forw;
+                               if ((bp->b_flags&B_READ) == 0)
+                                       tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
+                               iodone(bp);
+                       }
+                       tu.tu_state = TUS_INIT1;
+               } else {
+                       printf("tu%d: receive state error, state=",
+                                               (int)tudata.pk_unit);
+                       printstate(tu.tu_state);
+                       printf(", byte=%x\n", c & 0xff);
+                       if (tutab.b_actf)
+                               tu_restart();
+                       else
+                               wakeup((caddr_t)&tu);
+               }
+       }
+}
+
+/*
+ * TU58 transmitter interrupt
+ */
+tuxintr()
+{
+
+top:
+       if (tu.tu_wcnt) {
+               /* still stuff to send, send one byte */
+               while ((mfpr(CSTS) & READY) == 0)
+                       ;
+               mtpr(CSTD, *tu.tu_wbptr++);
+               tu.tu_wcnt--;
+               return;
+       }
+
+       /*
+        * Last message byte was sent out.
+        * Switch on state of transfer.
+        */
+       if (tudebug) {
+               printf("tuxintr: state=");
+               printstate(tu.tu_state);
+       }
+       switch(tu.tu_state) {
+
+       /*
+        * Two nulls have been sent, remove break, and send inits
+        */
+       case TUS_INIT1: 
+               mtpr(CSTS, IE);
+               printd("ON2 ");
+               tu.tu_state = TUS_INIT2;
+               tu.tu_wbptr = tuinit;
+               tu.tu_wcnt = sizeof (tuinit);
+               goto top;
+
+       /*
+        * Inits have been sent, wait for a continue msg.
+        */
+       case TUS_INIT2: 
+               (void) mfpr(CSRD);
+               mtpr(CSRS, IE);
+               tu.tu_flag = 1;
+               break;
+
+       /*
+        * Read cmd packet sent, get ready for data
+        */
+       case TUS_SENDR:
+               tu.tu_state = TUS_GETH;
+               tu.tu_rbptr = (u_char *)&tudata;
+               tu.tu_rcnt = 2;
+               tu.tu_flag = 1;
+               mtpr(CSTS, 0);  /* disable transmitter interrupts */
+               printd("OFF ");
+               break;
+
+       /*
+        * Write cmd packet sent, wait for continue
+        */
+       case TUS_SENDW: 
+               tu.tu_state = TUS_WAIT;
+               tu.tu_flag = 1;
+               if ((mfpr(CSRS)&IE) == 0) {
+                       printf("NO IE\n");
+                       mtpr(CSRS, IE);
+               }
+               break;
+
+       /*
+        * Header sent, send data.
+        */
+       case TUS_SENDH:
+               tu.tu_state = TUS_SENDD;
+               tu.tu_wbptr = (u_char *)tu.tu_addr;
+               tu.tu_wcnt = tudata.pk_mcount;
+               goto top;
+
+       /*
+        * Data sent, follow with checksum.
+        */
+       case TUS_SENDD: 
+               tu.tu_state = TUS_SENDC;
+               tu.tu_wbptr = (u_char *)&tudata.pk_chksum;
+               tu.tu_wcnt = sizeof tudata.pk_chksum;
+               goto top;
+
+       /* 
+        * Checksum sent, wait for continue.
+        */
+       case TUS_SENDC:
+               /*
+                * Updata buffer address and count.
+                */
+               tu.tu_addr += tudata.pk_mcount;
+               tu.tu_count -= tudata.pk_mcount;
+               if (tu.tu_count) {
+                       tu.tu_state = TUS_WAIT;
+                       tu.tu_flag = 1;
+                       break;
+               }
+
+               /*
+                * End of transmission, get ready for end packet.
+                */
+               tu.tu_state = TUS_GET;
+               tu.tu_rbptr = (u_char *)&tudata;
+               tu.tu_rcnt = sizeof (tudata);
+               tu.tu_flag = 1;
+               mtpr(CSTS, 0);
+               printd("OFF2 ");
+               break;
+
+       /*
+        * Random interrupt, probably from MRSP ACK
+        */
+       case TUS_IDLE:
+
+       default:
+               break;
+
+       }
+       if (tudebug) {
+               printd("  new tu_state=");
+               printstate(tu.tu_state);
+       }
+}
+
+/*
+ * Compute checksum TU58 fashion
+ */
+#ifdef lint
+tuchk(word, cp, n)
+       register word;
+       register unsigned short *cp;
+       int n;
+{
+       register int c = n >> 1;
+       register long temp;
+
+       do {
+               temp = *cp++;   /* temp, only because vax cc won't *r++ */
+               word += temp;
+       } while (--c > 0);
+       if (n & 1)
+               word += *(unsigned char *)cp;
+       while (word & 0xffff0000)
+               word = (word & 0xffff) + ((word >> 16) & 0xffff);
+       return (word);
+}
+#else
+tuchk(word0, wp, n)
+       register int word0;     /* r11 */
+       register char *wp;      /* r10 */
+       register int n;         /* r9 */
+{
+       asm("loop:");
+       asm("   addw2   (r10)+,r11");   /* add a word to sum */
+       asm("   adwc    $0,r11");       /* add in carry, end-around */
+       asm("   acbl    $2,$-2,r9,loop");       /* done yet? */
+       asm("   blbc    r9,ok");        /* odd byte count? */
+       asm("   movzbw  (r10),r10");    /* yes, get last byte */
+       asm("   addw2   r10,r11");      /* add it in */
+       asm("   adwc    $0,r11");       /* and the carry */
+       asm("ok:");
+       asm("   movl    r11,r0");       /* return sum */
+}
+#endif
+
+tuwatch()
+{
+       register int s;
+       register struct buf *bp;
+
+       if (tutimer == 0)
+               return;
+
+       if (tu.tu_flag == 0) {          /* if no read in progress - skip */
+               timeout(tuwatch, (caddr_t)0, hz);
+               return;
+       }
+       if (tu.tu_flag++ <= 40) {
+               timeout(tuwatch, (caddr_t)0, hz);
+               return;
+       }
+       printf("tu%d: read stalled\n", tudata.pk_unit);
+#ifdef TUDEBUG
+       printf("%X %X %X %X %X %X %X %X\n", tu.tu_rbptr, tu.tu_rcnt,
+               tu.tu_wbptr, tu.tu_wcnt, tu.tu_state, tu.tu_flag,
+               tu.tu_addr, tu.tu_count);
+#endif
+       s = splx(TUIPL);
+       tu.tu_flag = 0;
+       (void) mfpr(CSRD);
+       mtpr(CSRS, IE);         /* in case we were flushing */
+       mtpr(CSTS, IE);
+       tu.tu_state = TUS_IDLE;
+       if (!tutab.b_active) {
+               wakeup((caddr_t)&tu);
+               goto retry;
+       }
+       if (++tutab.b_errcnt <= 1) {
+               tustart();
+               goto retry;
+       }
+       if (bp = tutab.b_actf) {
+               bp->b_flags |= B_ERROR;
+               if ((bp->b_flags&B_READ) == 0)
+                       tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
+               iodone(bp);
+       }
+retry:
+       splx(s);
+       timeout(tuwatch, (caddr_t)0, hz);
+}
+
+tu_pee(cp)
+       char *cp;
+{
+       register int s;
+
+       s = splx(TUIPL);
+       if (++(*cp) > NTUQ)
+               sleep(cp, PRIBIO);
+       splx(s);
+}
+
+tu_vee(cp)
+       char *cp;
+{
+       register int s;
+
+       s = splx(TUIPL);
+       if (--(*cp) <= NTUQ)
+               wakeup(cp);
+       splx(s);
+}
+
+tu_restart()
+{
+       tureset();
+       timeout(tustart, (caddr_t)0, hz * 3);
+}
+
+#endif
diff --git a/usr/src/sys/vaxuba/rk.c b/usr/src/sys/vaxuba/rk.c
new file mode 100644 (file)
index 0000000..45c258c
--- /dev/null
@@ -0,0 +1,790 @@
+/*     rk.c    6.2     83/10/11        */
+
+#include "rk.h"
+#if NHK > 0
+int    rkpip;          /* DEBUG */
+int    rknosval;       /* DEBUG */
+#ifdef RKDEBUG
+int    rkdebug;
+#endif
+#ifdef RKBDEBUG
+int    rkbdebug;
+#endif
+/*
+ * RK611/RK0[67] disk driver
+ *
+ * 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
+ */
+#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/map.h"
+#include "../h/vm.h"
+#include "../h/dk.h"
+#include "../h/cmap.h"
+#include "../h/dkbad.h"
+#include "../h/uio.h"
+#include "../h/kernel.h"
+
+#include "../vax/cpu.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxuba/rkreg.h"
+
+struct rk_softc {
+       int     sc_softas;
+       int     sc_ndrive;
+       int     sc_wticks;
+       int     sc_recal;
+} rk_softc[NHK];
+
+/* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
+struct size {
+       daddr_t nblocks;
+       int     cyloff;
+} rk7_sizes[8] ={
+       15884,  0,              /* A=cyl 0 thru 240 */
+       10032,  241,            /* B=cyl 241 thru 392 */
+       53790,  0,              /* C=cyl 0 thru 814 */
+       0,      0,
+       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 */
+
+short  rktypes[] = { RK_CDT, 0 };
+
+int    rkprobe(), rkslave(), rkattach(), rkdgo(), rkintr();
+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];
+struct dkbad rkbad[NRK];
+struct buf brkbuf[NRK];
+
+struct rkst {
+       short   nsect;
+       short   ntrak;
+       short   nspc;
+       short   ncyl;
+       struct  size *sizes;
+} rkst[] = {
+       NRKSECT, NRKTRK, NRKSECT*NRKTRK,        NRK7CYL,        rk7_sizes,
+       NRKSECT, NRKTRK, NRKSECT*NRKTRK,        NRK6CYL,        rk6_sizes,
+};
+
+u_char         rk_offset[16] =
+  { 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];
+
+#define        b_cylin b_resid
+
+#ifdef INTRLVE
+daddr_t        dkblock();
+#endif
+
+int    rkwstart, rkwatch();
+
+rkprobe(reg)
+       caddr_t reg;
+{
+       register int 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;
+       return (sizeof (struct rkdevice));
+}
+
+rkslave(ui, reg)
+       struct uba_device *ui;
+       caddr_t reg;
+{
+       register struct rkdevice *rkaddr = (struct rkdevice *)reg;
+
+       ui->ui_type = 0;
+       rkaddr->rkcs1 = RK_CCLR;
+       rkaddr->rkcs2 = ui->ui_slave;
+       rkaddr->rkcs1 = RK_CDT|RK_DCLR|RK_GO;
+       rkwait(rkaddr);
+       DELAY(50);
+       if (rkaddr->rkcs2&RKCS2_NED || (rkaddr->rkds&RKDS_SVAL) == 0) {
+               rkaddr->rkcs1 = RK_CCLR;
+               return (0);
+       }
+       if (rkaddr->rkcs1&RK_CERR && rkaddr->rker&RKER_DTYE) {
+               ui->ui_type = 1;
+               rkaddr->rkcs1 = RK_CCLR;
+       }
+       return (1);
+}
+
+rkattach(ui)
+       register struct uba_device *ui;
+{
+
+       if (rkwstart == 0) {
+               timeout(rkwatch, (caddr_t)0, hz);
+               rkwstart++;
+       }
+       if (ui->ui_dk >= 0)
+               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;
+       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;
+{
+       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;
+       int s;
+
+       sz = (bp->b_bcount+511) >> 9;
+       unit = dkunit(bp);
+       if (unit >= NRK)
+               goto bad;
+       ui = rkdinfo[unit];
+       if (ui == 0 || ui->ui_alive == 0)
+               goto bad;
+       st = &rkst[ui->ui_type];
+       if (bp->b_blkno < 0 ||
+           (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
+               goto bad;
+       bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
+       s = spl5();
+       dp = &rkutab[ui->ui_unit];
+       disksort(dp, bp);
+       if (dp->b_active == 0) {
+               (void) rkustart(ui);
+               bp = &ui->ui_mi->um_tab;
+               if (bp->b_actf && bp->b_active == 0)
+                       (void) rkstart(ui->ui_mi);
+       }
+       splx(s);
+       return;
+
+bad:
+       bp->b_flags |= B_ERROR;
+       iodone(bp);
+       return;
+}
+
+rkustart(ui)
+       register struct uba_device *ui;
+{
+       register struct buf *bp, *dp;
+       register struct uba_ctlr *um;
+       register struct rkdevice *rkaddr;
+
+       if (ui == 0)
+               return;
+       dk_busy &= ~(1<<ui->ui_dk);
+       dp = &rkutab[ui->ui_unit];
+       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;
+               return;
+       }
+       if ((bp = dp->b_actf) == NULL)
+               return;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_CERR;
+       rkaddr->rkcs2 = ui->ui_slave;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
+       rkwait(rkaddr);
+       if ((rkaddr->rkds & RKDS_VV) == 0 || ui->ui_flags == 0) {
+               /* SHOULD WARN SYSTEM THAT THIS HAPPENED */
+               struct rkst *st = &rkst[ui->ui_type];
+               struct buf *bbp = &brkbuf[ui->ui_unit];
+
+               rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_PACK|RK_GO;
+               ui->ui_flags = 1;
+               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;
+               rkwait(rkaddr);
+       }
+       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;
+       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]++;
+       }
+       goto out;
+done:
+       if (dp->b_active != 2) {
+               dp->b_forw = NULL;
+               if (um->um_tab.b_actf == NULL)
+                       um->um_tab.b_actf = dp;
+               else
+                       um->um_tab.b_actl->b_forw = dp;
+               um->um_tab.b_actl = dp;
+               dp->b_active = 2;
+       }
+out:
+       return;
+}
+
+rkstart(um)
+       register struct uba_ctlr *um;
+{
+       register struct buf *bp, *dp;
+       register struct uba_device *ui;
+       register struct rkdevice *rkaddr;
+       struct rkst *st;
+       daddr_t bn;
+       int sn, tn, cmd;
+
+loop:
+       if ((dp = um->um_tab.b_actf) == NULL)
+               return;
+       if ((bp = dp->b_actf) == NULL) {
+               um->um_tab.b_actf = dp->b_forw;
+               goto loop;
+       }
+       um->um_tab.b_active++;
+       ui = rkdinfo[dkunit(bp)];
+       bn = dkblock(bp);
+       st = &rkst[ui->ui_type];
+       sn = bn%st->nspc;
+       tn = sn/st->nsect;
+       sn %= st->nsect;
+       rkaddr = (struct rkdevice *)ui->ui_addr;
+retry:
+       rkaddr->rkcs1 = RK_CCLR;
+       rkaddr->rkcs2 = ui->ui_slave;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|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)
+               cmd = rktypes[ui->ui_type]|RK_IE|RK_READ|RK_GO;
+       else
+               cmd = rktypes[ui->ui_type]|RK_IE|RK_WRITE|RK_GO;
+       um->um_cmd = cmd;
+       (void) ubago(ui);
+}
+
+rkdgo(um)
+       register struct uba_ctlr *um;
+{
+       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);
+}
+
+rkintr(rk11)
+       int rk11;
+{
+       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;
+
+       sc->sc_wticks = 0;
+       sc->sc_softas = 0;
+       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);
+               if (bp->b_flags&B_BAD)
+                       if (rkecc(ui, CONT))
+                               return;
+               if (rkaddr->rkcs1 & RK_CERR) {
+                       int recal;
+                       u_short ds = rkaddr->rkds;
+                       u_short cs2 = rkaddr->rkcs2;
+                       u_short er = rkaddr->rker;
+#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;
+                               sc->sc_recal = 0;
+                       } else if (er & RKER_BSE) {
+                               if (rkecc(ui, BSE))
+                                       return;
+                               else
+                                       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;
+                       if (ds&RKDS_DROT || er&(RKER_OPI|RKER_SKI|RKER_UNS) ||
+                           (um->um_tab.b_errcnt&07) == 4)
+                               recal = 1;
+                       rkaddr->rkcs1 = RK_CCLR;
+                       rkaddr->rkcs2 = ui->ui_slave;
+                       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
+                       rkwait(rkaddr);
+                       if (recal && um->um_tab.b_active == 0) {
+                               rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_IE|RK_RECAL|RK_GO;
+                               rkcyl[ui->ui_unit] = -1;
+                               sc->sc_recal = 0;
+                               goto nextrecal;
+                       }
+               }
+retry:
+               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;
+                       break;
+               }
+               ubadone(um);
+               if (um->um_tab.b_active) {
+                       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 = -rkaddr->rkwc * sizeof(short);
+                       iodone(bp);
+                       if (dp->b_actf)
+                               rkustart(ui);
+               }
+               as &= ~(1<<ui->ui_slave);
+       }
+       for (unit = 0; as; as >>= 1, unit++)
+               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)
+               rkstart(um);
+       if (((rkaddr->rkcs1) & RK_IE) == 0)
+               rkaddr->rkcs1 = RK_IE;
+}
+
+rkwait(addr)
+       register struct rkdevice *addr;
+{
+
+       while ((addr->rkcs1 & RK_CRDY) == 0)
+               ;
+}
+
+rkread(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRK)
+               return (ENXIO);
+       return (physio(rkstrategy, &rrkbuf[unit], dev, B_READ, minphys, uio));
+}
+
+rkwrite(dev, uio)
+       dev_t dev;
+       struct uio *uio;
+{
+       register int unit = minor(dev) >> 3;
+
+       if (unit >= NRK)
+               return (ENXIO);
+       return (physio(rkstrategy, &rrkbuf[unit], dev, B_WRITE, minphys, uio));
+}
+
+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 uba_ctlr *um = ui->ui_mi;
+       register struct rkst *st;
+       struct uba_regs *ubp = ui->ui_hd->uh_uba;
+       caddr_t addr;
+       int reg, npf, o, cmd, ubaddr;
+       int bn, cn, tn, sn;
+
+       if (flag == CONT)
+               npf = bp->b_error;
+       else
+               npf = btop((rk->rkwc * sizeof(short)) + bp->b_bcount);
+       reg = btop(um->um_ubinfo&0x3ffff) + npf;
+       o = (int)bp->b_un.b_addr & PGOFSET;
+       bn = dkblock(bp);
+       st = &rkst[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);
+       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;
+               }
+
+       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)
+                       return (0);
+               break;
+       }
+       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;
+       ubaddr = (int)ptob(reg) + o;
+       rk->rkba = ubaddr;
+       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;
+       um->um_tab.b_active = 2;        /* continuing */
+       um->um_tab.b_errcnt = 0;        /* error has been corrected */
+       return (1);
+}
+
+rkreset(uban)
+       int uban;
+{
+       register struct uba_ctlr *um;
+       register struct uba_device *ui;
+       register rk11, unit;
+
+       for (rk11 = 0; rk11 < NHK; rk11++) {
+               if ((um = rkminfo[rk11]) == 0 || um->um_ubanum != uban ||
+                   um->um_alive == 0)
+                       continue;
+               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;
+               rk_softc[um->um_ctlr].sc_wticks = 0;
+               if (um->um_ubinfo) {
+                       printf("<%d>", (um->um_ubinfo>>28)&0xf);
+                       um->um_ubinfo = 0;
+               }
+               for (unit = 0; unit < NRK; unit++) {
+                       if ((ui = rkdinfo[unit]) == 0)
+                               continue;
+                       if (ui->ui_alive == 0 || ui->ui_mi != um)
+                               continue;
+                       rkutab[unit].b_active = 0;
+                       (void) rkustart(ui);
+               }
+               (void) rkstart(um);
+       }
+}
+
+rkwatch()
+{
+       register struct uba_ctlr *um;
+       register rk11, unit;
+       register struct rk_softc *sc;
+
+       timeout(rkwatch, (caddr_t)0, hz);
+       for (rk11 = 0; rk11 < NHK; rk11++) {
+               um = rkminfo[rk11];
+               if (um == 0 || um->um_alive == 0)
+                       continue;
+               sc = &rk_softc[rk11];
+               if (um->um_tab.b_active == 0) {
+                       for (unit = 0; unit < NRK; unit++)
+                               if (rkutab[unit].b_active &&
+                                   rkdinfo[unit]->ui_mi == um)
+                                       goto active;
+                       sc->sc_wticks = 0;
+                       continue;
+               }
+active:
+               sc->sc_wticks++;
+               if (sc->sc_wticks >= 20) {
+                       sc->sc_wticks = 0;
+                       printf("hk%d: lost interrupt\n", rk11);
+                       ubareset(um->um_ubanum);
+               }
+       }
+}
+
+#define        DBSIZE  20
+
+rkdump(dev)
+       dev_t dev;
+{
+       struct rkdevice *rkaddr;
+       char *start;
+       int num, blk, unit;
+       struct size *sizes;
+       register struct uba_regs *uba;
+       register struct uba_device *ui;
+       register short *rp;
+       struct rkst *st;
+
+       unit = minor(dev) >> 3;
+       if (unit >= NRK)
+               return (ENXIO);
+#define        phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
+       ui = phys(struct uba_device *, rkdinfo[unit]);
+       if (ui->ui_alive == 0)
+               return (ENXIO);
+       uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
+       ubainit(uba);
+       rkaddr = (struct rkdevice *)ui->ui_physaddr;
+       num = maxfree;
+       start = 0;
+       rkaddr->rkcs1 = RK_CCLR;
+       rkaddr->rkcs2 = unit;
+       rkaddr->rkcs1 = rktypes[ui->ui_type]|RK_DCLR|RK_GO;
+       rkwait(rkaddr);
+       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);
+       if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
+               return (EINVAL);
+       while (num > 0) {
+               register struct pte *io;
+               register int i;
+               int cn, sn, tn;
+               daddr_t bn;
+
+               blk = num > DBSIZE ? DBSIZE : num;
+               io = uba->uba_map;
+               for (i = 0; i < blk; i++)
+                       *(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;
+               sn = bn%st->nspc;
+               tn = sn/st->nsect;
+               sn = sn%st->nsect;
+               rkaddr->rkcyl = cn;
+               rp = (short *) &rkaddr->rkda;
+               *rp = (tn << 8) + sn;
+               *--rp = 0;
+               *--rp = -blk*NBPG / sizeof (short);
+               *--rp = rktypes[ui->ui_type]|RK_GO|RK_WRITE;
+               rkwait(rkaddr);
+               if (rkaddr->rkcs1 & RK_CERR)
+                       return (EIO);
+               start += blk*NBPG;
+               num -= blk;
+       }
+       return (0);
+}
+rksize(dev)
+       dev_t dev;
+{
+       int unit = minor(dev) >> 3;
+       struct uba_device *ui;
+       struct rkst *st;
+
+       if (unit >= NRK || (ui = rkdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (-1);
+       st = &rkst[ui->ui_type];
+       return (st->sizes[minor(dev) & 07].nblocks);
+}
+#endif