V7M/sys/dev/tc.c

Compare this file to the similar file:
Show the results in this format:

#

/*
 * TC-11 DECtape driver
 */

#include "../h/param.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/dir.h"
#include "../h/user.h"

struct device {
	int	tccsr;
	union wb {
		int	w;
		char	b[2];
	} tccm;
	int	tcwc;
	int	tcba;
	int	tcdt;
};

struct	buf	tctab;
char	tcper[8];

#define	TCADDR	((struct device *) 0177340)
#define	NTCBLK	578

#define	TAPERR	0100000
#define	TREV	04000
#define	READY	0200
#define	IENABLE	0100
#define	UPS	0200
#define	ENDZ	0100000
#define	BLKM	02000
#define	ILGOP	010000
#define	SELERR	04000

#define	SAT	0
#define	RNUM	02
#define	RDATA	04
#define	SST	010
#define	WDATA	014
#define	GO	01

#define	SFORW	1
#define	SREV	2
#define	SIO	3

tcclose(dev)
{
	bflush(dev);
	tcper[dev&07] = 0;
}

tcstrategy(bp)
register struct buf *bp;
{

	if(bp->b_flags&B_PHYS)
		mapalloc(bp);
	bp->b_resid = 0;
	if(bp->b_blkno >= NTCBLK || tcper[minor(bp->b_dev)&07]) {
		bp->b_flags |= B_ERROR;
		iodone(bp);
		return;
	}
	bp->av_forw = 0;
	spl6();
	if (tctab.b_actf==0)
		tctab.b_actf = bp;
	else
		tctab.b_actl->av_forw = bp;
	tctab.b_actl = bp;
	if (tctab.b_active==0)
		tcstart();
	spl0();
}

tcstart()
{
	register struct buf *bp;
	register int com;
	register union wb *tccmp;

loop:
	tccmp = &TCADDR->tccm;
	if ((bp = tctab.b_actf) == 0)
		return;
	if(tcper[minor(bp->b_dev)&07]) {
		if((tctab.b_actf = bp->av_forw) == 0)
			tccmp->b[0] = SAT|GO;
		bp->b_flags |= B_ERROR;
		iodone(bp);
		goto loop;
	}
	if ((tccmp->b[1]&07) != minor(bp->b_dev))
		tccmp->b[0] = SAT|GO;
	tctab.b_errcnt = 20;
	tctab.b_active = SFORW;
	com = (minor(bp->b_dev)<<8) | IENABLE|RNUM|GO;
	if ((TCADDR->tccsr & UPS) == 0) {
		com |= TREV;
		tctab.b_active = SREV;
	}
	tccmp->w = com;
}

tcintr()
{
	register struct buf *bp;
	register union wb *tccmp;
	register int *tcdtp;

	tccmp = &TCADDR->tccm;
	tcdtp = &TCADDR->tccsr;
	bp = tctab.b_actf;
	if (tccmp->w&TAPERR) {
		if((*tcdtp&(ENDZ|BLKM)) == 0)
			deverror(bp, *tcdtp, 0);
		if(*tcdtp & (ILGOP|SELERR)) {
			tcper[bp->b_dev&07]++;
			tctab.b_errcnt = 0;
		}
		tccmp->w &= ~TAPERR;
		if (--tctab.b_errcnt == 0) {
			bp->b_flags |= B_ERROR;
			goto done;
		}
		if (tccmp->w&TREV) {
		setforw:
			tctab.b_active = SFORW;
			tccmp->w &= ~TREV;
		} else {
		setback:
			tctab.b_active = SREV;
			tccmp->w |= TREV;
		}
		tccmp->b[0] = IENABLE|RNUM|GO;
		return;
	}
	tcdtp = &TCADDR->tcdt;
	switch (tctab.b_active) {

	case SIO:
	done:
		tctab.b_active = 0;
		if (tctab.b_actf = bp->av_forw)
			tcstart();
		else
			TCADDR->tccm.b[0] = SAT|GO;
		iodone(bp);
		return;

	case SFORW:
		if (*tcdtp > bp->b_blkno)
			goto setback;
		if (*tcdtp < bp->b_blkno)
			goto setforw;
		*--tcdtp = (int)bp->b_un.b_addr;	/* core address */
		*--tcdtp = -(bp->b_bcount>>1);
		tccmp->b[0] = ((bp->b_xmem & 03) << 4) | IENABLE|GO
		    | (bp->b_flags&B_READ?RDATA:WDATA);
		tctab.b_active = SIO;
		return;

	case SREV:
		if (*tcdtp+3 > bp->b_blkno)
			goto setback;
		goto setforw;
	}
}