xref: /csrg-svn/sys/vax/uba/ts.c (revision 1918)
1*1918Swnj /*	ts.c	4.2	12/17/80	*/
21900Swnj 
31900Swnj #include "../conf/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"
191900Swnj 
201900Swnj struct	device {
21*1918Swnj 	u_short	tsdb;
22*1918Swnj 	u_short	tssr;
231900Swnj };
241900Swnj 
251900Swnj struct	buf	tstab;
261900Swnj struct	buf	rtsbuf;
271900Swnj struct	buf	ctsbuf;
281900Swnj 
291900Swnj #define	INF	1000000000
301900Swnj 
31*1918Swnj u_short	ts_uba;
321900Swnj long	ts_iouba;
331900Swnj char	ts_flags;
341900Swnj char	ts_openf;
351900Swnj daddr_t	ts_blkno;
361900Swnj daddr_t	ts_nxrec;
371900Swnj 
381900Swnj /* status message */
391900Swnj struct	sts {
40*1918Swnj 	u_short	s_sts;
41*1918Swnj 	u_short	xs0;
42*1918Swnj 	u_short	xs1;
43*1918Swnj 	u_short	xs2;
44*1918Swnj 	u_short	xs3;
451900Swnj };
461900Swnj 
471900Swnj /* Error codes in stat 0 */
481900Swnj #define	TMK	0100000
491900Swnj #define	RLS	040000
501900Swnj #define	ONL	0100
511900Swnj #define	WLE	04000
521900Swnj 
531900Swnj /* command message */
541900Swnj struct cmd {
55*1918Swnj 	u_short	c_cmd;
56*1918Swnj 	u_short	c_loba;
57*1918Swnj 	u_short	c_hiba;
58*1918Swnj 	u_short	c_size;
591900Swnj };
601900Swnj 
611900Swnj #define	ACK	0100000
621900Swnj #define	CVC	040000
631900Swnj #define	IE	0200
641900Swnj #define	READ	01
651900Swnj #define	REREAD	01001
661900Swnj 
671900Swnj #define	SETCHR	04
681900Swnj 
691900Swnj #define	WRITE	05
701900Swnj #define	REWRITE	01005
711900Swnj 
721900Swnj #define	SFORW	010
731900Swnj #define	SREV	0410
741900Swnj #define	REW	02010
751900Swnj 
761900Swnj #define	WTM	011
771900Swnj 
781900Swnj #define	GSTAT	017
791900Swnj 
801900Swnj /* characteristics data */
811900Swnj struct charac {
82*1918Swnj 	u_short	char_loba;
83*1918Swnj 	u_short	char_hiba;
84*1918Swnj 	u_short	char_size;
85*1918Swnj 	u_short	char_mode;
861900Swnj };
871900Swnj 
881900Swnj /* All the packets, collected */
891900Swnj struct tsmesg {
901900Swnj 	struct	cmd ts_cmd;
911900Swnj 	struct	sts ts_sts;
921900Swnj 	struct	charac ts_char;
931900Swnj 	int	align;		/* Should force alignment */
941900Swnj } ts;
951900Swnj 
961900Swnj /* Bits in (unibus) status register */
971900Swnj #define	SC	0100000
981900Swnj #define	SSR	0200
991900Swnj #define	OFL	0100
1001900Swnj #define	NBA	02000
1011900Swnj 
1021900Swnj /* states */
1031900Swnj #define	SIO	1
1041900Swnj #define	SSFOR	2
1051900Swnj #define	SSREV	3
1061900Swnj #define SRETRY	4
1071900Swnj #define SCOM	5
1081900Swnj #define SOK	6
1091900Swnj 
1101900Swnj #define H_WRITTEN 1
1111900Swnj 
1121900Swnj tsopen(dev, flag)
1131900Swnj {
1141900Swnj 	register struct device *tsaddr = TSADDR;
1151900Swnj 	static struct tsmesg *ubaddr;
1161900Swnj 
1171900Swnj 	tstab.b_flags |= B_TAPE;
1181900Swnj 	if (ts_openf) {
1191900Swnj 		u.u_error = ENXIO;
1201900Swnj 		return;
1211900Swnj 	}
1221900Swnj 	if (ubaddr==0 || tsaddr->tssr&(OFL|NBA) || (tsaddr->tssr&SSR)==0) {
1231900Swnj 		long i = 0;
1241900Swnj 		tsaddr->tssr = 0;
1251900Swnj 		while ((tsaddr->tssr & SSR)==0) {
1261900Swnj 			if (++i > 1000000) {
1271900Swnj 				printf("Tape unready\n");
1281900Swnj 				u.u_error = ENXIO;
1291900Swnj 				return;
1301900Swnj 			}
1311900Swnj 		}
1321900Swnj 	}
1331900Swnj 	if (tsaddr->tssr&OFL) {
1341900Swnj 		printf("Tape offline\n");
1351900Swnj 		u.u_error = ENXIO;
1361900Swnj 		return;
1371900Swnj 	}
1381900Swnj 	if (tsaddr->tssr&NBA) {
1391900Swnj 		ctsbuf.b_un.b_addr = (caddr_t) &ts;
1401900Swnj 		ctsbuf.b_bcount = sizeof(ts);
1411900Swnj 		if (ubaddr == 0)
1421900Swnj 			ubaddr = (struct tsmesg *)ubasetup(&ctsbuf, 0);
143*1918Swnj 		ts_uba = (u_short)((long)ubaddr + (((long)ubaddr >> 16) & 03));
1441900Swnj 		ts.ts_char.char_loba = (int)&ubaddr->ts_sts;
145*1918Swnj 		ts.ts_char.char_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
1461900Swnj 		ts.ts_char.char_size = sizeof(ts.ts_sts);
1471900Swnj 		ts.ts_char.char_mode = 0400;		/* Stop on 2 tape marks */
1481900Swnj 		ts.ts_cmd.c_cmd = ACK + 04;	/* write characteristics */
1491900Swnj 		ts.ts_cmd.c_loba = (int)&ubaddr->ts_char;
150*1918Swnj 		ts.ts_cmd.c_hiba = (u_short)((long)&ubaddr->ts_sts >> 16) & 03;
1511900Swnj 		ts.ts_cmd.c_size = sizeof(ts.ts_sts);
1521900Swnj 		tsaddr->tsdb = ts_uba;
1531900Swnj 	}
1541900Swnj 	ts_blkno = 0;
1551900Swnj 	ts_nxrec = INF;
1561900Swnj 	ts_flags = 0;
1571900Swnj 	if (u.u_error==0)
1581900Swnj 		ts_openf++;
1591900Swnj }
1601900Swnj 
1611900Swnj tsclose(dev, flag)
1621900Swnj {
1631900Swnj 
1641900Swnj 	if (flag == FWRITE || ((flag&FWRITE) && (ts_flags&H_WRITTEN))) {
1651900Swnj 		tscommand(WTM);
1661900Swnj 		tscommand(WTM);
1671900Swnj 		tscommand(SREV);
1681900Swnj 	}
1691900Swnj 	if ((minor(dev)&4) == 0)
1701900Swnj 		tscommand(REW);
1711900Swnj 	ts_openf = 0;
1721900Swnj }
1731900Swnj 
1741900Swnj tscommand(com)
1751900Swnj {
1761900Swnj 	register struct buf *bp;
1771900Swnj 
1781900Swnj 	bp = &ctsbuf;
1791900Swnj 	spl5();
1801900Swnj 	while(bp->b_flags&B_BUSY) {
1811900Swnj 		bp->b_flags |= B_WANTED;
1821900Swnj 		sleep((caddr_t)bp, PRIBIO);
1831900Swnj 	}
1841900Swnj 	spl0();
1851900Swnj 	bp->b_resid = com;
1861900Swnj 	bp->b_blkno = 0;
1871900Swnj 	bp->b_flags = B_BUSY|B_READ;
1881900Swnj 	tsstrategy(bp);
1891900Swnj 	iowait(bp);
1901900Swnj 	if(bp->b_flags&B_WANTED)
1911900Swnj 		wakeup((caddr_t)bp);
1921900Swnj 	bp->b_flags = 0;
1931900Swnj 	return(bp->b_resid);
1941900Swnj }
1951900Swnj 
1961900Swnj tsstrategy(bp)
1971900Swnj register struct buf *bp;
1981900Swnj {
1991900Swnj 	register daddr_t *p;
2001900Swnj 
2011900Swnj 	if(bp != &ctsbuf) {
2021900Swnj 		p = &ts_nxrec;
2031900Swnj 		if(dbtofsb(bp->b_blkno) > *p) {
2041900Swnj 			bp->b_flags |= B_ERROR;
2051900Swnj 			bp->b_error = ENXIO;
2061900Swnj 			iodone(bp);
2071900Swnj 			return;
2081900Swnj 		}
2091900Swnj 		if(dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
2101900Swnj 			bp->b_resid = bp->b_bcount;
2111900Swnj 			iodone(bp);
2121900Swnj 			return;
2131900Swnj 		}
2141900Swnj 		if ((bp->b_flags&B_READ)==0) {
2151900Swnj 			*p = dbtofsb(bp->b_blkno) + 1;
2161900Swnj 			ts_flags |= H_WRITTEN;
2171900Swnj 		}
2181900Swnj 	}
2191900Swnj 	bp->av_forw = NULL;
2201900Swnj 	spl5();
2211900Swnj 	if (tstab.b_actf == NULL)
2221900Swnj 		tstab.b_actf = bp;
2231900Swnj 	else
2241900Swnj 		tstab.b_actl->av_forw = bp;
2251900Swnj 	tstab.b_actl = bp;
2261900Swnj 	if (tstab.b_active==0)
2271900Swnj 		tsstart();
2281900Swnj 	spl0();
2291900Swnj }
2301900Swnj 
2311900Swnj tsstart()
2321900Swnj {
2331900Swnj 	register struct buf *bp;
2341900Swnj 	register struct device *tsaddr = TSADDR;
2351900Swnj 	daddr_t blkno;
2361900Swnj 
2371900Swnj     loop:
2381900Swnj 	if ((bp = tstab.b_actf) == NULL)
2391900Swnj 		return;
2401900Swnj 	blkno = ts_blkno;
2411900Swnj 	if (ts_openf < 0 || dbtofsb(bp->b_blkno) > ts_nxrec)
2421900Swnj 		goto abort;
2431900Swnj 	if (bp == &ctsbuf) {
2441900Swnj 		tstab.b_active = SCOM;
2451900Swnj 		ts.ts_cmd.c_cmd = ACK+CVC+IE+bp->b_resid;
2461900Swnj 		ts.ts_cmd.c_loba = 1;		/* count always 1 */
2471900Swnj 	} else if (blkno == dbtofsb(bp->b_blkno)) {
2481900Swnj 		tstab.b_active = SIO;
2491900Swnj 		ts_iouba = ubasetup(bp, 1);
250*1918Swnj 		ts.ts_cmd.c_loba = (u_short)ts_iouba;
251*1918Swnj 		ts.ts_cmd.c_hiba = (u_short)(ts_iouba >> 16) & 03;
2521900Swnj 		ts.ts_cmd.c_size = bp->b_bcount;
2531900Swnj 		if(bp->b_flags & B_READ)
2541900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+READ;
2551900Swnj 		else
2561900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+WRITE;
2571900Swnj 	} else {
2581900Swnj 		if (blkno < dbtofsb(bp->b_blkno)) {
2591900Swnj 			tstab.b_active = SSFOR;
2601900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SFORW;
2611900Swnj 			ts.ts_cmd.c_loba = dbtofsb(bp->b_blkno) - blkno;
2621900Swnj 		} else {
2631900Swnj 			tstab.b_active = SSREV;
2641900Swnj 			ts.ts_cmd.c_cmd = ACK+CVC+IE+SREV;
2651900Swnj 			ts.ts_cmd.c_loba = blkno - dbtofsb(bp->b_blkno);
2661900Swnj 		}
2671900Swnj 	}
2681900Swnj 	tsaddr->tsdb = ts_uba;
2691900Swnj 	return;
2701900Swnj 
2711900Swnj     abort:
2721900Swnj 	bp->b_flags |= B_ERROR;
2731900Swnj 
2741900Swnj     next:
2751900Swnj 	tstab.b_active = 0;
2761900Swnj 	tstab.b_actf = bp->av_forw;
2771900Swnj 	iodone(bp);
2781900Swnj 	goto loop;
2791900Swnj }
2801900Swnj 
2811900Swnj tsintr()
2821900Swnj {
2831900Swnj 	register struct buf *bp;
2841900Swnj 	register struct device *tsaddr = TSADDR;
2851900Swnj 	register err, errclass, state;
2861900Swnj 
2871900Swnj 	if ((bp = tstab.b_actf)==NULL)
2881900Swnj 		return;
2891900Swnj 	state = tstab.b_active;
2901900Swnj 	tstab.b_active = 0;
2911900Swnj 	err = tsaddr->tssr & 016;
2921900Swnj 	if ((tsaddr->tssr & SC) == 0)
2931900Swnj 		err = 0;
2941900Swnj 	errclass = 0;
2951900Swnj 	switch (err) {
2961900Swnj 	case 014:		/* unrecoverable */
2971900Swnj 	case 016:		/* fatal */
2981900Swnj 	case 002:		/* attention (shouldn't happen) */
2991900Swnj 	case 012:		/* "recoverable", but shouldn't happen */
3001900Swnj 		errclass = 2;
3011900Swnj 		break;
3021900Swnj 
3031900Swnj 	case 0:			/* all OK */
3041900Swnj 		break;
3051900Swnj 
3061900Swnj 	case 004:		/* status alert */
3071900Swnj 		if (ts.ts_sts.xs0&RLS && bp==&rtsbuf)	/* short record */
3081900Swnj 			break;
3091900Swnj 		if (ts.ts_sts.xs0 & TMK) {		/* tape mark */
3101900Swnj 			ts.ts_sts.rbpcr = bp->b_bcount;
3111900Swnj 			break;
3121900Swnj 		}
3131900Swnj 		errclass = 1;
3141900Swnj 		break;
3151900Swnj 
3161900Swnj 	case 010:		/* recoverable, tape moved */
3171900Swnj 		if (state==SIO && ++bp->b_errcnt < 10) {
3181900Swnj 			ts.ts_cmd.c_cmd |= 01000;	/* redo bit */
3191900Swnj 			tstab.b_active = SIO;
3201900Swnj 			tsaddr->tsdb = ts_uba;
3211900Swnj 			return;
3221900Swnj 		}
3231900Swnj 		errclass = 1;
3241900Swnj 		break;
3251900Swnj 
3261900Swnj 	case 006:		/* Function reject */
3271900Swnj 		if (state==SIO && ts.ts_sts.xs0 & WLE)
3281900Swnj 			printf("Tape needs a ring\n");
3291900Swnj 		if ((ts.ts_sts.xs0&ONL) == 0)		/* tape offline */
3301900Swnj 			printf("Tape offline\n");
3311900Swnj 		errclass = 2;
3321900Swnj 	}
3331900Swnj 	if (errclass)
3341900Swnj 		printf("tp: %o %o %o %o %o %o %o %o\n", tsaddr->tssr,
3351900Swnj 		  ts.ts_sts.s_sts, ts.ts_sts.len, ts.ts_sts.rbpcr,
3361900Swnj 		  ts.ts_sts.xs0, ts.ts_sts.xs1, ts.ts_sts.xs2, ts.ts_sts.xs3);
3371900Swnj 	switch(state) {
3381900Swnj 	case SIO:
3391900Swnj 		ts_blkno++;
3401900Swnj 		if (ts_iouba)
3411900Swnj 			ubafree(ts_iouba);
3421900Swnj 		else
3431900Swnj 			printf("uba alloc botch\n");
3441900Swnj 		ts_iouba = 0;
3451900Swnj 	case SCOM:
3461900Swnj 		tstab.b_errcnt = 0;
3471900Swnj 		tstab.b_actf = bp->av_forw;
3481900Swnj 		bp->b_resid = ts.ts_sts.rbpcr;
3491900Swnj 		iodone(bp);
3501900Swnj 		break;
3511900Swnj 
3521900Swnj 	case SSFOR:
3531900Swnj 	case SSREV:
3541900Swnj 		ts_blkno = dbtofsb(bp->b_blkno);
3551900Swnj 		break;
3561900Swnj 
3571900Swnj 	default:
3581900Swnj 		printf("Unknown tape interrupt\n");
3591900Swnj 		errclass = 2;
3601900Swnj 		break;
3611900Swnj 	}
3621900Swnj 	if (errclass > 1) {
3631900Swnj 		while (bp = tstab.b_actf) {
3641900Swnj 			bp->b_flags |= B_ERROR;
3651900Swnj 			iodone(bp);
3661900Swnj 			tstab.b_actf = bp->av_forw;
3671900Swnj 		}
3681900Swnj 	}
3691900Swnj 	tsstart();
3701900Swnj }
3711900Swnj 
3721900Swnj tsread(dev)
3731900Swnj {
3741900Swnj 	tsphys(dev);
3751900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_READ, minphys);
3761900Swnj }
3771900Swnj 
3781900Swnj tswrite(dev)
3791900Swnj {
3801900Swnj 	tsphys(dev);
3811900Swnj 	physio(tsstrategy, &rtsbuf, dev, B_WRITE, minphys);
3821900Swnj }
3831900Swnj 
3841900Swnj tsphys(dev)
3851900Swnj {
3861900Swnj 	register unit;
3871900Swnj 	daddr_t a;
3881900Swnj 
3891900Swnj 	a = u.u_offset >> 9;
3901900Swnj 	ts_blkno = dbtofsb(a);
3911900Swnj 	ts_nxrec = dbtofsb(a)+1;
3921900Swnj }
393*1918Swnj 
394*1918Swnj #define	UBMAP	(int *)0xf30800
395*1918Swnj 
396*1918Swnj int dtsinfo;
397*1918Swnj 
398*1918Swnj twall(start, num)
399*1918Swnj {
400*1918Swnj 	register struct device *tsaddr = TSPHYS;
401*1918Swnj 	register int *ubap = UBMAP;
402*1918Swnj 	register int p, i;
403*1918Swnj 
404*1918Swnj 	tsinit();
405*1918Swnj 	/* dump mem */
406*1918Swnj 	p = PG_V;
407*1918Swnj 	i = 0;
408*1918Swnj 	while (i<num) {
409*1918Swnj 		*(ubap) = p|i++;
410*1918Swnj 		*(ubap+1) = p|i;
411*1918Swnj 		dts.ts_cmd.c_loba = 0;
412*1918Swnj 		dts.ts_cmd.c_hiba = 0;
413*1918Swnj 		dts.ts_cmd.c_size = NBPG;
414*1918Swnj 		dts.ts_cmd.c_cmd = ACK+CVC+WRITE;
415*1918Swnj 		tsaddr->tsdb = dtsinfo;
416*1918Swnj 		twait();
417*1918Swnj 	}
418*1918Swnj 	printf("done\n");
419*1918Swnj }
420*1918Swnj 
421*1918Swnj tsinit()
422*1918Swnj {
423*1918Swnj 	register struct device *tsaddr = TSPHYS;
424*1918Swnj 	register struct tsmesg *tsm;
425*1918Swnj 	register int *ubap = UBMAP;
426*1918Swnj 	register i;
427*1918Swnj 
428*1918Swnj 	tsaddr->tssr = 0;
429*1918Swnj 	while ((tsaddr->tssr&SSR)==0)
430*1918Swnj 		;
431*1918Swnj 	i = (int)&dts;
432*1918Swnj 	i &= 0xefffff;
433*1918Swnj 	dtsinfo = ((i&0777)|02000);
434*1918Swnj 	tsm = (struct tsmesg *)dtsinfo;
435*1918Swnj 	i >>= 9;
436*1918Swnj 	i |= PG_V;
437*1918Swnj 	*(ubap+2) = i;
438*1918Swnj 	*(ubap+3) = i+1;
439*1918Swnj 	dts.ts_cmd.c_cmd = ACK + 04;
440*1918Swnj 	dts.ts_cmd.c_loba = &tsm->ts_char;
441*1918Swnj 	dts.ts_cmd.c_hiba = 0;
442*1918Swnj 	dts.ts_cmd.c_size = sizeof(dts.ts_char);
443*1918Swnj 	dts.ts_char.char_loba = &tsm->ts_sts;
444*1918Swnj 	dts.ts_char.char_hiba = 0;
445*1918Swnj 	dts.ts_char.char_size = sizeof(dts.ts_sts);
446*1918Swnj 	dts.ts_char.char_mode = 0400;
447*1918Swnj 	tsaddr->tsdb = dtsinfo;
448*1918Swnj 	twait();
449*1918Swnj }
450*1918Swnj 
451*1918Swnj teof()
452*1918Swnj {
453*1918Swnj 
454*1918Swnj 	dtscommand(WTM);
455*1918Swnj }
456*1918Swnj 
457*1918Swnj rewind()
458*1918Swnj {
459*1918Swnj 
460*1918Swnj 	dtscommand(REW);
461*1918Swnj }
462*1918Swnj 
463*1918Swnj dtscommand(com)
464*1918Swnj {
465*1918Swnj 	register struct device *tsaddr = TSPHYS;
466*1918Swnj 
467*1918Swnj 	dts.ts_cmd.c_cmd = ACK+CVC+com;
468*1918Swnj 	dts.ts_cmd.c_loba = 1;
469*1918Swnj 	tsaddr->tsdb = dtsinfo;
470*1918Swnj 	twait();
471*1918Swnj }
472*1918Swnj 
473*1918Swnj twait()
474*1918Swnj {
475*1918Swnj 	register struct device *tsaddr = TSPHYS;
476*1918Swnj 	register i;
477*1918Swnj 
478*1918Swnj 	while ((tsaddr->tssr&SSR)==0)
479*1918Swnj 		;
480*1918Swnj 	i = tsaddr->tssr;
481*1918Swnj 	if (i&SC)
482*1918Swnj 		printf("tssr %x ", i);
483*1918Swnj }
4841900Swnj #endif
485