xref: /csrg-svn/sys/vax/uba/uu.c (revision 49876)
123359Smckusick /*
229257Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323359Smckusick  * All rights reserved.  The Berkeley software License Agreement
423359Smckusick  * specifies the terms and conditions for redistribution.
523359Smckusick  *
6*49876Sbostic  *	@(#)uu.c	7.6 (Berkeley) 05/25/91
723359Smckusick  */
811876Shelge 
912332Shelge #include "uu.h"
1012857Shelge #if NUU > 0
1111876Shelge /*
1211896Shelge  * TU58 DECtape II/DL11 device driver
1311876Shelge  *
1413156Shelge  * The TU58 is treated as a block device (only).  Error detection and
1513156Shelge  * recovery is not very extensive, but sufficient to handle the most
1614091Shelge  * common errors. It is assumed that the TU58 will follow the RSP
1714091Shelge  * protocol exactly, very few protocol errors are checked for.
1814091Shelge  *
1914091Shelge  * To reduce interrupt latency, `options UUDMA' should be specified
2014091Shelge  * in the config file to make sure the `pseudo-DMA' code in locore.s
2114091Shelge  * will be compiled into the system. Otherwise overrun errors will
2214091Shelge  * occur frequently (these errors are not reported).
2314091Shelge  *
2414091Shelge  * TODO:
2514091Shelge  *
2614091Shelge  * - Add ioctl code to wind/rewind cassette
2714091Shelge  *
2811876Shelge  */
2911896Shelge 
3045810Sbostic #include "../include/pte.h"
3111896Shelge 
3245810Sbostic #include "sys/param.h"
3345810Sbostic #include "sys/systm.h"
3445810Sbostic #include "sys/buf.h"
3545810Sbostic #include "sys/conf.h"
3645810Sbostic #include "sys/time.h"
3745810Sbostic #include "sys/kernel.h"
3845810Sbostic #include "sys/errno.h"
3945810Sbostic #include "sys/file.h"
4011876Shelge 
4145810Sbostic #include "../include/cpu.h"
4212332Shelge #include "../vax/nexus.h"
4312937Shelge #include "../vax/rsp.h"
4412332Shelge 
4517084Sbloom #include "ubavar.h"
4617084Sbloom #include "ubareg.h"
4717084Sbloom #include "uureg.h"
4811876Shelge 
4911876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
5012857Shelge #define	WRV     01              /* bit in minor dev => write w. read verify */
5112332Shelge #define	NDPC	02		/* drives per controller */
5212857Shelge #define	NUX	NDPC * NUU	/* number of drives */
5314091Shelge #define	NUUQ	02		/* # of block which can be queued up */
5412857Shelge #define	UMASK	01		/* unit number mask */
5512937Shelge #define UUIPL	0x14		/* ipl level to use */
5611876Shelge 
5712857Shelge struct packet uucmd[NUU];	/* a command sent to the TU58 */
5812857Shelge struct packet uudata[NUU];	/* a command or data returned from TU58 */
5912857Shelge struct buf uitab[NUU];		/* buffer queue headers */
6011876Shelge 
6111876Shelge /*
6212937Shelge  * Driver soft carrier structure
6311876Shelge  */
6412937Shelge struct uu_softc {
6512937Shelge 	u_char	*tu_rbptr;	/* pointer to buffer for read */
6612937Shelge 	int	tu_rcnt;	/* how much to read */
6712937Shelge 	u_char	*tu_wbptr;	/* pointer to buffer for write */
6812937Shelge 	int	tu_wcnt;	/* how much to write */
6912937Shelge 	int	tu_state;	/* current state of tansfer operation */
7012937Shelge 	int	tu_flag;	/* read in progress flag */
7112937Shelge 	char	*tu_addr;	/* real buffer data address */
7212937Shelge 	int	tu_count;	/* real requested count */
7312937Shelge 	int	tu_serrs;	/* count of soft errors */
7412937Shelge 	int	tu_cerrs;	/* count of checksum errors */
7512937Shelge 	int	tu_herrs;	/* count of hard errors */
7612937Shelge 	char    tu_dopen[2];	/* drive is open */
7713014Shelge } uu_softc[NUU];
7811876Shelge 
7912937Shelge #if defined(VAX750) || defined(VAX730)
8012937Shelge extern char *tustates[];
8112937Shelge #else
8212937Shelge char *tustates[TUS_NSTATES] = {
8311876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
8413014Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
8511876Shelge };
8612937Shelge #endif
8712332Shelge 
8812857Shelge #define	UNIT(dev)	(minor(dev)>>1)
8911876Shelge 
9014091Shelge u_char	uunull[2] = { 0, 0 };		/* nulls to send for initialization */
9111896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
9211876Shelge 
9311896Shelge struct	uba_device	*uudinfo[NUU];
9411896Shelge 
9512857Shelge int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
9625521Stef u_short uustd[] = { 0176500, 0 };
9712857Shelge struct uba_driver uudriver =
9812857Shelge     { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
9911896Shelge 
10011896Shelge int	uuwstart;
10114152Shelge int	uuwake();
10214091Shelge static char uu_pcnt[NUX];		/* pee/vee counters, one per drive */
10311896Shelge 
10411876Shelge /*ARGSUSED*/
uuprobe(reg)10511896Shelge uuprobe(reg)
10611896Shelge 	caddr_t reg;
10711876Shelge {
10811896Shelge 	register int br, cvec;			/* value result */
10911896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
11011876Shelge 
11111876Shelge #ifdef lint
11211896Shelge 	br = 0; cvec = br; br = cvec;
11311896Shelge 	uurintr(0); uuxintr(0);
11411876Shelge #endif
11512857Shelge 	uuaddr->tcs = UUCS_INTR;
11612857Shelge 	DELAY(1000);
11712857Shelge 	uuaddr->tcs = 0;
11812857Shelge 	cvec -= 4;		/* since we are using the xmitter intrpt */
11911896Shelge 	return(sizeof (*uuaddr));
12011896Shelge }
12111896Shelge 
uuattach(ui)12211896Shelge uuattach(ui)
12312857Shelge 	register struct uba_device *ui;
12411896Shelge {
12511896Shelge }
12611896Shelge 
12711896Shelge /*ARGSUSED1*/
uuopen(dev,flag)12811896Shelge uuopen(dev, flag)
12911896Shelge 	dev_t dev;
13011896Shelge 	int flag;
13111896Shelge {
13211896Shelge 	register struct uba_device *ui;
13313014Shelge 	register struct uu_softc *uuc;
13411896Shelge 	register struct uudevice *uuaddr;
13540728Skarels 	int ctlr, unit = UNIT(dev), s, error;
13611896Shelge 
13712857Shelge 	ctlr = unit / NDPC;
13812857Shelge 	if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
13911876Shelge 		return (ENXIO);
14012937Shelge 	uuc = &uu_softc[ctlr];
14112937Shelge 	if (uuc->tu_dopen[unit&UMASK])
14211896Shelge 		return (EBUSY);
14311896Shelge 	if (uuwstart++ == 0)
14411896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
14511896Shelge 
14612937Shelge 	uuc->tu_dopen[unit&UMASK]++;
14712857Shelge 	uuaddr = (struct uudevice *)ui->ui_addr;
14812857Shelge 	s = splx(UUIPL);
14911876Shelge 	/*
15013014Shelge 	 * If the other device on this controller
15114091Shelge 	 * is already active, no need to initialize
15213014Shelge 	 */
15313014Shelge 	if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
15413156Shelge 		goto ok;
15513014Shelge 
15613014Shelge 	/*
15711896Shelge 	 * If the unit already initialized,
15811876Shelge 	 * just enable interrupts and return.
15911876Shelge 	 */
16012937Shelge 	if (uuc->tu_state == TUS_IDLE) {
16111896Shelge 		uuaddr->rcs = UUCS_INTR;
16212937Shelge 		goto ok;
16311876Shelge 	}
16411876Shelge 
16511876Shelge 	/*
16611876Shelge 	 * Must initialize, reset the cassette
16711876Shelge 	 * and wait for things to settle down.
16811876Shelge 	 */
16911896Shelge 	uureset(ctlr);
17040728Skarels 	if (error = tsleep((caddr_t)uuc, (PZERO+1) | PCATCH, devopn, 0)) {
17140728Skarels 		splx(s);
17240728Skarels 		return (error);
17340728Skarels 	}
17412857Shelge 	uitab[ctlr].b_active = NULL;
17512937Shelge 	if (uuc->tu_state != TUS_IDLE) {
17612937Shelge 		uuc->tu_state = TUS_INIT1;
17712937Shelge 		uuc->tu_dopen[unit&UMASK] = 0;
17812937Shelge 		uuc->tu_rcnt = uuc->tu_wcnt = 0;
17911896Shelge 		uuaddr->rcs = 0;
18011896Shelge 		uuaddr->tcs = 0;
18111896Shelge 		splx(s);
18212937Shelge 		return (EIO);
18311876Shelge 	}
18412937Shelge ok:
18511876Shelge 	splx(s);
18611876Shelge 	return (0);
18711876Shelge }
18811876Shelge 
18914091Shelge /*
19014091Shelge  * Wait for all outstanding IO on this drive
19114091Shelge  * complete, before closing. If both drives on
19214091Shelge  * this controller are idle, mark the controller
19314091Shelge  * `inactive'.
19414091Shelge  */
19514091Shelge 
uuclose(dev,flag)19611896Shelge uuclose(dev, flag)
19711896Shelge 	dev_t dev;
19811896Shelge 	int flag;
19911876Shelge {
20014091Shelge 	int s, unit = UNIT(dev);
20114091Shelge 	register struct uu_softc *uuc = &uu_softc[unit/NDPC];
20214091Shelge 	struct buf *bp, *last = NULL;
20314091Shelge 	struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
20411876Shelge 
20514091Shelge 	s = splx(UUIPL);
20614091Shelge 	while (uu_pcnt[unit])
20714091Shelge 		sleep(&uu_pcnt[unit], PRIBIO);
20814091Shelge 	/*
20914091Shelge 	 * No more writes are pending, scan the
21014091Shelge 	 * buffer queue for oustanding reads from
21114091Shelge 	 * this unit.
21214091Shelge 	 */
21314152Shelge 	for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) {
21414091Shelge 		if (bp->b_dev == dev)
21514091Shelge 			last = bp;
21614152Shelge 	}
21714152Shelge 	if (last) {
21814152Shelge 		last->b_flags |= B_CALL;
21914152Shelge 		last->b_iodone = uuwake;
22014152Shelge 		sleep((caddr_t)last, PRIBIO);
22114152Shelge 	}
22214091Shelge 	uuc->tu_dopen[unit&UMASK] = 0;
22314091Shelge 	if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
22414091Shelge 		uuc->tu_flag = 0;
22514091Shelge 		uuaddr->rcs = 0;
22614091Shelge 	}
22714091Shelge 	splx(s);
22840728Skarels 	return (0);
22911876Shelge }
23011876Shelge 
23114152Shelge uuwake(bp)
23214152Shelge 	struct buf *bp;
23314152Shelge {
23414152Shelge 	wakeup(bp);
23514152Shelge }
23614152Shelge 
uureset(ctlr)23711896Shelge uureset(ctlr)
23811896Shelge 	int ctlr;
23911876Shelge {
24013014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
24112332Shelge 	register struct packet *cmd = &uucmd[ctlr];
24212857Shelge 	struct uba_device *ui = uudinfo[ctlr];
24312857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
24411876Shelge 
24512857Shelge 	uitab[ctlr].b_active++;
24612937Shelge 	uuc->tu_state = TUS_INIT1;
24712937Shelge 	uuc->tu_wbptr = uunull;
24812937Shelge 	uuc->tu_wcnt = sizeof (uunull);
24914091Shelge 	uuc->tu_rcnt = 0;
25011896Shelge 	cmd->pk_flag = TUF_CMD;
25112332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
25211896Shelge 	cmd->pk_mod = 0;
25311896Shelge 	cmd->pk_seq = 0;
25412332Shelge 	cmd->pk_sw = 0;
25511896Shelge 	uuaddr->rcs = 0;
25611896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
25711896Shelge 	uuxintr(ctlr);				/* start output */
25811876Shelge }
25911876Shelge 
26011876Shelge /*
26111876Shelge  * Strategy routine for block I/O
26211876Shelge  */
uustrategy(bp)26311896Shelge uustrategy(bp)
26411876Shelge 	register struct buf *bp;
26511876Shelge {
26612332Shelge 	register struct buf *uutab;
26711896Shelge 	struct uba_device *ui;
26814091Shelge 	int s, unit = UNIT(bp->b_dev);
26911876Shelge 
27014091Shelge 	if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
27111896Shelge 		goto bad;
27212857Shelge 	ui = uudinfo[unit/NDPC];
27311896Shelge 	if (ui == 0 || ui->ui_alive == 0)
27411896Shelge 		goto bad;
27512857Shelge 	uutab = &uitab[unit/NDPC];	/* one request queue per controller */
27613156Shelge 	s = splx(UUIPL);
27712332Shelge 	if ((bp->b_flags&B_READ) == 0)
27814091Shelge 		tu_pee(&uu_pcnt[unit]);
27914091Shelge 	bp->b_actf = NULL;
28012332Shelge 	if (uutab->b_actf == NULL)
28112332Shelge 		uutab->b_actf = bp;
28212332Shelge 	else
28314091Shelge 		uutab->b_actl->b_actf = bp;
28412332Shelge 	uutab->b_actl = bp;
28512332Shelge 	if (uutab->b_active == 0)
28612857Shelge 		uustart(ui);
28711876Shelge 	splx(s);
28811896Shelge 	return;
28911896Shelge 
29011896Shelge bad:
29111896Shelge 	bp->b_flags |= B_ERROR;
29212332Shelge 	bp->b_error = ENXIO;
29311896Shelge 	iodone(bp);
29411896Shelge 	return;
29511876Shelge }
29611876Shelge 
29711876Shelge /*
29811876Shelge  * Start the transfer
29911876Shelge  */
uustart(ui)30012857Shelge uustart(ui)
30112857Shelge 	register struct uba_device *ui;
30211876Shelge {
30311876Shelge 	register struct buf *bp;
30413014Shelge 	register struct uu_softc *uuc;
30511896Shelge 	struct packet *cmd;
30614152Shelge 	int ctlr = ui->ui_unit, s;
30711876Shelge 
30812857Shelge 	if ((bp = uitab[ctlr].b_actf) == NULL)
30911876Shelge 		return;
31014152Shelge 	s = splx(UUIPL);
31112937Shelge 	uuc = &uu_softc[ctlr];
31212937Shelge 	if (uuc->tu_state != TUS_IDLE) {
31312332Shelge 		uureset(ctlr);
31414152Shelge 		splx(s);
31511876Shelge 		return;
31611876Shelge 	}
31714091Shelge 	cmd = &uucmd[ctlr];
31812857Shelge 	uitab[ctlr].b_active++;
31912937Shelge 	uitab[ctlr].b_errcnt = 0;
32012937Shelge 	uuc->tu_addr = bp->b_un.b_addr;
32112937Shelge 	uuc->tu_count = cmd->pk_count = bp->b_bcount;
32212937Shelge 	cmd->pk_block = bp->b_blkno;
32312937Shelge 	if (bp->b_flags&B_READ) {
32412937Shelge 		cmd->pk_op = TUOP_READ;
32512937Shelge 		cmd->pk_mod = 0;
32612937Shelge 		uuc->tu_state = TUS_SENDR;
32712937Shelge 	} else {
32812937Shelge 		cmd->pk_op = TUOP_WRITE;
32912937Shelge 		cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
33012937Shelge 		uuc->tu_state = TUS_SENDW;
33112937Shelge 	}
33214091Shelge 	cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
33312332Shelge 	cmd->pk_sw = 0;
33411896Shelge 	cmd->pk_chksum =
33512937Shelge 	    tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
33612937Shelge 	uuc->tu_wbptr = (u_char *)cmd;
33712937Shelge 	uuc->tu_wcnt = sizeof (*cmd);
33812332Shelge 	uuxintr(ctlr);
33914152Shelge 	splx(s);
34011876Shelge }
34111876Shelge 
34211876Shelge /*
34314091Shelge  * TU58 receiver interrupt, handles whatever condition the
34414091Shelge  * pseudo DMA routine in locore is unable to handle,
34514091Shelge  * or, if UUDMA is undefined, handle all receiver interrupt
34614091Shelge  * processing.
34711876Shelge  */
uurintr(ctlr)34812332Shelge uurintr(ctlr)
34912332Shelge 	int ctlr;
35011876Shelge {
35112857Shelge 	struct uba_device *ui = uudinfo[ctlr];
35213014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
35312857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
35412857Shelge 	register struct buf *uutab = &uitab[ctlr];
35512332Shelge 	struct packet *data, *cmd;
35612937Shelge 	struct buf *bp;
35712937Shelge 	int c, unit;
35811876Shelge 
35912857Shelge 	c = uuaddr->rdb;
36012937Shelge 	data = &uudata[ctlr];
36113014Shelge 	cmd = &uucmd[ctlr];
36213014Shelge #if !defined(UUDMA)
36313014Shelge 	if (c & UURDB_ERROR)
36413014Shelge 		uuc->tu_state = TUS_RCVERR;
36513014Shelge 	else {
36613014Shelge 		if (uuc->tu_rcnt) {
36713014Shelge 			*uuc->tu_rbptr++ = c;
36813014Shelge 			if (--uuc->tu_rcnt)
36913014Shelge 				return;
37013014Shelge 		}
37113014Shelge 	}
37213014Shelge #endif
37313014Shelge 
37413014Shelge 	/*
37513014Shelge 	 * Switch on the tu_state of the transfer.
37613014Shelge 	 */
37713014Shelge 	switch(uuc->tu_state) {
37813014Shelge 
37913014Shelge 	/*
38013014Shelge 	 * A data error occured in uudma
38113014Shelge 	 * (either overrun or break)
38213014Shelge 	 */
38313014Shelge 	case TUS_RCVERR:
38413156Shelge 		if ((c & UURDB_ORUN) == 0)
38513156Shelge 			printf("uu%d: break received, transfer restarted\n",
38613834Ssam 			    data->pk_unit);
38714091Shelge #ifdef UUDEBUG
38814091Shelge 		else
38914091Shelge 			printf("uu%d: data overrun, recovered\n",
39014091Shelge 			    data->pk_unit);
39114091Shelge #endif
39213156Shelge 		uuc->tu_serrs++;
39313014Shelge 		uu_restart(ctlr, ui);
39413014Shelge 		break;
39511876Shelge 
39611876Shelge 	/*
39711876Shelge 	 * If we get an unexpected "continue",
39811876Shelge 	 * start all over again...
39911876Shelge 	 */
40012937Shelge 	case TUS_INIT2:
40112937Shelge 		uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
40212937Shelge 		uuc->tu_flag = 0;
40312332Shelge 		wakeup((caddr_t)uuc);
40412857Shelge 		uustart(ui);
40511876Shelge 		break;
40611876Shelge 
40711876Shelge 	/*
40811876Shelge 	 * Only transition from this state
40911876Shelge 	 * is on a "continue", so if we don't
41011876Shelge 	 * get it, reset the world.
41111876Shelge 	 */
41212937Shelge 	case TUS_WAIT:			/* waiting for continue */
41312332Shelge 		switch(c) {
41412332Shelge 		case TUF_CONT:  /* got the expected continue */
41512937Shelge 			uuc->tu_flag = 0;
41612332Shelge 			data->pk_flag = TUF_DATA;
41712937Shelge 			data->pk_mcount = MIN(128, uuc->tu_count);
41812332Shelge 			data->pk_chksum =
41912937Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
42012332Shelge 				(int)data->pk_mcount);
42112937Shelge 			uuc->tu_state = TUS_SENDH;
42212937Shelge 			uuc->tu_wbptr = (u_char *)data;
42312937Shelge 			uuc->tu_wcnt = 2;
42412857Shelge 			uuxintr(ctlr);
42511876Shelge 			break;
42612332Shelge 
42712332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
42812937Shelge 			uuc->tu_state = TUS_GET;
42912937Shelge 			uuc->tu_rbptr = (u_char *)data;
43013014Shelge 			uuc->tu_rcnt = sizeof (*data) - 1;
43112937Shelge 			uuc->tu_flag = 1;
43212332Shelge 			uuaddr->tcs = 0;
43313014Shelge 			*uuc->tu_rbptr++ = c & UUDB_DMASK;
43413014Shelge 			break;
43512332Shelge 
43612332Shelge 		case TUF_INITF:
43712857Shelge 			uureset(ctlr);
43812332Shelge 			break;
43912332Shelge 
44012332Shelge 		default:        /* something random...bad news */
44112937Shelge 			uuc->tu_state = TUS_INIT1;
44212332Shelge 			break;
44311876Shelge 		}
44411876Shelge 		break;
44511876Shelge 
44612937Shelge 	case TUS_SENDW:
44712937Shelge 		if (c != TUF_CONT && c != TUF_INITF)
44811876Shelge 			goto bad;
44913014Shelge 		uu_restart(ctlr, ui);
45011876Shelge 		break;
45111876Shelge 
45211876Shelge 	/*
45311876Shelge 	 * Got header, now get data; amount to
45411896Shelge 	 * fetch is included in packet.
45513014Shelge 	 * (data packets are handled entirely
45613014Shelge 	 * in uudma)
45711876Shelge 	 */
45812937Shelge 	case TUS_GETH:
45913156Shelge #ifndef UUDMA
46013156Shelge 		if (data->pk_flag == TUF_DATA)
46113156Shelge 			uuc->tu_rbptr = (u_char *)uuc->tu_addr;
46213156Shelge #endif
46312937Shelge 		uuc->tu_rcnt = data->pk_mcount;
46412937Shelge 		uuc->tu_state = TUS_GETD;
46511876Shelge 		break;
46611876Shelge 
46711876Shelge 	/*
46811876Shelge 	 * Got the data, now fetch the checksum.
46911876Shelge 	 */
47012937Shelge 	case TUS_GETD:
47112937Shelge 		uuc->tu_rbptr = (u_char *)&data->pk_chksum;
47212937Shelge 		uuc->tu_rcnt = sizeof (data->pk_chksum);
47312937Shelge 		uuc->tu_state = TUS_GETC;
47411876Shelge 		break;
47511876Shelge 
47612937Shelge 	case TUS_GETC:
47711876Shelge 		/* got entire packet */
47812332Shelge 		if (data->pk_chksum !=
47912937Shelge 		    tuchk(*((short *)data), (u_short *)
48013014Shelge 		     (data->pk_flag == TUF_DATA ?
48113156Shelge 		     (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
48212332Shelge 		     (int)data->pk_mcount))
48313014Shelge 	case TUS_CHKERR:
48412937Shelge 			uuc->tu_cerrs++;
48513014Shelge 	case TUS_GET:
48612332Shelge 		if (data->pk_flag == TUF_DATA) {
48711876Shelge 			/* data packet, advance to next */
48812937Shelge 			uuc->tu_addr += data->pk_mcount;
48912937Shelge 			uuc->tu_count -= data->pk_mcount;
49012937Shelge 			uuc->tu_state = TUS_GETH;
49112937Shelge 			uuc->tu_rbptr = (u_char *)data;	/* next packet */
49212937Shelge 			uuc->tu_rcnt = 2;
49312332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
49411876Shelge 			/* end packet, idle and reenable transmitter */
49512937Shelge 			uuc->tu_state = TUS_IDLE;
49612937Shelge 			uuc->tu_flag = 0;
49712937Shelge 			uuaddr->tcs = UUCS_INTR;
49812937Shelge 			if ((bp = uutab->b_actf) == NULL) {
49913156Shelge 				printf("uu%d: no bp, active %d\n",
50013834Ssam 				    data->pk_unit, uitab[ctlr].b_active);
50112857Shelge 				uustart(ui);
50211876Shelge 				return;
50311876Shelge 			}
50414091Shelge 			unit = UNIT(bp->b_dev);
50512332Shelge 			if (data->pk_mod > 1) {        /* hard error */
50613014Shelge 				printf("uu%d: hard error bn%d,", unit,
50713834Ssam 				    bp->b_blkno);
50814091Shelge 				printf(" pk_mod 0%o\n", data->pk_mod&0xff);
50911876Shelge 				bp->b_flags |= B_ERROR;
51012937Shelge 				uuc->tu_herrs++;
51114091Shelge 			} else if (data->pk_mod)	/* soft error */
51212937Shelge 				uuc->tu_serrs++;
51312332Shelge 			uutab->b_active = NULL;
51414091Shelge 			uutab->b_actf = bp->b_actf;
51512937Shelge 			bp->b_resid = uuc->tu_count;
51611876Shelge 			if ((bp->b_flags&B_READ) == 0)
51714091Shelge 				tu_vee(&uu_pcnt[unit]);
51811876Shelge 			iodone(bp);
51912857Shelge 			uustart(ui);
52011876Shelge 		} else {
52113156Shelge 			/*
52213156Shelge 			 * Neither data nor end: data was lost
52314091Shelge 			 * somehow, flush and restart the transfer.
52413156Shelge 			 */
52514091Shelge 			uuaddr->rcs = 0;
52613014Shelge 			uu_restart(ctlr, ui);
52713156Shelge 			uuc->tu_serrs++;
52811876Shelge 		}
52911876Shelge 		break;
53011876Shelge 
53112937Shelge 	case TUS_IDLE:
53212937Shelge 	case TUS_INIT1:
53311876Shelge 		break;
53411876Shelge 
53511876Shelge 	default:
53611876Shelge bad:
53711876Shelge 		if (c == TUF_INITF) {
53813156Shelge 			printf("uu%d protocol error, state=", data->pk_unit);
53912937Shelge 			printstate(uuc->tu_state);
54011876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
54112332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
54212332Shelge 			uutab->b_active = NULL;
54312332Shelge 			if (bp = uutab->b_actf) {
54411876Shelge 				bp->b_flags |= B_ERROR;
54514091Shelge 				uutab->b_actf = bp->b_actf;
54611876Shelge 				if ((bp->b_flags&B_READ) == 0)
54714091Shelge 					tu_vee(&uu_pcnt[unit]);
54811876Shelge 				iodone(bp);
54911876Shelge 			}
55012937Shelge 			uuc->tu_state = TUS_INIT1;
55111876Shelge 		} else {
55212332Shelge 			printf("uu%d receive state error, state=",
55313156Shelge 				data->pk_unit);
55412937Shelge 			printstate(uuc->tu_state);
55513014Shelge 			printf(", byte=%x\n", c & 0xff);
55611876Shelge #ifdef notdef
55712937Shelge 			uuc->tu_state = TUS_INIT1;
55811876Shelge #endif
55912332Shelge 			wakeup((caddr_t)uuc);
56011876Shelge 		}
56111876Shelge 	}
56211876Shelge }
56311876Shelge 
56412937Shelge 
56512937Shelge /*
56611876Shelge  * TU58 transmitter interrupt
56711876Shelge  */
uuxintr(ctlr)56812332Shelge uuxintr(ctlr)
56912332Shelge 	int ctlr;
57011876Shelge {
57113014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
57212857Shelge 	register struct uudevice *uuaddr;
57312332Shelge 	register struct packet *data;
57412857Shelge 	struct uba_device *ui = uudinfo[ctlr];
57512332Shelge 	int c;
57611876Shelge 
57712857Shelge 	data = &uudata[ctlr];
57812857Shelge 	uuaddr = (struct uudevice *) ui->ui_addr;
57911876Shelge top:
58014091Shelge 	if (uuc->tu_wcnt > 0) {
58111876Shelge 		/* still stuff to send, send one byte */
58212332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
58311876Shelge 			;
58412937Shelge 		uuaddr->tdb = *uuc->tu_wbptr++;
58512937Shelge 		uuc->tu_wcnt--;
58611876Shelge 		return;
58711876Shelge 	}
58811876Shelge 
58911876Shelge 	/*
59011876Shelge 	 * Last message byte was sent out.
59112937Shelge 	 * Switch on tu_state of transfer.
59211876Shelge 	 */
59312937Shelge 	switch(uuc->tu_state) {
59411876Shelge 
59511876Shelge 	/*
59611876Shelge 	 * Two nulls have been sent, remove break, and send inits
59711876Shelge 	 */
59812937Shelge 	case TUS_INIT1:
59914091Shelge 		uuc->tu_flag = 0;
60012332Shelge 		uuaddr->tcs = UUCS_INTR;
60112937Shelge 		uuc->tu_state = TUS_INIT2;
60212937Shelge 		uuc->tu_wbptr = uuinit;
60312937Shelge 		uuc->tu_wcnt = sizeof (uuinit);
60411876Shelge 		goto top;
60511876Shelge 
60611876Shelge 	/*
60711876Shelge 	 * Inits have been sent, wait for a continue msg.
60811876Shelge 	 */
60912937Shelge 	case TUS_INIT2:
61012857Shelge 		c = uuaddr->rdb;	/* prevent overrun error */
61112332Shelge 		uuaddr->rcs = UUCS_INTR;
61212937Shelge 		uuc->tu_flag = 1;
61311876Shelge 		break;
61411876Shelge 
61511876Shelge 	/*
61611876Shelge 	 * Read cmd packet sent, get ready for data
61711876Shelge 	 */
61812937Shelge 	case TUS_SENDR:
61912937Shelge 		uuc->tu_state = TUS_GETH;
62012937Shelge 		uuc->tu_rbptr = (u_char *)data;
62112937Shelge 		uuc->tu_rcnt = 2;
62212937Shelge 		uuc->tu_flag = 1;
62314091Shelge 		uuaddr->tcs = 0;
62412937Shelge 		uuaddr->rcs = UUCS_INTR;
62511876Shelge 		break;
62611876Shelge 
62711876Shelge 	/*
62811876Shelge 	 * Write cmd packet sent, wait for continue
62911876Shelge 	 */
63012937Shelge 	case TUS_SENDW:
63112937Shelge 		uuc->tu_state = TUS_WAIT;
63212937Shelge 		uuc->tu_flag = 1;
63312332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
63411876Shelge 			printf("NO IE\n");
63512332Shelge 			uuaddr->rcs = UUCS_INTR;
63611876Shelge 		}
63711876Shelge 		break;
63811876Shelge 
63911876Shelge 	/*
64011876Shelge 	 * Header sent, send data.
64111876Shelge 	 */
64212937Shelge 	case TUS_SENDH:
64312937Shelge 		uuc->tu_state = TUS_SENDD;
64412937Shelge 		uuc->tu_wbptr = (u_char *)uuc->tu_addr;
64512937Shelge 		uuc->tu_wcnt = data->pk_mcount;
64611876Shelge 		goto top;
64711876Shelge 
64811876Shelge 	/*
64911876Shelge 	 * Data sent, follow with checksum.
65011876Shelge 	 */
65112937Shelge 	case TUS_SENDD:
65212937Shelge 		uuc->tu_state = TUS_SENDC;
65312937Shelge 		uuc->tu_wbptr = (u_char *)&data->pk_chksum;
65414091Shelge 		uuc->tu_wcnt = 2;
65511876Shelge 		goto top;
65611876Shelge 
65711876Shelge 	/*
65811876Shelge 	 * Checksum sent, wait for continue.
65911876Shelge 	 */
66012937Shelge 	case TUS_SENDC:
66111876Shelge 		/*
66212937Shelge 		 * Update buffer address and count.
66311876Shelge 		 */
66412937Shelge 		uuc->tu_addr += data->pk_mcount;
66512937Shelge 		uuc->tu_count -= data->pk_mcount;
66614091Shelge 		if (uuc->tu_count > 0) {
66712937Shelge 			uuc->tu_state = TUS_WAIT;
66812937Shelge 			uuc->tu_flag = 1;
66911876Shelge 			break;
67011876Shelge 		}
67111876Shelge 
67211876Shelge 		/*
67311876Shelge 		 * End of transmission, get ready for end packet.
67411876Shelge 		 */
67512937Shelge 		uuc->tu_state = TUS_GET;
67612937Shelge 		uuc->tu_rbptr = (u_char *)data;
67712937Shelge 		uuc->tu_rcnt = sizeof (*data);
67812937Shelge 		uuc->tu_flag = 1;
67914091Shelge 		uuaddr->tcs = 0;
68011876Shelge 		break;
68111876Shelge 
68211876Shelge 	/*
68312332Shelge 	 * Random interrupt
68411876Shelge 	 */
68513156Shelge 	case TUS_IDLE:		/* stray interrupt? */
68613156Shelge 
68711876Shelge 	default:
68811876Shelge 		break;
68911876Shelge 	}
69012937Shelge }
69112937Shelge 
uuwatch()69212937Shelge uuwatch()
69312937Shelge {
69413014Shelge 	register struct uu_softc *uuc;
69512937Shelge 	register struct uudevice *uuaddr;
69612937Shelge 	struct uba_device *ui;
69712937Shelge 	struct buf *bp, *uutab;
69812937Shelge 	int s, ctlr, active = 0;
69912937Shelge 
70012937Shelge 	for (ctlr=0; ctlr<NUU; ctlr++) {
70112937Shelge 		int i;
70212937Shelge 
70312937Shelge 		uuc = &uu_softc[ctlr];
70414091Shelge 
70514091Shelge 		if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
70614091Shelge 			active++;
70714091Shelge 		if (uuc->tu_flag == 0)
70814091Shelge 			/*
70914091Shelge 			 * If no read is in progress
71014091Shelge 			 * just skip
71114091Shelge 			 */
71214091Shelge 			continue;
71314091Shelge 
71412937Shelge 		ui = uudinfo[ctlr];
71512937Shelge 		uuaddr = (struct uudevice *)ui->ui_addr;
71612937Shelge 		uutab = &uitab[ctlr];
71714091Shelge 		if (uuc->tu_flag++ < 40)
71812937Shelge 			continue;
71913156Shelge 		printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
72014091Shelge #ifdef UUDEBUG
721*49876Sbostic 		printf("%lx %lx %lx %lx %lx %lx %lx\n",
722*49876Sbostic 		    uuc->tu_rbptr, uuc->tu_rcnt, uuc->tu_wbptr, uuc->tu_wcnt,
723*49876Sbostic 		    uuc->tu_state, uuc->tu_addr, uuc->tu_count);
72413834Ssam #endif
72514091Shelge 		s = splx(UUIPL);
72612937Shelge 		uuc->tu_flag = 0;
72712937Shelge 		i = uuaddr->rdb;		/* dummy */
72812937Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
72912937Shelge 		uuaddr->tcs = UUCS_INTR;
73012937Shelge 		uuc->tu_state = TUS_IDLE;
73112937Shelge 		if (!uutab->b_active) {
73212937Shelge 			wakeup((caddr_t)uuc);
73312937Shelge 			goto retry;
73412937Shelge 		}
73512937Shelge 		if (++uutab->b_errcnt <= 1) {
73612937Shelge 			uustart(ui);
73712937Shelge 			goto retry;
73812937Shelge 		}
73912937Shelge 		if (bp = uutab->b_actf) {
74012937Shelge 			bp->b_flags |= B_ERROR;
74112937Shelge 			if ((bp->b_flags&B_READ) == 0)
74214091Shelge 				tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
74312937Shelge 			iodone(bp);
74412937Shelge 		}
74512937Shelge retry:
74612937Shelge 		(void) splx(s);
74711876Shelge 	}
74812937Shelge 	if (active)
74912937Shelge 		timeout(uuwatch, (caddr_t)0, hz);
75012937Shelge 	else
75112937Shelge 		uuwstart = 0;
75212937Shelge 	return;
75311876Shelge }
75411876Shelge 
75512937Shelge #if !defined(VAX750) && !defined(VAX730)
75611876Shelge /*
75711876Shelge  * Compute checksum TU58 fashion
75811876Shelge  */
75911876Shelge #ifdef lint
tuchk(word,cp,n)76012937Shelge tuchk(word, cp, n)
76111876Shelge 	register word;
76211876Shelge 	register unsigned short *cp;
76311876Shelge 	int n;
76411876Shelge {
76511876Shelge 	register int c = n >> 1;
76611876Shelge 	register long temp;
76711876Shelge 
76811876Shelge 	do {
76911876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
77011876Shelge 		word += temp;
77111876Shelge 	} while (--c > 0);
77211876Shelge 	if (n & 1)
77311876Shelge 		word += *(unsigned char *)cp;
77411876Shelge 	while (word & 0xffff0000)
77511876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
77611876Shelge 	return (word);
77711876Shelge }
77811876Shelge #else
tuchk(word0,wp,n)77912937Shelge tuchk(word0, wp, n)
78011896Shelge 	register int word0;			/* r11 */
78111896Shelge 	register char *wp;			/* r10 */
78211896Shelge 	register int n;				/* r9 */
78311876Shelge {
78411876Shelge 	asm("loop:");
78511896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
78611896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
78711876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
78811896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
78911896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
79011896Shelge 	asm("	addw2	r10,r11");		/* add it in */
79111896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
79211876Shelge 	asm("ok:");
79311896Shelge 	asm("	movl	r11,r0");		/* return sum */
79411876Shelge }
79511876Shelge #endif
79611876Shelge 
79714091Shelge /*
79814091Shelge  * Make sure this incredibly slow device
79914091Shelge  * doesn't eat up all the buffers in the
80014091Shelge  * system by putting the requesting process
80114091Shelge  * (remember: this device is 'single-user')
80214091Shelge  * to sleep if the write-behind queue grows
80314091Shelge  * larger than NUUQ.
80414091Shelge  */
tu_pee(cp)80512937Shelge tu_pee(cp)
80614091Shelge 	char *cp;
80712332Shelge {
80812332Shelge 	register int s;
80912332Shelge 
81012857Shelge 	s = splx(UUIPL);
81114091Shelge 	if (++(*cp) > NUUQ)
81212332Shelge 		sleep(cp, PRIBIO);
81312332Shelge 	splx(s);
81412332Shelge }
81512332Shelge 
tu_vee(cp)81612937Shelge tu_vee(cp)
81714091Shelge 	char *cp;
81812332Shelge {
81912332Shelge 	register int s;
82012332Shelge 
82112857Shelge 	s = splx(UUIPL);
82214091Shelge 	if (--(*cp) <= NUUQ)
82312332Shelge 		wakeup(cp);
82411876Shelge 	splx(s);
82511876Shelge }
82611876Shelge #endif
82712332Shelge 
uuioctl(dev,cmd,data,flag)82812937Shelge uuioctl(dev, cmd, data, flag)
82912937Shelge 	dev_t dev;
83012937Shelge 	caddr_t data;
83112937Shelge {
83212937Shelge 	/*
83313156Shelge 	 * add code to wind/rewind cassette here
83412937Shelge 	 */
83512937Shelge 	return (ENXIO);
83612937Shelge }
83712937Shelge 
uu_restart(ctlr,ui)83813014Shelge uu_restart(ctlr, ui)
83913014Shelge 	int ctlr;
84013014Shelge 	struct uba_device *ui;
84113014Shelge {
84213014Shelge 	uureset(ctlr);
84313014Shelge 	timeout(uustart, (caddr_t)ui, hz * 3);
84413014Shelge }
84514091Shelge 
84614091Shelge #endif
847