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*/
rx50open(dev,flags)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*/
rx50close(dev,flags)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 */
rx50rw(dev,uio,flags)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
rx50intr()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