first understanding
authorSam Leffler <sam@ucbvax.Berkeley.EDU>
Tue, 22 Feb 1983 07:13:24 +0000 (23:13 -0800)
committerSam Leffler <sam@ucbvax.Berkeley.EDU>
Tue, 22 Feb 1983 07:13:24 +0000 (23:13 -0800)
SCCS-vsn: sys/vax/uba/rx.c 4.2

usr/src/sys/vax/uba/rx.c

index 02fb56f..4fca3ab 100644 (file)
@@ -1,26 +1,22 @@
-/*     rx.c    4.1     83/02/08        */
+/*     rx.c    4.2     83/02/21        */
 
 #include "rx.h"
 #if NFX > 0
 /*
  * RX02 floppy disk device driver
  *
 
 #include "rx.h"
 #if NFX > 0
 /*
  * RX02 floppy disk device driver
  *
- * From drivers by Richard Wales and Bill Shannon
- * (untested, or even compiled)
+ * WARNING, UNTESTED
  */
  */
+#include "../machine/pte.h"
+
 #include "../h/param.h"
 #include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/cpu.h"
 #include "../h/buf.h"
 #include "../h/buf.h"
+#include "../h/systm.h"
 #include "../h/conf.h"
 #include "../h/conf.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/map.h"
-#include "../h/pte.h"
-#include "../h/clist.h"
-#include "../h/tty.h"
-#include "../h/file.h"
+#include "../h/kernel.h"
+#include "../h/uio.h"
 
 
+#include "../vax/cpu.h"
 #include "../vax/nexus.h"
 #include "../vaxuba/ubavar.h"
 #include "../vaxuba/ubareg.h"
 #include "../vax/nexus.h"
 #include "../vaxuba/ubavar.h"
 #include "../vaxuba/ubareg.h"
@@ -36,18 +32,18 @@ struct      rx_ctlr {
 #define        RXS_FORMAT      5       /* format started */
 #define        RXS_RDSTAT      6       /* status read started */
 #define        RXS_RDERR       7       /* error read started */
 #define        RXS_FORMAT      5       /* format started */
 #define        RXS_RDSTAT      6       /* status read started */
 #define        RXS_RDERR       7       /* error read started */
+#define RXS_IDLE       8       /* device is idle */
        u_short rxc_rxcs;       /* extended error status */
        u_short rxc_rxdb;
        u_short rxc_rxxt[4];
        u_short rxc_rxcs;       /* extended error status */
        u_short rxc_rxdb;
        u_short rxc_rxxt[4];
-       u_short rxc_tocnt;      /* for watchdog routine */
-#define        RX_MAXTIMEOUT   20      /* # seconds to wait before giving up */
+#define        RX_MAXTIMEOUT   30      /* # seconds to wait before giving up */
 } rx_ctlr[NFX];
 struct buf     rrxbuf[NFX];    /* buffer for I/O */
 struct buf     erxbuf[NFX];    /* buffer for reading error status */
 
 /* per-drive data */
 struct rx_softc {
 } rx_ctlr[NFX];
 struct buf     rrxbuf[NFX];    /* buffer for I/O */
 struct buf     erxbuf[NFX];    /* buffer for reading error status */
 
 /* per-drive data */
 struct rx_softc {
-       int sc_flags;           /* drive status flags */
+       int     sc_flags;       /* drive status flags */
 #define        RXF_DBLDEN      0x01    /* use double density */
 #define        RXF_DIRECT      0x02    /* use direct sector mapping */
 #define        RXF_TRKZERO     0x04    /* start mapping on track 0 */
 #define        RXF_DBLDEN      0x01    /* use double density */
 #define        RXF_DIRECT      0x02    /* use direct sector mapping */
 #define        RXF_TRKZERO     0x04    /* start mapping on track 0 */
@@ -55,12 +51,16 @@ struct rx_softc {
 #define        RXF_OPEN        0x10    /* open */
 #define        RXF_DDMK        0x20    /* deleted-data mark detected */
 #define        RXF_USEWDDS     0x40    /* write deleted-data sector */
 #define        RXF_OPEN        0x10    /* open */
 #define        RXF_DDMK        0x20    /* deleted-data mark detected */
 #define        RXF_USEWDDS     0x40    /* write deleted-data sector */
-       int sc_csbits;          /* constant bits for CS register */
-       int sc_lsector;         /* logical sector number for I/O */
-       int sc_psector;         /* physical sector number for I/O */
-       int sc_ptrack;          /* physical track number for I/O */
+       int     sc_csbits;      /* constant bits for CS register */
+       int     sc_tocnt;       /* for watchdog routine */
 } rx_softc[NRX];
 
 } rx_softc[NRX];
 
