xref: /original-bsd/sys/vax/uba/rx.c (revision 1c14281d)
16d332d1bSmckusick /*
2131d4853Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
36d332d1bSmckusick  * All rights reserved.  The Berkeley software License Agreement
46d332d1bSmckusick  * specifies the terms and conditions for redistribution.
56d332d1bSmckusick  *
6*1c14281dSbostic  *	@(#)rx.c	7.5 (Berkeley) 12/16/90
76d332d1bSmckusick  */
8f05c6a60Ssam 
9f05c6a60Ssam #include "rx.h"
10f05c6a60Ssam #if NFX > 0
11f05c6a60Ssam /*
12f05c6a60Ssam  * RX02 floppy disk device driver
13f05c6a60Ssam  *
14f05c6a60Ssam  */
1512fa0442Shelge 
1612fa0442Shelge /*
175cdc5eccShelge  * TODO:
180099a24dShelge  *	- clean up the code for multisector transfers using
190099a24dShelge  *	  a 'transfer in progress' flag
200099a24dShelge  *	- Test Deleted Data read/write
2107190e5fShelge  *	- Test error handling/reporting and 'volume valid' stuff
225cdc5eccShelge  *
2312fa0442Shelge  * 	Note: If the drive subsystem is
2412fa0442Shelge  * 	powered off at boot time, the controller won't interrupt!
2512fa0442Shelge  */
2612fa0442Shelge 
27*1c14281dSbostic #include "../include/pte.h"
28f05c6a60Ssam 
29*1c14281dSbostic #include "sys/param.h"
30*1c14281dSbostic #include "sys/buf.h"
31*1c14281dSbostic #include "sys/systm.h"
32*1c14281dSbostic #include "sys/conf.h"
33*1c14281dSbostic #include "sys/errno.h"
34*1c14281dSbostic #include "sys/time.h"
35*1c14281dSbostic #include "sys/kernel.h"
36*1c14281dSbostic #include "sys/uio.h"
37*1c14281dSbostic #include "sys/file.h"
38a0407b1cSsam 
39*1c14281dSbostic #include "../include/cpu.h"
40f05c6a60Ssam #include "../vax/nexus.h"
4107190e5fShelge 
424ba4ebfbSbloom #include "ubavar.h"
434ba4ebfbSbloom #include "ubareg.h"
444ba4ebfbSbloom #include "rxreg.h"
45f05c6a60Ssam 
462eb71fd8Shelge #define b_cylin	b_resid
472eb71fd8Shelge 
48f05c6a60Ssam /* per-controller data */
49f05c6a60Ssam struct	rx_ctlr {
50f05c6a60Ssam 	int	rxc_state;	/* controller state */
51f05c6a60Ssam #define	RXS_READ	1	/* read started	*/
52f05c6a60Ssam #define	RXS_EMPTY	2	/* empty started */
53f05c6a60Ssam #define	RXS_FILL	3	/* fill started	*/
54f05c6a60Ssam #define	RXS_WRITE	4	/* write started */
55f05c6a60Ssam #define	RXS_FORMAT	5	/* format started */
56f05c6a60Ssam #define	RXS_RDSTAT	6	/* status read started */
57f05c6a60Ssam #define	RXS_RDERR	7	/* error read started */
58a0407b1cSsam #define	RXS_IDLE	8	/* device is idle */
59f05c6a60Ssam 	u_short	rxc_rxcs;	/* extended error status */
60f05c6a60Ssam 	u_short	rxc_rxdb;
61f05c6a60Ssam 	u_short	rxc_rxxt[4];
6212fa0442Shelge 	int	rxc_tocnt;	/* for watchdog routine */
63a0407b1cSsam #define	RX_MAXTIMEOUT	30	/* # seconds to wait before giving up */
64f05c6a60Ssam } rx_ctlr[NFX];
65da18c0ecShelge 
66da18c0ecShelge /* per-drive buffers */
67a59591daShelge struct buf	rrxbuf[NRX];	/* buffers for raw I/O */
68da18c0ecShelge struct buf	erxbuf[NRX];	/* buffers for reading error status */
695cdc5eccShelge struct buf	rxutab[NRX];	/* per drive buffers */
70f05c6a60Ssam 
71f05c6a60Ssam /* per-drive data */
72f05c6a60Ssam struct rx_softc {
73f05c6a60Ssam 	int	sc_flags;	/* drive status flags */
74e4af3149Shelge #define	RXF_DIRECT	0x01	/* if set: use direct sector mapping */
75e4af3149Shelge #define	RXF_TRKONE	0x02	/* if set: start mapping on track 1 */
760099a24dShelge #define	RXF_DBLDEN	0x04	/* use double density */
770099a24dShelge #define	RXF_DEVTYPE	0x07	/* mapping flags */
785cdc5eccShelge #define	RXF_LOCK	0x10	/* exclusive use */
79f05c6a60Ssam #define	RXF_DDMK	0x20	/* deleted-data mark detected */
80f05c6a60Ssam #define	RXF_USEWDDS	0x40	/* write deleted-data sector */
815cdc5eccShelge #define	RXF_FORMAT	0x80	/* format in progress */
82dfc0651cShelge #define	RXF_BAD		0x100	/* drive bad, cannot be used */
83f05c6a60Ssam 	int	sc_csbits;	/* constant bits for CS register */
842eb71fd8Shelge 	int	sc_open;	/* count number of opens */
855cdc5eccShelge 	int	sc_offset;	/* raw mode kludge to avoid restricting */
865cdc5eccShelge 				/* single sector transfers to start on */
875cdc5eccShelge 				/* DEV_BSIZE boundaries */
885cdc5eccShelge 	/*
895cdc5eccShelge 	 * The rest of this structure is used to
905cdc5eccShelge 	 * store temporaries while simulating multi
915cdc5eccShelge 	 * sector transfers
925cdc5eccShelge 	 */
935cdc5eccShelge 	caddr_t	sc_uaddr;	/* unibus base address */
945cdc5eccShelge 	long	sc_bcnt;	/* total transfer count */
95370c2a93Shelge 	long	sc_resid;	/* no. of bytes left to transfer */
96f05c6a60Ssam } rx_softc[NRX];
97f05c6a60Ssam 
98a0407b1cSsam struct rxerr {
99a0407b1cSsam 	short	rxcs;
100a0407b1cSsam 	short	rxdb;
101a0407b1cSsam 	short	rxxt[4];	/* error code dump from controller */
102fdaae61cShelge } rxerr[NRX];
103fdaae61cShelge /* End of per-drive data */
104a0407b1cSsam 
105f05c6a60Ssam struct	uba_device *rxdinfo[NRX];
106f05c6a60Ssam struct	uba_ctlr *rxminfo[NFX];
1072eb71fd8Shelge 
108dfc0651cShelge struct buf *savebp;
109dfc0651cShelge 
110fdaae61cShelge int rxprobe(), rxslave(), rxattach(), rxdgo(), rxintr(), rxwatch(), rxphys();
111f05c6a60Ssam u_short rxstd[] = { 0177170, 0177150, 0 };
112f05c6a60Ssam struct uba_driver fxdriver =
113f05c6a60Ssam   { rxprobe, rxslave, rxattach, rxdgo, rxstd, "rx", rxdinfo, "fx", rxminfo };
114f05c6a60Ssam 
115f05c6a60Ssam int	rxwstart;
116fdaae61cShelge #define	RXUNIT(dev)	(minor(dev)>>3)
117da18c0ecShelge #define	MASKREG(reg)	(reg&0xffff)
118f05c6a60Ssam 
119f05c6a60Ssam /* constants related to floppy data capacity */
120f05c6a60Ssam #define	RXSECS	2002				/* # sectors on a floppy */
1210099a24dShelge #define	DDSTATE	(sc->sc_csbits&RX_DDEN)
122f05c6a60Ssam #define	NBPS	(DDSTATE ? 256 : 128)		/* # bytes per sector */
123f05c6a60Ssam #define	RXSIZE	(DDSTATE ? 512512 : 256256)	/* # bytes per disk */
124f05c6a60Ssam #define	SECMASK	(DDSTATE ? 0xff : 0x7f)		/* shifted-out bits of offset */
125f05c6a60Ssam 
126f05c6a60Ssam #define	B_CTRL		0x80000000		/* control (format) request */
1270099a24dShelge #define B_RDSTAT	0x40000000		/* read drive status (open) */
128f05c6a60Ssam 
129f05c6a60Ssam /*ARGSUSED*/
rxprobe(reg)130f05c6a60Ssam rxprobe (reg)
131f05c6a60Ssam 	caddr_t reg;
132f05c6a60Ssam {
133f05c6a60Ssam 	register int br, cvec;			/* value-result */
134f05c6a60Ssam 	struct rxdevice *rxaddr = (struct rxdevice *)reg;
135f05c6a60Ssam 
136f05c6a60Ssam #ifdef lint
137f05c6a60Ssam 	br = 0; cvec = br; br = cvec;
138a0407b1cSsam 	rxintr(0);
139f05c6a60Ssam #endif lint
140f05c6a60Ssam 	rxaddr->rxcs = RX_INTR;
141f05c6a60Ssam 	DELAY(10);
142f05c6a60Ssam 	rxaddr->rxcs = 0;
143f05c6a60Ssam 	return (sizeof (*rxaddr));
144f05c6a60Ssam }
145f05c6a60Ssam 
14686e0f95cSbostic /*ARGSUSED*/
147f05c6a60Ssam rxslave(ui, reg)
148f05c6a60Ssam 	struct uba_device *ui;
149f05c6a60Ssam 	caddr_t reg;
150f05c6a60Ssam {
151f05c6a60Ssam 	return (ui->ui_slave == 0 || ui->ui_slave == 1);
152f05c6a60Ssam }
153f05c6a60Ssam 
154f05c6a60Ssam /*ARGSUSED*/
155f05c6a60Ssam rxattach(ui)
156f05c6a60Ssam 	struct uba_device *ui;
157f05c6a60Ssam {
158f05c6a60Ssam 
159f05c6a60Ssam }
160f05c6a60Ssam 
161f05c6a60Ssam /*ARGSUSED1*/
rxopen(dev,flag)162f05c6a60Ssam rxopen(dev, flag)
163f05c6a60Ssam 	dev_t dev;
164f05c6a60Ssam {
165f05c6a60Ssam 	register int unit = RXUNIT(dev);
166f05c6a60Ssam 	register struct rx_softc *sc;
167f05c6a60Ssam 	register struct uba_device *ui;
16812fa0442Shelge 	struct rx_ctlr *rxc;
169f05c6a60Ssam 
170fdaae61cShelge 	if (unit >= NRX || (ui = rxdinfo[unit]) == 0 || ui->ui_alive == 0)
171a0407b1cSsam 		return (ENXIO);
172f05c6a60Ssam 	sc = &rx_softc[unit];
1730099a24dShelge 	if (sc->sc_open == 0 && sc->sc_csbits == 0) {
1740099a24dShelge 		struct buf *bp = &erxbuf[unit];
1750099a24dShelge 		/*
1760099a24dShelge 		 * lock the device while an open
1770099a24dShelge 		 * is in progress
1780099a24dShelge 		 */
179e4af3149Shelge 		sc->sc_flags = (minor(dev) & RXF_DEVTYPE) | RXF_LOCK;
180a0407b1cSsam 		sc->sc_csbits = RX_INTR;
181a0407b1cSsam 		sc->sc_csbits |= ui->ui_slave == 0 ? RX_DRV0 : RX_DRV1;
1820099a24dShelge 
1830099a24dShelge 		bp->b_dev = dev;
1840099a24dShelge 		bp->b_flags = B_RDSTAT | B_BUSY;
1850099a24dShelge 		bp->b_error = 0;
1860099a24dShelge 		bp->b_blkno = 0;
187dfc0651cShelge 		sc->sc_offset = 0;
188dfc0651cShelge 		sc->sc_resid  = 0;
1890099a24dShelge 		/*
1900099a24dShelge 		 * read device status to determine if
1910099a24dShelge 		 * a floppy is present in the drive and
1920099a24dShelge 		 * what density it is
1930099a24dShelge 		 */
1940099a24dShelge 		rxstrategy(bp);
1950099a24dShelge 		iowait(bp);
1960099a24dShelge 		if (bp->b_flags & B_ERROR) {
1970099a24dShelge 			sc->sc_csbits = 0;
198ec691d4fSkarels 			sc->sc_flags &= ~RXF_LOCK;
1990099a24dShelge 			return (bp->b_error);
2000099a24dShelge 		}
2012eb71fd8Shelge 		if (rxwstart++ == 0) {
2020099a24dShelge 			rxc = &rx_ctlr[ui->ui_mi->um_ctlr];
20312fa0442Shelge 			rxc->rxc_tocnt = 0;
204e4af3149Shelge 			timeout(rxwatch, (caddr_t)0, hz);  /* start watchdog */
205a59591daShelge 		}
2060099a24dShelge #ifdef RXDEBUG
2070099a24dShelge 		printf("rxopen: csbits=0x%x\n", sc->sc_csbits);
2080099a24dShelge #endif
2090099a24dShelge 		sc->sc_flags &= ~RXF_LOCK;
2105cdc5eccShelge 	} else	{
2115cdc5eccShelge 		if (sc->sc_flags & RXF_LOCK)
2125cdc5eccShelge 			return(EBUSY);
2132eb71fd8Shelge 	}
214ec691d4fSkarels 	sc->sc_open = 1;
215a0407b1cSsam 	return (0);
216f05c6a60Ssam }
217f05c6a60Ssam 
218f05c6a60Ssam /*ARGSUSED1*/
rxclose(dev,flag)219f05c6a60Ssam rxclose(dev, flag)
220f05c6a60Ssam 	dev_t dev;
221f05c6a60Ssam {
222f05c6a60Ssam 	register struct rx_softc *sc = &rx_softc[RXUNIT(dev)];
223f05c6a60Ssam 
224ec691d4fSkarels 	sc->sc_open = 0;
225e4af3149Shelge #ifdef RXDEBUG
2265cdc5eccShelge 	printf("rxclose: dev=0x%x, sc_open=%d\n", dev, sc->sc_open);
227e4af3149Shelge #endif
228cc8db2eaSkarels 	return (0);
229f05c6a60Ssam }
230f05c6a60Ssam 
rxstrategy(bp)231f05c6a60Ssam rxstrategy(bp)
232f05c6a60Ssam 	register struct buf *bp;
233f05c6a60Ssam {
234f05c6a60Ssam 	struct uba_device *ui;
235a59591daShelge 	register struct buf *dp;
236a59591daShelge 	struct rx_softc *sc;
237a59591daShelge 	int s, unit = RXUNIT(bp->b_dev);
238f05c6a60Ssam 
2396623299cShelge 	if (unit >= NRX)
2406623299cShelge 		goto bad;
241a59591daShelge 	ui = rxdinfo[unit];
242a59591daShelge 	if (ui == 0 || ui->ui_alive == 0)
243a59591daShelge 		goto bad;
2440099a24dShelge 	sc = &rx_softc[unit];
245719bfd15Ssam 	if (bp->b_blkno < 0 || dbtob(bp->b_blkno) > RXSIZE)
246a59591daShelge 		goto bad;
247dfc0651cShelge 	if (sc->sc_flags & RXF_BAD) {
248dfc0651cShelge 		bp->b_error = EIO;
249dfc0651cShelge 		goto dbad;
250dfc0651cShelge 	}
251dfc0651cShelge 	s = spl5();
2522eb71fd8Shelge #ifdef RXDEBUG
253dfc0651cShelge 	printf("rxstrat: bp=0x%x, fl=0x%x, un=%d, bl=%d, cnt=%d\n",
2542eb71fd8Shelge 		bp, bp->b_flags, unit, bp->b_blkno, bp->b_bcount);
2552eb71fd8Shelge #endif
2562eb71fd8Shelge 	bp->b_cylin = bp->b_blkno;	/* don't care to calculate trackno */
2576623299cShelge 	dp = &rxutab[unit];
2586623299cShelge 	disksort(dp, bp);
2596623299cShelge 	if (dp->b_active == 0) {
2606623299cShelge 		rxustart(ui);
2616623299cShelge 		bp = &ui->ui_mi->um_tab;
2626623299cShelge 		if (bp->b_actf && bp->b_active == 0)
2636623299cShelge 			rxstart(ui->ui_mi);
2646623299cShelge 	}
265a59591daShelge 	splx(s);
266a59591daShelge 	return;
267a59591daShelge 
2682eb71fd8Shelge bad:
269dfc0651cShelge 	bp->b_error = ENXIO;
270dfc0651cShelge dbad:
2712eb71fd8Shelge 	bp->b_flags |= B_ERROR;
272f05c6a60Ssam 	iodone(bp);
273f05c6a60Ssam 	return;
274f05c6a60Ssam }
275f05c6a60Ssam 
276f05c6a60Ssam /*
277a59591daShelge  * Unit start routine.
2786623299cShelge  * Put this unit on the ready queue for the controller
279a59591daShelge  */
rxustart(ui)280a59591daShelge rxustart(ui)
281a59591daShelge 	register struct uba_device *ui;
282a59591daShelge {
2836623299cShelge 	struct buf *dp = &rxutab[ui->ui_unit];
2846623299cShelge 	struct uba_ctlr *um = ui->ui_mi;
285a59591daShelge 
286a59591daShelge 	dp->b_forw = NULL;
287a59591daShelge 	if (um->um_tab.b_actf == NULL)
288a59591daShelge 		um->um_tab.b_actf = dp;
289a59591daShelge 	else
290a59591daShelge 		um->um_tab.b_actl->b_forw = dp;
291a59591daShelge 	um->um_tab.b_actl = dp;
292a59591daShelge 	dp->b_active++;
293a59591daShelge }
294a59591daShelge /*
295f05c6a60Ssam  * Sector mapping routine.
296f05c6a60Ssam  * Two independent sets of choices are available:
297f05c6a60Ssam  *
298f05c6a60Ssam  * (a) The first logical sector may either be on track 1 or track 0.
299f05c6a60Ssam  * (b) The sectors on a track may either be taken in 2-for-1 interleaved
300f05c6a60Ssam  *	 fashion or directly.
301f05c6a60Ssam  * This gives a total of four possible mapping schemes.
302f05c6a60Ssam  *
303f05c6a60Ssam  * Physical tracks on the RX02 are numbered 0-76.  Physical sectors on
304f05c6a60Ssam  * each track are numbered 1-26.
305f05c6a60Ssam  *
306f05c6a60Ssam  * When interleaving is used, sectors on the first logical track are
307f05c6a60Ssam  * taken in the order 1, 3, 5, ..., 25, 2, 4, 6, ..., 26.  A skew of
308f05c6a60Ssam  * six sectors per track is also used (to allow time for the heads to
309f05c6a60Ssam  * move); hence, the sectors on the second logical track are taken in
310f05c6a60Ssam  * the order 7, 9, 11, ..., 25, 1, 3, 5, 8, 10, 12, ..., 26, 2, 4, 6;
311f05c6a60Ssam  * the third logical track starts with sector 13; and so on.
312f05c6a60Ssam  *
313f05c6a60Ssam  * When the mapping starts with track 1, track 0 is the last logical
314f05c6a60Ssam  * track, and this track is always handled directly (without inter-
315f05c6a60Ssam  * leaving), even when the rest of the disk is interleaved.  (This is
316f05c6a60Ssam  * still compatible with DEC RT-11, which does not use track 0 at all.)
317f05c6a60Ssam  */
318a0407b1cSsam rxmap(bp, psector, ptrack)
319a0407b1cSsam 	struct buf *bp;
320a0407b1cSsam 	int *psector, *ptrack;
321f05c6a60Ssam {
322f05c6a60Ssam 	register int lt, ls, ptoff;
323a0407b1cSsam 	struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
324f05c6a60Ssam 
325719bfd15Ssam 	ls = (dbtob(bp->b_blkno) + (sc->sc_offset - sc->sc_resid)) / NBPS;
326a0407b1cSsam 	lt = ls / 26;
327a0407b1cSsam 	ls %= 26;
328f05c6a60Ssam 	/*
329f05c6a60Ssam 	 * The "physical track offset" (ptoff) takes the
330f05c6a60Ssam 	 * starting physical track (0 or 1) and the desired
331f05c6a60Ssam 	 * interleaving into account.  If lt+ptoff >= 77,
332f05c6a60Ssam 	 * then interleaving is not performed.
333f05c6a60Ssam 	 */
334f05c6a60Ssam 	ptoff = 0;
335a0407b1cSsam 	if (sc->sc_flags & RXF_DIRECT)
336a0407b1cSsam 		ptoff = 77;
337e4af3149Shelge 	if (sc->sc_flags & RXF_TRKONE)
338f05c6a60Ssam 		ptoff++;
339f05c6a60Ssam 	if (lt + ptoff < 77)
340f05c6a60Ssam 		ls = ((ls << 1) + (ls >= 13) + (6*lt)) % 26;
341a0407b1cSsam 	*ptrack = (lt + ptoff) % 77;
342a0407b1cSsam 	*psector = ls + 1;
343f05c6a60Ssam }
344f05c6a60Ssam 
345a59591daShelge /*
3466623299cShelge  * Controller start routine.
3476623299cShelge  * Start a new transfer or continue a multisector
3486623299cShelge  * transfer. If this is a new transfer (dp->b_active == 1)
3496623299cShelge  * save the start address of the data buffer and the total
3506623299cShelge  * byte count in the soft control structure. These are
3516623299cShelge  * restored into the buffer structure when the transfer has
3526623299cShelge  * been completed, before calling 'iodone'.
353a59591daShelge  */
rxstart(um)354f05c6a60Ssam rxstart(um)
355f05c6a60Ssam 	register struct uba_ctlr *um;
356f05c6a60Ssam {
357f05c6a60Ssam 	register struct rxdevice *rxaddr;
358f05c6a60Ssam 	register struct rx_ctlr *rxc;
359f05c6a60Ssam 	register struct rx_softc *sc;
360a59591daShelge 	struct buf *dp, *bp;
361a0407b1cSsam 	int unit, sector, track;
362f05c6a60Ssam 
363a59591daShelge 	if (um->um_tab.b_active)
364f05c6a60Ssam 		return;
365a59591daShelge loop:
366a59591daShelge 	if ((dp = um->um_tab.b_actf) == NULL)
367a59591daShelge 		return;
368a59591daShelge 	if ((bp = dp->b_actf) == NULL) {
369a59591daShelge 		um->um_tab.b_actf = dp->b_forw;
370a59591daShelge 		goto loop;
371a59591daShelge 	}
37207190e5fShelge 	um->um_tab.b_active++;
373f05c6a60Ssam 	unit = RXUNIT(bp->b_dev);
374f05c6a60Ssam 	sc = &rx_softc[unit];
375dfc0651cShelge 	if (sc->sc_flags & RXF_BAD) {
376dfc0651cShelge 		rxpurge(um);
377dfc0651cShelge 		return;
378dfc0651cShelge 	}
3796623299cShelge 	if (dp->b_active == 1) {
3802eb71fd8Shelge 		sc->sc_resid = bp->b_bcount;
3816623299cShelge 		sc->sc_uaddr = bp->b_un.b_addr;
3826623299cShelge 		sc->sc_bcnt = bp->b_bcount;
3836623299cShelge 		sc->sc_offset += sc->sc_bcnt;
3846623299cShelge 		dp->b_active++;
3856623299cShelge 	}
386f05c6a60Ssam 	rxaddr = (struct rxdevice *)um->um_addr;
387f05c6a60Ssam 	rxc = &rx_ctlr[um->um_ctlr];
3882eb71fd8Shelge 	bp->b_bcount = sc->sc_resid;
389a59591daShelge 	if (bp->b_bcount > NBPS)
390a59591daShelge 		bp->b_bcount = NBPS;
39112fa0442Shelge 	rxc->rxc_tocnt = 0;
3922eb71fd8Shelge #ifdef RXDEBUG
3932eb71fd8Shelge 	printf("rxstart: ");
3942eb71fd8Shelge #endif
395b650353dShelge 	if (rxaddr->rxcs == 0x800) {
396b650353dShelge 		/*
3970099a24dShelge 		 * 'Volume valid'? (check if the
3980099a24dShelge 		 * drive unit has been powered down)
399b650353dShelge 		 */
400b650353dShelge 		rxaddr->rxcs = RX_INIT;
401b650353dShelge 		while((rxaddr->rxcs&RX_DONE) == 0)
402b650353dShelge 			;
403b650353dShelge 	}
404f05c6a60Ssam 	if (bp->b_flags & B_CTRL) {				/* format */
405f05c6a60Ssam 		rxc->rxc_state = RXS_FORMAT;
406f05c6a60Ssam 		rxaddr->rxcs = RX_FORMAT | sc->sc_csbits;
407a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
408f05c6a60Ssam 			;
409f05c6a60Ssam 		rxaddr->rxdb = 'I';
410f05c6a60Ssam 		return;
411f05c6a60Ssam 	}
4120099a24dShelge 	if (bp->b_flags & B_RDSTAT) {			/* read drive status */
4130099a24dShelge 		rxc->rxc_state = RXS_RDSTAT;
4140099a24dShelge 		rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
4150099a24dShelge 		return;
4160099a24dShelge 	}
41712fa0442Shelge 
418b650353dShelge 	if (bp->b_flags & B_READ) {
41912fa0442Shelge 		rxmap(bp, &sector, &track);			/* read */
4202eb71fd8Shelge #ifdef RXDEBUG
4212eb71fd8Shelge 		printf("read tr=%d, sc=%d", track, sector);
4222eb71fd8Shelge #endif
423f05c6a60Ssam 		rxc->rxc_state = RXS_READ;
424f05c6a60Ssam 		rxaddr->rxcs = RX_READ | sc->sc_csbits;
425a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
426f05c6a60Ssam 			;
427a0407b1cSsam 		rxaddr->rxdb = (u_short)sector;
428a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
429f05c6a60Ssam 			;
430a0407b1cSsam 		rxaddr->rxdb = (u_short)track;
431b650353dShelge 	} else {
4322eb71fd8Shelge #ifdef RXDEBUG
4332eb71fd8Shelge 		printf("write");
4342eb71fd8Shelge #endif
435b650353dShelge 		rxc->rxc_state = RXS_FILL;			/* write */
436b650353dShelge 		um->um_cmd = RX_FILL;
437b650353dShelge 		(void) ubago(rxdinfo[unit]);
438f05c6a60Ssam 	}
439b650353dShelge #ifdef RXDEBUG
4402eb71fd8Shelge 	printf("\n");
441b650353dShelge #endif
442f05c6a60Ssam }
443f05c6a60Ssam 
444f05c6a60Ssam rxdgo(um)
445f05c6a60Ssam 	struct uba_ctlr *um;
446f05c6a60Ssam {
447f05c6a60Ssam 	register struct rxdevice *rxaddr = (struct rxdevice *)um->um_addr;
448f05c6a60Ssam 	int ubinfo = um->um_ubinfo;
449a59591daShelge 	struct buf *bp = um->um_tab.b_actf->b_actf;
450f05c6a60Ssam 	struct rx_softc *sc = &rx_softc[RXUNIT(bp->b_dev)];
451f05c6a60Ssam 	struct rx_ctlr *rxc = &rx_ctlr[um->um_ctlr];
452f05c6a60Ssam 
453a59591daShelge 	rxaddr->rxcs = um->um_cmd | ((ubinfo & 0x30000) >> 4) | sc->sc_csbits;
454f05c6a60Ssam 	if (rxc->rxc_state != RXS_RDERR) {
455a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
456f05c6a60Ssam 			;
45712fa0442Shelge 		rxaddr->rxdb = (u_short) bp->b_bcount >> 1;
458f05c6a60Ssam 	}
459a0407b1cSsam 	while ((rxaddr->rxcs&RX_TREQ) == 0)
460f05c6a60Ssam 		;
46112fa0442Shelge 	rxaddr->rxdb = (u_short) ubinfo;
462f05c6a60Ssam }
463f05c6a60Ssam 
rxintr(ctlr)46412fa0442Shelge rxintr(ctlr)
46512fa0442Shelge 	int ctlr;
466f05c6a60Ssam {
46712fa0442Shelge 	int unit, sector, track;
46812fa0442Shelge 	struct uba_ctlr *um = rxminfo[ctlr];
469a0407b1cSsam 	register struct rxdevice *rxaddr;
470a59591daShelge 	register struct buf *bp, *dp;
47112fa0442Shelge 	register struct rx_softc *sc;
47212fa0442Shelge 	struct uba_device *ui;
473a0407b1cSsam 	struct rxerr *er;
47407190e5fShelge 	struct rx_ctlr *rxc;
475f05c6a60Ssam 
476a0407b1cSsam 	if (!um->um_tab.b_active)
477f05c6a60Ssam 		return;
478a59591daShelge 	dp = um->um_tab.b_actf;
479a59591daShelge 	if (!dp->b_active)
480a59591daShelge 		return;
48112fa0442Shelge 	bp = dp->b_actf;
48212fa0442Shelge 	unit = RXUNIT(bp->b_dev);
48312fa0442Shelge 	sc = &rx_softc[unit];
48412fa0442Shelge 	ui = rxdinfo[unit];
485a0407b1cSsam 	rxaddr = (struct rxdevice *)um->um_addr;
486a0407b1cSsam 	rxc = &rx_ctlr[um->um_ctlr];
48712fa0442Shelge 	rxc->rxc_tocnt = 0;
488da18c0ecShelge 	er = &rxerr[unit];
489b650353dShelge #ifdef RXDEBUG
490dfc0651cShelge 	printf("rxint: dev=%x, st=%d, cs=0x%x, db=0x%x\n",
491dfc0651cShelge 		bp->b_dev, rxc->rxc_state, rxaddr->rxcs, rxaddr->rxdb);
492b650353dShelge #endif
493a0407b1cSsam 	if ((rxaddr->rxcs & RX_ERR) &&
4946623299cShelge 	    (rxc->rxc_state != RXS_RDSTAT) && (rxc->rxc_state != RXS_RDERR))
495a0407b1cSsam 		goto error;
496f05c6a60Ssam 	switch (rxc->rxc_state) {
497f05c6a60Ssam 
498a0407b1cSsam 	/*
499a0407b1cSsam 	 * Incomplete commands.  Perform next step
500a0407b1cSsam 	 * and return.  Note that b_active is set on
501a0407b1cSsam 	 * entrance and, therefore, also on exit.
502a0407b1cSsam 	 */
503f05c6a60Ssam 	case RXS_READ:
504f05c6a60Ssam 		if (rxaddr->rxdb & RXES_DDMARK)
505f05c6a60Ssam 			sc->sc_flags |= RXF_DDMK;
506f05c6a60Ssam 		else
507f05c6a60Ssam 			sc->sc_flags &= ~RXF_DDMK;
508f05c6a60Ssam 		rxc->rxc_state = RXS_EMPTY;
509f05c6a60Ssam 		um->um_cmd = RX_EMPTY;
510f05c6a60Ssam 		(void) ubago(ui);
511f05c6a60Ssam 		return;
512f05c6a60Ssam 
513f05c6a60Ssam 	case RXS_FILL:
514f05c6a60Ssam 		rxc->rxc_state = RXS_WRITE;
515f05c6a60Ssam 		if (sc->sc_flags & RXF_USEWDDS) {
516f05c6a60Ssam 			rxaddr->rxcs = RX_WDDS | sc->sc_csbits;
517f05c6a60Ssam 			sc->sc_flags &= ~RXF_USEWDDS;
518f05c6a60Ssam 		} else
519f05c6a60Ssam 			rxaddr->rxcs = RX_WRITE | sc->sc_csbits;
5206623299cShelge 		rxmap(bp, &sector, &track);
521a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
522f05c6a60Ssam 			;
523a0407b1cSsam 		rxaddr->rxdb = sector;
524a0407b1cSsam 		while ((rxaddr->rxcs&RX_TREQ) == 0)
525f05c6a60Ssam 			;
526a0407b1cSsam 		rxaddr->rxdb = track;
527f05c6a60Ssam 		return;
528f05c6a60Ssam 
529a0407b1cSsam 	/*
530a0407b1cSsam 	 * Possibly completed command.
531a0407b1cSsam 	 */
532f05c6a60Ssam 	case RXS_RDSTAT:
5330099a24dShelge 		if (bp->b_flags & B_RDSTAT) {
5340099a24dShelge 			if ((rxaddr->rxdb&RXES_READY) == 0) {
5350099a24dShelge 				bp->b_flags |= B_ERROR;
5360099a24dShelge 				bp->b_error = ENODEV;
5370099a24dShelge 			} else {
5380099a24dShelge 				sc->sc_csbits |= rxaddr->rxdb&RXES_DBLDEN ?
5390099a24dShelge 					RX_DDEN : RX_SDEN;
5400099a24dShelge 			}
5410099a24dShelge 			goto rdone;
5420099a24dShelge 		}
543a0407b1cSsam 		if (rxaddr->rxdb&RXES_READY)
544f05c6a60Ssam 			goto rderr;
545dfc0651cShelge 		bp->b_error = ENODEV;
546f05c6a60Ssam 		bp->b_flags |= B_ERROR;
547a0407b1cSsam 		goto done;
548a0407b1cSsam 
549a0407b1cSsam 	/*
550a0407b1cSsam 	 * Command completed.
551a0407b1cSsam 	 */
552a0407b1cSsam 	case RXS_EMPTY:
553a0407b1cSsam 	case RXS_WRITE:
554a0407b1cSsam 		goto done;
555f05c6a60Ssam 
5560099a24dShelge 	case RXS_FORMAT:
5570099a24dShelge 		goto rdone;
5580099a24dShelge 
559f05c6a60Ssam 	case RXS_RDERR:
560dfc0651cShelge 		bp = savebp;
5616623299cShelge 		rxmap(bp, &sector, &track);
5626623299cShelge 		printf("rx%d: hard error, trk %d psec %d ",
5636623299cShelge 			unit, track, sector);
5646623299cShelge 		printf("cs=%b, db=%b, err=", MASKREG(er->rxcs),
5656623299cShelge 			RXCS_BITS, MASKREG(er->rxdb), RXES_BITS);
566e4af3149Shelge 		printf("%x, %x, %x, %x\n", MASKREG(er->rxxt[0]),
5676623299cShelge 			MASKREG(er->rxxt[1]), MASKREG(er->rxxt[2]),
5686623299cShelge 			MASKREG(er->rxxt[3]));
569a0407b1cSsam 		goto done;
570f05c6a60Ssam 
571f05c6a60Ssam 	default:
572a59591daShelge 		printf("rx%d: state %d (reset)\n", unit, rxc->rxc_state);
573a0407b1cSsam 		rxreset(um->um_ubanum);
574f05c6a60Ssam 		return;
575f05c6a60Ssam 	}
576f05c6a60Ssam error:
577f05c6a60Ssam 	/*
578f05c6a60Ssam 	 * In case of an error:
57907190e5fShelge 	 *  (a) Give up now if a format (ioctl) was in progress, if a
58007190e5fShelge 	 *	  density error was detected, or if the drive went offline
581f05c6a60Ssam 	 *  (b) Retry up to nine times if a CRC (data) error was detected,
582f05c6a60Ssam 	 *	  then give up if the error persists.
583f05c6a60Ssam 	 *  (c) In all other cases, reinitialize the drive and try the
584f05c6a60Ssam 	 *	  operation once more before giving up.
585f05c6a60Ssam 	 */
586a0407b1cSsam 	if (rxc->rxc_state == RXS_FORMAT || (rxaddr->rxdb&RXES_DENERR))
587f05c6a60Ssam 		goto giveup;
588f05c6a60Ssam 	if (rxaddr->rxdb & RXES_CRCERR) {
589dfc0651cShelge 		if (++um->um_tab.b_errcnt >= 10)
590f05c6a60Ssam 			goto giveup;
591f05c6a60Ssam 		goto retry;
592f05c6a60Ssam 	}
593dfc0651cShelge 	um->um_tab.b_errcnt += 9;
594dfc0651cShelge 	if (um->um_tab.b_errcnt >= 10)
595f05c6a60Ssam 		goto giveup;
596f05c6a60Ssam 	rxaddr->rxcs = RX_INIT;
597f05c6a60Ssam 	/* no way to get an interrupt for "init done", so just wait */
598b650353dShelge 	while ((rxaddr->rxcs&RX_DONE) == 0)
599f05c6a60Ssam 		;
60007190e5fShelge 	/* if someone opened the drive: give up */
60107190e5fShelge 	if ((rxaddr->rxdb&RXES_READY) == 0)
60207190e5fShelge 		goto giveup;
603f05c6a60Ssam retry:
604a0407b1cSsam 	/*
605a0407b1cSsam 	 * In case we already have UNIBUS resources, give
606a0407b1cSsam 	 * them back since we reallocate things in rxstart.
607a0407b1cSsam 	 */
608a0407b1cSsam 	if (um->um_ubinfo)
609a0407b1cSsam 		ubadone(um);
610da18c0ecShelge 	um->um_tab.b_active = 0;
611a0407b1cSsam 	rxstart(um);
612f05c6a60Ssam 	return;
613a0407b1cSsam 
614f05c6a60Ssam giveup:
615f05c6a60Ssam 	/*
616f05c6a60Ssam 	 * Hard I/O error --
617dfc0651cShelge 	 * ALL errors are considered fatal and will abort the
618dfc0651cShelge 	 * transfer and purge the i/o request queue
619f05c6a60Ssam 	 */
620dfc0651cShelge 	sc->sc_flags |= RXF_BAD;
621dfc0651cShelge 	sc->sc_resid = 0;	/* make sure the transfer is terminated */
622f05c6a60Ssam 	rxc->rxc_state = RXS_RDSTAT;
623f05c6a60Ssam 	rxaddr->rxcs = RX_RDSTAT | sc->sc_csbits;
624f05c6a60Ssam 	return;
625a0407b1cSsam 
626f05c6a60Ssam rderr:
627f05c6a60Ssam 	/*
628dfc0651cShelge 	 * A hard error (other than not ready) has occurred.
629f05c6a60Ssam 	 * Read the extended error status information.
630f05c6a60Ssam 	 * Before doing this, save the current CS and DB register values,
631f05c6a60Ssam 	 * because the read error status operation may modify them.
632dfc0651cShelge 	 * Insert buffer with request at the head of the queue.
633f05c6a60Ssam 	 */
634f05c6a60Ssam 	bp->b_error = EIO;
635f05c6a60Ssam 	bp->b_flags |= B_ERROR;
636dfc0651cShelge 	if (um->um_ubinfo)
637f05c6a60Ssam 		ubadone(um);
638dfc0651cShelge 	savebp = bp;
639f05c6a60Ssam 	er->rxcs = rxaddr->rxcs;
640f05c6a60Ssam 	er->rxdb = rxaddr->rxdb;
641e61c877eShelge 	bp = &erxbuf[unit];
642f05c6a60Ssam 	bp->b_un.b_addr = (caddr_t)er->rxxt;
643f05c6a60Ssam 	bp->b_bcount = sizeof (er->rxxt);
644f05c6a60Ssam 	bp->b_flags &= ~(B_DIRTY|B_UAREA|B_PHYS|B_PAGET);
6456623299cShelge 	if (dp->b_actf == NULL)
6466623299cShelge 		dp->b_actl = bp;
6476623299cShelge 	bp->b_forw = dp->b_actf;
6486623299cShelge 	dp->b_actf = bp;
649f05c6a60Ssam 	rxc->rxc_state = RXS_RDERR;
650f05c6a60Ssam 	um->um_cmd = RX_RDERR;
651f05c6a60Ssam 	(void) ubago(ui);
652a0407b1cSsam 	return;
6530099a24dShelge 
654a0407b1cSsam done:
6550099a24dShelge 	ubadone(um);
6560099a24dShelge rdone:
657a0407b1cSsam 	um->um_tab.b_active = 0;
658a59591daShelge 	um->um_tab.b_errcnt = 0;
6592eb71fd8Shelge 	if ((sc->sc_resid -= NBPS) > 0) {
660a59591daShelge 		bp->b_un.b_addr += NBPS;
661a59591daShelge 		rxstart(um);
662a59591daShelge 		return;
663a59591daShelge 	}
664a59591daShelge 	bp->b_un.b_addr = sc->sc_uaddr;
665a0407b1cSsam 	bp->b_resid = 0;
666a59591daShelge 	bp->b_bcount = sc->sc_bcnt;
6672eb71fd8Shelge 	dp->b_actf = bp->av_forw;
668a0407b1cSsam 	iodone(bp);
6692eb71fd8Shelge 	sc->sc_offset = 0;
670a0407b1cSsam 	rxc->rxc_state = RXS_IDLE;
671a59591daShelge 	um->um_tab.b_actf = dp->b_forw;
672a59591daShelge 	dp->b_active = 0;
673a59591daShelge 	dp->b_errcnt = 0;
6742eb71fd8Shelge #ifdef RXDEBUG
675dfc0651cShelge 	printf(".. bp=%x, new=%x\n", bp, dp->b_actf);
6762eb71fd8Shelge #endif
677a0407b1cSsam 	/*
6786623299cShelge 	 * If this unit has more work to do,
679a0407b1cSsam 	 * start it up right away
680a0407b1cSsam 	 */
6816623299cShelge 	if (dp->b_actf)
6826623299cShelge 		rxustart(ui);
6836623299cShelge 
684e61c877eShelge 	rxstart(um);
685f05c6a60Ssam }
686f05c6a60Ssam 
687f05c6a60Ssam /*ARGSUSED*/
688f05c6a60Ssam 
rxwatch()689e4af3149Shelge rxwatch()
690f05c6a60Ssam {
69107190e5fShelge 	register struct uba_device *ui;
6926623299cShelge 	register struct uba_ctlr *um;
69307190e5fShelge 	register struct rx_softc *sc;
69407190e5fShelge 	struct rx_ctlr *rxc;
69507190e5fShelge 	int i, dopen = 0;
696f05c6a60Ssam 
69707190e5fShelge 	for (i=0; i<NRX; i++) {
69807190e5fShelge 		ui = rxdinfo[i];
69907190e5fShelge 		if (ui == 0 || ui->ui_alive == 0)
7006623299cShelge 			continue;
701e4af3149Shelge 		sc = &rx_softc[i];
702e4af3149Shelge 		if ((sc->sc_open == 0) && (rxutab[i].b_active == 0)) {
70307190e5fShelge 			sc->sc_csbits = 0;
70407190e5fShelge 			continue;
70507190e5fShelge 		}
70607190e5fShelge 		dopen++;
707e4af3149Shelge 		um = ui->ui_mi;
70807190e5fShelge 		rxc = &rx_ctlr[um->um_ctlr];
709e4af3149Shelge 		if (++rxc->rxc_tocnt >= RX_MAXTIMEOUT) {
710e4af3149Shelge 			rxc->rxc_tocnt = 0;
711e4af3149Shelge 			if (um->um_tab.b_active) {
712e4af3149Shelge 				printf("rx%d: timeout\n", i);/* for debugging */
71307190e5fShelge 				rxintr(um->um_ctlr);
7146623299cShelge 			}
7156623299cShelge 		}
716e4af3149Shelge 	}
71707190e5fShelge 	if (dopen)
718e4af3149Shelge 		timeout(rxwatch, (caddr_t)0, hz);
71907190e5fShelge 	else
72007190e5fShelge 		rxwstart = 0;
721f05c6a60Ssam }
722f05c6a60Ssam 
rxreset(uban)723f05c6a60Ssam rxreset(uban)
724f05c6a60Ssam 	int uban;
725f05c6a60Ssam {
726f05c6a60Ssam 	register struct uba_ctlr *um;
727f05c6a60Ssam 	register struct rxdevice *rxaddr;
728f05c6a60Ssam 	register int ctlr;
729f05c6a60Ssam 
730f05c6a60Ssam 	for (ctlr = 0; ctlr < NFX; ctlr++) {
731f05c6a60Ssam 		if ((um = rxminfo[ctlr]) == 0 || um->um_ubanum != uban ||
732f05c6a60Ssam 		    um->um_alive == 0)
733f05c6a60Ssam 			continue;
73486e0f95cSbostic 		printf(" fx%d", ctlr);
73586e0f95cSbostic 		if (um->um_ubinfo) {
73686e0f95cSbostic 			printf("<%d>", UBAI_BDP(um->um_ubinfo));
737a0407b1cSsam 			um->um_ubinfo = 0;
73886e0f95cSbostic 		}
739f05c6a60Ssam 		rx_ctlr[ctlr].rxc_state = RXS_IDLE;
740f05c6a60Ssam 		rxaddr = (struct rxdevice *)um->um_addr;
741a0407b1cSsam 		rxaddr->rxcs = RX_INIT;
742b650353dShelge 		while ((rxaddr->rxcs&RX_DONE) == 0)
743f05c6a60Ssam 			;
744a0407b1cSsam 		rxstart(um);
745f05c6a60Ssam 	}
746f05c6a60Ssam }
747f05c6a60Ssam 
rxread(dev,uio)748a0407b1cSsam rxread(dev, uio)
749f05c6a60Ssam 	dev_t dev;
750a0407b1cSsam 	struct uio *uio;
751f05c6a60Ssam {
752a59591daShelge 	int unit = RXUNIT(dev);
753a59591daShelge 	struct rx_softc *sc = &rx_softc[unit];
754f05c6a60Ssam 
755a0407b1cSsam 	if (uio->uio_offset + uio->uio_resid > RXSIZE)
756a0407b1cSsam 		return (ENXIO);
757a0407b1cSsam 	if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
7585cdc5eccShelge 		return (ENXIO);
7596623299cShelge 	sc->sc_offset = uio->uio_offset % DEV_BSIZE;
760a59591daShelge 	return (physio(rxstrategy, &rrxbuf[unit], dev, B_READ, minphys, uio));
761f05c6a60Ssam }
762f05c6a60Ssam 
rxwrite(dev,uio)763a0407b1cSsam rxwrite(dev, uio)
764f05c6a60Ssam 	dev_t dev;
765a0407b1cSsam 	struct uio *uio;
766f05c6a60Ssam {
767a59591daShelge 	int unit = RXUNIT(dev);
768a59591daShelge 	struct rx_softc *sc = &rx_softc[unit];
769f05c6a60Ssam 
770a0407b1cSsam 	if (uio->uio_offset + uio->uio_resid > RXSIZE)
771a0407b1cSsam 		return (ENXIO);
772a0407b1cSsam 	if (uio->uio_offset < 0 || (uio->uio_offset & SECMASK) != 0)
7735cdc5eccShelge 		return (ENXIO);
7746623299cShelge 	sc->sc_offset = uio->uio_offset % DEV_BSIZE;
775a59591daShelge 	return(physio(rxstrategy, &rrxbuf[unit], dev, B_WRITE, minphys, uio));
776f05c6a60Ssam }
777f05c6a60Ssam 
778f05c6a60Ssam /*
779f05c6a60Ssam  * Control routine:
780e4af3149Shelge  * processes four kinds of requests:
781f05c6a60Ssam  *
782fdaae61cShelge  *	(1) Set density (i.e., format the diskette) according to
783e4af3149Shelge  *		  that specified data parameter
784f05c6a60Ssam  *	(2) Arrange for the next sector to be written with a deleted-
785f05c6a60Ssam  *		  data mark.
786f05c6a60Ssam  *	(3) Report whether the last sector read had a deleted-data mark
787e4af3149Shelge  *	(4) Report the density of the diskette in the indicated drive
788e4af3149Shelge  *	    (since the density it automatically determined by the driver,
789e4af3149Shelge  *	     this is the only way to let an application program know the
790e4af3149Shelge  *	     density)
791f05c6a60Ssam  *
792f05c6a60Ssam  * Requests relating to deleted-data marks can be handled right here.
793a59591daShelge  * A "set density" (format) request, however, must additionally be
794a59591daShelge  * processed through "rxstart", just like a read or write request.
795f05c6a60Ssam  */
796e4af3149Shelge 
797f05c6a60Ssam /*ARGSUSED3*/
rxioctl(dev,cmd,data,flag)798a0407b1cSsam rxioctl(dev, cmd, data, flag)
799f05c6a60Ssam 	dev_t dev;
800a0407b1cSsam 	caddr_t data;
801f05c6a60Ssam {
802f05c6a60Ssam 	int unit = RXUNIT(dev);
803f05c6a60Ssam 	struct rx_softc *sc = &rx_softc[unit];
804f05c6a60Ssam 
805dfc0651cShelge 	switch (cmd) {
806f05c6a60Ssam 
807a0407b1cSsam 	case RXIOC_FORMAT:
808f05c6a60Ssam 		if ((flag&FWRITE) == 0)
809a0407b1cSsam 			return (EBADF);
8105cdc5eccShelge 		if (sc->sc_open > 1)
8115cdc5eccShelge 			return (EBUSY);
812bc9f8c06Shelge 		if (*(int *)data)
813bc9f8c06Shelge 			sc->sc_csbits |= RX_DDEN;
814bc9f8c06Shelge 		else
815bc9f8c06Shelge 			sc->sc_csbits &= ~RX_DDEN;
816e61c877eShelge 		return (rxformat(dev));
817a0407b1cSsam 
818a0407b1cSsam 	case RXIOC_WDDS:
819f05c6a60Ssam 		sc->sc_flags |= RXF_USEWDDS;
820a0407b1cSsam 		return (0);
821f05c6a60Ssam 
822a0407b1cSsam 	case RXIOC_RDDSMK:
823a0407b1cSsam 		*(int *)data = sc->sc_flags & RXF_DDMK;
824a0407b1cSsam 		return (0);
8250099a24dShelge 
8260099a24dShelge 	case RXIOC_GDENS:
8270099a24dShelge 		*(int *)data = sc->sc_csbits & RX_DDEN;
8280099a24dShelge 		return (0);
829a0407b1cSsam 	}
830a0407b1cSsam 	return (ENXIO);
831f05c6a60Ssam }
832f05c6a60Ssam 
833a0407b1cSsam /*
834a0407b1cSsam  * Initiate a format command.
835a0407b1cSsam  */
rxformat(dev)836e61c877eShelge rxformat(dev)
837e61c877eShelge 	dev_t dev;
838a0407b1cSsam {
839a59591daShelge 	int unit = RXUNIT(dev);
840a0407b1cSsam 	struct buf *bp;
841a59591daShelge 	struct rx_softc *sc = &rx_softc[unit];
84286e0f95cSbostic 	int error = 0;
843a0407b1cSsam 
844a59591daShelge 	bp = &rrxbuf[unit];
845f05c6a60Ssam 	bp->b_flags = B_BUSY | B_CTRL;
8465cdc5eccShelge 	sc->sc_flags = RXF_FORMAT | RXF_LOCK;
847f05c6a60Ssam 	bp->b_dev = dev;
848f05c6a60Ssam 	bp->b_error = 0;
8490099a24dShelge 	bp->b_blkno = 0;
850f05c6a60Ssam 	rxstrategy(bp);
851f05c6a60Ssam 	iowait(bp);
852a0407b1cSsam 	if (bp->b_flags & B_ERROR)
853a0407b1cSsam 		error = bp->b_error;
854f05c6a60Ssam 	bp->b_flags &= ~B_BUSY;
8555cdc5eccShelge 	sc->sc_flags &= ~RXF_LOCK;
856a0407b1cSsam 	return (error);
857f05c6a60Ssam }
858dfc0651cShelge 
859dfc0651cShelge /*
860dfc0651cShelge  * A permanent hard error condition has occured,
861dfc0651cShelge  * purge the buffer queue
862dfc0651cShelge  */
rxpurge(um)863dfc0651cShelge rxpurge(um)
864dfc0651cShelge 	register struct uba_ctlr *um;
865dfc0651cShelge {
866dfc0651cShelge 	register struct buf *bp, *dp;
867dfc0651cShelge 
868dfc0651cShelge 	dp = um->um_tab.b_actf;
869dfc0651cShelge 	while (dp->b_actf) {
870dfc0651cShelge 		dp->b_errcnt++;
871dfc0651cShelge 		bp = dp->b_actf;
872dfc0651cShelge 		bp->b_error = EIO;
873dfc0651cShelge 		bp->b_flags |= B_ERROR;
874dfc0651cShelge 		iodone(bp);
875dfc0651cShelge 		dp->b_actf = bp->av_forw;
876dfc0651cShelge 	}
877dfc0651cShelge }
878f05c6a60Ssam #endif
879