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 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)rx50.c 7.2 (Berkeley) 05/09/89 21 */ 22 23 #if VAX8200 24 25 /* 26 * Routines to handle the console RX50. 27 */ 28 29 #include "param.h" 30 #include "time.h" 31 #include "kernel.h" 32 #include "vmmac.h" 33 #include "buf.h" 34 #include "errno.h" 35 #include "uio.h" 36 37 #include "cpu.h" 38 #include "rx50reg.h" 39 40 struct rx50device rx50device; 41 42 #define rx50unit(dev) minor(dev) 43 44 struct rx50state { 45 short rs_flags; /* see below */ 46 short rs_drive; /* current drive number */ 47 u_int rs_blkno; /* current block number */ 48 } rx50state; 49 50 /* flags */ 51 #define RS_0OPEN 0x01 /* drive 0 open -- must be first */ 52 #define RS_1OPEN 0x02 /* drive 1 open -- must be second */ 53 #define RS_BUSY 0x04 /* operation in progress */ 54 #define RS_WANT 0x08 /* wakeup when done */ 55 #define RS_DONE 0x20 /* I/O operation done */ 56 #define RS_ERROR 0x40 /* error bit set at interrupt */ 57 58 /* 59 * Open a console RX50. 60 */ 61 /*ARGSUSED*/ 62 rx50open(dev, flags) 63 dev_t dev; 64 int flags; 65 { 66 int unit; 67 68 /* only on 8200 (yet) */ 69 if (cpu != VAX_8200 || (unit = rx50unit(dev)) >= 2) 70 return (ENXIO); 71 72 /* enforce exclusive access */ 73 if (rx50state.rs_flags & (1 << unit)) 74 return (EBUSY); 75 rx50state.rs_flags |= 1 << unit; 76 return (0); 77 } 78 79 /* 80 * Close a console RX50. 81 */ 82 /*ARGSUSED*/ 83 rx50close(dev, flags) 84 dev_t dev; 85 int flags; 86 { 87 88 rx50state.rs_flags &= ~(1 << dev); /* atomic */ 89 } 90 91 /* 92 * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE). 93 */ 94 rx50operation(dev, uio, flags) 95 dev_t dev; 96 register struct uio *uio; 97 int flags; 98 { 99 register struct rx50device *rxaddr; 100 register struct rx50state *rs; 101 register char *cp; 102 register int error, i, t; 103 char secbuf[512]; 104 static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 }; 105 106 /* enforce whole-sector I/O */ 107 if ((uio->uio_offset & 511) || (uio->uio_resid & 511)) 108 return (EINVAL); 109 110 rs = &rx50state; 111 112 /* lock out others */ 113 i = spl4(); 114 while (rs->rs_flags & RS_BUSY) { 115 rs->rs_flags |= RS_WANT; 116 sleep((caddr_t) &rx50state, PZERO - 1); 117 } 118 rs->rs_flags |= RS_BUSY; 119 rs->rs_drive = rx50unit(dev); 120 splx(i); 121 122 rxaddr = &rx50device; 123 error = 0; 124 125 while (uio->uio_resid) { 126 rs->rs_blkno = uio->uio_offset >> 9; 127 if (rs->rs_blkno >= RX50MAXSEC) { 128 if (rs->rs_blkno > RX50MAXSEC) 129 error = EINVAL; 130 else if (uio->uio_rw == UIO_WRITE) 131 error = ENOSPC; 132 /* else ``eof'' */ 133 break; 134 } 135 rs->rs_flags &= ~(RS_ERROR | RS_DONE); 136 if (uio->uio_rw == UIO_WRITE) { 137 /* copy the data to the RX50 silo */ 138 error = uiomove(secbuf, 512, uio); 139 if (error) 140 break; 141 i = rxaddr->rxrda; 142 for (cp = secbuf, i = 512; --i >= 0;) 143 rxaddr->rxfdb = *cp++; 144 i = RXCMD_WRITE; 145 } else 146 i = RXCMD_READ; 147 rxaddr->rxcmd = i | driveselect[rs->rs_drive]; 148 i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC); 149 rxaddr->rxtrk = t == 79 ? 0 : t + 1; 150 #ifdef notdef 151 rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4); 152 #else 153 rxaddr->rxsec = RX50SKEW(i, t); 154 #endif 155 i = rxaddr->rxgo; /* start it up */ 156 i = spl4(); 157 while ((rs->rs_flags & RS_DONE) == 0) 158 sleep((caddr_t) &rs->rs_blkno, PRIBIO); 159 splx(i); 160 if (rs->rs_flags & RS_ERROR) { 161 error = EIO; 162 break; 163 } 164 if (uio->uio_rw == UIO_READ) { 165 /* copy the data out of the silo */ 166 i = rxaddr->rxrda; 167 for (cp = secbuf, i = 512; --i >= 0;) 168 *cp++ = rxaddr->rxedb; 169 error = uiomove(secbuf, 512, uio); 170 if (error) 171 break; 172 } 173 } 174 175 /* let others in */ 176 rs->rs_flags &= ~RS_BUSY; 177 if (rs->rs_flags & RS_WANT) 178 wakeup((caddr_t) rs); 179 180 return (error); 181 } 182 183 rx50intr() 184 { 185 register struct rx50device *rxaddr = &rx50device; 186 register struct rx50state *rs = &rx50state; 187 int i; 188 189 #ifdef lint 190 i = 0; i = i; 191 #endif 192 193 /* ignore spurious interrupts */ 194 if ((rxaddr->rxcmd & RXCMD_DONE) == 0) 195 return; 196 if ((rs->rs_flags & RS_BUSY) == 0) { 197 printf("stray rx50 interrupt ignored\n"); 198 return; 199 } 200 if (rxaddr->rxcmd & RXCMD_ERROR) { 201 printf( 202 "csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n", 203 rs->rs_drive + 1, rs->rs_blkno, 204 rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec, 205 rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext); 206 rxaddr->rxcmd = RXCMD_RESET; 207 i = rxaddr->rxgo; 208 rs->rs_flags |= RS_ERROR; 209 } 210 rs->rs_flags |= RS_DONE; 211 wakeup((caddr_t) &rs->rs_blkno); 212 } 213 #endif 214