+struct rxerr {
+       short   rxcs;
+       short   rxdb;
+       short   rxxt[4];        /* error code dump from controller */
+} rxerr[NFX];
+
 struct uba_device *rxdinfo[NRX];
 struct uba_ctlr *rxminfo[NFX];
 int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr();
 struct uba_device *rxdinfo[NRX];
 struct uba_ctlr *rxminfo[NFX];
 int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr();
@@ -72,30 +72,27 @@ struct uba_driver fxdriver =
 int    rxwstart;
 #define        RXUNIT(dev)     (minor(dev)>>4)
 
 int    rxwstart;
 #define        RXUNIT(dev)     (minor(dev)>>4)
 
-/* a drive's letter name, based on density and sector mapping */
-#define        DEVNAME(dev)    ('a'+((dev)&DEVTYPE))
-#define        UNITNAME(unit)  DEVNAME(sc->sc_flags)
-
 /* constants related to floppy data capacity */
 #define        RXSECS  2002                            /* # sectors on a floppy */
 /* constants related to floppy data capacity */
 #define        RXSECS  2002                            /* # sectors on a floppy */
-#define        DDSTATE (sc->sc_flags&DBLDEN)           /* double-density device? */
+#define        DDSTATE (sc->sc_flags&RXF_DBLDEN)
 #define        NBPS    (DDSTATE ? 256 : 128)           /* # bytes per sector */
 #define        NWPS    (DDSTATE ? 128 : 64)            /* # words per sector */
 #define        RXSIZE  (DDSTATE ? 512512 : 256256)     /* # bytes per disk */
 #define        SECSHFT (DDSTATE ? 8 : 7)               /* # bits to shift for sctr # */
 #define        SECMASK (DDSTATE ? 0xff : 0x7f)         /* shifted-out bits of offset */
 
 #define        NBPS    (DDSTATE ? 256 : 128)           /* # bytes per sector */
 #define        NWPS    (DDSTATE ? 128 : 64)            /* # words per sector */
 #define        RXSIZE  (DDSTATE ? 512512 : 256256)     /* # bytes per disk */
 #define        SECSHFT (DDSTATE ? 8 : 7)               /* # bits to shift for sctr # */
 #define        SECMASK (DDSTATE ? 0xff : 0x7f)         /* shifted-out bits of offset */
 
