xref: /netbsd/sys/arch/vax/vax/crx.c (revision 6550d01e)
1 /*	$NetBSD: crx.c,v 1.13 2008/03/11 05:34:03 matt 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.13 2008/03/11 05:34:03 matt 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 	crxopen, crxclose, crxrw, crxrw, noioctl,
63 	nostop, notty, nopoll, nommap, nokqfilter,
64 };
65 
66 extern struct	rx50device *rx50device_ptr;
67 #define rxaddr	rx50device_ptr
68 extern struct	ka820port *ka820port_ptr;
69 
70 #define	rx50unit(dev)	minor(dev)
71 
72 struct rx50state {
73 	short	rs_flags;	/* see below */
74 	short	rs_drive;	/* current drive number */
75 	u_int	rs_blkno;	/* current block number */
76 } rx50state;
77 
78 /* flags */
79 #define	RS_0OPEN	0x01	/* drive 0 open -- must be first */
80 #define	RS_1OPEN	0x02	/* drive 1 open -- must be second */
81 #define	RS_BUSY		0x04	/* operation in progress */
82 #define	RS_WANT		0x08	/* wakeup when done */
83 #define	RS_DONE		0x20	/* I/O operation done */
84 #define	RS_ERROR	0x40	/* error bit set at interrupt */
85 
86 #if 0
87 #define CRXDEBUG	1
88 #endif
89 
90 /*
91  * Open a console RX50.
92  */
93 /*ARGSUSED*/
94 int
95 crxopen(dev_t dev, int flags, int fmt, struct lwp *l)
96 {
97 	int unit;
98 
99 #if	CRXDEBUG
100 	printf("crxopen(csa%d)\n", rx50unit(dev));
101 #endif
102 	if ((unit = rx50unit(dev)) >= 2)
103 		return (ENXIO);
104 
105 	/* enforce exclusive access */
106 	if (rx50state.rs_flags & (1 << unit))
107 		return (EBUSY);
108 	rx50state.rs_flags |= 1 << unit;
109 
110 	return (0);
111 }
112 
113 /*
114  * Close a console RX50.
115  */
116 /*ARGSUSED*/
117 int
118 crxclose(dev_t dev, int flags, int fmt, struct lwp *l)
119 {
120 #if	CRXDEBUG
121 	printf("crxclose(csa%d)\n", rx50unit(dev));
122 #endif
123 	rx50state.rs_flags &= ~(1 << rx50unit(dev));	/* atomic */
124 	return 0;
125 }
126 
127 /*
128  * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE).
129  */
130 int
131 crxrw(dev_t dev, struct uio *uio, int flags)
132 {
133 	struct rx50state *rs;
134 	char *cp;
135 	int error, i, t;
136 	char secbuf[512];
137 	static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 };
138 
139 #if	CRXDEBUG
140 	printf("crxrw(csa%d): %s\n",
141 		rx50unit(dev), uio->uio_rw==UIO_READ?"read":"write");
142 	printf("crxrw: ka820port = %x\n", ka820port_ptr->csr);
143 #endif
144 	/* enforce whole-sector I/O */
145 	if ((uio->uio_offset & 511) || (uio->uio_resid & 511))
146 		return (EINVAL);
147 
148 	rs = &rx50state;
149 
150 	/* lock out others */
151 	i = splvm();
152 	while (rs->rs_flags & RS_BUSY) {
153 		rs->rs_flags |= RS_WANT;
154 		(void) tsleep(&rx50state, PRIBIO, "crxbusy", 0);
155 	}
156 	rs->rs_flags |= RS_BUSY;
157 	rs->rs_drive = rx50unit(dev);
158 	splx(i);
159 
160 	rxaddr = rx50device_ptr;
161 	error = 0;
162 
163 	while (uio->uio_resid) {
164 		rs->rs_blkno = uio->uio_offset >> 9;
165 		if (rs->rs_blkno >= RX50MAXSEC) {
166 			if (rs->rs_blkno > RX50MAXSEC)
167 				error = EINVAL;
168 			else if (uio->uio_rw == UIO_WRITE)
169 				error = ENOSPC;
170 			/* else ``eof'' */
171 			break;
172 		}
173 		rs->rs_flags &= ~(RS_ERROR | RS_DONE);
174 		if (uio->uio_rw == UIO_WRITE) {
175 			/* copy the data to the RX50 silo */
176 			error = uiomove(secbuf, 512, uio);
177 			if (error)
178 				break;
179 			i = rxaddr->rxrda;
180 			for (cp = secbuf, i = 512; --i >= 0;)
181 				rxaddr->rxfdb = *cp++;
182 			i = RXCMD_WRITE;
183 		} else
184 			i = RXCMD_READ;
185 		rxaddr->rxcmd = i | driveselect[rs->rs_drive];
186 		i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC);
187 		rxaddr->rxtrk = t == 79 ? 0 : t + 1;
188 #ifdef notdef
189 		rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4);
190 #else
191 		rxaddr->rxsec = RX50SKEW(i, t);
192 #endif
193 #if	CRXDEBUG
194 		printf("crx: going off\n");
195 		printf("crxrw: ka820port = %x\n", ka820port_ptr->csr);
196 #endif
197 		rxaddr->rxgo = 0;	/* start it up */
198 		ka820port_ptr->csr |= KA820PORT_RXIRQ;
199 		i = splvm();
200 		while ((rs->rs_flags & RS_DONE) == 0) {
201 #if	CRXDEBUG
202 			printf("crx: sleeping on I/O\n");
203 			printf("crxopen: ka820port = %x\n", ka820port_ptr->csr);
204 #endif
205 			(void) tsleep(&rs->rs_blkno, PRIBIO, "crxrw", 0);
206 		}
207 		splx(i);
208 		if (rs->rs_flags & RS_ERROR) {
209 			error = EIO;
210 			break;
211 		}
212 		if (uio->uio_rw == UIO_READ) {
213 			/* copy the data out of the silo */
214 			i = rxaddr->rxrda;
215 			for (cp = secbuf, i = 512; --i >= 0;)
216 				*cp++ = rxaddr->rxedb;
217 			error = uiomove(secbuf, 512, uio);
218 			if (error)
219 				break;
220 		}
221 	}
222 
223 	/* let others in */
224 #if	CRXDEBUG
225 	printf("crx: let others in\n");
226 #endif
227 	rs->rs_flags &= ~RS_BUSY;
228 	if (rs->rs_flags & RS_WANT)
229 		wakeup((void *) rs);
230 
231 	return (error);
232 }
233 
234 void
235 crxintr(void *arg)
236 {
237 	struct rx50state *rs = &rx50state;
238 
239 	/* ignore spurious interrupts */
240 	if ((rxaddr->rxcmd & RXCMD_DONE) == 0)
241 		return;
242 	if ((rs->rs_flags & RS_BUSY) == 0) {
243 		printf("stray rx50 interrupt ignored (rs_flags: 0x%x, rxcmd: 0x%x)\n",
244 			rs->rs_flags, rxaddr->rxcmd);
245 		return;
246 	}
247 	if (rxaddr->rxcmd & RXCMD_ERROR) {
248 		printf(
249 	"csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n",
250 			rs->rs_drive + 1, rs->rs_blkno,
251 			rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec,
252 			rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext);
253 		rxaddr->rxcmd = RXCMD_RESET;
254 		rxaddr->rxgo = 0;
255 		rs->rs_flags |= RS_ERROR;
256 	}
257 	rs->rs_flags |= RS_DONE;
258 	wakeup((void *) &rs->rs_blkno);
259 }
260