⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tu.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -