xref: /netbsd-src/sys/arch/vax/vax/crx.c (revision 05682c670570e712564e9f11e2270b67c6aa9c1a)
1 /*	$NetBSD: crx.c,v 1.16 2023/12/17 15:06:33 andvar Exp $	*/
2 /*
3  * Copyright (c) 1988 Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)rx50.c	7.5 (Berkeley) 12/16/90
34  */
35 
36 /*
37  * Routines to handle the console RX50.
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: crx.c,v 1.16 2023/12/17 15:06:33 andvar Exp $");
42 
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/buf.h>
48 #include <sys/errno.h>
49 #include <sys/uio.h>
50 #include <sys/device.h>
51 #include <sys/systm.h>
52 #include <sys/conf.h>
53 
54 #include <machine/ka820.h>
55 #include <vax/vax/crx.h>
56 
57 static dev_type_open(crxopen);
58 static dev_type_close(crxclose);
59 static dev_type_read(crxrw);
60 
61 const struct cdevsw crx_cdevsw = {
62 	.d_open = crxopen,
63 	.d_close = crxclose,
64 	.d_read = crxrw,
65 	.d_write = crxrw,
66 	.d_ioctl = noioctl,
67 	.d_stop = nostop,
68 	.d_tty = notty,
69 	.d_poll = nopoll,
70 	.d_mmap = nommap,
71 	.d_kqfilter = nokqfilter,
72 	.d_discard = nodiscard,
73 	.d_flag = 0
74 };
75 
76 extern struct	rx50device *rx50device_ptr;
77 #define rxaddr	rx50device_ptr
78 extern struct	ka820port *ka820port_ptr;
79 
80 #define	rx50unit(dev)	minor(dev)
81 
82 struct rx50state {
83 	short	rs_flags;	/* see below */
84 	short	rs_drive;	/* current drive number */
85 	u_int	rs_blkno;	/* current block number */
86 } rx50state;
87 
88 /* flags */
89 #define	RS_0OPEN	0x01	/* drive 0 open -- must be first */
90 #define	RS_1OPEN	0x02	/* drive 1 open -- must be second */
91 #define	RS_BUSY		0x04	/* operation in progress */
92 #define	RS_WANT		0x08	/* wakeup when done */
93 #define	RS_DONE		0x20	/* I/O operation done */
94 #define	RS_ERROR	0x40	/* error bit set at interrupt */
95 
96 #if 0
97 #define CRXDEBUG	1
98 #endif
99 
100 /*
101  * Open a console RX50.
102  */
103 /*ARGSUSED*/
104 int
crxopen(dev_t dev,int flags,int fmt,struct lwp * l)105 crxopen(dev_t dev, int flags, int fmt, struct lwp *l)
106 {
107 	int unit;
108 
109 #if	CRXDEBUG
110 	printf("crxopen(csa%d)\n", rx50unit(dev));
111 #endif
112 	if ((unit = rx50unit(dev)) >= 2)
113 		return (ENXIO);
114 
115 	/* enforce exclusive access */
116 	if (rx50state.rs_flags & (1 << unit))
117 		return (EBUSY);
118 	rx50state.rs_flags |= 1 << unit;
119 
120 	return (0);
121 }
122 
123 /*
124  * Close a console RX50.
125  */
126 /*ARGSUSED*/
127 int
crxclose(dev_t dev,int flags,int fmt,struct lwp * l)128 crxclose(dev_t dev, int flags, int fmt, struct lwp *l)
129 {
130 #if	CRXDEBUG
131 	printf("crxclose(csa%d)\n", rx50unit(dev));
132 #endif
133 	rx50state.rs_flags &= ~(1 << rx50unit(dev));	/* atomic */
134 	return 0;
135 }
136 
137 /*
138  * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE).
139  */
140 int
crxrw(dev_t dev,struct uio * uio,int flags)141 crxrw(dev_t dev, struct uio *uio, int flags)
142 {
143 	struct rx50state *rs;
144 	char *cp;
145 	int error, i, t;
146 	char secbuf[512];
147 	static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 };
148 
149 #if	CRXDEBUG
150 	printf("crxrw(csa%d): %s\n",
151 		rx50unit(dev), uio->uio_rw==UIO_READ?"read":"write");
152 	printf("crxrw: ka820port = %lx\n", ka820port_ptr->csr);
153 #endif
154 	/* enforce whole-sector I/O */
155 	if ((uio->uio_offset & 511) || (uio->uio_resid & 511))
156 		return (EINVAL);
157 
158 	rs = &rx50state;
159 
160 	/* lock out others */
161 	i = splvm();
162 	while (rs->rs_flags & RS_BUSY) {
163 		rs->rs_flags |= RS_WANT;
164 		(void) tsleep(&rx50state, PRIBIO, "crxbusy", 0);
165 	}
166 	rs->rs_flags |= RS_BUSY;
167 	rs->rs_drive = rx50unit(dev);
168 	splx(i);
169 
170 	rxaddr = rx50device_ptr;
171 	error = 0;
172 
173 	while (uio->uio_resid) {
174 		rs->rs_blkno = uio->uio_offset >> 9;
175 		if (rs->rs_blkno >= RX50MAXSEC) {
176 			if (rs->rs_blkno > RX50MAXSEC)
177 				error = EINVAL;
178 			else if (uio->uio_rw == UIO_WRITE)
179 				error = ENOSPC;
180 			/* else ``eof'' */
181 			break;
182 		}
183 		rs->rs_flags &= ~(RS_ERROR | RS_DONE);
184 		if (uio->uio_rw == UIO_WRITE) {
185 			/* copy the data to the RX50 silo */
186 			error = uiomove(secbuf, 512, uio);
187 			if (error)
188 				break;
189 			i = rxaddr->rxrda;
190 			for (cp = secbuf, i = 512; --i >= 0;)
191 				rxaddr->rxfdb = *cp++;
192 			i = RXCMD_WRITE;
193 		} else
194 			i = RXCMD_READ;
195 		rxaddr->rxcmd = i | driveselect[rs->rs_drive];
196 		i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC);
197 		rxaddr->rxtrk = t == 79 ? 0 : t + 1;
198 #ifdef notdef
199 		rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4);
200 #else
201 		rxaddr->rxsec = RX50SKEW(i, t);
202 #endif
203 #if	CRXDEBUG
204 		printf("crx: going off\n");
205 		printf("crxrw: ka820port = %lx\n", ka820port_ptr->csr);
206 #endif
207 		rxaddr->rxgo = 0;	/* start it up */
208 		ka820port_ptr->csr |= KA820PORT_RXIRQ;
209 		i = splvm();
210 		while ((rs->rs_flags & RS_DONE) == 0) {
211 #if	CRXDEBUG
212 			printf("crx: sleeping on I/O\n");
213 			printf("crxopen: ka820port = %lx\n", ka820port_ptr->csr);
214 #endif
215 			(void) tsleep(&rs->rs_blkno, PRIBIO, "crxrw", 0);
216 		}
217 		splx(i);
218 		if (rs->rs_flags & RS_ERROR) {
219 			error = EIO;
220 			break;
221 		}
222 		if (uio->uio_rw == UIO_READ) {
223 			/* copy the data out of the silo */
224 			i = rxaddr->rxrda;
225 			for (cp = secbuf, i = 512; --i >= 0;)
226 				*cp++ = rxaddr->rxedb;
227 			error = uiomove(secbuf, 512, uio);
228 			if (error)
229 				break;
230 		}
231 	}
232 
233 	/* let others in */
234 #if	CRXDEBUG
235 	printf("crx: let others in\n");
236 #endif
237 	rs->rs_flags &= ~RS_BUSY;
238 	if (rs->rs_flags & RS_WANT)
239 		wakeup((void *) rs);
240 
241 	return (error);
242 }
243 
244 void
crxintr(void * arg)245 crxintr(void *arg)
246 {
247 	struct rx50state *rs = &rx50state;
248 
249 	/* ignore spurious interrupts */
250 	if ((rxaddr->rxcmd & RXCMD_DONE) == 0)
251 		return;
252 	if ((rs->rs_flags & RS_BUSY) == 0) {
253 		printf("stray rx50 interrupt ignored (rs_flags: 0x%x, rxcmd: 0x%x)\n",
254 			rs->rs_flags, rxaddr->rxcmd);
255 		return;
256 	}
257 	if (rxaddr->rxcmd & RXCMD_ERROR) {
258 		printf(
259 	"csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n",
260 			rs->rs_drive + 1, rs->rs_blkno,
261 			rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec,
262 			rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext);
263 		rxaddr->rxcmd = RXCMD_RESET;
264 		rxaddr->rxgo = 0;
265 		rs->rs_flags |= RS_ERROR;
266 	}
267 	rs->rs_flags |= RS_DONE;
268 	wakeup((void *) &rs->rs_blkno);
269 }
270