xref: /original-bsd/sys/vax/vax/rx50.c (revision 4da674f5)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)rx50.c	7.5 (Berkeley) 12/16/90
11  */
12 
13 #if VAX8200
14 
15 /*
16  * Routines to handle the console RX50.
17  */
18 
19 #include "sys/param.h"
20 #include "sys/time.h"
21 #include "sys/kernel.h"
22 #include "sys/vmmac.h"
23 #include "sys/buf.h"
24 #include "sys/errno.h"
25 #include "sys/uio.h"
26 
27 #include "../include/cpu.h"
28 #include "rx50reg.h"
29 
30 struct	rx50device rx50device;
31 
32 #define	rx50unit(dev)	minor(dev)
33 
34 struct rx50state {
35 	short	rs_flags;	/* see below */
36 	short	rs_drive;	/* current drive number */
37 	u_int	rs_blkno;	/* current block number */
38 } rx50state;
39 
40 /* flags */
41 #define	RS_0OPEN	0x01	/* drive 0 open -- must be first */
42 #define	RS_1OPEN	0x02	/* drive 1 open -- must be second */
43 #define	RS_BUSY		0x04	/* operation in progress */
44 #define	RS_WANT		0x08	/* wakeup when done */
45 #define	RS_DONE		0x20	/* I/O operation done */
46 #define	RS_ERROR	0x40	/* error bit set at interrupt */
47 
48 /*
49  * Open a console RX50.
50  */
51 /*ARGSUSED*/
52 rx50open(dev, flags)
53 	dev_t dev;
54 	int flags;
55 {
56 	int unit;
57 
58 	/* only on 8200 (yet) */
59 	if (cpu != VAX_8200 || (unit = rx50unit(dev)) >= 2)
60 		return (ENXIO);
61 
62 	/* enforce exclusive access */
63 	if (rx50state.rs_flags & (1 << unit))
64 		return (EBUSY);
65 	rx50state.rs_flags |= 1 << unit;
66 	return (0);
67 }
68 
69 /*
70  * Close a console RX50.
71  */
72 /*ARGSUSED*/
73 rx50close(dev, flags)
74 	dev_t dev;
75 	int flags;
76 {
77 
78 	rx50state.rs_flags &= ~(1 << dev);	/* atomic */
79 }
80 
81 /*
82  * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE).
83  */
84 rx50rw(dev, uio, flags)
85 	dev_t dev;
86 	register struct uio *uio;
87 	int flags;
88 {
89 	register struct rx50device *rxaddr;
90 	register struct rx50state *rs;
91 	register char *cp;
92 	register int error, i, t;
93 	char secbuf[512];
94 	static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 };
95 
96 	/* enforce whole-sector I/O */
97 	if ((uio->uio_offset & 511) || (uio->uio_resid & 511))
98 		return (EINVAL);
99 
100 	rs = &rx50state;
101 
102 	/* lock out others */
103 	i = spl4();
104 	while (rs->rs_flags & RS_BUSY) {
105 		rs->rs_flags |= RS_WANT;
106 		sleep((caddr_t) &rx50state, PZERO - 1);
107 	}
108 	rs->rs_flags |= RS_BUSY;
109 	rs->rs_drive = rx50unit(dev);
110 	splx(i);
111 
112 	rxaddr = &rx50device;
113 	error = 0;
114 
115 	while (uio->uio_resid) {
116 		rs->rs_blkno = uio->uio_offset >> 9;
117 		if (rs->rs_blkno >= RX50MAXSEC) {
118 			if (rs->rs_blkno > RX50MAXSEC)
119 				error = EINVAL;
120 			else if (uio->uio_rw == UIO_WRITE)
121 				error = ENOSPC;
122 			/* else ``eof'' */
123 			break;
124 		}
125 		rs->rs_flags &= ~(RS_ERROR | RS_DONE);
126 		if (uio->uio_rw == UIO_WRITE) {
127 			/* copy the data to the RX50 silo */
128 			error = uiomove(secbuf, 512, uio);
129 			if (error)
130 				break;
131 			i = rxaddr->rxrda;
132 			for (cp = secbuf, i = 512; --i >= 0;)
133 				rxaddr->rxfdb = *cp++;
134 			i = RXCMD_WRITE;
135 		} else
136 			i = RXCMD_READ;
137 		rxaddr->rxcmd = i | driveselect[rs->rs_drive];
138 		i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC);
139 		rxaddr->rxtrk = t == 79 ? 0 : t + 1;
140 #ifdef notdef
141 		rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4);
142 #else
143 		rxaddr->rxsec = RX50SKEW(i, t);
144 #endif
145 		i = rxaddr->rxgo;	/* start it up */
146 		i = spl4();
147 		while ((rs->rs_flags & RS_DONE) == 0)
148 			sleep((caddr_t) &rs->rs_blkno, PRIBIO);
149 		splx(i);
150 		if (rs->rs_flags & RS_ERROR) {
151 			error = EIO;
152 			break;
153 		}
154 		if (uio->uio_rw == UIO_READ) {
155 			/* copy the data out of the silo */
156 			i = rxaddr->rxrda;
157 			for (cp = secbuf, i = 512; --i >= 0;)
158 				*cp++ = rxaddr->rxedb;
159 			error = uiomove(secbuf, 512, uio);
160 			if (error)
161 				break;
162 		}
163 	}
164 
165 	/* let others in */
166 	rs->rs_flags &= ~RS_BUSY;
167 	if (rs->rs_flags & RS_WANT)
168 		wakeup((caddr_t) rs);
169 
170 	return (error);
171 }
172 
173 rx50intr()
174 {
175 	register struct rx50device *rxaddr = &rx50device;
176 	register struct rx50state *rs = &rx50state;
177 	int i;
178 
179 #ifdef lint
180 	i = 0; i = i;
181 #endif
182 
183 	/* ignore spurious interrupts */
184 	if ((rxaddr->rxcmd & RXCMD_DONE) == 0)
185 		return;
186 	if ((rs->rs_flags & RS_BUSY) == 0) {
187 		printf("stray rx50 interrupt ignored\n");
188 		return;
189 	}
190 	if (rxaddr->rxcmd & RXCMD_ERROR) {
191 		printf(
192 	"csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n",
193 			rs->rs_drive + 1, rs->rs_blkno,
194 			rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec,
195 			rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext);
196 		rxaddr->rxcmd = RXCMD_RESET;
197 		i = rxaddr->rxgo;
198 		rs->rs_flags |= RS_ERROR;
199 	}
200 	rs->rs_flags |= RS_DONE;
201 	wakeup((caddr_t) &rs->rs_blkno);
202 }
203 #endif
204