📄 tu.c
字号:
#ifndef lintstatic char *sccsid = "@(#)tu.c 4.1 ULTRIX 7/2/90";#endif lint#if defined(VAX750) || defined(VAX730)/* * Modification History * * 14-Sep-89 jaw * Reschedule call to biodone with timeout because * 750 tu58 interrupts at ipl 17 and biodone must run at 15. * * 30-May-89 * Added include of ../../machine/common/cpuconf.h which * is where cpu type definitions were moved. * * 06-Jan-1987 - pmk * Fixed tutimer checks in tuopen, tuclose & tuwatch * so we don't get multiple calls to tuwatch. This should fix * the timeout problem. Add timeout count and check in tuwatch. * On timeout restart command, give up after 3 trys. * * 16-Dec-1986 - pmk * Vax 750's should now only use MRSP. Change code * to use MRSP for 750. Also fix protocol error to reinitialize * tu58 as it should. Fixed end packet error detection and added * ascii strings to the output. * * 27-Nov-1985 - lp * Put #ifdef TUDEBUG around all debug statements. 'Fixed' * stall/panic problem on 750/730's. Made overruns only take upto * five seconds to be corrected. The stall has still been seen on * a 730 running multi but then you're not supposed to run this * hog multiuser anyway! Fixed typo in TUS_GET state where it * calculated the checksum a second time for the 750 & never * did it for the 730. * * TU58 DECtape II device driver * * TU58 console cassette driver (for VAX-11/750 or VAX-11/730). * The TU58 is treated as a block device (only). Error detection and * recovery is not extensive, but sufficient for most situations. It is * assumed that the TU58 will follow the RSP (or MRSP) protocol exactly, * very few protocol errors are checked for. It is also assumed that * the 730 uses Modified RSP (MRSP), while the 750 may use either RSP * or MRSP depending on whether defined(MRSP) is true or not. * In the case of a 750 without MRSP, the only way for the CPU to * keep up with the tu58 is to lock out virtually everything else. * * NOTE: Reading large amounts of data from the tu58 is likely * to crash your system if you are running multiuser. * ******FOR SINGLE USER USE ONLY***** */#include "../h/param.h"#include "../h/systm.h"#include "../h/buf.h"#include "../h/conf.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/kernel.h"#include "../vax/cpu.h"#include "../../machine/common/cpuconf.h"#include "../vax/mtpr.h"#include "../vax/rsp.h"#ifdef TUDEBUG#define printd if(tudebug) printf#ifdef printdint tudebug; /* printd */#endif printd#endifextern int biodone();#define NTU ((cpu == VAX_750) ? 1 : 2)#define DNUM 01 /* mask for drive number (should match NTU) */#define NTUBLK 512 /* number of blocks on a TU58 cassette */#define WRV 02 /* bit in minor dev => write w. read verify */#define NTUQ 2 /* # of blocks which can be queued up */#define TUIPL ((cpu == VAX_750) ? 0x17 : 0x14)#define MAXERRS 3#ifndef MRSP#define MRSP 1#endif/* * State information */struct tu { u_char *tu_rbptr; /* pointer to buffer for read */ int tu_rcnt; /* how much to read */ u_char *tu_wbptr; /* pointer to buffer for write */ int tu_wcnt; /* how much to write */ int tu_state; /* current state of tansfer operation */ int tu_flag; /* read in progress flag */ char *tu_addr; /* real buffer data address */ int tu_count; /* real requested count */ u_short tu_toerrs; /* count of timeout errors */ u_short tu_poerrs; /* count of timeout errors */ u_short tu_serrs; /* count of soft errors */ u_short tu_cerrs; /* count of checksum errors */ u_short tu_herrs; /* count of hard errors */ char tu_dopen[2]; /* drive is open */} tu;/* * Device register bits */#define READY 0200 /* transmitter ready */#define DONE 0200 /* receiver done */#define IE 0100 /* interrupt enable */#define BREAK 1 /* send break */struct packet tucmd; /* a command sent to the TU58 */struct packet tudata; /* a command or data returned from TU58 */char *tustates[TUS_NSTATES] = { "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR", "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"};char *errstrgs[] = { "(Failed Self-Test)", "(Partial Operation End Of Medium)", "(Bad Unit Number)", "(No Cartridge)", "(Write Protected)", "(Data Check Error)", "(Seek Error Block Not Found)", "(Motor Stopped)", "(Bad Op Code)","(Bad Block Number > 511)", "(Nonknown)"};u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */static char tu_pcnt[2]; /* pee/vee counters */int tutimer = 0;int tuwake();struct buf tutab; /* I/O queue header *//* * Open the TU58 *//*ARGSUSED*/tuopen(dev, flag){ extern int tuwatch(); register int s;#ifdef lint turintr(); tuwintr();#endif if ((minor(dev)&DNUM) >= NTU) return (ENXIO); if (tu.tu_dopen[minor(dev)&DNUM]) return (EBUSY); if (tutimer++ == 0) timeout(tuwatch, (caddr_t)0, hz); tutimer++; s = splx(TUIPL); tu.tu_dopen[minor(dev)&DNUM]++; /* * If the cassette's already initialized, * just enable interrupts and return. */ if (tu.tu_state == TUS_IDLE) { mtpr(CSRS, IE); goto ok; } /* * Must initialize, reset the cassette * and wait for things to settle down. */ tureset(); sleep((caddr_t)&tu, PZERO+1); tutab.b_active = NULL; if (tu.tu_state != TUS_IDLE) { tu.tu_state = TUS_INIT1; tu.tu_dopen[minor(dev)&DNUM] = 0; tu.tu_rcnt = tu.tu_wcnt = 0; mtpr(CSTS, 0); mtpr(CSRS, 0); splx(s); return (EIO); }ok: splx(s); return (0);}/* * Close the TU58, but make sure all * outstanding i/o is complete first.. */tuclose(dev, flag) dev_t dev; int flag;{ register int s, unit = minor(dev); register struct buf *bp, *last = NULL; s = splx(TUIPL); while (tu_pcnt[unit]) sleep(&tu_pcnt[unit], PRIBIO); /* * No more writes are pending, scan the * buffer queue for oustanding reads from * this unit. */ for (bp = tutab.b_actf; bp; bp = bp->av_forw) { if (bp->b_dev == dev) last = bp; } if (last) { last->b_flags |= B_CALL; last->b_iodone = tuwake; sleep((caddr_t)last, PRIBIO); } tu.tu_dopen[unit&DNUM] = 0; if (!tu.tu_dopen[0] && !tu.tu_dopen[1]) { tutimer = -1; mtpr(CSRS, 0); tu.tu_flag = 0; } splx(s);}tuwake(bp) struct buf *bp;{ wakeup(bp);}/* * Reset the TU58 */tureset(){ mtpr(CSRS, 0); tu.tu_state = TUS_INIT1; tu.tu_wbptr = tunull; tu.tu_wcnt = sizeof (tunull); tucmd.pk_flag = TUF_CMD; tucmd.pk_mcount = sizeof (tucmd) - 4; tucmd.pk_mod = 0; tucmd.pk_seq = 0; tucmd.pk_sw = MRSP ? TUSW_MRSP : 0; tutab.b_active++; mtpr(CSTS, IE | BREAK); tuxintr(); /* start output */}/* * Strategy routine for block I/O */tustrategy(bp) register struct buf *bp;{ register int s; if (bp->b_blkno >= NTUBLK) { bp->b_flags |= B_ERROR; timeout(iodone,bp,1); return; } if ((bp->b_flags&B_READ) == 0) tu_pee(&tu_pcnt[minor(bp->b_dev)&DNUM]); bp->av_forw = NULL; s = splx(TUIPL); if (tutab.b_actf == NULL) tutab.b_actf = bp; else tutab.b_actl->av_forw = bp; tutab.b_actl = bp; splx(s); if (tutab.b_active == NULL) tustart();}/* * Start the transfer */tustart(){ register struct buf *bp; register int s; if ((bp = tutab.b_actf) == NULL) return; s = splx(TUIPL); if (tu.tu_state != TUS_IDLE) { tureset(); splx(s); return; } tutab.b_active++; tutab.b_errcnt = 0; tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE; tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ? TUMD_WRV : 0; tucmd.pk_unit = (minor(bp->b_dev)&DNUM); tucmd.pk_sw = MRSP ? TUSW_MRSP : 0; tucmd.pk_count = tu.tu_count = bp->b_bcount; tucmd.pk_block = bp->b_blkno; tucmd.pk_chksum = tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op, (int)tucmd.pk_mcount); tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW; tu.tu_addr = bp->b_un.b_addr; tu.tu_wbptr = (u_char *)&tucmd; tu.tu_wcnt = sizeof (tucmd); tuxintr(); splx(s);}/* * TU58 receiver interrupt */turintr(){ register struct buf *bp; register int c; register char *sp; c = mfpr(CSRD)&0xff; if (MRSP) { while ((mfpr(CSTS)&READY) == 0) ; mtpr(CSTD, TUF_CONT); /* ACK */ if (tu.tu_rcnt) { *tu.tu_rbptr++ = c; if (--tu.tu_rcnt) return; } } /* * Switch on the state of the transfer. */ switch(tu.tu_state) { /* * Probably an overrun error, * cannot happen if MRSP is used */ case TUS_RCVERR: mtpr(CSRS, 0); /* flush */ printf("tu%d: data overrun, xfer restarted\n" , tudata.pk_unit); /* DEBUG */ tu.tu_serrs++; tu_restart(); break; /* * If we get an unexpected "continue", * start all over again... */ case TUS_INIT2: tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;#ifdef TUDEBG if(tudebug) printstate(tu.tu_state);#endif if (tu.tu_state == TUS_IDLE) mtpr(CSTS, IE); tu.tu_flag = 0; wakeup((caddr_t)&tu); tustart(); break; /* * Only transition from this state * is on a "continue", so if we don't * get it, reset the world. */ case TUS_WAIT: /* waiting for continue */ switch(c) { case TUF_CONT: /* got the expected continue */ tu.tu_flag = 0; tudata.pk_flag = TUF_DATA; tudata.pk_mcount = MIN(128, tu.tu_count); tudata.pk_chksum = tuchk(*((short *)&tudata), (caddr_t)tu.tu_addr, (int)tudata.pk_mcount); tu.tu_state = TUS_SENDH; tu.tu_wbptr = (u_char *)&tudata; tu.tu_wcnt = 2; tuxintr(); break; case TUF_CMD: /* sending us an END packet...error */ tu.tu_state = TUS_GET; tu.tu_rbptr = (u_char *) &tudata; tu.tu_rcnt = sizeof (tudata) - 1; tu.tu_flag = 1; mtpr (CSTS, 0); *tu.tu_rbptr++ = c; break; case TUF_INITF: tureset(); break; default: /* something random...bad news */ tu.tu_state = TUS_INIT1; break; } break; case TUS_SENDW: if (c != TUF_CONT && c != TUF_INITF) goto bad; tureset(); break; /* * Got header, now get data; amount to * fetch is included in packet. */ case TUS_GETH: if (MRSP) switch (tudata.pk_flag) { case TUF_DATA: tu.tu_rbptr = (u_char *)tu.tu_addr; break; case TUF_CMD: if (tudata.pk_mcount == (sizeof(tudata) - 4)) break; default: c = TUF_INITF; goto bad;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -