135045Skarels /* 235045Skarels * Copyright (c) 1988 Regents of the University of California. 335045Skarels * All rights reserved. 435045Skarels * 535045Skarels * This code is derived from software contributed to Berkeley by 635045Skarels * Chris Torek. 735045Skarels * 835045Skarels * Redistribution and use in source and binary forms are permitted 935045Skarels * provided that the above copyright notice and this paragraph are 1035045Skarels * duplicated in all such forms and that any documentation, 1135045Skarels * advertising materials, and other materials related to such 1235045Skarels * distribution and use acknowledge that the software was developed 1335045Skarels * by the University of California, Berkeley. The name of the 1435045Skarels * University may not be used to endorse or promote products derived 1535045Skarels * from this software without specific prior written permission. 1635045Skarels * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1735045Skarels * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1835045Skarels * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1935045Skarels * 20*40912Ssklower * @(#)rx50.c 7.3 (Berkeley) 04/12/90 2135045Skarels */ 2235045Skarels 2335045Skarels #if VAX8200 2435045Skarels 2535045Skarels /* 2635045Skarels * Routines to handle the console RX50. 2735045Skarels */ 2835045Skarels 2935045Skarels #include "param.h" 3035045Skarels #include "time.h" 3135045Skarels #include "kernel.h" 3235045Skarels #include "vmmac.h" 3335045Skarels #include "buf.h" 3435045Skarels #include "errno.h" 3535045Skarels #include "uio.h" 3635045Skarels 3735045Skarels #include "cpu.h" 3835045Skarels #include "rx50reg.h" 3935045Skarels 4035045Skarels struct rx50device rx50device; 4135045Skarels 4235045Skarels #define rx50unit(dev) minor(dev) 4335045Skarels 4435045Skarels struct rx50state { 4535045Skarels short rs_flags; /* see below */ 4635045Skarels short rs_drive; /* current drive number */ 4735045Skarels u_int rs_blkno; /* current block number */ 4835045Skarels } rx50state; 4935045Skarels 5035045Skarels /* flags */ 5135045Skarels #define RS_0OPEN 0x01 /* drive 0 open -- must be first */ 5235045Skarels #define RS_1OPEN 0x02 /* drive 1 open -- must be second */ 5335045Skarels #define RS_BUSY 0x04 /* operation in progress */ 5435045Skarels #define RS_WANT 0x08 /* wakeup when done */ 5535045Skarels #define RS_DONE 0x20 /* I/O operation done */ 5635045Skarels #define RS_ERROR 0x40 /* error bit set at interrupt */ 5735045Skarels 5835045Skarels /* 5935045Skarels * Open a console RX50. 6035045Skarels */ 6135045Skarels /*ARGSUSED*/ 6235045Skarels rx50open(dev, flags) 6335045Skarels dev_t dev; 6435045Skarels int flags; 6535045Skarels { 6635045Skarels int unit; 6735045Skarels 6835045Skarels /* only on 8200 (yet) */ 6935045Skarels if (cpu != VAX_8200 || (unit = rx50unit(dev)) >= 2) 7035045Skarels return (ENXIO); 7135045Skarels 7235045Skarels /* enforce exclusive access */ 7335045Skarels if (rx50state.rs_flags & (1 << unit)) 7435045Skarels return (EBUSY); 7535045Skarels rx50state.rs_flags |= 1 << unit; 7635045Skarels return (0); 7735045Skarels } 7835045Skarels 7935045Skarels /* 8035045Skarels * Close a console RX50. 8135045Skarels */ 8235045Skarels /*ARGSUSED*/ 8335045Skarels rx50close(dev, flags) 8435045Skarels dev_t dev; 8535045Skarels int flags; 8635045Skarels { 8735045Skarels 8835045Skarels rx50state.rs_flags &= ~(1 << dev); /* atomic */ 8935045Skarels } 9035045Skarels 9135045Skarels /* 9237759Smckusick * Perform a read (uio->uio_rw==UIO_READ) or write (uio->uio_rw==UIO_WRITE). 9335045Skarels */ 94*40912Ssklower rx50rw(dev, uio, flags) 9535045Skarels dev_t dev; 9635045Skarels register struct uio *uio; 9737759Smckusick int flags; 9835045Skarels { 9935045Skarels register struct rx50device *rxaddr; 10035045Skarels register struct rx50state *rs; 10135045Skarels register char *cp; 10235045Skarels register int error, i, t; 10335045Skarels char secbuf[512]; 10435045Skarels static char driveselect[2] = { RXCMD_DRIVE0, RXCMD_DRIVE1 }; 10535045Skarels 10635045Skarels /* enforce whole-sector I/O */ 10735045Skarels if ((uio->uio_offset & 511) || (uio->uio_resid & 511)) 10835045Skarels return (EINVAL); 10935045Skarels 11035045Skarels rs = &rx50state; 11135045Skarels 11235045Skarels /* lock out others */ 11335045Skarels i = spl4(); 11435045Skarels while (rs->rs_flags & RS_BUSY) { 11535045Skarels rs->rs_flags |= RS_WANT; 11635045Skarels sleep((caddr_t) &rx50state, PZERO - 1); 11735045Skarels } 11835045Skarels rs->rs_flags |= RS_BUSY; 11935045Skarels rs->rs_drive = rx50unit(dev); 12035045Skarels splx(i); 12135045Skarels 12235045Skarels rxaddr = &rx50device; 12335045Skarels error = 0; 12435045Skarels 12535045Skarels while (uio->uio_resid) { 12635045Skarels rs->rs_blkno = uio->uio_offset >> 9; 12735045Skarels if (rs->rs_blkno >= RX50MAXSEC) { 12835045Skarels if (rs->rs_blkno > RX50MAXSEC) 12935045Skarels error = EINVAL; 13037759Smckusick else if (uio->uio_rw == UIO_WRITE) 13135045Skarels error = ENOSPC; 13235045Skarels /* else ``eof'' */ 13335045Skarels break; 13435045Skarels } 13535045Skarels rs->rs_flags &= ~(RS_ERROR | RS_DONE); 13637759Smckusick if (uio->uio_rw == UIO_WRITE) { 13735045Skarels /* copy the data to the RX50 silo */ 13837759Smckusick error = uiomove(secbuf, 512, uio); 13935045Skarels if (error) 14035045Skarels break; 14135045Skarels i = rxaddr->rxrda; 14235045Skarels for (cp = secbuf, i = 512; --i >= 0;) 14335045Skarels rxaddr->rxfdb = *cp++; 14435045Skarels i = RXCMD_WRITE; 14535045Skarels } else 14635045Skarels i = RXCMD_READ; 14735045Skarels rxaddr->rxcmd = i | driveselect[rs->rs_drive]; 14835045Skarels i = rs->rs_blkno - ((t = rs->rs_blkno / RX50SEC) * RX50SEC); 14935045Skarels rxaddr->rxtrk = t == 79 ? 0 : t + 1; 15035045Skarels #ifdef notdef 15135045Skarels rxaddr->rxsec = "\1\3\5\7\11\1\3\5\7"[(2*t + i) % 5] + (i > 4); 15235045Skarels #else 15335045Skarels rxaddr->rxsec = RX50SKEW(i, t); 15435045Skarels #endif 15535045Skarels i = rxaddr->rxgo; /* start it up */ 15635045Skarels i = spl4(); 15735045Skarels while ((rs->rs_flags & RS_DONE) == 0) 15835045Skarels sleep((caddr_t) &rs->rs_blkno, PRIBIO); 15935045Skarels splx(i); 16035045Skarels if (rs->rs_flags & RS_ERROR) { 16135045Skarels error = EIO; 16235045Skarels break; 16335045Skarels } 16437759Smckusick if (uio->uio_rw == UIO_READ) { 16535045Skarels /* copy the data out of the silo */ 16635045Skarels i = rxaddr->rxrda; 16735045Skarels for (cp = secbuf, i = 512; --i >= 0;) 16835045Skarels *cp++ = rxaddr->rxedb; 16937759Smckusick error = uiomove(secbuf, 512, uio); 17035045Skarels if (error) 17135045Skarels break; 17235045Skarels } 17335045Skarels } 17435045Skarels 17535045Skarels /* let others in */ 17635045Skarels rs->rs_flags &= ~RS_BUSY; 17735045Skarels if (rs->rs_flags & RS_WANT) 17835045Skarels wakeup((caddr_t) rs); 17935045Skarels 18035045Skarels return (error); 18135045Skarels } 18235045Skarels 18335045Skarels rx50intr() 18435045Skarels { 18535045Skarels register struct rx50device *rxaddr = &rx50device; 18635045Skarels register struct rx50state *rs = &rx50state; 18735045Skarels int i; 18835045Skarels 18935045Skarels #ifdef lint 19035045Skarels i = 0; i = i; 19135045Skarels #endif 19235045Skarels 19335045Skarels /* ignore spurious interrupts */ 19435045Skarels if ((rxaddr->rxcmd & RXCMD_DONE) == 0) 19535045Skarels return; 19635045Skarels if ((rs->rs_flags & RS_BUSY) == 0) { 19735045Skarels printf("stray rx50 interrupt ignored\n"); 19835045Skarels return; 19935045Skarels } 20035045Skarels if (rxaddr->rxcmd & RXCMD_ERROR) { 20135045Skarels printf( 20235045Skarels "csa%d: hard error sn%d: cmd=%x trk=%x sec=%x csc=%x ict=%x ext=%x\n", 20335045Skarels rs->rs_drive + 1, rs->rs_blkno, 20435045Skarels rxaddr->rxcmd, rxaddr->rxtrk, rxaddr->rxsec, 20535045Skarels rxaddr->rxcsc, rxaddr->rxict, rxaddr->rxext); 20635045Skarels rxaddr->rxcmd = RXCMD_RESET; 20735045Skarels i = rxaddr->rxgo; 20835045Skarels rs->rs_flags |= RS_ERROR; 20935045Skarels } 21035045Skarels rs->rs_flags |= RS_DONE; 21135045Skarels wakeup((caddr_t) &rs->rs_blkno); 21235045Skarels } 21335045Skarels #endif 214