xref: /csrg-svn/sys/vax/uba/rx.c (revision 45805)
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, &sector, &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, &sector, &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, &sector, &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