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