123341Smckusick /*
229240Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323341Smckusick * All rights reserved. The Berkeley software License Agreement
423341Smckusick * specifies the terms and conditions for redistribution.
523341Smckusick *
6*45805Sbostic * @(#)rx.c 7.5 (Berkeley) 12/16/90
723341Smckusick */
810773Ssam
910773Ssam #include "rx.h"
1010773Ssam #if NFX > 0
1110773Ssam /*
1210773Ssam * RX02 floppy disk device driver
1310773Ssam *
1410773Ssam */
1511750Shelge
1611750Shelge /*
1711891Shelge * TODO:
1811911Shelge * - clean up the code for multisector transfers using
1911911Shelge * a 'transfer in progress' flag
2011911Shelge * - Test Deleted Data read/write
2111913Shelge * - Test error handling/reporting and 'volume valid' stuff
2211891Shelge *
2311750Shelge * Note: If the drive subsystem is
2411750Shelge * powered off at boot time, the controller won't interrupt!
2511750Shelge */
2611750Shelge
27*45805Sbostic #include "../include/pte.h"
2811205Ssam
29*45805Sbostic #include "sys/param.h"
30*45805Sbostic #include "sys/buf.h"
31*45805Sbostic #include "sys/systm.h"
32*45805Sbostic #include "sys/conf.h"
33*45805Sbostic #include "sys/errno.h"
34*45805Sbostic #include "sys/time.h"
35*45805Sbostic #include "sys/kernel.h"
36*45805Sbostic #include "sys/uio.h"
37*45805Sbostic #include "sys/file.h"
3810773Ssam
39*45805Sbostic #include "../include/cpu.h"
4010773Ssam #include "../vax/nexus.h"
4111913Shelge
4217078Sbloom #include "ubavar.h"
4317078Sbloom #include "ubareg.h"
4417078Sbloom #include "rxreg.h"
4510773Ssam
4611848Shelge #define b_cylin b_resid
4711848Shelge
4810773Ssam /* per-controller data */
4910773Ssam struct rx_ctlr {
5010773Ssam int rxc_state; /* controller state */
5110773Ssam #define RXS_READ 1 /* read started */
5210773Ssam #define RXS_EMPTY 2 /* empty started */
5310773Ssam #define RXS_FILL 3 /* fill started */
5410773Ssam #define RXS_WRITE 4 /* write started */
5510773Ssam #define RXS_FORMAT 5 /* format started */
5610773Ssam #define RXS_RDSTAT 6 /* status read started */
5710773Ssam #define RXS_RDERR 7 /* error read started */
5811838Shelge #define RXS_IDLE 8 /* device is idle */
5910773Ssam u_short rxc_rxcs; /* extended error status */
6010773Ssam u_short rxc_rxdb;
6110773Ssam u_short rxc_rxxt[4];
6211750Shelge int rxc_tocnt; /* for watchdog routine */
6311205Ssam #define RX_MAXTIMEOUT 30 /* # seconds to wait before giving up */
6410773Ssam } rx_ctlr[NFX];
6510773Ssam
6611649Shelge /* per-drive buffers */
6711729Shelge struct buf rrxbuf[NRX]; /* buffers for raw I/O */
6811649Shelge struct buf erxbuf[NRX]; /* buffers for reading error status */
6911891Shelge struct buf rxutab[NRX]; /* per drive buffers */
7011649Shelge
7110773Ssam /* per-drive data */
7210773Ssam struct rx_softc {
7311205Ssam int sc_flags; /* drive status flags */
7412060Shelge #define RXF_DIRECT 0x01 /* if set: use direct sector mapping */
7512060Shelge #define RXF_TRKONE 0x02 /* if set: start mapping on track 1 */
7611911Shelge #define RXF_DBLDEN 0x04 /* use double density */
7711911Shelge #define RXF_DEVTYPE 0x07 /* mapping flags */
7811891Shelge #define RXF_LOCK 0x10 /* exclusive use */
7910773Ssam #define RXF_DDMK 0x20 /* deleted-data mark detected */
8010773Ssam #define RXF_USEWDDS 0x40 /* write deleted-data sector */
8111891Shelge #define RXF_FORMAT 0x80 /* format in progress */
8212365Shelge #define RXF_BAD 0x100 /* drive bad, cannot be used */
8311205Ssam int sc_csbits; /* constant bits for CS register */
8411848Shelge int sc_open; /* count number of opens */
8511891Shelge int sc_offset; /* raw mode kludge to avoid restricting */
8611891Shelge /* single sector transfers to start on */
8711891Shelge /* DEV_BSIZE boundaries */
8811891Shelge /*
8911891Shelge * The rest of this structure is used to
9011891Shelge * store temporaries while simulating multi
9111891Shelge * sector transfers
9211891Shelge */
9311891Shelge caddr_t sc_uaddr; /* unibus base address */
9411891Shelge long sc_bcnt; /* total transfer count */
9511914Shelge long sc_resid; /* no. of bytes left to transfer */
9610773Ssam } rx_softc[NRX];
9710773Ssam
9811205Ssam struct rxerr {
9911205Ssam short rxcs;
10011205Ssam short rxdb;
10111205Ssam short rxxt[4]; /* error code dump from controller */
10211633Shelge } rxerr[NRX];
10311633Shelge /* End of per-drive data */
10411205Ssam
10510773Ssam struct uba_device *rxdinfo[NRX];
10610773Ssam struct uba_ctlr *rxminfo[NFX];
10711848Shelge
10812365Shelge struct buf *savebp;
10912365Shelge
11011633Shelge int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr(), rxwatch(), rxphys();
11110773Ssam u_short rxstd[] = { 0177170, 0177150, 0 };
11210773Ssam struct uba_driver fxdriver =
11310773Ssam { rxprobe, rxslave, rxattach, rxdgo, rxstd, "rx", rxdinfo, "fx", rxminfo };
11410773Ssam
11510773Ssam int rxwstart;
11611633Shelge #define RXUNIT(dev) (minor(dev)>>3)
11711838Shelge #define MASKREG(reg) (reg&0xffff)
11810773Ssam
11910773Ssam /* constants related to floppy data capacity */
12010773Ssam #define RXSECS 2002 /* # sectors on a floppy */
12111911Shelge #define DDSTATE (sc->sc_csbits&RX_DDEN)
12210773Ssam #define NBPS (DDSTATE ? 256 : 128) /* # bytes per sector */
12310773Ssam #define RXSIZE (DDSTATE ? 512512 : 256256) /* # bytes per disk */
12410773Ssam #define SECMASK (DDSTATE ? 0xff : 0x7f) /* shifted-out bits of offset */
12510773Ssam
12611911Shelge #define B_CTRL 0x80000000 /* control (format) request */
12711911Shelge #define B_RDSTAT 0x40000000 /* read drive status (open) */
12810773Ssam
12910773Ssam /*ARGSUSED*/
rxprobe(reg)13010773Ssam rxprobe (reg)
13110773Ssam caddr_t reg;
13210773Ssam {
13311205Ssam register int br, cvec; /* value-result */
13410773Ssam struct rxdevice *rxaddr = (struct rxdevice *)reg;
13510773Ssam
13610773Ssam #ifdef lint
13710773Ssam br = 0; cvec = br; br = cvec;
13811205Ssam rxintr(0);
13910773Ssam #endif lint
14010773Ssam rxaddr->rxcs = RX_INTR;
14110773Ssam DELAY(10);
14210773Ssam rxaddr->rxcs = 0;
14310773Ssam return (sizeof (*rxaddr));
14410773Ssam }
14510773Ssam
14633407Sbostic /*ARGSUSED*/
14711838Shelge rxslave(ui, reg)
14810773Ssam struct uba_device *ui;
14910773Ssam caddr_t reg;
15010773Ssam {
15110773Ssam return (ui->ui_slave == 0 || ui->ui_slave == 1);
15210773Ssam }
15310773Ssam
15410773Ssam /*ARGSUSED*/
15510773Ssam rxattach(ui)
15610773Ssam struct uba_device *ui;
15710773Ssam {
15810773Ssam
15910773Ssam }
16010773Ssam
16110773Ssam /*ARGSUSED1*/
rxopen(dev,flag)16210773Ssam rxopen(dev, flag)
16310773Ssam dev_t dev;
16410773Ssam {
16510773Ssam register int unit = RXUNIT(dev);
16610773Ssam register struct rx_softc *sc;
16710773Ssam register struct uba_device *ui;
16811750Shelge struct rx_ctlr *rxc;
16910773Ssam
17011633Shelge if (unit >= NRX || (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0)
17111205Ssam return (ENXIO);
17210773Ssam sc = &rx_softc[unit];
17311911Shelge if (sc->sc_open == 0 && sc->sc_csbits == 0) {
17411911Shelge struct buf *bp = &erxbuf[unit];
17511911Shelge /*
17611911Shelge * lock the device while an open
17711911Shelge * is in progress
17811911Shelge */
17912060Shelge sc->sc_flags = (minor(dev) & RXF_DEVTYPE) | RXF_LOCK;
18011848Shelge sc->sc_csbits = RX_INTR;
18111848Shelge sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1;
18211911Shelge
18311911Shelge bp->b_dev = dev;
18411911Shelge bp->b_flags = B_RDSTAT | B_BUSY;
18511911Shelge bp->b_error = 0;
18611911Shelge bp->b_blkno = 0;
18712365Shelge sc->sc_offset = 0;
18812365Shelge sc->sc_resid = 0;
18911911Shelge /*
19011911Shelge * read device status to determine if
19111911Shelge * a floppy is present in the drive and
19211911Shelge * what density it is
19311911Shelge */
19411911Shelge rxstrategy(bp);
19511911Shelge iowait(bp);
19611911Shelge if (bp->b_flags & B_ERROR) {
19711911Shelge sc->sc_csbits = 0;
19816706Skarels sc->sc_flags &= ~RXF_LOCK;
19911911Shelge return (bp->b_error);
20011911Shelge }
20111848Shelge if (rxwstart++ == 0) {
20211911Shelge rxc = &rx_ctlr[ui->ui_mi->um_ctlr];
20311848Shelge rxc->rxc_tocnt = 0;
20412060Shelge timeout(rxwatch, (caddr_t)0, hz); /* start watchdog */
20511848Shelge }
20611911Shelge #ifdef RXDEBUG
20711911Shelge printf("rxopen: csbits=0x%x\n", sc->sc_csbits);
20811911Shelge #endif
20911911Shelge sc->sc_flags &= ~RXF_LOCK;
21011891Shelge } else {
21111911Shelge if (sc->sc_flags & RXF_LOCK)
21211891Shelge return(EBUSY);
21311729Shelge }
21416706Skarels sc->sc_open = 1;
21511205Ssam return (0);
21610773Ssam }
21710773Ssam
21810773Ssam /*ARGSUSED1*/
rxclose(dev,flag)21910773Ssam rxclose(dev, flag)
22010773Ssam dev_t dev;
22110773Ssam {
22210773Ssam register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
22310773Ssam
22416706Skarels sc->sc_open = 0;
22512060Shelge #ifdef RXDEBUG
22611891Shelge printf("rxclose: dev=0x%x, sc_open=%d\n", dev, sc->sc_open);
22712060Shelge #endif
22840727Skarels return (0);
22910773Ssam }
23010773Ssam
rxstrategy(bp)23110773Ssam rxstrategy(bp)
23210773Ssam register struct buf *bp;
23310773Ssam {
23410773Ssam struct uba_device *ui;
23511729Shelge register struct buf *dp;
23611729Shelge struct rx_softc *sc;
23711729Shelge int s, unit = RXUNIT(bp->b_dev);
23810773Ssam
23911838Shelge if (unit >= NRX)
24011838Shelge goto bad;
24111729Shelge ui = rxdinfo[unit];
24211729Shelge if (ui == 0 || ui->ui_alive == 0)
24311729Shelge goto bad;
24411911Shelge sc = &rx_softc[unit];
24512648Ssam if (bp->b_blkno < 0 || dbtob(bp->b_blkno) > RXSIZE)
24611729Shelge goto bad;
24712365Shelge if (sc->sc_flags & RXF_BAD) {
24812365Shelge bp->b_error = EIO;
24912365Shelge goto dbad;
25012365Shelge }
25112365Shelge s = spl5();
25211848Shelge #ifdef RXDEBUG
25312365Shelge printf("rxstrat: bp=0x%x, fl=0x%x, un=%d, bl=%d, cnt=%d\n",
25411848Shelge bp, bp->b_flags, unit, bp->b_blkno, bp->b_bcount);
25511848Shelge #endif
25611848Shelge bp->b_cylin = bp->b_blkno; /* don't care to calculate trackno */
25711838Shelge dp = &rxutab[unit];
25811729Shelge disksort(dp, bp);
25911838Shelge if (dp->b_active == 0) {
26011838Shelge rxustart(ui);
26111838Shelge bp = &ui->ui_mi->um_tab;
26211838Shelge if (bp->b_actf && bp->b_active == 0)
26311838Shelge rxstart(ui->ui_mi);
26411838Shelge }
26510773Ssam splx(s);
26611729Shelge return;
26711729Shelge
26811848Shelge bad:
26912365Shelge bp->b_error = ENXIO;
27012365Shelge dbad:
27111848Shelge bp->b_flags |= B_ERROR;
27211729Shelge iodone(bp);
27311729Shelge return;
27410773Ssam }
27510773Ssam
27610773Ssam /*
27711729Shelge * Unit start routine.
27811838Shelge * Put this unit on the ready queue for the controller
27911729Shelge */
rxustart(ui)28011729Shelge rxustart(ui)
28111729Shelge register struct uba_device *ui;
28211729Shelge {
28311838Shelge struct buf *dp = &rxutab[ui->ui_unit];
28411838Shelge struct uba_ctlr *um = ui->ui_mi;
28511838Shelge
28611838Shelge dp->b_forw = NULL;
28711838Shelge if (um->um_tab.b_actf == NULL)
28811838Shelge um->um_tab.b_actf = dp;
28911838Shelge else
29011838Shelge um->um_tab.b_actl->b_forw = dp;
29111838Shelge um->um_tab.b_actl = dp;
29211838Shelge dp->b_active++;
29311729Shelge }
29411729Shelge /*
29510773Ssam * Sector mapping routine.
29610773Ssam * Two independent sets of choices are available:
29710773Ssam *
29810773Ssam * (a) The first logical sector may either be on track 1 or track 0.
29910773Ssam * (b) The sectors on a track may either be taken in 2-for-1 interleaved
30010773Ssam * fashion or directly.
30110773Ssam * This gives a total of four possible mapping schemes.
30210773Ssam *
30310773Ssam * Physical tracks on the RX02 are numbered 0-76. Physical sectors on
30410773Ssam * each track are numbered 1-26.
30510773Ssam *
30610773Ssam * When interleaving is used, sectors on the first logical track are
30710773Ssam * taken in the order 1, 3, 5, ..., 25, 2, 4, 6, ..., 26. A skew of
30810773Ssam * six sectors per track is also used (to allow time for the heads to
30910773Ssam * move); hence, the sectors on the second logical track are taken in
31010773Ssam * the order 7, 9, 11, ..., 25, 1, 3, 5, 8, 10, 12, ..., 26, 2, 4, 6;
31110773Ssam * the third logical track starts with sector 13; and so on.
31210773Ssam *
31310773Ssam * When the mapping starts with track 1, track 0 is the last logical
31410773Ssam * track, and this track is always handled directly (without inter-
31510773Ssam * leaving), even when the rest of the disk is interleaved. (This is
31610773Ssam * still compatible with DEC RT-11, which does not use track 0 at all.)
31710773Ssam */
31811205Ssam rxmap(bp, psector, ptrack)
31911205Ssam struct buf *bp;
32011205Ssam int *psector, *ptrack;
32110773Ssam {
32210773Ssam register int lt, ls, ptoff;
32311205Ssam struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
32410773Ssam
32512648Ssam ls = (dbtob(bp->b_blkno) + (sc->sc_offset - sc->sc_resid)) / NBPS;
32611205Ssam lt = ls / 26;
32711205Ssam ls %= 26;
32810773Ssam /*
32910773Ssam * The "physical track offset" (ptoff) takes the
33010773Ssam * starting physical track (0 or 1) and the desired
33110773Ssam * interleaving into account. If lt+ptoff >= 77,
33210773Ssam * then interleaving is not performed.
33310773Ssam */
33410773Ssam ptoff = 0;
33511911Shelge if (sc->sc_flags & RXF_DIRECT)
33611205Ssam ptoff = 77;
33712060Shelge if (sc->sc_flags & RXF_TRKONE)
33810773Ssam ptoff++;
33910773Ssam if (lt + ptoff < 77)
34010773Ssam ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
34111205Ssam *ptrack = (lt + ptoff) % 77;
34211205Ssam *psector = ls + 1;
34310773Ssam }
34410773Ssam
34511729Shelge /*
34611838Shelge * Controller start routine.
34711838Shelge * Start a new transfer or continue a multisector
34811838Shelge * transfer. If this is a new transfer (dp->b_active == 1)
34911838Shelge * save the start address of the data buffer and the total
35011838Shelge * byte count in the soft control structure. These are
35111838Shelge * restored into the buffer structure when the transfer has
35211838Shelge * been completed, before calling 'iodone'.
35311729Shelge */
rxstart(um)35410773Ssam rxstart(um)
35510773Ssam register struct uba_ctlr *um;
35610773Ssam {
35710773Ssam register struct rxdevice *rxaddr;
35810773Ssam register struct rx_ctlr *rxc;
35910773Ssam register struct rx_softc *sc;
36011729Shelge struct buf *dp, *bp;
36111205Ssam int unit, sector, track;
36210773Ssam
36311729Shelge if (um->um_tab.b_active)
36410773Ssam return;
36511729Shelge loop:
36611729Shelge if ((dp = um->um_tab.b_actf) == NULL)
36711729Shelge return;
36811729Shelge if ((bp = dp->b_actf) == NULL) {
36911729Shelge um->um_tab.b_actf = dp->b_forw;
37011729Shelge goto loop;
37111729Shelge }
37211913Shelge um->um_tab.b_active++;
37310773Ssam unit = RXUNIT(bp->b_dev);
37410773Ssam sc = &rx_softc[unit];
37512365Shelge if (sc->sc_flags & RXF_BAD) {
37612365Shelge rxpurge(um);
37712365Shelge return;
37812365Shelge }
37911838Shelge if (dp->b_active == 1) {
38011848Shelge sc->sc_resid = bp->b_bcount;
38111838Shelge sc->sc_uaddr = bp->b_un.b_addr;
38211838Shelge sc->sc_bcnt = bp->b_bcount;
38311838Shelge sc->sc_offset += sc->sc_bcnt;
38411838Shelge dp->b_active++;
38511838Shelge }
38610773Ssam rxaddr = (struct rxdevice *)um->um_addr;
38710773Ssam rxc = &rx_ctlr[um->um_ctlr];
38811848Shelge bp->b_bcount = sc->sc_resid;
38911729Shelge if (bp->b_bcount > NBPS)
39011729Shelge bp->b_bcount = NBPS;
39111750Shelge rxc->rxc_tocnt = 0;
39211848Shelge #ifdef RXDEBUG
39311848Shelge printf("rxstart: ");
39411848Shelge #endif
39511766Shelge if (rxaddr->rxcs == 0x800) {
39611766Shelge /*
39711911Shelge * 'Volume valid'? (check if the
39811911Shelge * drive unit has been powered down)
39911766Shelge */
40011766Shelge rxaddr->rxcs = RX_INIT;
40111766Shelge while((rxaddr->rxcs&RX_DONE) == 0)
40211766Shelge ;
40311766Shelge }
40411911Shelge if (bp->b_flags & B_CTRL) { /* format */
40510773Ssam rxc->rxc_state = RXS_FORMAT;
40610773Ssam rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
40711205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
40810773Ssam ;
40910773Ssam rxaddr->rxdb = 'I';
41010773Ssam return;
41110773Ssam }
41211911Shelge if (bp->b_flags & B_RDSTAT) { /* read drive status */
41311911Shelge rxc->rxc_state = RXS_RDSTAT;
41411911Shelge rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
41511911Shelge return;
41611911Shelge }
41711750Shelge
41811911Shelge if (bp->b_flags & B_READ) {
41911750Shelge rxmap(bp, §or, &track); /* read */
42011848Shelge #ifdef RXDEBUG
42111848Shelge printf("read tr=%d, sc=%d", track, sector);
42211848Shelge #endif
42310773Ssam rxc->rxc_state = RXS_READ;
42410773Ssam rxaddr->rxcs = RX_READ | sc->sc_csbits;
42511205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
42610773Ssam ;
42711205Ssam rxaddr->rxdb = (u_short)sector;
42811205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
42910773Ssam ;
43011205Ssam rxaddr->rxdb = (u_short)track;
43111766Shelge } else {
43211848Shelge #ifdef RXDEBUG
43311848Shelge printf("write");
43411848Shelge #endif
43511766Shelge rxc->rxc_state = RXS_FILL; /* write */
43611766Shelge um->um_cmd = RX_FILL;
43711766Shelge (void) ubago(rxdinfo[unit]);
43810773Ssam }
43911766Shelge #ifdef RXDEBUG
44011848Shelge printf("\n");
44111766Shelge #endif
44210773Ssam }
44310773Ssam
44410773Ssam rxdgo(um)
44510773Ssam struct uba_ctlr *um;
44610773Ssam {
44710773Ssam register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr;
44810773Ssam int ubinfo = um->um_ubinfo;
44911729Shelge struct buf *bp = um->um_tab.b_actf->b_actf;
45010773Ssam struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
45110773Ssam struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
45210773Ssam
45311729Shelge rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
45410773Ssam if (rxc->rxc_state != RXS_RDERR) {
45511205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
45610773Ssam ;
45711750Shelge rxaddr->rxdb = (u_short) bp->b_bcount >> 1;
45810773Ssam }
45911205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
46010773Ssam ;
46111750Shelge rxaddr->rxdb = (u_short) ubinfo;
46210773Ssam }
46310773Ssam
rxintr(ctlr)46411750Shelge rxintr(ctlr)
46511750Shelge int ctlr;
46610773Ssam {
46711750Shelge int unit, sector, track;
46811750Shelge struct uba_ctlr *um = rxminfo[ctlr];
46911205Ssam register struct rxdevice *rxaddr;
47011729Shelge register struct buf *bp, *dp;
47111750Shelge register struct rx_softc *sc;
47211750Shelge struct uba_device *ui;
47311205Ssam struct rxerr *er;
47411913Shelge struct rx_ctlr *rxc;
47510773Ssam
47611205Ssam if (!um->um_tab.b_active)
47710773Ssam return;
47811729Shelge dp = um->um_tab.b_actf;
47911729Shelge if (!dp->b_active)
48011729Shelge return;
48111750Shelge bp = dp->b_actf;
48211750Shelge unit = RXUNIT(bp->b_dev);
48311750Shelge sc = &rx_softc[unit];
48411750Shelge ui = rxdinfo[unit];
48511205Ssam rxaddr = (struct rxdevice *)um->um_addr;
48611205Ssam rxc = &rx_ctlr[um->um_ctlr];
48711750Shelge rxc->rxc_tocnt = 0;
48811649Shelge er = &rxerr[unit];
48911766Shelge #ifdef RXDEBUG
49012365Shelge printf("rxint: dev=%x, st=%d, cs=0x%x, db=0x%x\n",
49112365Shelge bp->b_dev, rxc->rxc_state, rxaddr->rxcs, rxaddr->rxdb);
49211766Shelge #endif
49311205Ssam if ((rxaddr->rxcs & RX_ERR) &&
49411838Shelge (rxc->rxc_state != RXS_RDSTAT) && (rxc->rxc_state != RXS_RDERR))
49511205Ssam goto error;
49610773Ssam switch (rxc->rxc_state) {
49710773Ssam
49811205Ssam /*
49911205Ssam * Incomplete commands. Perform next step
50011205Ssam * and return. Note that b_active is set on
50111205Ssam * entrance and, therefore, also on exit.
50211205Ssam */
50310773Ssam case RXS_READ:
50410773Ssam if (rxaddr->rxdb & RXES_DDMARK)
50510773Ssam sc->sc_flags |= RXF_DDMK;
50610773Ssam else
50710773Ssam sc->sc_flags &= ~RXF_DDMK;
50810773Ssam rxc->rxc_state = RXS_EMPTY;
50910773Ssam um->um_cmd = RX_EMPTY;
51010773Ssam (void) ubago(ui);
51110773Ssam return;
51210773Ssam
51310773Ssam case RXS_FILL:
51410773Ssam rxc->rxc_state = RXS_WRITE;
51510773Ssam if (sc->sc_flags & RXF_USEWDDS) {
51610773Ssam rxaddr->rxcs = RX_WDDS | sc->sc_csbits;
51710773Ssam sc->sc_flags &= ~RXF_USEWDDS;
51810773Ssam } else
51910773Ssam rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
52011838Shelge rxmap(bp, §or, &track);
52111205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
52210773Ssam ;
52311205Ssam rxaddr->rxdb = sector;
52411205Ssam while ((rxaddr->rxcs&RX_TREQ) == 0)
52510773Ssam ;
52611205Ssam rxaddr->rxdb = track;
52710773Ssam return;
52810773Ssam
52911205Ssam /*
53011205Ssam * Possibly completed command.
53111205Ssam */
53210773Ssam case RXS_RDSTAT:
53311911Shelge if (bp->b_flags & B_RDSTAT) {
53411911Shelge if ((rxaddr->rxdb&RXES_READY) == 0) {
53511911Shelge bp->b_flags |= B_ERROR;
53611911Shelge bp->b_error = ENODEV;
53711911Shelge } else {
53811911Shelge sc->sc_csbits |= rxaddr->rxdb&RXES_DBLDEN ?
53911911Shelge RX_DDEN : RX_SDEN;
54011911Shelge }
54111911Shelge goto rdone;
54211911Shelge }
54311205Ssam if (rxaddr->rxdb&RXES_READY)
54410773Ssam goto rderr;
54512365Shelge bp->b_error = ENODEV;
54610773Ssam bp->b_flags |= B_ERROR;
54711205Ssam goto done;
54810773Ssam
54911205Ssam /*
55011205Ssam * Command completed.
55111205Ssam */
55211205Ssam case RXS_EMPTY:
55311205Ssam case RXS_WRITE:
55411205Ssam goto done;
55511205Ssam
55611911Shelge case RXS_FORMAT:
55711911Shelge goto rdone;
55811911Shelge
55910773Ssam case RXS_RDERR:
56012365Shelge bp = savebp;
56111205Ssam rxmap(bp, §or, &track);
56211838Shelge printf("rx%d: hard error, trk %d psec %d ",
56311838Shelge unit, track, sector);
56411838Shelge printf("cs=%b, db=%b, err=", MASKREG(er->rxcs),
56511838Shelge RXCS_BITS, MASKREG(er->rxdb), RXES_BITS);
56612060Shelge printf("%x, %x, %x, %x\n", MASKREG(er->rxxt[0]),
56711838Shelge MASKREG(er->rxxt[1]), MASKREG(er->rxxt[2]),
56811838Shelge MASKREG(er->rxxt[3]));
56911205Ssam goto done;
57010773Ssam
57110773Ssam default:
57211729Shelge printf("rx%d: state %d (reset)\n", unit, rxc->rxc_state);
57311205Ssam rxreset(um->um_ubanum);
57410773Ssam return;
57510773Ssam }
57610773Ssam error:
57710773Ssam /*
57810773Ssam * In case of an error:
57911913Shelge * (a) Give up now if a format (ioctl) was in progress, if a
58011913Shelge * density error was detected, or if the drive went offline
58110773Ssam * (b) Retry up to nine times if a CRC (data) error was detected,
58210773Ssam * then give up if the error persists.
58310773Ssam * (c) In all other cases, reinitialize the drive and try the
58410773Ssam * operation once more before giving up.
58510773Ssam */
58611205Ssam if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR))
58710773Ssam goto giveup;
58810773Ssam if (rxaddr->rxdb & RXES_CRCERR) {
58912365Shelge if (++um->um_tab.b_errcnt >= 10)
59010773Ssam goto giveup;
59110773Ssam goto retry;
59210773Ssam }
59312365Shelge um->um_tab.b_errcnt += 9;
59412365Shelge if (um->um_tab.b_errcnt >= 10)
59510773Ssam goto giveup;
59610773Ssam rxaddr->rxcs = RX_INIT;
59710773Ssam /* no way to get an interrupt for "init done", so just wait */
59811766Shelge while ((rxaddr->rxcs&RX_DONE) == 0)
59910773Ssam ;
60011913Shelge /* if someone opened the drive: give up */
60111913Shelge if ((rxaddr->rxdb&RXES_READY) == 0)
60211913Shelge goto giveup;
60310773Ssam retry:
60411205Ssam /*
60511205Ssam * In case we already have UNIBUS resources, give
60611205Ssam * them back since we reallocate things in rxstart.
60711205Ssam */
60811205Ssam if (um->um_ubinfo)
60911205Ssam ubadone(um);
61011649Shelge um->um_tab.b_active = 0;
61111205Ssam rxstart(um);
61210773Ssam return;
61311205Ssam
61410773Ssam giveup:
61510773Ssam /*
61610773Ssam * Hard I/O error --
61712365Shelge * ALL errors are considered fatal and will abort the
61812365Shelge * transfer and purge the i/o request queue
61910773Ssam */
62012365Shelge sc->sc_flags |= RXF_BAD;
62112365Shelge sc->sc_resid = 0; /* make sure the transfer is terminated */
62210773Ssam rxc->rxc_state = RXS_RDSTAT;
62310773Ssam rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
62410773Ssam return;
62511205Ssam
62610773Ssam rderr:
62710773Ssam /*
62812365Shelge * A hard error (other than not ready) has occurred.
62910773Ssam * Read the extended error status information.
63010773Ssam * Before doing this, save the current CS and DB register values,
63110773Ssam * because the read error status operation may modify them.
63212365Shelge * Insert buffer with request at the head of the queue.
63310773Ssam */
63410773Ssam bp->b_error = EIO;
63510773Ssam bp->b_flags |= B_ERROR;
63612365Shelge if (um->um_ubinfo)
63712365Shelge ubadone(um);
63812365Shelge savebp = bp;
63910773Ssam er->rxcs = rxaddr->rxcs;
64010773Ssam er->rxdb = rxaddr->rxdb;
64111214Shelge bp = &erxbuf[unit];
64210773Ssam bp->b_un.b_addr = (caddr_t)er->rxxt;
64310773Ssam bp->b_bcount = sizeof (er->rxxt);
64410773Ssam bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
64511838Shelge if (dp->b_actf == NULL)
64611838Shelge dp->b_actl = bp;
64711838Shelge bp->b_forw = dp->b_actf;
64811838Shelge dp->b_actf = bp;
64910773Ssam rxc->rxc_state = RXS_RDERR;
65010773Ssam um->um_cmd = RX_RDERR;
65110773Ssam (void) ubago(ui);
65211205Ssam return;
65311911Shelge
65411205Ssam done:
65511911Shelge ubadone(um);
65611911Shelge rdone:
65711205Ssam um->um_tab.b_active = 0;
65811729Shelge um->um_tab.b_errcnt = 0;
65911848Shelge if ((sc->sc_resid -= NBPS) > 0) {
66011729Shelge bp->b_un.b_addr += NBPS;
66111729Shelge rxstart(um);
66211729Shelge return;
66311729Shelge }
66411729Shelge bp->b_un.b_addr = sc->sc_uaddr;
66511205Ssam bp->b_resid = 0;
66611729Shelge bp->b_bcount = sc->sc_bcnt;
66711848Shelge dp->b_actf = bp->av_forw;
66811205Ssam iodone(bp);
66911848Shelge sc->sc_offset = 0;
67011205Ssam rxc->rxc_state = RXS_IDLE;
67111729Shelge um->um_tab.b_actf = dp->b_forw;
67211729Shelge dp->b_active = 0;
67311729Shelge dp->b_errcnt = 0;
67411848Shelge #ifdef RXDEBUG
67512365Shelge printf(".. bp=%x, new=%x\n", bp, dp->b_actf);
67611848Shelge #endif
67711205Ssam /*
67811838Shelge * If this unit has more work to do,
67911205Ssam * start it up right away
68011205Ssam */
68111838Shelge if (dp->b_actf)
68211838Shelge rxustart(ui);
68311838Shelge
68411838Shelge rxstart(um);
68510773Ssam }
68610773Ssam
68710773Ssam /*ARGSUSED*/
68810773Ssam
rxwatch()68912060Shelge rxwatch()
69010773Ssam {
69111913Shelge register struct uba_device *ui;
69211838Shelge register struct uba_ctlr *um;
69311913Shelge register struct rx_softc *sc;
69411913Shelge struct rx_ctlr *rxc;
69511913Shelge int i, dopen = 0;
69610773Ssam
69711913Shelge for (i=0; i<NRX; i++) {
69811913Shelge ui = rxdinfo[i];
69911913Shelge if (ui == 0 || ui->ui_alive == 0)
70011913Shelge continue;
70112060Shelge sc = &rx_softc[i];
70212060Shelge if ((sc->sc_open == 0) && (rxutab[i].b_active == 0)) {
70311913Shelge sc->sc_csbits = 0;
70411913Shelge continue;
70511838Shelge }
70611913Shelge dopen++;
70712060Shelge um = ui->ui_mi;
70811913Shelge rxc = &rx_ctlr[um->um_ctlr];
70912060Shelge if (++rxc->rxc_tocnt >= RX_MAXTIMEOUT) {
71012060Shelge rxc->rxc_tocnt = 0;
71112060Shelge if (um->um_tab.b_active) {
71212060Shelge printf("rx%d: timeout\n", i);/* for debugging */
71312060Shelge rxintr(um->um_ctlr);
71412060Shelge }
71511913Shelge }
71611838Shelge }
71711913Shelge if (dopen)
71812060Shelge timeout(rxwatch, (caddr_t)0, hz);
71911913Shelge else
72011913Shelge rxwstart = 0;
72110773Ssam }
72210773Ssam
rxreset(uban)72310773Ssam rxreset(uban)
72410773Ssam int uban;
72510773Ssam {
72610773Ssam register struct uba_ctlr *um;
72710773Ssam register struct rxdevice *rxaddr;
72810773Ssam register int ctlr;
72910773Ssam
73010773Ssam for (ctlr = 0; ctlr < NFX; ctlr++) {
73110773Ssam if ((um = rxminfo[ctlr]) == 0 || um->um_ubanum != uban ||
73210773Ssam um->um_alive == 0)
73310773Ssam continue;
73433407Sbostic printf(" fx%d", ctlr);
73533407Sbostic if (um->um_ubinfo) {
73633407Sbostic printf("<%d>", UBAI_BDP(um->um_ubinfo));
73711205Ssam um->um_ubinfo = 0;
73833407Sbostic }
73910773Ssam rx_ctlr[ctlr].rxc_state = RXS_IDLE;
74010773Ssam rxaddr = (struct rxdevice *)um->um_addr;
74111205Ssam rxaddr->rxcs = RX_INIT;
74211766Shelge while ((rxaddr->rxcs&RX_DONE) == 0)
74310773Ssam ;
74411205Ssam rxstart(um);
74510773Ssam }
74610773Ssam }
74710773Ssam
rxread(dev,uio)74811205Ssam rxread(dev, uio)
74910773Ssam dev_t dev;
75011205Ssam struct uio *uio;
75110773Ssam {
75211838Shelge int unit = RXUNIT(dev);
75311729Shelge struct rx_softc *sc = &rx_softc[unit];
75410773Ssam
75511205Ssam if (uio->uio_offset + uio->uio_resid > RXSIZE)
75611205Ssam return (ENXIO);
75711205Ssam if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
75811891Shelge return (ENXIO);
75911838Shelge sc->sc_offset = uio->uio_offset % DEV_BSIZE;
76011729Shelge return (physio(rxstrategy, &rrxbuf[unit], dev, B_READ, minphys, uio));
76110773Ssam }
76210773Ssam
rxwrite(dev,uio)76311205Ssam rxwrite(dev, uio)
76410773Ssam dev_t dev;
76511205Ssam struct uio *uio;
76610773Ssam {
76711729Shelge int unit = RXUNIT(dev);
76811729Shelge struct rx_softc *sc = &rx_softc[unit];
76910773Ssam
77011205Ssam if (uio->uio_offset + uio->uio_resid > RXSIZE)
77111205Ssam return (ENXIO);
77211205Ssam if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
77311891Shelge return (ENXIO);
77411838Shelge sc->sc_offset = uio->uio_offset % DEV_BSIZE;
77511729Shelge return(physio(rxstrategy, &rrxbuf[unit], dev, B_WRITE, minphys, uio));
77610773Ssam }
77710773Ssam
77810773Ssam /*
77910773Ssam * Control routine:
78012060Shelge * processes four kinds of requests:
78110773Ssam *
78211633Shelge * (1) Set density (i.e., format the diskette) according to
78312060Shelge * that specified data parameter
78410773Ssam * (2) Arrange for the next sector to be written with a deleted-
78510773Ssam * data mark.
78610773Ssam * (3) Report whether the last sector read had a deleted-data mark
78712060Shelge * (4) Report the density of the diskette in the indicated drive
78812060Shelge * (since the density it automatically determined by the driver,
78912060Shelge * this is the only way to let an application program know the
79012060Shelge * density)
79110773Ssam *
79210773Ssam * Requests relating to deleted-data marks can be handled right here.
79311729Shelge * A "set density" (format) request, however, must additionally be
79411729Shelge * processed through "rxstart", just like a read or write request.
79510773Ssam */
79612060Shelge
79710773Ssam /*ARGSUSED3*/
rxioctl(dev,cmd,data,flag)79811205Ssam rxioctl(dev, cmd, data, flag)
79910773Ssam dev_t dev;
80011205Ssam caddr_t data;
80110773Ssam {
80210773Ssam int unit = RXUNIT(dev);
80310773Ssam struct rx_softc *sc = &rx_softc[unit];
80410773Ssam
80512365Shelge switch (cmd) {
80610773Ssam
80711205Ssam case RXIOC_FORMAT:
80810773Ssam if ((flag&FWRITE) == 0)
80911205Ssam return (EBADF);
81012648Ssam if (sc->sc_open > 1)
81112060Shelge return (EBUSY);
81212103Shelge if (*(int *)data)
81312103Shelge sc->sc_csbits |= RX_DDEN;
81412103Shelge else
81512103Shelge sc->sc_csbits &= ~RX_DDEN;
81611214Shelge return (rxformat(dev));
81710773Ssam
81811205Ssam case RXIOC_WDDS:
81911205Ssam sc->sc_flags |= RXF_USEWDDS;
82011205Ssam return (0);
82110773Ssam
82211205Ssam case RXIOC_RDDSMK:
82311205Ssam *(int *)data = sc->sc_flags & RXF_DDMK;
82411205Ssam return (0);
82511911Shelge
82611911Shelge case RXIOC_GDENS:
82711911Shelge *(int *)data = sc->sc_csbits & RX_DDEN;
82811911Shelge return (0);
82910773Ssam }
83011205Ssam return (ENXIO);
83111205Ssam }
83210773Ssam
83311205Ssam /*
83411205Ssam * Initiate a format command.
83511205Ssam */
rxformat(dev)83611214Shelge rxformat(dev)
83711214Shelge dev_t dev;
83811205Ssam {
83911729Shelge int unit = RXUNIT(dev);
84011205Ssam struct buf *bp;
84111729Shelge struct rx_softc *sc = &rx_softc[unit];
84233407Sbostic int error = 0;
84311205Ssam
84411729Shelge bp = &rrxbuf[unit];
84510773Ssam bp->b_flags = B_BUSY | B_CTRL;
84611891Shelge sc->sc_flags = RXF_FORMAT | RXF_LOCK;
84710773Ssam bp->b_dev = dev;
84810773Ssam bp->b_error = 0;
84911911Shelge bp->b_blkno = 0;
85011911Shelge rxstrategy(bp);
85110773Ssam iowait(bp);
85211205Ssam if (bp->b_flags & B_ERROR)
85311205Ssam error = bp->b_error;
85410773Ssam bp->b_flags &= ~B_BUSY;
85511891Shelge sc->sc_flags &= ~RXF_LOCK;
85611205Ssam return (error);
85710773Ssam }
85812365Shelge
85912365Shelge /*
86012365Shelge * A permanent hard error condition has occured,
86112365Shelge * purge the buffer queue
86212365Shelge */
rxpurge(um)86312365Shelge rxpurge(um)
86412365Shelge register struct uba_ctlr *um;
86512365Shelge {
86612365Shelge register struct buf *bp, *dp;
86712365Shelge
86812365Shelge dp = um->um_tab.b_actf;
86912365Shelge while (dp->b_actf) {
87012365Shelge dp->b_errcnt++;
87112365Shelge bp = dp->b_actf;
87212365Shelge bp->b_error = EIO;
87312365Shelge bp->b_flags |= B_ERROR;
87412365Shelge iodone(bp);
87512365Shelge dp->b_actf = bp->av_forw;
87612365Shelge }
87712365Shelge }
87810773Ssam #endif
879