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