-#define        B_CTRL  0x80000000              /* control (format) request */
+#define        B_CTRL  0x80000000                      /* control (format) request */
 
 /*ARGSUSED*/
 rxprobe (reg)
        caddr_t reg;
 {
 
 /*ARGSUSED*/
 rxprobe (reg)
        caddr_t reg;
 {
-       register int br, cvec;          /* value-result */
+       register int br, cvec;                  /* value-result */
        struct rxdevice *rxaddr = (struct rxdevice *)reg;
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
        struct rxdevice *rxaddr = (struct rxdevice *)reg;
 
 #ifdef lint
        br = 0; cvec = br; br = cvec;
+       rxintr(0);
 #endif lint
        rxaddr->rxcs = RX_INTR;
        DELAY(10);
 #endif lint
        rxaddr->rxcs = RX_INTR;
        DELAY(10);
@@ -128,19 +125,17 @@ rxopen(dev, flag)
        register struct rx_softc *sc;
        register struct uba_device *ui;
 
        register struct rx_softc *sc;
        register struct uba_device *ui;
 
-       if (unit >= NRX || (minor(dev) & (0xf^DEVTYPE)) ||
-           (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0) {
-               u.u_error = ENXIO;
-               return;
-       }
+       if (unit >= NRX || (minor(dev) & 0x8) ||
+           (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0)
+               return (ENXIO);
        sc = &rx_softc[unit];
        sc = &rx_softc[unit];
-       if (sc->sc_flags & RXF_OPEN) {
-               u.u_error = EBUSY;
-               return;
-       }
-       sc->sc_flags = RXF_OPEN | (minor(dev) & DEVTYPE);
-       sc->sc_csbits |= (ui->ui_slave == 1 ? RX_DRV1 : RX_DRV0) |
-                ((minor(dev) & DBLDEN) ? RX_DDEN : RX_SDEN) | RX_INTR;
+       if (sc->sc_flags & RXF_OPEN)
+               return (EBUSY);
+       sc->sc_flags = RXF_OPEN | (minor(dev) & RXF_DEVTYPE);
+       sc->sc_csbits = RX_INTR;
+       sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1;
+       sc->sc_csbits |= minor(dev) & RXF_DBLDEN ? RX_DDEN : RX_SDEN;
+       return (0);
 }
 
 /*ARGSUSED1*/
 }
 
 /*ARGSUSED1*/
@@ -160,6 +155,7 @@ rxstrategy(bp)
        struct uba_device *ui;
        register struct rx_softc *sc;
        register struct uba_ctlr *um;
        struct uba_device *ui;
        register struct rx_softc *sc;
        register struct uba_ctlr *um;
+       int s;
 
        ui = rxdinfo[RXUNIT(bp->b_dev)];
        if (ui == 0 || ui->ui_alive == 0) {
 
        ui = rxdinfo[RXUNIT(bp->b_dev)];
        if (ui == 0 || ui->ui_alive == 0) {
@@ -167,17 +163,17 @@ rxstrategy(bp)
                iodone(bp);
                return;
        }
                iodone(bp);
                return;
        }
-       s = spl5();
        um = ui->ui_mi;
        bp->b_actf = NULL;
        um = ui->ui_mi;
        bp->b_actf = NULL;
+       s = spl5();
        if (um->um_tab.b_actf->b_actf == NULL)
                um->um_tab.b_actf->b_actf = bp;
        else
                um->um_tab.b_actf->b_actl->b_forw = bp;
        um->um_tab.b_actf->b_actl = bp;
        bp = um->um_tab.b_actf;
        if (um->um_tab.b_actf->b_actf == NULL)
                um->um_tab.b_actf->b_actf = bp;
        else
                um->um_tab.b_actf->b_actl->b_forw = bp;
        um->um_tab.b_actf->b_actl = bp;
        bp = um->um_tab.b_actf;
-       if (bp->b_actf && bp->b_active == 0)
-               (void) rxstart(um);
+       if (!um->um_tab.b_active && bp->b_actf)
+               rxstart(um);
        splx(s);
 }
 
        splx(s);
 }
 
@@ -205,13 +201,16 @@ rxstrategy(bp)
  * leaving), even when the rest of the disk is interleaved.  (This is
  * still compatible with DEC RT-11, which does not use track 0 at all.)
  */
  * leaving), even when the rest of the disk is interleaved.  (This is
  * still compatible with DEC RT-11, which does not use track 0 at all.)
  */
-rxmap(sc)
-       register struct rx_softc *sc;
+rxmap(bp, psector, ptrack)
+       struct buf *bp;
+       int *psector, *ptrack;
 {
        register int lt, ls, ptoff;
 {
        register int lt, ls, ptoff;
+       struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
 
 
-       lt = sc->sc_lsector / 26;
-       ls = sc->sc_lsector % 26;
+       ls = bp->b_blkno * (NBPS / DEV_BLKSIZE);
+       lt = ls / 26;
+       ls %= 26;
        /*
         * The "physical track offset" (ptoff) takes the
         * starting physical track (0 or 1) and the desired
        /*
         * The "physical track offset" (ptoff) takes the
         * starting physical track (0 or 1) and the desired
@@ -219,14 +218,14 @@ rxmap(sc)
         * then interleaving is not performed.
         */
        ptoff = 0;
         * then interleaving is not performed.
         */
        ptoff = 0;
-       if (sc->sc_flags&DIRECT)
-               ptoff += 77;
-       if (sc->sc_flags&TRKZERO)
+       if (sc->sc_flags&RXF_DIRECT)
+               ptoff = 77;
+       if (sc->sc_flags&RXF_TRKZERO)
                ptoff++;
        if (lt + ptoff < 77)
                ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
                ptoff++;
        if (lt + ptoff < 77)
                ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
-       sc->sc_ptrack = (lt + ptoff) % 77;
-       sc->sc_psector = ls + 1;
+       *ptrack = (lt + ptoff) % 77;
+       *psector = ls + 1;
 }
 
 rxstart(um)
 }
 
 rxstart(um)
