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