1 /* $NetBSD: crx.c,v 1.7 2002/10/23 09:12:37 jdolecek 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. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)rx50.c 7.5 (Berkeley) 12/16/90 38 */ 39 40 /* 41 * Routines to handle the console RX50. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/time.h> 46 #include <sys/proc.h> 47 #include <sys/kernel.h> 48 #include <sys/buf.h> 49 #include <sys/errno.h> 50 #include <sys/uio.h> 51 #include <sys/device.h> 52 #include <sys/systm.h> 53 #include <sys/conf.h> 54 55 #include <machine/ka820.h> 56 #include <vax/vax/crx.h> 57 58 dev_type_open(crxopen); 59 dev_type_close(crxclose); 60 dev_type_read(crxrw); 61 62 const struct cdevsw crx_cdevsw = { 63 crxopen, crxclose, crxrw, crxrw, noioctl, 64 nostop, notty, nopoll, nommap, nokqfilter, 65 }; 66 67 extern struct rx50device *rx50device_ptr; 68 #define rxaddr rx50device_ptr 69 extern struct ka820port *ka820port_ptr; 70 71 #define rx50unit(dev) minor(dev) 72 73 struct rx50state { 74 short rs_flags; /* see below */ 75 short rs_drive; /* current drive number */ 76 u_int rs_blkno; /* current block number */ 77 } rx50state; 78 79 /* flags */ 80 #define RS_0OPEN 0x01 /* drive 0 open -- must be first */ 81 #define RS_1OPEN 0x02 /* drive 1 open -- must be second */ 82 #define RS_BUSY 0x04 /* operation in progress */ 83 #define RS_WANT 0x08 /* wakeup when done */ 84 #define RS_DONE 0x20 /* I/O operation done */ 85 #define RS_ERROR 0x40 /* error bit set at interrupt */ 86 87 #if 0 88 #define CRXDEBUG 1 89 #endif 90 91 /* 92 * Open a console RX50. 93 */ 94 /*ARGSUSED*/ 95 int 96 crxopen(dev, flags, fmt, p) 97 dev_t dev; 98 int flags, fmt; 99 struct proc *p; 100 { 101 int unit; 102 103 #if CRXDEBUG 104 printf("crxopen(csa%d)\n", minor(dev)); 105 #endif 106 if ((unit = rx50unit(dev)) >= 2) 107 return (ENXIO); 108 109 /* enforce exclusive access */ 110 if (rx50state.rs_flags & (1 << unit)) 111 return (EBUSY); 112 rx50state.rs_flags |= 1 << unit; 113 114 return (0); 115 } 116 117 /* 118 * Close a console RX50. 119 */ 120 /*ARGSUSED*/ 121 int 122 crxclose(dev, flags, fmt, p) 123 dev_t dev; 124 int flags, fmt; 125 struct proc *p; 126 { 127 #if CRXDEBUG 128 printf("crxclose(csa%d)\n", minor(dev)); 129 #endif 130 131 rx50state.rs_flags &= ~(1 << dev); /* atomic */ 132 return 0; 133 } 134 135 /* 136 * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE). 137 */ 138 int 139 crxrw(dev, uio, flags) 140 dev_t dev; 141 register struct uio *uio; 142 int flags; 143 { 144 register struct rx50state *rs; 145 register char *cp; 146 register int error, i, t; 147 char secbuf[512]; 148 static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 }; 149 150 #if CRXDEBUG 151 printf("crxrw(csa%d): %s\n", 152 minor(dev), uio->uio_rw==UIO_READ?"read":"write"); 153 printf("crxrw: ka820port = %x\n", ka820port_ptr->csr); 154 #endif 155 /* enforce whole-sector I/O */ 156 if ((uio->uio_offset & 511) || (uio->uio_resid & 511)) 157 return (EINVAL); 158 159 rs = &rx50state; 160 161 /* lock out others */ 162 i = spl4(); 163 while (rs->rs_flags & RS_BUSY) { 164 rs->rs_flags |= RS_WANT; 165 (void) tsleep(&rx50state, PRIBIO, "crxbusy", 0); 166 } 167 rs->rs_flags |= RS_BUSY; 168 rs->rs_drive = rx50unit(dev); 169 splx(i); 170 171 rxaddr = rx50device_ptr; 172 error = 0; 173 174 while (uio->uio_resid) { 175 rs->rs_blkno = uio->uio_offset >> 9; 176 if (rs->rs_blkno >= RX50MAXSEC) { 177 if (rs->rs_blkno > RX50MAXSEC) 178 error = EINVAL; 179 else if (uio->uio_rw == UIO_WRITE) 180 error = ENOSPC; 181 /* else ``eof'' */ 182 break; 183 } 184 rs->rs_flags &= ~(RS_ERROR | RS_DONE); 185 if (uio->uio_rw == UIO_WRITE) { 186 /* copy the data to the RX50 silo */ 187 error = uiomove(secbuf, 512, uio); 188 if (error) 189 break; 190 i = rxaddr->rxrda; 191 for (cp = secbuf, i = 512; --i >= 0;) 192 rxaddr->rxfdb = *cp++; 193 i = RXCMD_WRITE; 194 } else 195 i = RXCMD_READ; 196 rxaddr->rxcmd = i | driveselect[rs->rs_drive]; 197 i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC); 198 rxaddr->rxtrk = t == 79 ? 0 : t + 1; 199 #ifdef notdef 200 rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4); 201 #else 202 rxaddr->rxsec = RX50SKEW(i, t); 203 #endif 204 #if CRXDEBUG 205 printf("crx: going off\n"); 206 printf("crxrw: ka820port = %x\n", ka820port_ptr->csr); 207 #endif 208 rxaddr->rxgo = 0; /* start it up */ 209 ka820port_ptr->csr |= KA820PORT_RXIRQ; 210 i = spl4(); 211 while ((rs->rs_flags & RS_DONE) == 0) { 212 #if CRXDEBUG 213 printf("crx: sleeping on I/O\n"); 214 printf("crxopen: ka820port = %x\n", ka820port_ptr->csr); 215 #endif 216 (void) tsleep(&rs->rs_blkno, PRIBIO, "crxrw", 0); 217 } 218 splx(i); 219 if (rs->rs_flags & RS_ERROR) { 220 error = EIO; 221 break; 222 } 223 if (uio->uio_rw == UIO_READ) { 224 /* copy the data out of the silo */ 225 i = rxaddr->rxrda; 226 for (cp = secbuf, i = 512; --i >= 0;) 227 *cp++ = rxaddr->rxedb; 228 error = uiomove(secbuf, 512, uio); 229 if (error) 230 break; 231 } 232 } 233 234 /* let others in */ 235 #if CRXDEBUG 236 printf("crx: let others in\n"); 237 #endif 238 rs->rs_flags &= ~RS_BUSY; 239 if (rs->rs_flags & RS_WANT) 240 wakeup((caddr_t) rs); 241 242 return (error); 243 } 244 245 void 246 crxintr(arg) 247 void *arg; 248 { 249 register struct rx50state *rs = &rx50state; 250 251 /* ignore spurious interrupts */ 252 if ((rxaddr->rxcmd & RXCMD_DONE) == 0) 253 return; 254 if ((rs->rs_flags & RS_BUSY) == 0) { 255 printf("stray rx50 interrupt ignored (rs_flags: 0x%x, rxcmd: 0x%x)\n", 256 rs->rs_flags, rxaddr->rxcmd); 257 return; 258 } 259 if (rxaddr->rxcmd & RXCMD_ERROR) { 260 printf( 261 "csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n", 262 rs->rs_drive + 1, rs->rs_blkno, 263 rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec, 264 rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext); 265 rxaddr->rxcmd = RXCMD_RESET; 266 rxaddr->rxgo = 0; 267 rs->rs_flags |= RS_ERROR; 268 } 269 rs->rs_flags |= RS_DONE; 270 wakeup((caddr_t) &rs->rs_blkno); 271 } 272