@@ -236,36 +235,37 @@ rxstart(um)
        register struct rx_ctlr *rxc;
        register struct rx_softc *sc;
        struct buf *bp;
        register struct rx_ctlr *rxc;
        register struct rx_softc *sc;
        struct buf *bp;
-       int unit;
+       int unit, sector, track;
 
 
-       if ((bp = um->um_tab.b_actf->b_actf) == NULL)
+       if (um->um_tab.b_active || (bp = um->um_tab.b_actf->b_actf) == NULL)
                return;
                return;
+       um->um_tab.b_active++;
        unit = RXUNIT(bp->b_dev);
        sc = &rx_softc[unit];
        unit = RXUNIT(bp->b_dev);
        sc = &rx_softc[unit];
-       sc->sc_tocnt = 0;
        rxaddr = (struct rxdevice *)um->um_addr;
        rxc = &rx_ctlr[um->um_ctlr];
        rxaddr = (struct rxdevice *)um->um_addr;
        rxc = &rx_ctlr[um->um_ctlr];
-       if (bp->b_flags&B_CTRL) {               /* format */
+       rxtimo(bp->b_dev);                              /* start watchdog */
+       if (bp->b_flags&B_CTRL) {                       /* format */
                rxc->rxc_state = RXS_FORMAT;
                rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
                rxc->rxc_state = RXS_FORMAT;
                rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                rxaddr->rxdb = 'I';
                return;
        }
                        ;
                rxaddr->rxdb = 'I';
                return;
        }
-       if (bp->b_flags&B_READ) {               /* read */
+       if (bp->b_flags&B_READ) {                       /* read */
+               rxmap(bp, &sector, &track);
                rxc->rxc_state = RXS_READ;
                rxaddr->rxcs = RX_READ | sc->sc_csbits;
                rxc->rxc_state = RXS_READ;
                rxaddr->rxcs = RX_READ | sc->sc_csbits;
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                        ;
-               rxaddr->rxdb = sc->sc_psector;
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               rxaddr->rxdb = (u_short)sector;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                        ;
-               rxaddr->rxdb = sc->sc_ptrack;
+               rxaddr->rxdb = (u_short)track;
                return;
        }
                return;
        }
-       /* write */
-       rxc->rxc_state = RXS_FILL;
+       rxc->rxc_state = RXS_FILL;                      /* write */
        um->um_cmd = RX_FILL;
        (void) ubago(rxdinfo[unit]);
 }
        um->um_cmd = RX_FILL;
        (void) ubago(rxdinfo[unit]);
 }
@@ -280,57 +280,47 @@ rxdgo(um)
        struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
 
        bp = um->um_tab.b_actf;
        struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
 
        bp = um->um_tab.b_actf;
-       rx_softc[RXUNIT(bp->b_actf->b_dev)].sc_tocnt = 0;
-       bp->b_active++;
+       sc->sc_tocnt = 0;
        if (rxc->rxc_state != RXS_RDERR) {
        if (rxc->rxc_state != RXS_RDERR) {
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                        ;
-               rxaddr->rxdb = bp->b_count >> 1;
+               rxaddr->rxdb = bp->b_bcount >> 1;
        }
        }
-       while ((rxaddr->rxcs&RXTREQ) == 0)
+       while ((rxaddr->rxcs&RX_TREQ) == 0)
                ;
                ;
-       rxaddr->rxdb = ubinfo & 0xffff;
+       rxaddr->rxdb = ubinfo;
        rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
 }
 
        rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
 }
 
