xref: /csrg-svn/sys/hp300/dev/ct.c (revision 65638)
141480Smckusick /*
263151Sbostic  * Copyright (c) 1982, 1990, 1993
363151Sbostic  *	The Regents of the University of California.  All rights reserved.
441480Smckusick  *
541480Smckusick  * %sccs.include.redist.c%
641480Smckusick  *
7*65638Sbostic  *	@(#)ct.c	8.2 (Berkeley) 01/12/94
841480Smckusick  */
941480Smckusick 
1041480Smckusick #include "ct.h"
1141480Smckusick #if NCT > 0
1241480Smckusick /*
1341480Smckusick  * CS80 cartridge tape driver (9144, 88140, 9145)
1441480Smckusick  *
1541480Smckusick  * Reminder:
1641480Smckusick  *	C_CC bit (character count option) when used in the CS/80 command
1741480Smckusick  *	'set options' will cause the tape not to stream.
1841480Smckusick  *
1941480Smckusick  * TODO:
2041480Smckusick  *	make filesystem compatible
2141480Smckusick  *	make block mode work according to mtio(4) spec. (if possible)
2241480Smckusick  *	merge with cs80 disk driver
2341480Smckusick  *	finish support of 9145
2441480Smckusick  */
2541480Smckusick 
2656507Sbostic #include <sys/param.h>
2756507Sbostic #include <sys/buf.h>
2856507Sbostic #include <sys/ioctl.h>
2956507Sbostic #include <sys/mtio.h>
3056507Sbostic #include <sys/tprintf.h>
3156507Sbostic #include <sys/proc.h>
3249132Skarels 
3356507Sbostic #include <hp/dev/device.h>
3441480Smckusick 
3556507Sbostic #include <hp300/dev/ctreg.h>
3656507Sbostic 
3741480Smckusick /* number of eof marks to remember */
3841480Smckusick #define EOFS	128
3941480Smckusick 
4041480Smckusick int	ctinit(), ctstart(), ctgo(), ctintr();
4141480Smckusick struct	driver ctdriver = {
4241480Smckusick 	ctinit, "ct", ctstart, ctgo, ctintr,
4341480Smckusick };
4441480Smckusick 
4541480Smckusick struct	ct_softc {
4641480Smckusick 	struct	hp_device *sc_hd;
4741480Smckusick 	struct	ct_iocmd sc_ioc;
4841480Smckusick 	struct	ct_rscmd sc_rsc;
4941480Smckusick 	struct	ct_stat sc_stat;
5041480Smckusick 	struct	ct_ssmcmd sc_ssmc;
5141480Smckusick 	struct	ct_srcmd sc_src;
5241480Smckusick 	struct	ct_soptcmd sc_soptc;
5341480Smckusick 	struct	ct_ulcmd sc_ul;
5441480Smckusick 	struct	ct_wfmcmd sc_wfm;
5541480Smckusick 	struct	ct_clearcmd sc_clear;
5641480Smckusick 	struct	buf *sc_bp;
5741480Smckusick 	int	sc_blkno;
5841480Smckusick 	int	sc_cmd;
5941480Smckusick 	int	sc_resid;
6041480Smckusick 	char	*sc_addr;
6141480Smckusick 	int	sc_flags;
6241480Smckusick 	short	sc_type;
6341480Smckusick 	short	sc_punit;
6449132Skarels 	tpr_t	sc_tpr;
6541480Smckusick 	struct	devqueue sc_dq;
6641480Smckusick 	int	sc_eofp;
6741480Smckusick 	int	sc_eofs[EOFS];
6841480Smckusick } ct_softc[NCT];
6941480Smckusick 
7041480Smckusick /* flags */
7141480Smckusick #define	CTF_OPEN	0x01
7241480Smckusick #define	CTF_ALIVE	0x02
7341480Smckusick #define	CTF_WRT		0x04
7441480Smckusick #define	CTF_CMD		0x08
7541480Smckusick #define	CTF_IO		0x10
7641480Smckusick #define	CTF_BEOF	0x20
7741480Smckusick #define	CTF_AEOF	0x40
7841480Smckusick #define	CTF_EOT		0x80
7941480Smckusick #define	CTF_STATWAIT	0x100
8041480Smckusick #define CTF_CANSTREAM	0x200
8141480Smckusick #define	CTF_WRTTN	0x400
8241480Smckusick 
8341480Smckusick struct	ctinfo {
8441480Smckusick 	short	hwid;
8541480Smckusick 	short	punit;
8641480Smckusick 	char	*desc;
8741480Smckusick } ctinfo[] = {
8841480Smckusick 	CT7946ID,	1,	"7946A",
8941480Smckusick 	CT7912PID,	1,	"7912P",
9041480Smckusick 	CT7914PID,	1,	"7914P",
9141480Smckusick 	CT9144ID,	0,	"9144",
9241480Smckusick 	CT9145ID,	0,	"9145",
9341480Smckusick };
9441480Smckusick int	nctinfo = sizeof(ctinfo) / sizeof(ctinfo[0]);
9541480Smckusick 
9641480Smckusick struct	buf cttab[NCT];
9741480Smckusick struct	buf ctbuf[NCT];
9841480Smckusick 
9941480Smckusick #define	CT_NOREW	4
10041480Smckusick #define	CT_STREAM	8
10141480Smckusick #define	UNIT(x)		(minor(x) & 3)
10241480Smckusick #define	ctpunit(x)	((x) & 7)
10341480Smckusick 
10441480Smckusick #ifdef DEBUG
10541480Smckusick int ctdebug = 0;
10641480Smckusick #define CDB_FILES	0x01
10741480Smckusick #define CT_BSF		0x02
10841480Smckusick #endif
10941480Smckusick 
11041480Smckusick ctinit(hd)
11141480Smckusick 	register struct hp_device *hd;
11241480Smckusick {
11341480Smckusick 	register struct ct_softc *sc = &ct_softc[hd->hp_unit];
11456388Smckusick 	register struct buf *bp;
11541480Smckusick 
11656388Smckusick 	for (bp = cttab; bp < &cttab[NCT]; bp++)
11756388Smckusick 		bp->b_actb = &bp->b_actf;
11841480Smckusick 	sc->sc_hd = hd;
11941480Smckusick 	sc->sc_punit = ctpunit(hd->hp_flags);
12041480Smckusick 	if (ctident(sc, hd) < 0)
12141480Smckusick 		return(0);
12241480Smckusick 	ctreset(sc, hd);
12341480Smckusick 	sc->sc_dq.dq_ctlr = hd->hp_ctlr;
12441480Smckusick 	sc->sc_dq.dq_unit = hd->hp_unit;
12541480Smckusick 	sc->sc_dq.dq_slave = hd->hp_slave;
12641480Smckusick 	sc->sc_dq.dq_driver = &ctdriver;
12741480Smckusick 	sc->sc_flags |= CTF_ALIVE;
12841480Smckusick 	return(1);
12941480Smckusick }
13041480Smckusick 
13141480Smckusick ctident(sc, hd)
13241480Smckusick 	register struct ct_softc *sc;
13341480Smckusick 	register struct hp_device *hd;
13441480Smckusick {
13541480Smckusick 	struct ct_describe desc;
13641480Smckusick 	u_char stat, cmd[3];
13741480Smckusick 	char name[7];
13841480Smckusick 	int id, i;
13941480Smckusick 
14041480Smckusick 	/*
14141480Smckusick 	 * Read device id and verify that:
14241480Smckusick 	 * 1. It is a CS80 device
14341480Smckusick 	 * 2. It is one of our recognized tape devices
14441480Smckusick 	 * 3. It has the proper physical unit number
14541480Smckusick 	 */
14641480Smckusick 	id = hpibid(hd->hp_ctlr, hd->hp_slave);
14741480Smckusick 	if ((id & 0x200) == 0)
14841480Smckusick 		return(-1);
14941480Smckusick 	for (i = 0; i < nctinfo; i++)
15041480Smckusick 		if (id == ctinfo[i].hwid)
15141480Smckusick 			break;
15241480Smckusick 	if (i == nctinfo || sc->sc_punit != ctinfo[i].punit)
15341480Smckusick 		return(-1);
15441480Smckusick 	id = i;
15541480Smckusick 
15641480Smckusick 	/*
15741480Smckusick 	 * Collect device description.
15841480Smckusick 	 * Right now we only need this to differentiate 7945 from 7946.
15941480Smckusick 	 * Note that we always issue the describe command to unit 0.
16041480Smckusick 	 */
16141480Smckusick 	cmd[0] = C_SUNIT(0);
16241480Smckusick 	cmd[1] = C_SVOL(0);
16341480Smckusick 	cmd[2] = C_DESC;
16441480Smckusick 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, cmd, sizeof(cmd));
16541480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_EXEC, &desc, 37);
16641480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
16741480Smckusick 	bzero(name, sizeof(name));
16841480Smckusick 	if (!stat) {
16941480Smckusick 		register int n = desc.d_name;
17041480Smckusick 		for (i = 5; i >= 0; i--) {
17141480Smckusick 			name[i] = (n & 0xf) + '0';
17241480Smckusick 			n >>= 4;
17341480Smckusick 		}
17441480Smckusick 	}
17541480Smckusick 	switch (ctinfo[id].hwid) {
17641480Smckusick 	case CT7946ID:
17741480Smckusick 		if (bcmp(name, "079450", 6) == 0)
17841480Smckusick 			return(-1);		/* not really a 7946 */
17941480Smckusick 		/* fall into... */
18041480Smckusick 	case CT9144ID:
18141480Smckusick 	case CT9145ID:
18241480Smckusick 		sc->sc_type = CT9144;
18341480Smckusick 		sc->sc_flags |= CTF_CANSTREAM;
18441480Smckusick 		break;
18541480Smckusick 
18641480Smckusick 	case CT7912PID:
18741480Smckusick 	case CT7914PID:
18841480Smckusick 		sc->sc_type = CT88140;
18941480Smckusick 		break;
19041480Smckusick 	}
19141480Smckusick 	printf("ct%d: %s %stape\n", hd->hp_unit, ctinfo[id].desc,
19241480Smckusick 	       (sc->sc_flags & CTF_CANSTREAM) ? "streaming " : " ");
19341480Smckusick 	return(id);
19441480Smckusick }
19541480Smckusick 
19641480Smckusick ctreset(sc, hd)
19741480Smckusick 	register struct ct_softc *sc;
19841480Smckusick 	register struct hp_device *hd;
19941480Smckusick {
20041480Smckusick 	u_char stat;
20141480Smckusick 
20241480Smckusick 	sc->sc_clear.unit = C_SUNIT(sc->sc_punit);
20341480Smckusick 	sc->sc_clear.cmd = C_CLEAR;
20441480Smckusick 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_TCMD, &sc->sc_clear,
20541480Smckusick 		sizeof(sc->sc_clear));
20641480Smckusick 	hpibswait(hd->hp_ctlr, hd->hp_slave);
20741480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
20841480Smckusick 	sc->sc_src.unit = C_SUNIT(CTCTLR);
20941480Smckusick 	sc->sc_src.nop = C_NOP;
21041480Smckusick 	sc->sc_src.cmd = C_SREL;
21141480Smckusick 	sc->sc_src.param = C_REL;
21241480Smckusick 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_src,
21341480Smckusick 		sizeof(sc->sc_src));
21441480Smckusick 	hpibswait(hd->hp_ctlr, hd->hp_slave);
21541480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
21641480Smckusick 	sc->sc_ssmc.unit = C_SUNIT(sc->sc_punit);
21741480Smckusick 	sc->sc_ssmc.cmd = C_SSM;
21841480Smckusick 	sc->sc_ssmc.refm = REF_MASK;
21941480Smckusick 	sc->sc_ssmc.fefm = FEF_MASK;
22041480Smckusick 	sc->sc_ssmc.aefm = AEF_MASK;
22141480Smckusick 	sc->sc_ssmc.iefm = IEF_MASK;
22241480Smckusick 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_ssmc,
22341480Smckusick 		sizeof(sc->sc_ssmc));
22441480Smckusick 	hpibswait(hd->hp_ctlr, hd->hp_slave);
22541480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
22641480Smckusick 	sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
22741480Smckusick 	sc->sc_soptc.nop = C_NOP;
22841480Smckusick 	sc->sc_soptc.cmd = C_SOPT;
22941480Smckusick 	sc->sc_soptc.opt = C_SPAR;
23041480Smckusick 	hpibsend(hd->hp_ctlr, hd->hp_slave, C_CMD, &sc->sc_soptc,
23141480Smckusick 		sizeof(sc->sc_soptc));
23241480Smckusick 	hpibswait(hd->hp_ctlr, hd->hp_slave);
23341480Smckusick 	hpibrecv(hd->hp_ctlr, hd->hp_slave, C_QSTAT, &stat, sizeof(stat));
23441480Smckusick }
23541480Smckusick 
23641480Smckusick /*ARGSUSED*/
23749132Skarels ctopen(dev, flag, type, p)
23841480Smckusick 	dev_t dev;
23949132Skarels 	int flag, type;
24049132Skarels 	struct proc *p;
24141480Smckusick {
24241480Smckusick 	register struct ct_softc *sc = &ct_softc[UNIT(dev)];
24341480Smckusick 	u_char stat;
24441480Smckusick 	int cc;
24541480Smckusick 
24641480Smckusick 	if (UNIT(dev) >= NCT || (sc->sc_flags & CTF_ALIVE) == 0)
24741480Smckusick 		return(ENXIO);
24841480Smckusick 	if (sc->sc_flags & CTF_OPEN)
24941480Smckusick 		return(EBUSY);
25041480Smckusick 	sc->sc_soptc.unit = C_SUNIT(sc->sc_punit);
25141480Smckusick 	sc->sc_soptc.nop = C_NOP;
25241480Smckusick 	sc->sc_soptc.cmd = C_SOPT;
25341480Smckusick 	if ((dev & CT_STREAM) && (sc->sc_flags & CTF_CANSTREAM))
25441480Smckusick 		sc->sc_soptc.opt = C_SPAR | C_IMRPT;
25541480Smckusick 	else
25641480Smckusick 		sc->sc_soptc.opt = C_SPAR;
25741480Smckusick 	/*
25841480Smckusick 	 * Check the return of hpibsend() and hpibswait().
25941480Smckusick 	 * Drive could be loading/unloading a tape. If not checked,
26041480Smckusick 	 * driver hangs.
26141480Smckusick 	 */
26241480Smckusick 	cc = hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
26341480Smckusick 	              C_CMD, &sc->sc_soptc, sizeof(sc->sc_soptc));
26441480Smckusick 	if (cc != sizeof(sc->sc_soptc))
26541480Smckusick 		return(EBUSY);
26641480Smckusick 	hpibswait(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave);
26741480Smckusick 	cc = hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT,
26841480Smckusick 	              &stat, sizeof(stat));
26941480Smckusick 	if (cc != sizeof(stat))
27041480Smckusick 		return(EBUSY);
27149132Skarels 	sc->sc_tpr = tprintf_open(p);
27241480Smckusick 	sc->sc_flags |= CTF_OPEN;
27341480Smckusick 	return(0);
27441480Smckusick }
27541480Smckusick 
27641480Smckusick /*ARGSUSED*/
27741480Smckusick ctclose(dev, flag)
27841480Smckusick 	dev_t dev;
279*65638Sbostic 	int flag;
28041480Smckusick {
28141480Smckusick 	register struct ct_softc *sc = &ct_softc[UNIT(dev)];
28241480Smckusick 
28341480Smckusick 	if ((sc->sc_flags & (CTF_WRT|CTF_WRTTN)) == (CTF_WRT|CTF_WRTTN) &&
28441480Smckusick 	    (sc->sc_flags & CTF_EOT) == 0 ) { /* XXX return error if EOT ?? */
28541480Smckusick 		ctcommand(dev, MTWEOF, 2);
28641480Smckusick 		ctcommand(dev, MTBSR, 1);
28741480Smckusick 		if (sc->sc_eofp == EOFS - 1)
28841480Smckusick 			sc->sc_eofs[EOFS - 1]--;
28941480Smckusick 		else
29041480Smckusick 			sc->sc_eofp--;
29141480Smckusick #ifdef DEBUG
29241480Smckusick 		if(ctdebug & CT_BSF)
29341480Smckusick 			printf("ct%d: ctclose backup eofs prt %d blk %d\n",
29441480Smckusick 			       UNIT(dev), sc->sc_eofp, sc->sc_eofs[sc->sc_eofp]);
29541480Smckusick #endif
29641480Smckusick 	}
29741480Smckusick 	if ((minor(dev) & CT_NOREW) == 0)
29841480Smckusick 		ctcommand(dev, MTREW, 1);
29941480Smckusick 	sc->sc_flags &= ~(CTF_OPEN | CTF_WRT | CTF_WRTTN);
30049132Skarels 	tprintf_close(sc->sc_tpr);
30141480Smckusick #ifdef DEBUG
30241480Smckusick 	if (ctdebug & CDB_FILES)
30341480Smckusick 		printf("ctclose: flags %x\n", sc->sc_flags);
30441480Smckusick #endif
30541480Smckusick 	return(0);	/* XXX */
30641480Smckusick }
30741480Smckusick 
30841480Smckusick ctcommand(dev, cmd, cnt)
30941480Smckusick 	dev_t dev;
310*65638Sbostic 	int cmd;
31141480Smckusick 	register int cnt;
31241480Smckusick {
31341480Smckusick 	register struct ct_softc *sc = &ct_softc[UNIT(dev)];
31441480Smckusick 	register struct buf *bp = &ctbuf[UNIT(dev)];
31541480Smckusick 	register struct buf *nbp = 0;
31641480Smckusick 
31741480Smckusick 	if (cmd == MTBSF && sc->sc_eofp == EOFS - 1) {
31841480Smckusick 		cnt = sc->sc_eofs[EOFS - 1] - cnt;
31941480Smckusick 		ctcommand(dev, MTREW, 1);
32041480Smckusick 		ctcommand(dev, MTFSF, cnt);
32141480Smckusick 		cnt = 2;
32241480Smckusick 		cmd = MTBSR;
32341480Smckusick 	}
32441480Smckusick 
32541480Smckusick 	if (cmd == MTBSF && sc->sc_eofp - cnt < 0) {
32641480Smckusick 		cnt = 1;
32741480Smckusick 		cmd = MTREW;
32841480Smckusick 	}
32941480Smckusick 
33041480Smckusick 	sc->sc_flags |= CTF_CMD;
33141480Smckusick 	sc->sc_bp = bp;
33241480Smckusick 	sc->sc_cmd = cmd;
33341480Smckusick 	bp->b_dev = dev;
33441480Smckusick 	if (cmd == MTFSF) {
33541480Smckusick 		nbp = (struct buf *)geteblk(MAXBSIZE);
33641480Smckusick 		bp->b_un.b_addr = nbp->b_un.b_addr;
33741480Smckusick 		bp->b_bcount = MAXBSIZE;
33841480Smckusick 	}
33941480Smckusick again:
34041480Smckusick 	bp->b_flags = B_BUSY;
34141480Smckusick 	if (cmd == MTBSF) {
34241480Smckusick 		sc->sc_blkno = sc->sc_eofs[sc->sc_eofp];
34341480Smckusick 		sc->sc_eofp--;
34441480Smckusick #ifdef DEBUG
34541480Smckusick 		if (ctdebug & CT_BSF)
34641480Smckusick 			printf("ct%d: backup eof pos %d blk %d\n",
34741480Smckusick 			       UNIT(dev), sc->sc_eofp,
34841480Smckusick 			       sc->sc_eofs[sc->sc_eofp]);
34941480Smckusick #endif
35041480Smckusick 	}
35141480Smckusick 	ctstrategy(bp);
35241480Smckusick 	iowait(bp);
35341480Smckusick 	if (--cnt > 0)
35441480Smckusick 		goto again;
35541480Smckusick 	bp->b_flags = 0;
35641480Smckusick 	sc->sc_flags &= ~CTF_CMD;
35741480Smckusick 	if (nbp)
35841480Smckusick 		brelse(nbp);
35941480Smckusick }
36041480Smckusick 
36141480Smckusick ctstrategy(bp)
36241480Smckusick 	register struct buf *bp;
36341480Smckusick {
36441480Smckusick 	register struct buf *dp;
36541480Smckusick 	register int s, unit;
36641480Smckusick 
36741480Smckusick 	unit = UNIT(bp->b_dev);
36841480Smckusick 	dp = &cttab[unit];
36956388Smckusick 	bp->b_actf = NULL;
37041480Smckusick 	s = splbio();
37156388Smckusick 	bp->b_actb = dp->b_actb;
37256388Smckusick 	*dp->b_actb = bp;
37356388Smckusick 	dp->b_actb = &bp->b_actf;
37441480Smckusick 	if (dp->b_active == 0) {
37541480Smckusick 		dp->b_active = 1;
37641480Smckusick 		ctustart(unit);
37741480Smckusick 	}
37841480Smckusick 	splx(s);
37941480Smckusick }
38041480Smckusick 
38141480Smckusick ctustart(unit)
38241480Smckusick 	register int unit;
38341480Smckusick {
38441480Smckusick 	register struct ct_softc *sc = &ct_softc[unit];
38541480Smckusick 	register struct buf *bp;
38641480Smckusick 
38741480Smckusick 	bp = cttab[unit].b_actf;
38841480Smckusick 	sc->sc_addr = bp->b_un.b_addr;
38941480Smckusick 	sc->sc_resid = bp->b_bcount;
39041480Smckusick 	if (hpibreq(&sc->sc_dq))
39141480Smckusick 		ctstart(unit);
39241480Smckusick }
39341480Smckusick 
39441480Smckusick ctstart(unit)
39541480Smckusick 	register int unit;
39641480Smckusick {
39741480Smckusick 	register struct ct_softc *sc = &ct_softc[unit];
39856388Smckusick 	register struct buf *bp, *dp;
39941480Smckusick 	register int i;
40041480Smckusick 
40141480Smckusick 	bp = cttab[unit].b_actf;
40241480Smckusick again:
40341480Smckusick 	if ((sc->sc_flags & CTF_CMD) && sc->sc_bp == bp) {
40441480Smckusick 		switch(sc->sc_cmd) {
40541480Smckusick 
40641480Smckusick 		case MTFSF:
40741480Smckusick 			bp->b_flags |= B_READ;
40841480Smckusick 			goto mustio;
40941480Smckusick 
41041480Smckusick 		case MTBSF:
41141480Smckusick 			goto gotaddr;
41241480Smckusick 
41341480Smckusick 		case MTOFFL:
41441480Smckusick 			sc->sc_blkno = 0;
41541480Smckusick 			sc->sc_ul.unit = C_SUNIT(sc->sc_punit);
41641480Smckusick 			sc->sc_ul.cmd = C_UNLOAD;
41741480Smckusick 			hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
41841480Smckusick 				C_CMD, &sc->sc_ul, sizeof(sc->sc_ul));
41941480Smckusick 			break;
42041480Smckusick 
42141480Smckusick 		case MTWEOF:
42241480Smckusick 			sc->sc_blkno++;
42341480Smckusick 			sc->sc_flags |= CTF_WRT;
42441480Smckusick 			sc->sc_wfm.unit = C_SUNIT(sc->sc_punit);
42541480Smckusick 			sc->sc_wfm.cmd = C_WFM;
42641480Smckusick 			hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
42741480Smckusick 				C_CMD, &sc->sc_wfm, sizeof(sc->sc_wfm));
42841480Smckusick 			ctaddeof(unit);
42941480Smckusick 			break;
43041480Smckusick 
43141480Smckusick 		case MTBSR:
43241480Smckusick 			sc->sc_blkno--;
43341480Smckusick 			goto gotaddr;
43441480Smckusick 
43541480Smckusick 		case MTFSR:
43641480Smckusick 			sc->sc_blkno++;
43741480Smckusick 			goto gotaddr;
43841480Smckusick 
43941480Smckusick 		case MTREW:
44041480Smckusick 			sc->sc_blkno = 0;
44141480Smckusick #ifdef DEBUG
44241480Smckusick 			if(ctdebug & CT_BSF)
44341480Smckusick 				printf("ct%d: clearing eofs\n", unit);
44441480Smckusick #endif
44541480Smckusick 			for (i=0; i<EOFS; i++)
44641480Smckusick 				sc->sc_eofs[i] = 0;
44741480Smckusick 			sc->sc_eofp = 0;
44841480Smckusick 
44941480Smckusick gotaddr:
45041480Smckusick 			sc->sc_ioc.saddr = C_SADDR;
45141480Smckusick 			sc->sc_ioc.addr0 = 0;
45241480Smckusick 			sc->sc_ioc.addr = sc->sc_blkno;
45341480Smckusick 			sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
45441480Smckusick 			sc->sc_ioc.nop2 = C_NOP;
45541480Smckusick 			sc->sc_ioc.slen = C_SLEN;
45641480Smckusick 			sc->sc_ioc.len = 0;
45741480Smckusick 			sc->sc_ioc.nop3 = C_NOP;
45841480Smckusick 			sc->sc_ioc.cmd = C_READ;
45941480Smckusick 			hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave,
46041480Smckusick 				C_CMD, &sc->sc_ioc, sizeof(sc->sc_ioc));
46141480Smckusick 			break;
46241480Smckusick 		}
46341480Smckusick 	}
46441480Smckusick 	else {
46541480Smckusick mustio:
46641480Smckusick 		if ((bp->b_flags & B_READ) &&
46741480Smckusick 		    sc->sc_flags & (CTF_BEOF|CTF_EOT)) {
46841480Smckusick #ifdef DEBUG
46941480Smckusick 			if (ctdebug & CDB_FILES)
47041480Smckusick 				printf("ctstart: before flags %x\n", sc->sc_flags);
47141480Smckusick #endif
47241480Smckusick 			if (sc->sc_flags & CTF_BEOF) {
47341480Smckusick 				sc->sc_flags &= ~CTF_BEOF;
47441480Smckusick 				sc->sc_flags |= CTF_AEOF;
47541480Smckusick #ifdef DEBUG
47641480Smckusick 				if (ctdebug & CDB_FILES)
47741480Smckusick 					printf("ctstart: after flags %x\n", sc->sc_flags);
47841480Smckusick #endif
47941480Smckusick 			}
48041480Smckusick 			bp->b_resid = bp->b_bcount;
48141480Smckusick 			iodone(bp);
48241480Smckusick 			hpibfree(&sc->sc_dq);
48356388Smckusick 			if (dp = bp->b_actf)
48456388Smckusick 				dp->b_actb = bp->b_actb;
48556388Smckusick 			else
48656388Smckusick 				cttab[unit].b_actb = bp->b_actb;
48756388Smckusick 			*bp->b_actb = dp;
48856388Smckusick 			if ((bp = dp) == NULL) {
48941480Smckusick 				cttab[unit].b_active = 0;
49041480Smckusick 				return;
49141480Smckusick 			}
49241480Smckusick 			sc->sc_addr = bp->b_un.b_addr;
49341480Smckusick 			sc->sc_resid = bp->b_bcount;
49441480Smckusick 			if (hpibreq(&sc->sc_dq))
49541480Smckusick 				goto again;
49641480Smckusick 			return;
49741480Smckusick 		}
49841480Smckusick 		sc->sc_flags |= CTF_IO;
49941480Smckusick 		sc->sc_ioc.unit = C_SUNIT(sc->sc_punit);
50041480Smckusick 		sc->sc_ioc.saddr = C_SADDR;
50141480Smckusick 		sc->sc_ioc.addr0 = 0;
50241480Smckusick 		sc->sc_ioc.addr = sc->sc_blkno;
50341480Smckusick 		sc->sc_ioc.nop2 = C_NOP;
50441480Smckusick 		sc->sc_ioc.slen = C_SLEN;
50541480Smckusick 		sc->sc_ioc.len = sc->sc_resid;
50641480Smckusick 		sc->sc_ioc.nop3 = C_NOP;
50741480Smckusick 		if (bp->b_flags & B_READ)
50841480Smckusick 			sc->sc_ioc.cmd = C_READ;
50941480Smckusick 		else {
51041480Smckusick 			sc->sc_ioc.cmd = C_WRITE;
51141480Smckusick 			sc->sc_flags |= (CTF_WRT | CTF_WRTTN);
51241480Smckusick 		}
51341480Smckusick 		hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_CMD,
51441480Smckusick 			&sc->sc_ioc, sizeof(sc->sc_ioc));
51541480Smckusick 	}
51641480Smckusick 	hpibawait(sc->sc_hd->hp_ctlr);
51741480Smckusick }
51841480Smckusick 
51941480Smckusick ctgo(unit)
52041480Smckusick 	register int unit;
52141480Smckusick {
52241480Smckusick 	register struct ct_softc *sc = &ct_softc[unit];
52341480Smckusick 	register struct buf *bp;
52441480Smckusick 
52541480Smckusick 	bp = cttab[unit].b_actf;
52641480Smckusick 	hpibgo(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_EXEC,
52741480Smckusick 		sc->sc_addr, sc->sc_resid, bp->b_flags & B_READ);
52841480Smckusick }
52941480Smckusick 
53041480Smckusick /*
53141480Smckusick  * Hideous grue to handle EOF/EOT (mostly for reads)
53241480Smckusick  */
53341480Smckusick cteof(sc, bp)
53441480Smckusick 	register struct ct_softc *sc;
53541480Smckusick 	register struct buf *bp;
53641480Smckusick {
53741480Smckusick 	long blks;
53841480Smckusick 
53941480Smckusick 	/*
54041480Smckusick 	 * EOT on a write is an error.
54141480Smckusick 	 */
54241480Smckusick 	if ((bp->b_flags & B_READ) == 0) {
54341480Smckusick 		bp->b_resid = bp->b_bcount;
54441480Smckusick 		bp->b_flags |= B_ERROR;
54541480Smckusick 		bp->b_error = ENOSPC;
54641480Smckusick 		sc->sc_flags |= CTF_EOT;
54741480Smckusick 		return;
54841480Smckusick 	}
54941480Smckusick 	/*
55041480Smckusick 	 * Use returned block position to determine how many blocks
55141480Smckusick 	 * we really read and update b_resid.
55241480Smckusick 	 */
55341480Smckusick 	blks = sc->sc_stat.c_blk - sc->sc_blkno - 1;
55441480Smckusick #ifdef DEBUG
55541480Smckusick 	if (ctdebug & CDB_FILES)
55641480Smckusick 		printf("cteof: bc %d oblk %d nblk %d read %d, resid %d\n",
55741480Smckusick 		       bp->b_bcount, sc->sc_blkno, sc->sc_stat.c_blk,
55841480Smckusick 		       blks, bp->b_bcount - CTKTOB(blks));
55941480Smckusick #endif
56041480Smckusick 	if (blks == -1) { /* 9145 on EOF does not change sc_stat.c_blk */
56141480Smckusick 		blks = 0;
56241480Smckusick 		sc->sc_blkno++;
56341480Smckusick 	}
56441480Smckusick 	else {
56541480Smckusick 		sc->sc_blkno = sc->sc_stat.c_blk;
56641480Smckusick 	}
56741480Smckusick 	bp->b_resid = bp->b_bcount - CTKTOB(blks);
56841480Smckusick 	/*
56941480Smckusick 	 * If we are at physical EOV or were after an EOF,
57041480Smckusick 	 * we are now at logical EOT.
57141480Smckusick 	 */
57241480Smckusick 	if ((sc->sc_stat.c_aef & AEF_EOV) ||
57341480Smckusick 	    (sc->sc_flags & CTF_AEOF)) {
57441480Smckusick 		sc->sc_flags |= CTF_EOT;
57541480Smckusick 		sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF);
57641480Smckusick 	}
57741480Smckusick 	/*
57841480Smckusick 	 * If we were before an EOF or we have just completed a FSF,
57941480Smckusick 	 * we are now after EOF.
58041480Smckusick 	 */
58141480Smckusick 	else if ((sc->sc_flags & CTF_BEOF) ||
58241480Smckusick 		 (sc->sc_flags & CTF_CMD) && sc->sc_cmd == MTFSF) {
58341480Smckusick 		sc->sc_flags |= CTF_AEOF;
58441480Smckusick 		sc->sc_flags &= ~CTF_BEOF;
58541480Smckusick 	}
58641480Smckusick 	/*
58741480Smckusick 	 * Otherwise if we read something we are now before EOF
58841480Smckusick 	 * (and no longer after EOF).
58941480Smckusick 	 */
59041480Smckusick 	else if (blks) {
59141480Smckusick 		sc->sc_flags |= CTF_BEOF;
59241480Smckusick 		sc->sc_flags &= ~CTF_AEOF;
59341480Smckusick 	}
59441480Smckusick 	/*
59541480Smckusick 	 * Finally, if we didn't read anything we just passed an EOF
59641480Smckusick 	 */
59741480Smckusick 	else
59841480Smckusick 		sc->sc_flags |= CTF_AEOF;
59941480Smckusick #ifdef DEBUG
60041480Smckusick 	if (ctdebug & CDB_FILES)
60141480Smckusick 		printf("cteof: leaving flags %x\n", sc->sc_flags);
60241480Smckusick #endif
60341480Smckusick }
60441480Smckusick 
60541480Smckusick ctintr(unit)
60641480Smckusick 	register int unit;
60741480Smckusick {
60841480Smckusick 	register struct ct_softc *sc = &ct_softc[unit];
60956388Smckusick 	register struct buf *bp, *dp;
61041480Smckusick 	u_char stat;
61141480Smckusick 
61241480Smckusick 	bp = cttab[unit].b_actf;
61341480Smckusick 	if (bp == NULL) {
61441480Smckusick 		printf("ct%d: bp == NULL\n", unit);
61541480Smckusick 		return;
61641480Smckusick 	}
61741480Smckusick 	if (sc->sc_flags & CTF_IO) {
61841480Smckusick 		sc->sc_flags &= ~CTF_IO;
61941480Smckusick 		if (hpibustart(sc->sc_hd->hp_ctlr))
62041480Smckusick 			ctgo(unit);
62141480Smckusick 		return;
62241480Smckusick 	}
62341480Smckusick 	if ((sc->sc_flags & CTF_STATWAIT) == 0) {
62441480Smckusick 		if (hpibpptest(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave) == 0) {
62541480Smckusick 			sc->sc_flags |= CTF_STATWAIT;
62641480Smckusick 			hpibawait(sc->sc_hd->hp_ctlr);
62741480Smckusick 			return;
62841480Smckusick 		}
62941480Smckusick 	} else
63041480Smckusick 		sc->sc_flags &= ~CTF_STATWAIT;
63141480Smckusick 	hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT, &stat, 1);
63241480Smckusick #ifdef DEBUG
63341480Smckusick 	if (ctdebug & CDB_FILES)
63441480Smckusick 		printf("ctintr: before flags %x\n", sc->sc_flags);
63541480Smckusick #endif
63641480Smckusick 	if (stat) {
63741480Smckusick 		sc->sc_rsc.unit = C_SUNIT(sc->sc_punit);
63841480Smckusick 		sc->sc_rsc.cmd = C_STATUS;
63941480Smckusick 		hpibsend(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_CMD,
64041480Smckusick 			&sc->sc_rsc, sizeof(sc->sc_rsc));
64141480Smckusick 		hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_EXEC,
64241480Smckusick 			&sc->sc_stat, sizeof(sc->sc_stat));
64341480Smckusick 		hpibrecv(sc->sc_hd->hp_ctlr, sc->sc_hd->hp_slave, C_QSTAT,
64441480Smckusick 			&stat, 1);
64541480Smckusick #ifdef DEBUG
64641480Smckusick 		if (ctdebug & CDB_FILES)
64741480Smckusick 			printf("ctintr: return stat 0x%x, A%x F%x blk %d\n",
64841480Smckusick 			       stat, sc->sc_stat.c_aef,
64941480Smckusick 			       sc->sc_stat.c_fef, sc->sc_stat.c_blk);
65041480Smckusick #endif
65141480Smckusick 		if (stat == 0) {
65241480Smckusick 			if (sc->sc_stat.c_aef & (AEF_EOF | AEF_EOV)) {
65341480Smckusick 				cteof(sc, bp);
65441480Smckusick 				ctaddeof(unit);
65541480Smckusick 				goto done;
65641480Smckusick 			}
65741480Smckusick 			if (sc->sc_stat.c_fef & FEF_PF) {
65841480Smckusick 				ctreset(sc, sc->sc_hd);
65941480Smckusick 				ctstart(unit);
66041480Smckusick 				return;
66141480Smckusick 			}
66241480Smckusick 			if (sc->sc_stat.c_fef & FEF_REXMT) {
66341480Smckusick 				ctstart(unit);
66441480Smckusick 				return;
66541480Smckusick 			}
66641480Smckusick 			if (sc->sc_stat.c_aef & 0x5800) {
66741480Smckusick 				if (sc->sc_stat.c_aef & 0x4000)
66849132Skarels 					tprintf(sc->sc_tpr,
66941480Smckusick 						"ct%d: uninitialized media\n",
67041480Smckusick 						unit);
67141480Smckusick 				if (sc->sc_stat.c_aef & 0x1000)
67249132Skarels 					tprintf(sc->sc_tpr,
67341480Smckusick 						"ct%d: not ready\n", unit);
67441480Smckusick 				if (sc->sc_stat.c_aef & 0x0800)
67549132Skarels 					tprintf(sc->sc_tpr,
67641480Smckusick 						"ct%d: write protect\n", unit);
67741480Smckusick 			} else {
67841480Smckusick 				printf("ct%d err: v%d u%d ru%d bn%d, ",
67941480Smckusick 				       unit,
68041480Smckusick 				       (sc->sc_stat.c_vu>>4)&0xF,
68141480Smckusick 				       sc->sc_stat.c_vu&0xF,
68241480Smckusick 				       sc->sc_stat.c_pend,
68341480Smckusick 				       sc->sc_stat.c_blk);
68441480Smckusick 				printf("R0x%x F0x%x A0x%x I0x%x\n",
68541480Smckusick 				       sc->sc_stat.c_ref,
68641480Smckusick 				       sc->sc_stat.c_fef,
68741480Smckusick 				       sc->sc_stat.c_aef,
68841480Smckusick 				       sc->sc_stat.c_ief);
68941480Smckusick 			}
69041480Smckusick 		} else
69141480Smckusick 			printf("ct%d: request status failed\n", unit);
69241480Smckusick 		bp->b_flags |= B_ERROR;
69341480Smckusick 		bp->b_error = EIO;
69441480Smckusick 		goto done;
69541480Smckusick 	} else
69641480Smckusick 		bp->b_resid = 0;
69741480Smckusick 	if (sc->sc_flags & CTF_CMD) {
69841480Smckusick 		switch (sc->sc_cmd) {
69941480Smckusick 		case MTFSF:
70041480Smckusick 			sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF);
70141480Smckusick 			sc->sc_blkno += CTBTOK(sc->sc_resid);
70241480Smckusick 			ctstart(unit);
70341480Smckusick 			return;
70441480Smckusick 		case MTBSF:
70541480Smckusick 			sc->sc_flags &= ~(CTF_AEOF|CTF_BEOF|CTF_EOT);
70641480Smckusick 			break;
70741480Smckusick 		case MTBSR:
70841480Smckusick 			sc->sc_flags &= ~CTF_BEOF;
70941480Smckusick 			if (sc->sc_flags & CTF_EOT) {
71041480Smckusick 				sc->sc_flags |= CTF_AEOF;
71141480Smckusick 				sc->sc_flags &= ~CTF_EOT;
71241480Smckusick 			} else if (sc->sc_flags & CTF_AEOF) {
71341480Smckusick 				sc->sc_flags |= CTF_BEOF;
71441480Smckusick 				sc->sc_flags &= ~CTF_AEOF;
71541480Smckusick 			}
71641480Smckusick 			break;
71741480Smckusick 		case MTWEOF:
71841480Smckusick 			sc->sc_flags &= ~CTF_BEOF;
71941480Smckusick 			if (sc->sc_flags & (CTF_AEOF|CTF_EOT)) {
72041480Smckusick 				sc->sc_flags |= CTF_EOT;
72141480Smckusick 				sc->sc_flags &= ~CTF_AEOF;
72241480Smckusick 			} else
72341480Smckusick 				sc->sc_flags |= CTF_AEOF;
72441480Smckusick 			break;
72541480Smckusick 		case MTREW:
72641480Smckusick 		case MTOFFL:
72741480Smckusick 			sc->sc_flags &= ~(CTF_BEOF|CTF_AEOF|CTF_EOT);
72841480Smckusick 			break;
72941480Smckusick 		}
73041480Smckusick 	} else {
73141480Smckusick 		sc->sc_flags &= ~CTF_AEOF;
73241480Smckusick 		sc->sc_blkno += CTBTOK(sc->sc_resid);
73341480Smckusick 	}
73441480Smckusick done:
73541480Smckusick #ifdef DEBUG
73641480Smckusick 	if (ctdebug & CDB_FILES)
73741480Smckusick 		printf("ctintr: after flags %x\n", sc->sc_flags);
73841480Smckusick #endif
73956388Smckusick 	if (dp = bp->b_actf)
74056388Smckusick 		dp->b_actb = bp->b_actb;
74156388Smckusick 	else
74256388Smckusick 		cttab[unit].b_actb = bp->b_actb;
74356388Smckusick 	*bp->b_actb = dp;
74441480Smckusick 	iodone(bp);
74541480Smckusick 	hpibfree(&sc->sc_dq);
74641480Smckusick 	if (cttab[unit].b_actf == NULL) {
74741480Smckusick 		cttab[unit].b_active = 0;
74841480Smckusick 		return;
74941480Smckusick 	}
75041480Smckusick 	ctustart(unit);
75141480Smckusick }
75241480Smckusick 
75341480Smckusick ctread(dev, uio)
75441480Smckusick 	dev_t dev;
75541480Smckusick 	struct uio *uio;
75641480Smckusick {
75741480Smckusick 	register int unit = UNIT(dev);
75841480Smckusick 
75941480Smckusick 	return(physio(ctstrategy, &ctbuf[unit], dev, B_READ, minphys, uio));
76041480Smckusick }
76141480Smckusick 
76241480Smckusick ctwrite(dev, uio)
76341480Smckusick 	dev_t dev;
76441480Smckusick 	struct uio *uio;
76541480Smckusick {
76641480Smckusick 	register int unit = UNIT(dev);
76741480Smckusick 
76841480Smckusick 	return(physio(ctstrategy, &ctbuf[unit], dev, B_WRITE, minphys, uio));
76941480Smckusick }
77041480Smckusick 
77141480Smckusick /*ARGSUSED*/
77241480Smckusick ctioctl(dev, cmd, data, flag)
77341480Smckusick 	dev_t dev;
774*65638Sbostic 	int cmd, flag;
77541480Smckusick 	caddr_t data;
77641480Smckusick {
77741480Smckusick 	register struct mtop *op;
77841480Smckusick 	register int cnt;
77941480Smckusick 
78041480Smckusick 	switch (cmd) {
78141480Smckusick 
78241480Smckusick 	case MTIOCTOP:
78341480Smckusick 		op = (struct mtop *)data;
78441480Smckusick 		switch(op->mt_op) {
78541480Smckusick 
78641480Smckusick 		case MTWEOF:
78741480Smckusick 		case MTFSF:
78841480Smckusick 		case MTBSR:
78941480Smckusick 		case MTBSF:
79041480Smckusick 		case MTFSR:
79141480Smckusick 			cnt = op->mt_count;
79241480Smckusick 			break;
79341480Smckusick 
79441480Smckusick 		case MTREW:
79541480Smckusick 		case MTOFFL:
79641480Smckusick 			cnt = 1;
79741480Smckusick 			break;
79841480Smckusick 
79941480Smckusick 		default:
80041480Smckusick 			return(EINVAL);
80141480Smckusick 		}
80241480Smckusick 		ctcommand(dev, op->mt_op, cnt);
80341480Smckusick 		break;
80441480Smckusick 
80541480Smckusick 	case MTIOCGET:
80641480Smckusick 		break;
80741480Smckusick 
80841480Smckusick 	default:
80941480Smckusick 		return(EINVAL);
81041480Smckusick 	}
81141480Smckusick 	return(0);
81241480Smckusick }
81341480Smckusick 
81441480Smckusick /*ARGSUSED*/
81541480Smckusick ctdump(dev)
81641480Smckusick 	dev_t dev;
81741480Smckusick {
81841480Smckusick 	return(ENXIO);
81941480Smckusick }
82041480Smckusick 
82141480Smckusick ctaddeof(unit)
82241480Smckusick 	int unit;
82341480Smckusick {
82441480Smckusick 	register struct ct_softc *sc = &ct_softc[unit];
82541480Smckusick 
82641480Smckusick 	if (sc->sc_eofp == EOFS - 1)
82741480Smckusick 		sc->sc_eofs[EOFS - 1]++;
82841480Smckusick 	else {
82941480Smckusick 		sc->sc_eofp++;
83041480Smckusick 		if (sc->sc_eofp == EOFS - 1)
83141480Smckusick 			sc->sc_eofs[EOFS - 1] = EOFS;
83241480Smckusick 		else
83341480Smckusick 			/* save blkno */
83441480Smckusick 			sc->sc_eofs[sc->sc_eofp] = sc->sc_blkno - 1;
83541480Smckusick 	}
83641480Smckusick #ifdef DEBUG
83741480Smckusick 	if (ctdebug & CT_BSF)
83841480Smckusick 		printf("ct%d: add eof pos %d blk %d\n",
83941480Smckusick 		       unit, sc->sc_eofp,
84041480Smckusick 		       sc->sc_eofs[sc->sc_eofp]);
84141480Smckusick #endif
84241480Smckusick }
84341480Smckusick #endif
844