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 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 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 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 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