-rxintr(ctlr)
-       int ctlr;
+rxintr(dev)
+       dev_t dev;
 {
 {
-       struct uba_ctlr *um = rxminfo[ctlr];
-       register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr;
-       register struct buf *bp = &rrxbuf[ctlr];
-       int unit = RXUNIT(bp->b_dev);
+       int unit = RXUNIT(dev), sector, track;
+       struct uba_ctlr *um = rxminfo[unit];
+       register struct rxdevice *rxaddr;
+       register struct buf *bp;
        register struct rx_softc *sc = &rx_softc[unit];
        struct uba_device *ui = rxdinfo[unit];
        register struct rx_softc *sc = &rx_softc[unit];
        struct uba_device *ui = rxdinfo[unit];
-       struct rxerr *er = &rxerr[ctlr];
-       register struct rx_ctlr *rxc = &rx_ctlr[ctlr];
-       register struct rxdeferr *ed;
-
-       if (um->um_tab.b_actf->b_active) {
-               bp = um->um_tab.b_actf->b_actf;
-               if ((rxaddr->rxcs & RXERR) &&
-                   rxc->rxc_state != RXS_RDSTAT && rxc->rxc_state != RXS_RDERR)
-                       bp->b_flags |= B_ERROR;
-               ubadone(um);
-               um->um_tab.b_actf->b_active = 0;
-               um->um_tab.b_actf->b_actf = bp->b_forw;
-               bp->b_active = 0;
-               bp->b_errcnt = 0;
-               bp->b_resid = 0;
-               iodone(bp);
-       }
-       if (um->um_tab.b_actf->b_actf == 0) {
-               sc->sc_iostate &= ~VAS_DMA;
-               if (sc->sc_iostate&VAS_WANT) {
-                       sc->sc_iostate &= ~VAS_WANT;
-                       wakeup((caddr_t)&sc->sc_iostate);
-               }
+       struct rxerr *er;
+       register struct rx_ctlr *rxc;
+
+       sc->sc_tocnt = 0;
+       if (!um->um_tab.b_active)
                return;
                return;
-       }
-       if (um->um_tab.b_actf->b_active == 0)
-               rxstart(um);
+       rxaddr = (struct rxdevice *)um->um_addr;
+       rxc = &rx_ctlr[um->um_ctlr];
+       er = &rxerr[um->um_ctlr];
+       bp = um->um_tab.b_actf->b_actf;
+       if ((rxaddr->rxcs & RX_ERR) &&
+           rxc->rxc_state != RXS_RDSTAT && rxc->rxc_state != RXS_RDERR)
+               goto error;
        switch (rxc->rxc_state) {
 
        switch (rxc->rxc_state) {
 
+       /*
+        * Incomplete commands.  Perform next step
+        * and return.  Note that b_active is set on
+        * entrance and, therefore, also on exit.
+        */
        case RXS_READ:
                if (rxaddr->rxdb & RXES_DDMARK)
                        sc->sc_flags |= RXF_DDMK;
        case RXS_READ:
                if (rxaddr->rxdb & RXES_DDMARK)
                        sc->sc_flags |= RXF_DDMK;
@@ -348,53 +338,48 @@ rxintr(ctlr)
                        sc->sc_flags &= ~RXF_USEWDDS;
                } else
                        rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
                        sc->sc_flags &= ~RXF_USEWDDS;
                } else
                        rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                        ;
-               rxaddr->rxdb = sc->sc_psector;
-               while ((rxaddr->rxcs&RXTREQ) == 0)
+               rxmap(bp, &sector, &track);
+               rxaddr->rxdb = sector;
+               while ((rxaddr->rxcs&RX_TREQ) == 0)
                        ;
                        ;
-               rxaddr->rxdb = sc->sc_ptrack;
+               rxaddr->rxdb = track;
                return;
 
                return;
 
-       case RXS_EMPTY:
-       case RXS_WRITE:
-       case RXS_FORMAT:
-               bp->b_resid = 0;
-               break;
-
+       /*
+        * Possibly completed command.
+        */
        case RXS_RDSTAT:
        case RXS_RDSTAT:
-               if (rxaddr->rxdb&RX_READY)
+               if (rxaddr->rxdb&RXES_READY)
                        goto rderr;
                bp->b_error = EBUSY;
                bp->b_flags |= B_ERROR;
                        goto rderr;
                bp->b_error = EBUSY;
                bp->b_flags |= B_ERROR;
-               break;
+               goto done;
+
+       /*
+        * Command completed.
+        */
+       case RXS_EMPTY:
+       case RXS_WRITE: 
+       case RXS_FORMAT:
+               goto done;
 
        case RXS_RDERR:
 
        case RXS_RDERR:
-               printf("rx%d%c: hard error, lsn%d (trk %d psec %d) ",
-                       unit, UNITNAME(unit),
-                       sc->sc_lsector, sc->sc_ptrack, sc->sc_psector);
-               ed = rxdeferr;
-               while (; ed->errval && ed->errval != (er->rxxt[0]&0xff); ed++)
-                       ;
-               printf ("cs=%b, db=%b, err=%x (%s)\n",
-                       er->rxcs&0xffff, rxaddr->rxcs_BITS,
-                       er->rxdb&0x0ffff, RXES_BITS,
-                       er->rxxt[0]&0xffff, ed->errmsg);
-               break;
+               rxmap(bp, &sector, &track);
+               printf("rx%d: hard error, lsn%d (trk %d psec %d) ",
+                       unit, bp->b_blkno * (NBPS / DEV_BLKSIZE),
+                       track, sector);
+               printf("cs=%b, db=%b, err=%x\n", er->rxcs, 
+                       RXCS_BITS, er->rxdb, RXES_BITS, er->rxxt[0]);
+               goto done;
 
        default:
 
        default:
-               printf ("rx%d: state %d (reset)",
-                       unit, State);
-               rxreset (unit);
+               printf("rx%d: state %d (reset)", unit, rxc->rxc_state);
+               rxreset(um->um_ubanum);
                printf("\n");
                return;
        }
                printf("\n");
                return;
        }
