xref: /csrg-svn/sys/vax/uba/ts.c (revision 1947)
1*1947Swnj /*	ts.c	4.4	12/20/80	*/
21900Swnj 
31941Swnj #include "ts.h"
41900Swnj #if NTS > 0
51900Swnj /*
61900Swnj  * TS11 tape driver
71900Swnj  */
81900Swnj 
91900Swnj #include "../h/param.h"
101900Swnj #include "../h/systm.h"
111900Swnj #include "../h/buf.h"
121900Swnj #include "../h/conf.h"
131900Swnj #include "../h/dir.h"
141900Swnj #include "../h/file.h"
151900Swnj #include "../h/user.h"
161900Swnj #include "../h/pte.h"
171900Swnj #include "../h/map.h"
181900Swnj #include "../h/uba.h"
19*1947Swnj #include "../h/vm.h"
201900Swnj 
211900Swnj struct	device {
221918Swnj 	u_short	tsdb;
231918Swnj 	u_short	tssr;
241900Swnj };
251900Swnj 
261900Swnj struct	buf	tstab;
271900Swnj struct	buf	rtsbuf;
281900Swnj struct	buf	ctsbuf;
291900Swnj 
301900Swnj #define	INF	1000000000
311900Swnj 
321918Swnj u_short	ts_uba;
331900Swnj long	ts_iouba;
341900Swnj char	ts_flags;
351900Swnj char	ts_openf;
361900Swnj daddr_t	ts_blkno;
371900Swnj daddr_t	ts_nxrec;
381900Swnj 
391900Swnj /* status message */
401900Swnj struct	sts {
411918Swnj 	u_short	s_sts;
42*1947Swnj 	u_short	len;
43*1947Swnj 	u_short rbpcr;
441918Swnj 	u_short	xs0;
451918Swnj 	u_short	xs1;
461918Swnj 	u_short	xs2;
471918Swnj 	u_short	xs3;
481900Swnj };
491900Swnj 
501900Swnj /* Error codes in stat 0 */
511900Swnj #define	TMK	0100000
521900Swnj #define	RLS	040000
531900Swnj #define	ONL	0100
541900Swnj #define	WLE	04000
551900Swnj 
561900Swnj /* command message */
571900Swnj struct cmd {
581918Swnj 	u_short	c_cmd;
591918Swnj 	u_short	c_loba;
601918Swnj 	u_short	c_hiba;
611918Swnj 	u_short	c_size;
621900Swnj };
631900Swnj 
641900Swnj #define	ACK	0100000
651900Swnj #define	CVC	040000
661900Swnj #define	IE	0200
671900Swnj #define	READ	01
681900Swnj #define	REREAD	01001
691900Swnj 
701900Swnj #define	SETCHR	04
711900Swnj 
721900Swnj #define	WRITE	05
731900Swnj #define	REWRITE	01005
741900Swnj 
751900Swnj #define	SFORW	010
761900Swnj #define	SREV	0410
771900Swnj #define	REW	02010
781900Swnj 
791900Swnj #define	WTM	011
801900Swnj 
811900Swnj #define	GSTAT	017
821900Swnj 
831900Swnj /* characteristics data */
841900Swnj struct charac {
851918Swnj 	u_short	char_loba;
861918Swnj 	u_short	char_hiba;
871918Swnj 	u_short	char_size;
881918Swnj 	u_short	char_mode;
891900Swnj };
901900Swnj 
911900Swnj /* All the packets, collected */
921900Swnj struct tsmesg {
931900Swnj 	struct	cmd ts_cmd;
941900Swnj 	struct	sts ts_sts;
951900Swnj 	struct	charac ts_char;
961900Swnj 	int	align;		/* Should force alignment */
971900Swnj } ts;
981900Swnj 
991900Swnj /* Bits in (unibus) status register */
1001900Swnj #define	SC	0100000
1011900Swnj #define	SSR	0200
1021900Swnj #define	OFL	0100
1031900Swnj #define	NBA	02000
1041900Swnj 
1051900Swnj /* states */
1061900Swnj #define	SIO	1
1071900Swnj #define	SSFOR	2
1081900Swnj #define	SSREV	3
1091900Swnj #define SRETRY	4
1101900Swnj #define SCOM	5
1111900Swnj #define SOK	6
1121900Swnj 
1131900Swnj #define H_WRITTEN 1
1141900Swnj 
1151900Swnj tsopen(dev, flag)
1161900Swnj {
1171900Swnj 	register struct device *tsaddr = TSADDR;
1181900Swnj 	static struct tsmesg *ubaddr;
1191900Swnj 
1201900Swnj 	tstab.b_flags |= B_TAPE;
1211900Swnj 	if (ts_openf) {
1221900Swnj 		u.u_error = ENXIO;
1231900Swnj 		return;
1241900Swnj 	}
1251900Swnj 	if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) {
1261900Swnj 		long i = 0;
1271900Swnj 		tsaddr->tssr = 0;
1281900Swnj 		while ((tsaddr->tssr & SSR)==0) {
1291900Swnj 			if (++i > 1000000) {
1301900Swnj 				printf("Tape unready\n");
1311900Swnj 				u.u_error = ENXIO;
1321900Swnj 				return;
1331900Swnj 			}
1341900Swnj 		}
1351900Swnj 	}
1361900Swnj 	if (tsaddr->tssr&OFL) {
1371900Swnj 		printf("Tape offline\n");
1381900Swnj 		u.u_error = ENXIO;
1391900Swnj 		return;
1401900Swnj 	}
1411900Swnj 	if (tsaddr->tssr&NBA) {
1421900Swnj 		ctsbuf.b_un.b_addr = (caddr_t) &ts;
1431900Swnj 		ctsbuf.b_bcount = sizeof(ts);
1441900Swnj 		if (ubaddr == 0)
1451900Swnj 			ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0);
1461918Swnj 		ts_uba = (u_short)((long)ubaddr + (((long)ubaddr >> 16) & 03));
1471900Swnj 		ts.ts_char.char_loba = (int)&ubaddr->ts_sts;
1481918Swnj 		ts.ts_char.char_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
1491900Swnj 		ts.ts_char.char_size = sizeof(ts.ts_sts);
1501900Swnj 		ts.ts_char.char_mode = 0400;		/* Stop on 2 tape marks */
1511900Swnj 		ts.ts_cmd.c_cmd = ACK + 04;	/* write characteristics */
1521900Swnj 		ts.ts_cmd.c_loba = (int)&ubaddr->ts_char;
1531918Swnj 		ts.ts_cmd.c_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
1541900Swnj 		ts.ts_cmd.c_size = sizeof(ts.ts_sts);
1551900Swnj 		tsaddr->tsdb = ts_uba;
1561900Swnj 	}
1571900Swnj 	ts_blkno = 0;
1581900Swnj 	ts_nxrec = INF;
1591900Swnj 	ts_flags = 0;
1601900Swnj 	if (u.u_error==0)
1611900Swnj 		ts_openf++;
1621900Swnj }
1631900Swnj 
1641900Swnj tsclose(dev, flag)
1651900Swnj {
1661900Swnj 
1671900Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) {
1681900Swnj 		tscommand(WTM);
1691900Swnj 		tscommand(WTM);
1701900Swnj 		tscommand(SREV);
1711900Swnj 	}
1721900Swnj 	if ((minor(dev)&4) == 0)
1731900Swnj 		tscommand(REW);
1741900Swnj 	ts_openf = 0;
1751900Swnj }
1761900Swnj 
1771900Swnj tscommand(com)
1781900Swnj {
1791900Swnj 	register struct buf *bp;
1801900Swnj 
1811900Swnj 	bp = &ctsbuf;
1821900Swnj 	spl5();
1831900Swnj 	while(bp->b_flags&B_BUSY) {
1841900Swnj 		bp->b_flags |= B_WANTED;
1851900Swnj 		sleep((caddr_t)bp, PRIBIO);
1861900Swnj 	}
1871900Swnj 	spl0();
1881900Swnj 	bp->b_resid = com;
1891900Swnj 	bp->b_blkno = 0;
1901900Swnj 	bp->b_flags = B_BUSY|B_READ;
1911900Swnj 	tsstrategy(bp);
1921900Swnj 	iowait(bp);
1931900Swnj 	if(bp->b_flags&B_WANTED)
1941900Swnj 		wakeup((caddr_t)bp);
1951900Swnj 	bp->b_flags = 0;
1961900Swnj 	return(bp->b_resid);
1971900Swnj }
1981900Swnj 
1991900Swnj tsstrategy(bp)
2001900Swnj register struct buf *bp;
2011900Swnj {
2021900Swnj 	register daddr_t *p;
2031900Swnj 
2041900Swnj 	if(bp != &ctsbuf) {
2051900Swnj 		p = &ts_nxrec;
2061900Swnj 		if(dbtofsb(bp->b_blkno) > *p) {
2071900Swnj 			bp->b_flags |= B_ERROR;
2081900Swnj 			bp->b_error = ENXIO;
2091900Swnj 			iodone(bp);
2101900Swnj 			return;
2111900Swnj 		}
2121900Swnj 		if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2131900Swnj 			bp->b_resid = bp->b_bcount;
2141900Swnj 			iodone(bp);
2151900Swnj 			return;
2161900Swnj 		}
2171900Swnj 		if ((bp->b_flags&B_READ)==0) {
2181900Swnj 			*p = dbtofsb(bp->b_blkno) + 1;
2191900Swnj 			ts_flags |= H_WRITTEN;
2201900Swnj 		}
2211900Swnj 	}
2221900Swnj 	bp->av_forw = NULL;
2231900Swnj 	spl5();
2241900Swnj 	if (tstab.b_actf == NULL)
2251900Swnj 		tstab.b_actf = bp;
2261900Swnj 	else
2271900Swnj 		tstab.b_actl->av_forw = bp;
2281900Swnj 	tstab.b_actl = bp;
2291900Swnj 	if (tstab.b_active==0)
2301900Swnj 		tsstart();
2311900Swnj 	spl0();
2321900Swnj }
2331900Swnj 
2341900Swnj tsstart()
2351900Swnj {
2361900Swnj 	register struct buf *bp;
2371900Swnj 	register struct device *tsaddr = TSADDR;
2381900Swnj 	daddr_t blkno;
2391900Swnj 
2401900Swnj     loop:
2411900Swnj 	if ((bp = tstab.b_actf) == NULL)
2421900Swnj 		return;
2431900Swnj 	blkno = ts_blkno;
2441900Swnj 	if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec)
2451900Swnj 		goto abort;
2461900Swnj 	if (bp == &ctsbuf) {
2471900Swnj 		tstab.b_active = SCOM;
2481900Swnj 		ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid;
2491900Swnj 		ts.ts_cmd.c_loba = 1;		/* count always 1 */
2501900Swnj 	} else if (blkno == dbtofsb(bp->b_blkno)) {
2511900Swnj 		tstab.b_active = SIO;
2521900Swnj 		ts_iouba = ubasetup(bp, 1);
2531918Swnj 		ts.ts_cmd.c_loba = (u_short)ts_iouba;
2541918Swnj 		ts.ts_cmd.c_hiba = (u_short)(ts_iouba >> 16) & 03;
2551900Swnj 		ts.ts_cmd.c_size = bp->b_bcount;
2561900Swnj 		if(bp->b_flags & B_READ)
2571900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+READ;
2581900Swnj 		else
2591900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE;
2601900Swnj 	} else {
2611900Swnj 		if (blkno < dbtofsb(bp->b_blkno)) {
2621900Swnj 			tstab.b_active = SSFOR;
2631900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW;
2641900Swnj 			ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno;
2651900Swnj 		} else {
2661900Swnj 			tstab.b_active = SSREV;
2671900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV;
2681900Swnj 			ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno);
2691900Swnj 		}
2701900Swnj 	}
2711900Swnj 	tsaddr->tsdb = ts_uba;
2721900Swnj 	return;
2731900Swnj 
2741900Swnj     abort:
2751900Swnj 	bp->b_flags |= B_ERROR;
2761900Swnj 
2771900Swnj     next:
2781900Swnj 	tstab.b_active = 0;
2791900Swnj 	tstab.b_actf = bp->av_forw;
2801900Swnj 	iodone(bp);
2811900Swnj 	goto loop;
2821900Swnj }
2831900Swnj 
2841900Swnj tsintr()
2851900Swnj {
2861900Swnj 	register struct buf *bp;
2871900Swnj 	register struct device *tsaddr = TSADDR;
2881900Swnj 	register err, errclass, state;
2891900Swnj 
2901900Swnj 	if ((bp = tstab.b_actf)==NULL)
2911900Swnj 		return;
2921900Swnj 	state = tstab.b_active;
2931900Swnj 	tstab.b_active = 0;
2941900Swnj 	err = tsaddr->tssr & 016;
2951900Swnj 	if ((tsaddr->tssr & SC) == 0)
2961900Swnj 		err = 0;
2971900Swnj 	errclass = 0;
2981900Swnj 	switch (err) {
2991900Swnj 	case 014:		/* unrecoverable */
3001900Swnj 	case 016:		/* fatal */
3011900Swnj 	case 002:		/* attention (shouldn't happen) */
3021900Swnj 	case 012:		/* "recoverable", but shouldn't happen */
3031900Swnj 		errclass = 2;
3041900Swnj 		break;
3051900Swnj 
3061900Swnj 	case 0:			/* all OK */
3071900Swnj 		break;
3081900Swnj 
3091900Swnj 	case 004:		/* status alert */
3101900Swnj 		if (ts.ts_sts.xs0&RLS && bp==&rtsbuf)	/* short record */
3111900Swnj 			break;
3121900Swnj 		if (ts.ts_sts.xs0 & TMK) {		/* tape mark */
3131900Swnj 			ts.ts_sts.rbpcr = bp->b_bcount;
3141900Swnj 			break;
3151900Swnj 		}
3161900Swnj 		errclass = 1;
3171900Swnj 		break;
3181900Swnj 
3191900Swnj 	case 010:		/* recoverable, tape moved */
3201900Swnj 		if (state==SIO && ++bp->b_errcnt < 10) {
3211900Swnj 			ts.ts_cmd.c_cmd |= 01000;	/* redo bit */
3221900Swnj 			tstab.b_active = SIO;
3231900Swnj 			tsaddr->tsdb = ts_uba;
3241900Swnj 			return;
3251900Swnj 		}
3261900Swnj 		errclass = 1;
3271900Swnj 		break;
3281900Swnj 
3291900Swnj 	case 006:		/* Function reject */
3301900Swnj 		if (state==SIO && ts.ts_sts.xs0 & WLE)
3311900Swnj 			printf("Tape needs a ring\n");
3321900Swnj 		if ((ts.ts_sts.xs0&ONL) == 0)		/* tape offline */
3331900Swnj 			printf("Tape offline\n");
3341900Swnj 		errclass = 2;
3351900Swnj 	}
3361900Swnj 	if (errclass)
3371900Swnj 		printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr,
3381900Swnj 		  ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr,
3391900Swnj 		  ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3);
3401900Swnj 	switch(state) {
3411900Swnj 	case SIO:
3421900Swnj 		ts_blkno++;
3431900Swnj 		if (ts_iouba)
3441900Swnj 			ubafree(ts_iouba);
3451900Swnj 		else
3461900Swnj 			printf("uba alloc botch\n");
3471900Swnj 		ts_iouba = 0;
3481900Swnj 	case SCOM:
3491900Swnj 		tstab.b_errcnt = 0;
3501900Swnj 		tstab.b_actf = bp->av_forw;
3511900Swnj 		bp->b_resid = ts.ts_sts.rbpcr;
3521900Swnj 		iodone(bp);
3531900Swnj 		break;
3541900Swnj 
3551900Swnj 	case SSFOR:
3561900Swnj 	case SSREV:
3571900Swnj 		ts_blkno = dbtofsb(bp->b_blkno);
3581900Swnj 		break;
3591900Swnj 
3601900Swnj 	default:
3611900Swnj 		printf("Unknown tape interrupt\n");
3621900Swnj 		errclass = 2;
3631900Swnj 		break;
3641900Swnj 	}
3651900Swnj 	if (errclass > 1) {
3661900Swnj 		while (bp = tstab.b_actf) {
3671900Swnj 			bp->b_flags |= B_ERROR;
3681900Swnj 			iodone(bp);
3691900Swnj 			tstab.b_actf = bp->av_forw;
3701900Swnj 		}
3711900Swnj 	}
3721900Swnj 	tsstart();
3731900Swnj }
3741900Swnj 
3751900Swnj tsread(dev)
3761900Swnj {
3771900Swnj 	tsphys(dev);
3781900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_READ, minphys);
3791900Swnj }
3801900Swnj 
3811900Swnj tswrite(dev)
3821900Swnj {
3831900Swnj 	tsphys(dev);
3841900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys);
3851900Swnj }
3861900Swnj 
3871900Swnj tsphys(dev)
3881900Swnj {
3891900Swnj 	register unit;
3901900Swnj 	daddr_t a;
3911900Swnj 
3921900Swnj 	a = u.u_offset >> 9;
3931900Swnj 	ts_blkno = dbtofsb(a);
3941900Swnj 	ts_nxrec = dbtofsb(a)+1;
3951900Swnj }
3961918Swnj 
3971918Swnj #define	UBMAP	(int *)0xf30800
3981918Swnj 
3991918Swnj int dtsinfo;
400*1947Swnj struct tsmesg dts;
4011918Swnj 
4021918Swnj twall(start, num)
4031918Swnj {
4041918Swnj 	register struct device *tsaddr = TSPHYS;
4051918Swnj 	register int *ubap = UBMAP;
4061918Swnj 	register int p, i;
4071918Swnj 
4081918Swnj 	tsinit();
4091918Swnj 	/* dump mem */
4101918Swnj 	p = PG_V;
4111918Swnj 	i = 0;
4121918Swnj 	while (i<num) {
4131918Swnj 		*(ubap) = p|i++;
4141918Swnj 		*(ubap+1) = p|i;
4151918Swnj 		dts.ts_cmd.c_loba = 0;
4161918Swnj 		dts.ts_cmd.c_hiba = 0;
4171918Swnj 		dts.ts_cmd.c_size = NBPG;
4181918Swnj 		dts.ts_cmd.c_cmd = ACK+CVC+WRITE;
4191918Swnj 		tsaddr->tsdb = dtsinfo;
4201918Swnj 		twait();
4211918Swnj 	}
4221918Swnj 	printf("done\n");
4231918Swnj }
4241918Swnj 
4251918Swnj tsinit()
4261918Swnj {
4271918Swnj 	register struct device *tsaddr = TSPHYS;
4281918Swnj 	register struct tsmesg *tsm;
4291918Swnj 	register int *ubap = UBMAP;
4301918Swnj 	register i;
4311918Swnj 
4321918Swnj 	tsaddr->tssr = 0;
4331918Swnj 	while ((tsaddr->tssr&SSR)==0)
4341918Swnj 		;
4351918Swnj 	i = (int)&dts;
4361918Swnj 	i &= 0xefffff;
4371918Swnj 	dtsinfo = ((i&0777)|02000);
4381918Swnj 	tsm = (struct tsmesg *)dtsinfo;
4391918Swnj 	i >>= 9;
4401918Swnj 	i |= PG_V;
4411918Swnj 	*(ubap+2) = i;
4421918Swnj 	*(ubap+3) = i+1;
4431918Swnj 	dts.ts_cmd.c_cmd = ACK + 04;
444*1947Swnj 	dts.ts_cmd.c_loba = (int)&tsm->ts_char;
4451918Swnj 	dts.ts_cmd.c_hiba = 0;
4461918Swnj 	dts.ts_cmd.c_size = sizeof(dts.ts_char);
447*1947Swnj 	dts.ts_char.char_loba = (int)&tsm->ts_sts;
4481918Swnj 	dts.ts_char.char_hiba = 0;
4491918Swnj 	dts.ts_char.char_size = sizeof(dts.ts_sts);
4501918Swnj 	dts.ts_char.char_mode = 0400;
4511918Swnj 	tsaddr->tsdb = dtsinfo;
4521918Swnj 	twait();
4531918Swnj }
4541918Swnj 
4551918Swnj teof()
4561918Swnj {
4571918Swnj 
4581918Swnj 	dtscommand(WTM);
4591918Swnj }
4601918Swnj 
4611918Swnj rewind()
4621918Swnj {
4631918Swnj 
4641918Swnj 	dtscommand(REW);
4651918Swnj }
4661918Swnj 
4671918Swnj dtscommand(com)
4681918Swnj {
4691918Swnj 	register struct device *tsaddr = TSPHYS;
4701918Swnj 
4711918Swnj 	dts.ts_cmd.c_cmd = ACK+CVC+com;
4721918Swnj 	dts.ts_cmd.c_loba = 1;
4731918Swnj 	tsaddr->tsdb = dtsinfo;
4741918Swnj 	twait();
4751918Swnj }
4761918Swnj 
4771918Swnj twait()
4781918Swnj {
4791918Swnj 	register struct device *tsaddr = TSPHYS;
4801918Swnj 	register i;
4811918Swnj 
4821918Swnj 	while ((tsaddr->tssr&SSR)==0)
4831918Swnj 		;
4841918Swnj 	i = tsaddr->tssr;
4851918Swnj 	if (i&SC)
4861918Swnj 		printf("tssr %x ", i);
4871918Swnj }
4881900Swnj #endif
489