xref: /csrg-svn/sys/vax/uba/rx.c (revision 11649)
1*11649Shelge /*	rx.c	4.6	83/03/23	*/
210773Ssam 
310773Ssam #include "rx.h"
410773Ssam #if NFX > 0
510773Ssam /*
610773Ssam  * RX02 floppy disk device driver
710773Ssam  *
8*11649Shelge  * -- WARNING, UNTESTED --
910773Ssam  */
1011205Ssam #include "../machine/pte.h"
1111205Ssam 
1210773Ssam #include "../h/param.h"
1311205Ssam #include "../h/buf.h"
1410773Ssam #include "../h/systm.h"
1510773Ssam #include "../h/conf.h"
1611214Shelge #include "../h/errno.h"
1711214Shelge #include "../h/time.h"
1811205Ssam #include "../h/kernel.h"
1911205Ssam #include "../h/uio.h"
2011214Shelge #include "../h/file.h"
2110773Ssam 
2211205Ssam #include "../vax/cpu.h"
2310773Ssam #include "../vax/nexus.h"
2410773Ssam #include "../vaxuba/ubavar.h"
2510773Ssam #include "../vaxuba/ubareg.h"
2610773Ssam #include "../vaxuba/rxreg.h"
2710773Ssam 
2810773Ssam /* per-controller data */
2910773Ssam struct	rx_ctlr {
3010773Ssam 	int	rxc_state;	/* controller state */
3110773Ssam #define	RXS_READ	1	/* read started	*/
3210773Ssam #define	RXS_EMPTY	2	/* empty started */
3310773Ssam #define	RXS_FILL	3	/* fill started	*/
3410773Ssam #define	RXS_WRITE	4	/* write started */
3510773Ssam #define	RXS_FORMAT	5	/* format started */
3610773Ssam #define	RXS_RDSTAT	6	/* status read started */
3710773Ssam #define	RXS_RDERR	7	/* error read started */
3811205Ssam #define RXS_IDLE	8	/* device is idle */
3910773Ssam 	u_short	rxc_rxcs;	/* extended error status */
4010773Ssam 	u_short	rxc_rxdb;
4110773Ssam 	u_short	rxc_rxxt[4];
4211205Ssam #define	RX_MAXTIMEOUT	30	/* # seconds to wait before giving up */
4310773Ssam } rx_ctlr[NFX];
4410773Ssam 
45*11649Shelge /* per-drive buffers */
46*11649Shelge struct buf	rrxbuf[NRX];	/* buffers for I/O */
47*11649Shelge struct buf	erxbuf[NRX];	/* buffers for reading error status */
48*11649Shelge 
4910773Ssam /* per-drive data */
5010773Ssam struct rx_softc {
5111205Ssam 	int	sc_flags;	/* drive status flags */
5210773Ssam #define	RXF_DBLDEN	0x01	/* use double density */
5310773Ssam #define	RXF_DIRECT	0x02	/* use direct sector mapping */
5410773Ssam #define	RXF_TRKZERO	0x04	/* start mapping on track 0 */
5510773Ssam #define	RXF_DEVTYPE	0x07	/* density and mapping flags */
5610773Ssam #define	RXF_OPEN	0x10	/* open */
5710773Ssam #define	RXF_DDMK	0x20	/* deleted-data mark detected */
5810773Ssam #define	RXF_USEWDDS	0x40	/* write deleted-data sector */
5911205Ssam 	int	sc_csbits;	/* constant bits for CS register */
6011205Ssam 	int	sc_tocnt;	/* for watchdog routine */
6110773Ssam } rx_softc[NRX];
6210773Ssam 
6311205Ssam struct rxerr {
6411205Ssam 	short	rxcs;
6511205Ssam 	short	rxdb;
6611205Ssam 	short	rxxt[4];	/* error code dump from controller */
6711633Shelge } rxerr[NRX];
6811633Shelge /* End of per-drive data */
6911205Ssam 
7010773Ssam struct	uba_device *rxdinfo[NRX];
7110773Ssam struct	uba_ctlr *rxminfo[NFX];
7211633Shelge int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr(), rxwatch(), rxphys();
7310773Ssam u_short rxstd[] = { 0177170, 0177150, 0 };
7410773Ssam struct uba_driver fxdriver =
7510773Ssam   { rxprobe, rxslave, rxattach, rxdgo, rxstd, "rx", rxdinfo, "fx", rxminfo };
7610773Ssam 
7710773Ssam int	rxwstart;
7811633Shelge #define	RXUNIT(dev)	(minor(dev)>>3)
79*11649Shelge #define MASKREG(reg)	(reg&0xffff)
8010773Ssam 
8110773Ssam /* constants related to floppy data capacity */
8210773Ssam #define	RXSECS	2002				/* # sectors on a floppy */
8311205Ssam #define	DDSTATE	(sc->sc_flags&RXF_DBLDEN)
8410773Ssam #define	NBPS	(DDSTATE ? 256 : 128)		/* # bytes per sector */
8510773Ssam #define	NWPS	(DDSTATE ? 128 : 64)		/* # words per sector */
8610773Ssam #define	RXSIZE	(DDSTATE ? 512512 : 256256)	/* # bytes per disk */
8710773Ssam #define	SECSHFT	(DDSTATE ? 8 : 7)		/* # bits to shift for sctr # */
8810773Ssam #define	SECMASK	(DDSTATE ? 0xff : 0x7f)		/* shifted-out bits of offset */
8910773Ssam 
9011205Ssam #define	B_CTRL	0x80000000			/* control (format) request */
9110773Ssam 
9210773Ssam /*ARGSUSED*/
9310773Ssam rxprobe (reg)
9410773Ssam 	caddr_t reg;
9510773Ssam {
9611205Ssam 	register int br, cvec;			/* value-result */
9710773Ssam 	struct rxdevice *rxaddr = (struct rxdevice *)reg;
9810773Ssam 
9910773Ssam #ifdef lint
10010773Ssam 	br = 0; cvec = br; br = cvec;
10111205Ssam 	rxintr(0);
10210773Ssam #endif lint
10310773Ssam 	rxaddr->rxcs = RX_INTR;
10410773Ssam 	DELAY(10);
10510773Ssam 	rxaddr->rxcs = 0;
10610773Ssam 	return (sizeof (*rxaddr));
10710773Ssam }
10810773Ssam 
10910773Ssam rxslave(ui,reg)
11010773Ssam 	struct uba_device *ui;
11110773Ssam 	caddr_t reg;
11210773Ssam {
11310773Ssam 
11410773Ssam 	ui->ui_dk = 1;
11510773Ssam 	return (ui->ui_slave == 0 || ui->ui_slave == 1);
11610773Ssam }
11710773Ssam 
11810773Ssam /*ARGSUSED*/
11910773Ssam rxattach(ui)
12010773Ssam 	struct uba_device *ui;
12110773Ssam {
12210773Ssam 
12310773Ssam }
12410773Ssam 
12510773Ssam /*ARGSUSED1*/
12610773Ssam rxopen(dev, flag)
12710773Ssam 	dev_t dev;
12810773Ssam 	int flag;
12910773Ssam {
13010773Ssam 	register int unit = RXUNIT(dev);
13110773Ssam 	register struct rx_softc *sc;
13210773Ssam 	register struct uba_device *ui;
13310773Ssam 
13411633Shelge 	if (unit >= NRX || (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0)
13511205Ssam 		return (ENXIO);
13610773Ssam 	sc = &rx_softc[unit];
13711205Ssam 	if (sc->sc_flags & RXF_OPEN)
13811205Ssam 		return (EBUSY);
13911205Ssam 	sc->sc_flags = RXF_OPEN | (minor(dev) & RXF_DEVTYPE);
14011205Ssam 	sc->sc_csbits = RX_INTR;
14111205Ssam 	sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1;
14211205Ssam 	sc->sc_csbits |= minor(dev) & RXF_DBLDEN ? RX_DDEN : RX_SDEN;
14311205Ssam 	return (0);
14410773Ssam }
14510773Ssam 
14610773Ssam /*ARGSUSED1*/
14710773Ssam rxclose(dev, flag)
14810773Ssam 	dev_t dev;
14910773Ssam 	int flag;
15010773Ssam {
15110773Ssam 	register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
15210773Ssam 
15310773Ssam 	sc->sc_flags &= ~RXF_OPEN;
15410773Ssam 	sc->sc_csbits = 0;
15510773Ssam }
15610773Ssam 
15710773Ssam rxstrategy(bp)
15810773Ssam 	register struct buf *bp;
15910773Ssam {
16010773Ssam 	struct uba_device *ui;
16110773Ssam 	register struct uba_ctlr *um;
16211205Ssam 	int s;
16310773Ssam 
16410773Ssam 	ui = rxdinfo[RXUNIT(bp->b_dev)];
16510773Ssam 	if (ui == 0 || ui->ui_alive == 0) {
16610773Ssam 		bp->b_flags |= B_ERROR;
16710773Ssam 		iodone(bp);
16810773Ssam 		return;
16910773Ssam 	}
17010773Ssam 	um = ui->ui_mi;
17110773Ssam 	bp->b_actf = NULL;
17211205Ssam 	s = spl5();
173*11649Shelge 	if (um->um_tab.b_actf == NULL)
174*11649Shelge 		um->um_tab.b_actf = bp;
17510773Ssam 	else
176*11649Shelge 		um->um_tab.b_actl->b_forw = bp;
177*11649Shelge 	um->um_tab.b_actl = bp;
178*11649Shelge 	rxstart(um);
17910773Ssam 	splx(s);
18010773Ssam }
18110773Ssam 
18210773Ssam /*
18310773Ssam  * Sector mapping routine.
18410773Ssam  * Two independent sets of choices are available:
18510773Ssam  *
18610773Ssam  * (a) The first logical sector may either be on track 1 or track 0.
18710773Ssam  * (b) The sectors on a track may either be taken in 2-for-1 interleaved
18810773Ssam  *	 fashion or directly.
18910773Ssam  * This gives a total of four possible mapping schemes.
19010773Ssam  *
19110773Ssam  * Physical tracks on the RX02 are numbered 0-76.  Physical sectors on
19210773Ssam  * each track are numbered 1-26.
19310773Ssam  *
19410773Ssam  * When interleaving is used, sectors on the first logical track are
19510773Ssam  * taken in the order 1, 3, 5, ..., 25, 2, 4, 6, ..., 26.  A skew of
19610773Ssam  * six sectors per track is also used (to allow time for the heads to
19710773Ssam  * move); hence, the sectors on the second logical track are taken in
19810773Ssam  * the order 7, 9, 11, ..., 25, 1, 3, 5, 8, 10, 12, ..., 26, 2, 4, 6;
19910773Ssam  * the third logical track starts with sector 13; and so on.
20010773Ssam  *
20110773Ssam  * When the mapping starts with track 1, track 0 is the last logical
20210773Ssam  * track, and this track is always handled directly (without inter-
20310773Ssam  * leaving), even when the rest of the disk is interleaved.  (This is
20410773Ssam  * still compatible with DEC RT-11, which does not use track 0 at all.)
20510773Ssam  */
20611205Ssam rxmap(bp, psector, ptrack)
20711205Ssam 	struct buf *bp;
20811205Ssam 	int *psector, *ptrack;
20910773Ssam {
21010773Ssam 	register int lt, ls, ptoff;
21111205Ssam 	struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
21210773Ssam 
213*11649Shelge 	ls = ( bp->b_blkno * DEV_BSIZE ) / NBPS;
21411205Ssam 	lt = ls / 26;
21511205Ssam 	ls %= 26;
21610773Ssam 	/*
21710773Ssam 	 * The "physical track offset" (ptoff) takes the
21810773Ssam 	 * starting physical track (0 or 1) and the desired
21910773Ssam 	 * interleaving into account.  If lt+ptoff >= 77,
22010773Ssam 	 * then interleaving is not performed.
22110773Ssam 	 */
22210773Ssam 	ptoff = 0;
22311205Ssam 	if (sc->sc_flags&RXF_DIRECT)
22411205Ssam 		ptoff = 77;
22511205Ssam 	if (sc->sc_flags&RXF_TRKZERO)
22610773Ssam 		ptoff++;
22710773Ssam 	if (lt + ptoff < 77)
22810773Ssam 		ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
22911205Ssam 	*ptrack = (lt + ptoff) % 77;
23011205Ssam 	*psector = ls + 1;
23110773Ssam }
23210773Ssam 
23310773Ssam rxstart(um)
23410773Ssam 	register struct uba_ctlr *um;
23510773Ssam {
23610773Ssam 	register struct rxdevice *rxaddr;
23710773Ssam 	register struct rx_ctlr *rxc;
23810773Ssam 	register struct rx_softc *sc;
23910773Ssam 	struct buf *bp;
24011205Ssam 	int unit, sector, track;
24110773Ssam 
242*11649Shelge 	if (um->um_tab.b_active || (bp = um->um_tab.b_actf) == NULL)
24310773Ssam 		return;
24411205Ssam 	um->um_tab.b_active++;
24510773Ssam 	unit = RXUNIT(bp->b_dev);
24610773Ssam 	sc = &rx_softc[unit];
24710773Ssam 	rxaddr = (struct rxdevice *)um->um_addr;
24810773Ssam 	rxc = &rx_ctlr[um->um_ctlr];
24911205Ssam 	rxtimo(bp->b_dev);				/* start watchdog */
25011205Ssam 	if (bp->b_flags&B_CTRL) {			/* format */
25110773Ssam 		rxc->rxc_state = RXS_FORMAT;
25210773Ssam 		rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
25311205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
25410773Ssam 			;
25510773Ssam 		rxaddr->rxdb = 'I';
25610773Ssam 		return;
25710773Ssam 	}
25811205Ssam 	if (bp->b_flags&B_READ) {			/* read */
25911205Ssam 		rxmap(bp, &sector, &track);
26010773Ssam 		rxc->rxc_state = RXS_READ;
26110773Ssam 		rxaddr->rxcs = RX_READ | sc->sc_csbits;
26211633Shelge 		printf("rxstart: (read) track=%d, sector=%d\n", track, sector);
26311205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
26410773Ssam 			;
26511205Ssam 		rxaddr->rxdb = (u_short)sector;
26611205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
26710773Ssam 			;
26811205Ssam 		rxaddr->rxdb = (u_short)track;
26910773Ssam 		return;
27010773Ssam 	}
27111205Ssam 	rxc->rxc_state = RXS_FILL;			/* write */
27210773Ssam 	um->um_cmd = RX_FILL;
27310773Ssam 	(void) ubago(rxdinfo[unit]);
27410773Ssam }
27510773Ssam 
27610773Ssam rxdgo(um)
27710773Ssam 	struct uba_ctlr *um;
27810773Ssam {
27910773Ssam 	register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr;
28010773Ssam 	int ubinfo = um->um_ubinfo;
281*11649Shelge 	struct buf *bp = um->um_tab.b_actf;
28210773Ssam 	struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
28310773Ssam 	struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
28410773Ssam 
28511205Ssam 	sc->sc_tocnt = 0;
28610773Ssam 	if (rxc->rxc_state != RXS_RDERR) {
28711205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
28810773Ssam 			;
28911205Ssam 		rxaddr->rxdb = bp->b_bcount >> 1;
29010773Ssam 	}
29111205Ssam 	while ((rxaddr->rxcs&RX_TREQ) == 0)
29210773Ssam 		;
29311205Ssam 	rxaddr->rxdb = ubinfo;
29410773Ssam 	rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
29510773Ssam }
29610773Ssam 
29711205Ssam rxintr(dev)
29811205Ssam 	dev_t dev;
29910773Ssam {
30011205Ssam 	int unit = RXUNIT(dev), sector, track;
30111205Ssam 	struct uba_ctlr *um = rxminfo[unit];
30211205Ssam 	register struct rxdevice *rxaddr;
30311205Ssam 	register struct buf *bp;
30410773Ssam 	register struct rx_softc *sc = &rx_softc[unit];
30510773Ssam 	struct uba_device *ui = rxdinfo[unit];
30611205Ssam 	struct rxerr *er;
30711205Ssam 	register struct rx_ctlr *rxc;
30810773Ssam 
30911205Ssam 	sc->sc_tocnt = 0;
31011205Ssam 	if (!um->um_tab.b_active)
31110773Ssam 		return;
31211205Ssam 	rxaddr = (struct rxdevice *)um->um_addr;
31311205Ssam 	rxc = &rx_ctlr[um->um_ctlr];
314*11649Shelge 	er = &rxerr[unit];
315*11649Shelge 	bp = um->um_tab.b_actf;
316*11649Shelge 	printf("rxintr: unit=%d, state=0x%x, ctrlr status=0x%x\n",
317*11649Shelge 		unit, rxc->rxc_state, rxaddr->rxcs);
31811205Ssam 	if ((rxaddr->rxcs & RX_ERR) &&
31911205Ssam 	    rxc->rxc_state != RXS_RDSTAT && rxc->rxc_state != RXS_RDERR)
32011205Ssam 		goto error;
32110773Ssam 	switch (rxc->rxc_state) {
32210773Ssam 
32311205Ssam 	/*
32411205Ssam 	 * Incomplete commands.  Perform next step
32511205Ssam 	 * and return.  Note that b_active is set on
32611205Ssam 	 * entrance and, therefore, also on exit.
32711205Ssam 	 */
32810773Ssam 	case RXS_READ:
32910773Ssam 		if (rxaddr->rxdb & RXES_DDMARK)
33010773Ssam 			sc->sc_flags |= RXF_DDMK;
33110773Ssam 		else
33210773Ssam 			sc->sc_flags &= ~RXF_DDMK;
33310773Ssam 		rxc->rxc_state = RXS_EMPTY;
33410773Ssam 		um->um_cmd = RX_EMPTY;
33510773Ssam 		(void) ubago(ui);
33610773Ssam 		return;
33710773Ssam 
33810773Ssam 	case RXS_FILL:
33910773Ssam 		rxc->rxc_state = RXS_WRITE;
34010773Ssam 		if (sc->sc_flags & RXF_USEWDDS) {
34110773Ssam 			rxaddr->rxcs = RX_WDDS | sc->sc_csbits;
34210773Ssam 			sc->sc_flags &= ~RXF_USEWDDS;
34310773Ssam 		} else
34410773Ssam 			rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
34511205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
34610773Ssam 			;
34711205Ssam 		rxmap(bp, &sector, &track);
34811205Ssam 		rxaddr->rxdb = sector;
34911205Ssam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
35010773Ssam 			;
35111205Ssam 		rxaddr->rxdb = track;
35210773Ssam 		return;
35310773Ssam 
35411205Ssam 	/*
35511205Ssam 	 * Possibly completed command.
35611205Ssam 	 */
35710773Ssam 	case RXS_RDSTAT:
35811205Ssam 		if (rxaddr->rxdb&RXES_READY)
35910773Ssam 			goto rderr;
36010773Ssam 		bp->b_error = EBUSY;
36110773Ssam 		bp->b_flags |= B_ERROR;
36211205Ssam 		goto done;
36310773Ssam 
36411205Ssam 	/*
36511205Ssam 	 * Command completed.
36611205Ssam 	 */
36711205Ssam 	case RXS_EMPTY:
36811205Ssam 	case RXS_WRITE:
36911205Ssam 	case RXS_FORMAT:
37011205Ssam 		goto done;
37111205Ssam 
37210773Ssam 	case RXS_RDERR:
37311205Ssam 		rxmap(bp, &sector, &track);
37411205Ssam 		printf("rx%d: hard error, lsn%d (trk %d psec %d) ",
37511214Shelge 			unit, bp->b_blkno * (NBPS / DEV_BSIZE),
37611205Ssam 			track, sector);
377*11649Shelge 		printf("cs=%b, db=%b, err=%x\n", MASKREG(er->rxcs),
378*11649Shelge 			RXCS_BITS, MASKREG(er->rxdb), RXES_BITS,
379*11649Shelge 			MASKREG(er->rxxt[0]));
380*11649Shelge 		printf("errstatus: 0x%x, 0x%x, 0x%x, 0x%x\n", er->rxxt[0],
381*11649Shelge 			er->rxxt[1], er->rxxt[2], er->rxxt[3]);
38211205Ssam 		goto done;
38310773Ssam 
38410773Ssam 	default:
38511205Ssam 		printf("rx%d: state %d (reset)", unit, rxc->rxc_state);
38611205Ssam 		rxreset(um->um_ubanum);
38710773Ssam 		printf("\n");
38810773Ssam 		return;
38910773Ssam 	}
39010773Ssam error:
39110773Ssam 	/*
39210773Ssam 	 * In case of an error:
39310773Ssam 	 *  (a) Give up now if a format (ioctl) was in progress, or if a
39410773Ssam 	 *	  density error was detected.
39510773Ssam 	 *  (b) Retry up to nine times if a CRC (data) error was detected,
39610773Ssam 	 *	  then give up if the error persists.
39710773Ssam 	 *  (c) In all other cases, reinitialize the drive and try the
39810773Ssam 	 *	  operation once more before giving up.
39910773Ssam 	 */
40011205Ssam 	if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR))
40110773Ssam 		goto giveup;
40210773Ssam 	if (rxaddr->rxdb & RXES_CRCERR) {
40310773Ssam 		if (++bp->b_errcnt >= 10)
40410773Ssam 			goto giveup;
40510773Ssam 		goto retry;
40610773Ssam 	}
40710773Ssam 	bp->b_errcnt += 9;
40810773Ssam 	if (bp->b_errcnt >= 10)
40910773Ssam 		goto giveup;
41010773Ssam 	rxaddr->rxcs = RX_INIT;
41110773Ssam 	/* no way to get an interrupt for "init done", so just wait */
41211205Ssam 	while ((rxaddr->rxdb&RX_DONE) == 0)
41310773Ssam 		;
41410773Ssam retry:
41511205Ssam 	/*
41611205Ssam 	 * In case we already have UNIBUS resources, give
41711205Ssam 	 * them back since we reallocate things in rxstart.
418*11649Shelge 	 * Also, the active flag must be reset, otherwise rxstart
419*11649Shelge 	 * will refuse to restart the transfer
42011205Ssam 	 */
42111205Ssam 	if (um->um_ubinfo)
42211205Ssam 		ubadone(um);
423*11649Shelge 	um->um_tab.b_active = 0;
42411205Ssam 	rxstart(um);
42510773Ssam 	return;
42611205Ssam 
42710773Ssam giveup:
42810773Ssam 	/*
42910773Ssam 	 * Hard I/O error --
43011205Ssam 	 * Density errors are not noted on the console since the
43111205Ssam 	 * only way to determine the density of an unknown disk
43211205Ssam 	 * is to try one density or the other at random and see
43311205Ssam 	 * which one doesn't give a density error.
43410773Ssam 	 */
43510773Ssam 	if (rxaddr->rxdb & RXES_DENERR) {
43611205Ssam 		bp->b_error = EIO;
43710773Ssam 		bp->b_flags |= B_ERROR;
43810773Ssam 		goto done;
43910773Ssam 	}
44010773Ssam 	rxc->rxc_state = RXS_RDSTAT;
44110773Ssam 	rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
44210773Ssam 	return;
44311205Ssam 
44410773Ssam rderr:
44510773Ssam 	/*
44610773Ssam 	 * A hard error (other than not ready or density) has occurred.
44710773Ssam 	 * Read the extended error status information.
44810773Ssam 	 * Before doing this, save the current CS and DB register values,
44910773Ssam 	 * because the read error status operation may modify them.
45011205Ssam 	 * Insert buffer with request at the head of the queue.
45110773Ssam 	 */
45210773Ssam 	bp->b_error = EIO;
45310773Ssam 	bp->b_flags |= B_ERROR;
45410773Ssam 	ubadone(um);
45510773Ssam 	er->rxcs = rxaddr->rxcs;
45610773Ssam 	er->rxdb = rxaddr->rxdb;
45711214Shelge 	bp = &erxbuf[unit];
45810773Ssam 	bp->b_un.b_addr = (caddr_t)er->rxxt;
45910773Ssam 	bp->b_bcount = sizeof (er->rxxt);
46010773Ssam 	bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
461*11649Shelge 	if (um->um_tab.b_actf == NULL)
462*11649Shelge 		um->um_tab.b_actl = bp;
463*11649Shelge 	bp->b_forw = um->um_tab.b_actf;
464*11649Shelge 	um->um_tab.b_actf = bp;
46510773Ssam 	rxc->rxc_state = RXS_RDERR;
46610773Ssam 	um->um_cmd = RX_RDERR;
46710773Ssam 	(void) ubago(ui);
46811205Ssam 	return;
46911205Ssam done:
47011205Ssam 	um->um_tab.b_active = 0;
471*11649Shelge 	um->um_tab.b_actf = bp->b_forw;
47211205Ssam 	bp->b_resid = 0;
47311205Ssam 	iodone(bp);
47411205Ssam 	rxc->rxc_state = RXS_IDLE;
47511205Ssam 	ubadone(um);
47611205Ssam 	/*
477*11649Shelge 	 * If this unit (controller) has more work to do,
47811205Ssam 	 * start it up right away
47911205Ssam 	 */
480*11649Shelge 	if (um->um_tab.b_actf)
48111214Shelge 		rxstart(um);
48210773Ssam }
48310773Ssam 
48410773Ssam /*ARGSUSED*/
48510773Ssam minrxphys(bp)
48610773Ssam 	struct buf *bp;
48710773Ssam {
48811214Shelge 	struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
48910773Ssam 
49010773Ssam 	if (bp->b_bcount > NBPS)
49110773Ssam 		bp->b_bcount = NBPS;
49210773Ssam }
49310773Ssam 
49411205Ssam rxtimo(dev)
49511205Ssam 	dev_t dev;
49610773Ssam {
49710773Ssam 	register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
49810773Ssam 
49911205Ssam 	if (sc->sc_flags & RXF_OPEN)
50011205Ssam 		timeout(rxtimo, (caddr_t)dev, hz);
50110773Ssam 	if (++sc->sc_tocnt < RX_MAXTIMEOUT)
50210773Ssam 		return;
503*11649Shelge 	printf("rx: timeout on dev %d\n", dev);
50410773Ssam 	rxintr(dev);
50510773Ssam }
50610773Ssam 
50710773Ssam rxreset(uban)
50810773Ssam 	int uban;
50910773Ssam {
51010773Ssam 	register struct uba_ctlr *um;
51110773Ssam 	register struct rxdevice *rxaddr;
51210773Ssam 	register int ctlr;
51310773Ssam 
51410773Ssam 	for (ctlr = 0; ctlr < NFX; ctlr++) {
51510773Ssam 		if ((um = rxminfo[ctlr]) == 0 || um->um_ubanum != uban ||
51610773Ssam 		    um->um_alive == 0)
51710773Ssam 			continue;
51811633Shelge 		printf(" fx%d: ", ctlr);
51910773Ssam 		if (um->um_ubinfo) {
52010773Ssam 			printf("<%d>", (um->um_ubinfo>>28)&0xf);
52111205Ssam 			um->um_ubinfo = 0;
52210773Ssam 		}
52310773Ssam 		rx_ctlr[ctlr].rxc_state = RXS_IDLE;
52410773Ssam 		rxaddr = (struct rxdevice *)um->um_addr;
52511205Ssam 		rxaddr->rxcs = RX_INIT;
52611205Ssam 		while ((rxaddr->rxdb&RX_DONE) == 0)
52710773Ssam 			;
52811205Ssam 		rxstart(um);
52910773Ssam 	}
53010773Ssam }
53110773Ssam 
53211205Ssam rxread(dev, uio)
53310773Ssam 	dev_t dev;
53411205Ssam 	struct uio *uio;
53510773Ssam {
53610773Ssam 	int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
53711214Shelge 	struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
53810773Ssam 
53911205Ssam 	if (uio->uio_offset + uio->uio_resid > RXSIZE)
54011205Ssam 		return (ENXIO);
54111205Ssam 	if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
54211205Ssam 		return (EIO);
54311633Shelge 	return (physio(rxstrategy, &rrxbuf[ctlr], dev, B_READ, minrxphys, uio));
54410773Ssam }
54510773Ssam 
54611205Ssam rxwrite(dev, uio)
54710773Ssam 	dev_t dev;
54811205Ssam 	struct uio *uio;
54910773Ssam {
55010773Ssam 	int unit = RXUNIT(dev), ctlr = rxdinfo[unit]->ui_ctlr;
55111214Shelge 	struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
55210773Ssam 
55311205Ssam 	if (uio->uio_offset + uio->uio_resid > RXSIZE)
55411205Ssam 		return (ENXIO);
55511205Ssam 	if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
55611205Ssam 		return (EIO);
55711633Shelge 	return(physio(rxstrategy, &rrxbuf[ctlr], dev, B_WRITE, minrxphys, uio));
55810773Ssam }
55910773Ssam 
56010773Ssam /*
56110773Ssam  * Control routine:
56210773Ssam  * processes three kinds of requests:
56310773Ssam  *
56411633Shelge  *	(1) Set density (i.e., format the diskette) according to
56511633Shelge  *		  that specified by the open device.
56610773Ssam  *	(2) Arrange for the next sector to be written with a deleted-
56710773Ssam  *		  data mark.
56810773Ssam  *	(3) Report whether the last sector read had a deleted-data mark
56910773Ssam  *		  (by returning with an EIO error code if it did).
57010773Ssam  *
57110773Ssam  * Requests relating to deleted-data marks can be handled right here.
57210773Ssam  * A "set density" request, however, must additionally be processed
57310773Ssam  * through "rxstart", just like a read or write request.
57410773Ssam  */
57510773Ssam /*ARGSUSED3*/
57611205Ssam rxioctl(dev, cmd, data, flag)
57710773Ssam 	dev_t dev;
57810773Ssam 	int cmd;
57911205Ssam 	caddr_t data;
58010773Ssam 	int flag;
58110773Ssam {
58210773Ssam 	int unit = RXUNIT(dev);
58310773Ssam 	struct rx_softc *sc = &rx_softc[unit];
58410773Ssam 
58510773Ssam 	switch (cmd) {
58610773Ssam 
58711205Ssam 	case RXIOC_FORMAT:
58810773Ssam 		if ((flag&FWRITE) == 0)
58911205Ssam 			return (EBADF);
59011214Shelge 		return (rxformat(dev));
59110773Ssam 
59211205Ssam 	case RXIOC_WDDS:
59311205Ssam 		sc->sc_flags |= RXF_USEWDDS;
59411205Ssam 		return (0);
59510773Ssam 
59611205Ssam 	case RXIOC_RDDSMK:
59711205Ssam 		*(int *)data = sc->sc_flags & RXF_DDMK;
59811205Ssam 		return (0);
59910773Ssam 	}
60011205Ssam 	return (ENXIO);
60111205Ssam }
60210773Ssam 
60311205Ssam /*
60411205Ssam  * Initiate a format command.
60511205Ssam  */
60611214Shelge rxformat(dev)
60711214Shelge 	dev_t dev;
60811205Ssam {
60911214Shelge 	int ctlr = rxdinfo[RXUNIT(dev)]->ui_mi->um_ctlr;
61011205Ssam 	struct buf *bp;
61111214Shelge 	struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
61211205Ssam 	int s, error = 0;
61311205Ssam 
614*11649Shelge 	bp = &rrxbuf[RXUNIT(dev)];
61510773Ssam 	s = spl5();
61610773Ssam 	while (bp->b_flags & B_BUSY)
61710773Ssam 		sleep(bp, PRIBIO);
61810773Ssam 	bp->b_flags = B_BUSY | B_CTRL;
61910773Ssam 	splx(s);
62011205Ssam 	sc->sc_flags = RXS_FORMAT;
62110773Ssam 	bp->b_dev = dev;
62210773Ssam 	bp->b_error = 0;
62311205Ssam 	bp->b_resid = 0;
62410773Ssam 	rxstrategy (bp);
62510773Ssam 	iowait(bp);
62611205Ssam 	if (bp->b_flags & B_ERROR)
62711205Ssam 		error = bp->b_error;
62810773Ssam 	bp->b_flags &= ~B_BUSY;
62911205Ssam 	wakeup((caddr_t)bp);
63011205Ssam 	return (error);
63110773Ssam }
63210773Ssam #endif
633