-done:
-       rxc->rxc_state = RXS_IDLE;
-       ubadone(um);
-       iodone(bp);
-       return;
-
 error:
        /*
         * In case of an error:
 error:
        /*
         * In case of an error:
@@ -405,10 +390,9 @@ error:
         *  (c) In all other cases, reinitialize the drive and try the
         *        operation once more before giving up.
         */
         *  (c) In all other cases, reinitialize the drive and try the
         *        operation once more before giving up.
         */
-       if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RX_DENERR))
+       if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR))
                goto giveup;
        if (rxaddr->rxdb & RXES_CRCERR) {
                goto giveup;
        if (rxaddr->rxdb & RXES_CRCERR) {
-               sc->sc_errs++;
                if (++bp->b_errcnt >= 10)
                        goto giveup;
                goto retry;
                if (++bp->b_errcnt >= 10)
                        goto giveup;
                goto retry;
@@ -418,39 +402,42 @@ error:
                goto giveup;
        rxaddr->rxcs = RX_INIT;
        /* no way to get an interrupt for "init done", so just wait */
                goto giveup;
        rxaddr->rxcs = RX_INIT;
        /* no way to get an interrupt for "init done", so just wait */
-       while ((rxaddr->rxdb&RX_IDONE) == 0)
+       while ((rxaddr->rxdb&RX_DONE) == 0)
                ;
 retry:
                ;
 retry:
-       rxstart(ui->ui_mi);
+       /*
+        * In case we already have UNIBUS resources, give
+        * them back since we reallocate things in rxstart.
+        */
+       if (um->um_ubinfo)
+               ubadone(um);
+       rxstart(um);
        return;
        return;
+
 giveup:
        /*
         * Hard I/O error --
 giveup:
        /*
         * Hard I/O error --
-        * read the error registers, print them on the console, and give up.
-        * The reason for the "read status" is that I don't want to clutter
-        * the system log with errors for "drive not ready" conditions
-        * (which usually mean that the user tried to do I/O without a disk
-        * in the drive), and the only way to determine whether the drive is
-        * ready is by doing a "read status" before examining RX2ES.
-        * Density errors are not noted on the console either, since the
-        * only way to determine the density of an unknown disk is to try
-        * one density or the other at random and see which one doesn't give
-        * a density error.
+        * Density errors are not noted on the console since the
+        * only way to determine the density of an unknown disk
+        * is to try one density or the other at random and see
+        * which one doesn't give a density error.
         */
        if (rxaddr->rxdb & RXES_DENERR) {
         */
        if (rxaddr->rxdb & RXES_DENERR) {
-               bp->b_error = ENODEV;
+               bp->b_error = EIO;
                bp->b_flags |= B_ERROR;
                goto done;
        }
        rxc->rxc_state = RXS_RDSTAT;
        rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
        return;
                bp->b_flags |= B_ERROR;
                goto done;
        }
        rxc->rxc_state = RXS_RDSTAT;
        rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
        return;
+
 rderr:
        /*
         * A hard error (other than not ready or density) has occurred.
         * Read the extended error status information.
         * Before doing this, save the current CS and DB register values,
         * because the read error status operation may modify them.
 rderr:
        /*
         * A hard error (other than not ready or density) has occurred.
         * Read the extended error status information.
         * Before doing this, save the current CS and DB register values,
         * because the read error status operation may modify them.
+        * Insert buffer with request at the head of the queue.
         */
        bp->b_error = EIO;
        bp->b_flags |= B_ERROR;
         */
        bp->b_error = EIO;
        bp->b_flags |= B_ERROR;
@@ -461,10 +448,27 @@ rderr:
        bp->b_un.b_addr = (caddr_t)er->rxxt;
        bp->b_bcount = sizeof (er->rxxt);
        bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
        bp->b_un.b_addr = (caddr_t)er->rxxt;
        bp->b_bcount = sizeof (er->rxxt);
        bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
-       um->um_tab.b_actf = bp->b_actf = bp;
+       if (um->um_tab.b_actf->b_actf == NULL)
+               um->um_tab.b_actf->b_actl = bp;
+       bp->b_forw = um->um_tab.b_actf->b_actf;
+       um->um_tab.b_actf->b_actf = bp;
        rxc->rxc_state = RXS_RDERR;
        um->um_cmd = RX_RDERR;
        (void) ubago(ui);
        rxc->rxc_state = RXS_RDERR;
        um->um_cmd = RX_RDERR;
        (void) ubago(ui);
+       return;
+done:
+       um->um_tab.b_active = 0;
+       um->um_tab.b_actf->b_actf = bp->b_forw;
+       bp->b_resid = 0;
+       iodone(bp);
+       rxc->rxc_state = RXS_IDLE;
+       ubadone(um);
+       /*
+        * If this unit has more work to do,
+        * start it up right away
+        */
+       if (um->um_tab->b_actf->b_actf)
+               rxstart(ui);
 }
 
 /*ARGSUSED*/
 }
 
 /*ARGSUSED*/
@@ -476,15 +480,15 @@ minrxphys(bp)
                bp->b_bcount = NBPS;
 }
 
                bp->b_bcount = NBPS;
 }
 
-rxtimo()
+rxtimo(dev)
+       dev_t dev;
 {
        register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
 
 {
        register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
 
-       if (sc->sc_openf)
-               timeout(rxtimo, (caddr_t)dev, hz/2);
+       if (sc->sc_flags & RXF_OPEN)
+               timeout(rxtimo, (caddr_t)dev, hz);
        if (++sc->sc_tocnt < RX_MAXTIMEOUT)
                return;
        if (++sc->sc_tocnt < RX_MAXTIMEOUT)
                return;
-       sc->sc_tocnt = 0;
        rxintr(dev);
 }
 
        rxintr(dev);
 }
 
@@ -502,43 +506,41 @@ rxreset(uban)
                printf(" fx%d", ctlr);
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
                printf(" fx%d", ctlr);
                if (um->um_ubinfo) {
                        printf("<%d>", (um->um_ubinfo>>28)&0xf);
-                       ubadone (um);
+                       um->um_ubinfo = 0;
                }
                rx_ctlr[ctlr].rxc_state = RXS_IDLE;
                rxaddr = (struct rxdevice *)um->um_addr;
                }
                rx_ctlr[ctlr].rxc_state = RXS_IDLE;
                rxaddr = (struct rxdevice *)um->um_addr;
-               rxaddr->rxcs = RXINIT;
-               while ((rxaddr->rxdb&RX_IDONE) == 0)
+               rxaddr->rxcs = RX_INIT;
+               while ((rxaddr->rxdb&RX_DONE) == 0)
                        ;
                        ;
-               (void) rxstart(um);
+               rxstart(um);
        }
 }
 
        }
 }
 
-rxread(dev)
+rxread(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
 
 {
        int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
 
-       if (u.u_offset + u.u_count > RXSIZE) {
-               u.u_error = ENXIO;
-               return;
-       }
-       if (u.u_offset < 0 || (u.u_offset & SECMASK) != 0)
-               goto bad;
-       physio(rxstrategy, &rrxbuf[ctlr], dev, B_READ, minrxphys);
+       if (uio->uio_offset + uio->uio_resid > RXSIZE)
+               return (ENXIO);
+       if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
+               return (EIO);
+       return (physio(rxstrategy, &rrxbuf[ctlr], dev, B_READ, minrxphys));
 }
 
 }
 
-rxwrite(dev)
+rxwrite(dev, uio)
        dev_t dev;
        dev_t dev;
+       struct uio *uio;
 {
        int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
 
 {
        int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
 
-       if (u.u_offset + u.u_count > RXSIZE) {
-               u.u_error = ENXIO;
-               return;
-       }
-       if (u.u_offset < 0 || (u.u_offset & SECMASK) != 0)
-               goto bad;
-       physio(rxstrategy, &rrxbuf[ctlr], dev, B_WRITE, minrxphys);
+       if (uio->uio_offset + uio->uio_resid > RXSIZE)
+               return (ENXIO);
+       if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
+               return (EIO);
+       return (physio(rxstrategy, &rrxbuf[ctlr], dev, B_WRITE, minrxphys));
 }
 
 /*
 }
 
 /*
@@ -554,67 +556,62 @@ rxwrite(dev)
  * Requests relating to deleted-data marks can be handled right here.
  * A "set density" request, however, must additionally be processed
  * through "rxstart", just like a read or write request.
  * Requests relating to deleted-data marks can be handled right here.
  * A "set density" request, however, must additionally be processed
  * through "rxstart", just like a read or write request.
- *
- * Note that there was a bug in sys/ioctl.c which failed to pass the
- * "flag" argument to the device "ioctl" routine.  This bug had to be
- * fixed to allow "rxioctl" to determine whether the device is open
- * for input or output, since certain control calls are legal only for
- * input or only for output.
  */
 /*ARGSUSED3*/
  */
 /*ARGSUSED3*/
-rxioctl(dev, cmd, addr, flag)
+rxioctl(dev, cmd, data, flag)
        dev_t dev;
        int cmd;
        dev_t dev;
        int cmd;
-       caddr_t addr;
+       caddr_t data;
        int flag;
 {   
        int unit = RXUNIT(dev);
        struct rx_softc *sc = &rx_softc[unit];
        int flag;
 {   
        int unit = RXUNIT(dev);
        struct rx_softc *sc = &rx_softc[unit];
-       register struct buf *bp;
-       int ctlr, s;
 
        switch (cmd) {
 
 
        switch (cmd) {
 
-       case IO_FORMAT:
-               break;
-
-       case IO_WDDS:
+       case RXIOC_FORMAT:
                if ((flag&FWRITE) == 0)
                if ((flag&FWRITE) == 0)
-                       u.u_error = EBADF;
-               else
-                       sc->sc_flags |= RXF_USEWDDS;
-               return;
+                       return (EBADF);
+               return (rxformat(unit));
 
 
-       case IO_RDDSMK:
-               if ((flag&FREAD) == 0)
-                       u.u_error = EBADF;
-               else if (sc->sc_flags & RXF_DDMK)
-                       u.u_error = EIO;
-               return;
+       case RXIOC_WDDS:
+               sc->sc_flags |= RXF_USEWDDS;
+               return (0);
 
 
-       default:
-               u.u_error = ENXIO;
-               return;
+       case RXIOC_RDDSMK:
+               *(int *)data = sc->sc_flags & RXF_DDMK;
+               return (0);
        }
        }
+       return (ENXIO);
+}
+
+/*
+ * Initiate a format command.
+ */
+rxformat(unit)
+       int unit;
+{
+       int ctlr = rxdinfo[unit]->ui_mi->um_ctlr;
+       struct buf *bp;
+       struct rx_softc *sc = &rx_softc[unit];
+       int s, error = 0;
 
 
-       if ((flag&FWRITE) == 0) {
-               u.u_error = EBADF;
-               return;
-       }
-       ctl = rxdinfo[unit]->ui_mi->um_ctlr;
        bp = &rrxbuf[ctlr];
        s = spl5();
        while (bp->b_flags & B_BUSY)
                sleep(bp, PRIBIO);
        bp->b_flags = B_BUSY | B_CTRL;
        splx(s);
        bp = &rrxbuf[ctlr];
        s = spl5();
        while (bp->b_flags & B_BUSY)
                sleep(bp, PRIBIO);
        bp->b_flags = B_BUSY | B_CTRL;
        splx(s);
+       sc->sc_flags = RXS_FORMAT;
        bp->b_dev = dev;
        bp->b_error = 0;
        bp->b_dev = dev;
        bp->b_error = 0;
-       u.u_offset = 0;
-       bp->b_bcount = NBPS;
+       bp->b_resid = 0;
        rxstrategy (bp);
        iowait(bp);
        rxstrategy (bp);
        iowait(bp);
+       if (bp->b_flags & B_ERROR)
+               error = bp->b_error;
        bp->b_flags &= ~B_BUSY;
        bp->b_flags &= ~B_BUSY;
-       wakeup(bp);
+       wakeup((caddr_t)bp);
+       return (error);
 }
 #endif
 }
 #endif