xref: /csrg-svn/sys/vax/uba/uu.c (revision 14091)
1*14091Shelge /*	uu.c	4.9	83/07/24	*/
211876Shelge 
312332Shelge #include "uu.h"
412857Shelge #if NUU > 0
511876Shelge /*
611896Shelge  * TU58 DECtape II/DL11 device driver
711876Shelge  *
813156Shelge  * The TU58 is treated as a block device (only).  Error detection and
913156Shelge  * recovery is not very extensive, but sufficient to handle the most
10*14091Shelge  * common errors. It is assumed that the TU58 will follow the RSP
11*14091Shelge  * protocol exactly, very few protocol errors are checked for.
12*14091Shelge  *
13*14091Shelge  * To reduce interrupt latency, `options UUDMA' should be specified
14*14091Shelge  * in the config file to make sure the `pseudo-DMA' code in locore.s
15*14091Shelge  * will be compiled into the system. Otherwise overrun errors will
16*14091Shelge  * occur frequently (these errors are not reported).
17*14091Shelge  *
18*14091Shelge  * TODO:
19*14091Shelge  *
20*14091Shelge  * - Add ioctl code to wind/rewind cassette
21*14091Shelge  *
2211876Shelge  */
2311896Shelge 
2412332Shelge #include "../machine/pte.h"
2511896Shelge 
2611876Shelge #include "../h/param.h"
2711876Shelge #include "../h/systm.h"
2811876Shelge #include "../h/buf.h"
2911876Shelge #include "../h/conf.h"
3012332Shelge #include "../h/time.h"
3111896Shelge #include "../h/kernel.h"
3211896Shelge #include "../h/errno.h"
3311896Shelge #include "../h/file.h"
3411876Shelge 
3511876Shelge #include "../vax/cpu.h"
3612332Shelge #include "../vax/nexus.h"
3712937Shelge #include "../vax/rsp.h"
3812332Shelge 
3911896Shelge #include "../vaxuba/ubavar.h"
4011896Shelge #include "../vaxuba/ubareg.h"
4111896Shelge #include "../vaxuba/uureg.h"
4211876Shelge 
4311876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
4412857Shelge #define	WRV     01              /* bit in minor dev => write w. read verify */
4512332Shelge #define	NDPC	02		/* drives per controller */
4612857Shelge #define	NUX	NDPC * NUU	/* number of drives */
47*14091Shelge #define	NUUQ	02		/* # of block which can be queued up */
4812857Shelge #define	UMASK	01		/* unit number mask */
4912937Shelge #define UUIPL	0x14		/* ipl level to use */
5011876Shelge 
5112857Shelge struct packet uucmd[NUU];	/* a command sent to the TU58 */
5212857Shelge struct packet uudata[NUU];	/* a command or data returned from TU58 */
5312857Shelge struct buf uitab[NUU];		/* buffer queue headers */
5411876Shelge 
5511876Shelge /*
5612937Shelge  * Driver soft carrier structure
5711876Shelge  */
5812937Shelge struct uu_softc {
5912937Shelge 	u_char	*tu_rbptr;	/* pointer to buffer for read */
6012937Shelge 	int	tu_rcnt;	/* how much to read */
6112937Shelge 	u_char	*tu_wbptr;	/* pointer to buffer for write */
6212937Shelge 	int	tu_wcnt;	/* how much to write */
6312937Shelge 	int	tu_state;	/* current state of tansfer operation */
6412937Shelge 	int	tu_flag;	/* read in progress flag */
6512937Shelge 	char	*tu_addr;	/* real buffer data address */
6612937Shelge 	int	tu_count;	/* real requested count */
6712937Shelge 	int	tu_serrs;	/* count of soft errors */
6812937Shelge 	int	tu_cerrs;	/* count of checksum errors */
6912937Shelge 	int	tu_herrs;	/* count of hard errors */
7012937Shelge 	char    tu_dopen[2];	/* drive is open */
7113014Shelge } uu_softc[NUU];
7211876Shelge 
7312937Shelge #if defined(VAX750) || defined(VAX730)
7412937Shelge extern char *tustates[];
7512937Shelge #else
7612937Shelge char *tustates[TUS_NSTATES] = {
7711876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
7813014Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
7911876Shelge };
8012937Shelge #endif
8112332Shelge 
8212857Shelge #define	UNIT(dev)	(minor(dev)>>1)
8311876Shelge 
84*14091Shelge u_char	uunull[2] = { 0, 0 };		/* nulls to send for initialization */
8511896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
8611876Shelge 
8711896Shelge struct	uba_device	*uudinfo[NUU];
8811896Shelge 
8912857Shelge int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
9012857Shelge u_short uustd[] = { 0176500 };
9112857Shelge struct uba_driver uudriver =
9212857Shelge     { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
9311896Shelge 
9411896Shelge int	uuwstart;
95*14091Shelge static char uu_pcnt[NUX];		/* pee/vee counters, one per drive */
9611896Shelge 
9711876Shelge /*ARGSUSED*/
9811896Shelge uuprobe(reg)
9911896Shelge 	caddr_t reg;
10011876Shelge {
10111896Shelge 	register int br, cvec;			/* value result */
10211896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
10311876Shelge 
10411876Shelge #ifdef lint
10511896Shelge 	br = 0; cvec = br; br = cvec;
10611896Shelge 	uurintr(0); uuxintr(0);
10711876Shelge #endif
10812857Shelge 	uuaddr->tcs = UUCS_INTR;
10912857Shelge 	DELAY(1000);
11012857Shelge 	uuaddr->tcs = 0;
11112857Shelge 	cvec -= 4;		/* since we are using the xmitter intrpt */
11211896Shelge 	return(sizeof (*uuaddr));
11311896Shelge }
11411896Shelge 
11511896Shelge uuattach(ui)
11612857Shelge 	register struct uba_device *ui;
11711896Shelge {
11811896Shelge }
11911896Shelge 
12011896Shelge /*ARGSUSED1*/
12111896Shelge uuopen(dev, flag)
12211896Shelge 	dev_t dev;
12311896Shelge 	int flag;
12411896Shelge {
12511896Shelge 	register struct uba_device *ui;
12613014Shelge 	register struct uu_softc *uuc;
12711896Shelge 	register struct uudevice *uuaddr;
12812332Shelge 	int ctlr, unit = UNIT(dev), s;
12911896Shelge 
13012857Shelge 	ctlr = unit / NDPC;
13112857Shelge 	if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
13211876Shelge 		return (ENXIO);
13312937Shelge 	uuc = &uu_softc[ctlr];
13412937Shelge 	if (uuc->tu_dopen[unit&UMASK])
13511896Shelge 		return (EBUSY);
13611896Shelge 	if (uuwstart++ == 0)
13711896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
13811896Shelge 
13912937Shelge 	uuc->tu_dopen[unit&UMASK]++;
14012857Shelge 	uuaddr = (struct uudevice *)ui->ui_addr;
14112857Shelge 	s = splx(UUIPL);
14211876Shelge 	/*
14313014Shelge 	 * If the other device on this controller
144*14091Shelge 	 * is already active, no need to initialize
14513014Shelge 	 */
14613014Shelge 	if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
14713156Shelge 		goto ok;
14813014Shelge 
14913014Shelge 	/*
15011896Shelge 	 * If the unit already initialized,
15111876Shelge 	 * just enable interrupts and return.
15211876Shelge 	 */
15312937Shelge 	if (uuc->tu_state == TUS_IDLE) {
15411896Shelge 		uuaddr->rcs = UUCS_INTR;
15512937Shelge 		goto ok;
15611876Shelge 	}
15711876Shelge 
15811876Shelge 	/*
15911876Shelge 	 * Must initialize, reset the cassette
16011876Shelge 	 * and wait for things to settle down.
16111876Shelge 	 */
16211896Shelge 	uureset(ctlr);
16311896Shelge 	sleep((caddr_t)uuc, PZERO+1);
16412857Shelge 	uitab[ctlr].b_active = NULL;
16512937Shelge 	if (uuc->tu_state != TUS_IDLE) {
16612937Shelge 		uuc->tu_state = TUS_INIT1;
16712937Shelge 		uuc->tu_dopen[unit&UMASK] = 0;
16812937Shelge 		uuc->tu_rcnt = uuc->tu_wcnt = 0;
16911896Shelge 		uuaddr->rcs = 0;
17011896Shelge 		uuaddr->tcs = 0;
17111896Shelge 		splx(s);
17212937Shelge 		return (EIO);
17311876Shelge 	}
17412937Shelge ok:
17511876Shelge 	splx(s);
17611876Shelge 	return (0);
17711876Shelge }
17811876Shelge 
179*14091Shelge /*
180*14091Shelge  * Wait for all outstanding IO on this drive
181*14091Shelge  * complete, before closing. If both drives on
182*14091Shelge  * this controller are idle, mark the controller
183*14091Shelge  * `inactive'.
184*14091Shelge  */
185*14091Shelge 
18611896Shelge uuclose(dev, flag)
18711896Shelge 	dev_t dev;
18811896Shelge 	int flag;
18911876Shelge {
190*14091Shelge 	int s, unit = UNIT(dev);
191*14091Shelge 	register struct uu_softc *uuc = &uu_softc[unit/NDPC];
192*14091Shelge 	struct buf *bp, *last = NULL;
193*14091Shelge 	struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
19411876Shelge 
195*14091Shelge 	s = splx(UUIPL);
196*14091Shelge 	while (uu_pcnt[unit])
197*14091Shelge 		sleep(&uu_pcnt[unit], PRIBIO);
198*14091Shelge 	/*
199*14091Shelge 	 * No more writes are pending, scan the
200*14091Shelge 	 * buffer queue for oustanding reads from
201*14091Shelge 	 * this unit.
202*14091Shelge 	 */
203*14091Shelge 	for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf)
204*14091Shelge 		if (bp->b_dev == dev)
205*14091Shelge 			last = bp;
206*14091Shelge 	if (last)
207*14091Shelge 		iowait(last);
208*14091Shelge 	uuc->tu_dopen[unit&UMASK] = 0;
209*14091Shelge 	if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
210*14091Shelge 		uuc->tu_flag = 0;
211*14091Shelge 		uuaddr->rcs = 0;
212*14091Shelge 		/*
213*14091Shelge 		 * Make sure the device is left in a
214*14091Shelge 		 * known state....
215*14091Shelge 		 */
216*14091Shelge 		if (uuc->tu_state != TUS_IDLE)
217*14091Shelge 			uuc->tu_state = TUS_INIT1;
218*14091Shelge 	}
219*14091Shelge 	splx(s);
22011876Shelge }
22111876Shelge 
22211896Shelge uureset(ctlr)
22311896Shelge 	int ctlr;
22411876Shelge {
22513014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
22612332Shelge 	register struct packet *cmd = &uucmd[ctlr];
22712857Shelge 	struct uba_device *ui = uudinfo[ctlr];
22812857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
22911876Shelge 
23012857Shelge 	uitab[ctlr].b_active++;
23112937Shelge 	uuc->tu_state = TUS_INIT1;
23212937Shelge 	uuc->tu_wbptr = uunull;
23312937Shelge 	uuc->tu_wcnt = sizeof (uunull);
234*14091Shelge 	uuc->tu_rcnt = 0;
23511896Shelge 	cmd->pk_flag = TUF_CMD;
23612332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
23711896Shelge 	cmd->pk_mod = 0;
23811896Shelge 	cmd->pk_seq = 0;
23912332Shelge 	cmd->pk_sw = 0;
24011896Shelge 	uuaddr->rcs = 0;
24111896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
24211896Shelge 	uuxintr(ctlr);				/* start output */
24311876Shelge }
24411876Shelge 
24511876Shelge /*
24611876Shelge  * Strategy routine for block I/O
24711876Shelge  */
24811896Shelge uustrategy(bp)
24911876Shelge 	register struct buf *bp;
25011876Shelge {
25112332Shelge 	register struct buf *uutab;
25211896Shelge 	struct uba_device *ui;
253*14091Shelge 	int s, unit = UNIT(bp->b_dev);
25411876Shelge 
255*14091Shelge 	if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
25611896Shelge 		goto bad;
25712857Shelge 	ui = uudinfo[unit/NDPC];
25811896Shelge 	if (ui == 0 || ui->ui_alive == 0)
25911896Shelge 		goto bad;
26012857Shelge 	uutab = &uitab[unit/NDPC];	/* one request queue per controller */
26113156Shelge 	s = splx(UUIPL);
26212332Shelge 	if ((bp->b_flags&B_READ) == 0)
263*14091Shelge 		tu_pee(&uu_pcnt[unit]);
264*14091Shelge 	bp->b_actf = NULL;
26512332Shelge 	if (uutab->b_actf == NULL)
26612332Shelge 		uutab->b_actf = bp;
26712332Shelge 	else
268*14091Shelge 		uutab->b_actl->b_actf = bp;
26912332Shelge 	uutab->b_actl = bp;
27012332Shelge 	if (uutab->b_active == 0)
27112857Shelge 		uustart(ui);
27211876Shelge 	splx(s);
27311896Shelge 	return;
27411896Shelge 
27511896Shelge bad:
27611896Shelge 	bp->b_flags |= B_ERROR;
27712332Shelge 	bp->b_error = ENXIO;
27811896Shelge 	iodone(bp);
27911896Shelge 	return;
28011876Shelge }
28111876Shelge 
28211876Shelge /*
28311876Shelge  * Start the transfer
28411876Shelge  */
28512857Shelge uustart(ui)
28612857Shelge 	register struct uba_device *ui;
28711876Shelge {
28811876Shelge 	register struct buf *bp;
28913014Shelge 	register struct uu_softc *uuc;
29011896Shelge 	struct packet *cmd;
29112857Shelge 	int ctlr = ui->ui_unit;
29211876Shelge 
29312857Shelge 	if ((bp = uitab[ctlr].b_actf) == NULL)
29411876Shelge 		return;
29512937Shelge 	uuc = &uu_softc[ctlr];
29612937Shelge 	if (uuc->tu_state != TUS_IDLE) {
29712332Shelge 		uureset(ctlr);
29811876Shelge 		return;
29911876Shelge 	}
300*14091Shelge 	cmd = &uucmd[ctlr];
30112857Shelge 	uitab[ctlr].b_active++;
30212937Shelge 	uitab[ctlr].b_errcnt = 0;
30312937Shelge 	uuc->tu_addr = bp->b_un.b_addr;
30412937Shelge 	uuc->tu_count = cmd->pk_count = bp->b_bcount;
30512937Shelge 	cmd->pk_block = bp->b_blkno;
30612937Shelge 	if (bp->b_flags&B_READ) {
30712937Shelge 		cmd->pk_op = TUOP_READ;
30812937Shelge 		cmd->pk_mod = 0;
30912937Shelge 		uuc->tu_state = TUS_SENDR;
31012937Shelge 	} else {
31112937Shelge 		cmd->pk_op = TUOP_WRITE;
31212937Shelge 		cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
31312937Shelge 		uuc->tu_state = TUS_SENDW;
31412937Shelge 	}
315*14091Shelge 	cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
31612332Shelge 	cmd->pk_sw = 0;
31711896Shelge 	cmd->pk_chksum =
31812937Shelge 	    tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
31912937Shelge 	uuc->tu_wbptr = (u_char *)cmd;
32012937Shelge 	uuc->tu_wcnt = sizeof (*cmd);
32112332Shelge 	uuxintr(ctlr);
32211876Shelge }
32311876Shelge 
32411876Shelge /*
325*14091Shelge  * TU58 receiver interrupt, handles whatever condition the
326*14091Shelge  * pseudo DMA routine in locore is unable to handle,
327*14091Shelge  * or, if UUDMA is undefined, handle all receiver interrupt
328*14091Shelge  * processing.
32911876Shelge  */
33012332Shelge uurintr(ctlr)
33112332Shelge 	int ctlr;
33211876Shelge {
33312857Shelge 	struct uba_device *ui = uudinfo[ctlr];
33413014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
33512857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
33612857Shelge 	register struct buf *uutab = &uitab[ctlr];
33712332Shelge 	struct packet *data, *cmd;
33812937Shelge 	struct buf *bp;
33912937Shelge 	int c, unit;
34011876Shelge 
34112857Shelge 	c = uuaddr->rdb;
34212937Shelge 	data = &uudata[ctlr];
34313014Shelge 	cmd = &uucmd[ctlr];
34413014Shelge #if !defined(UUDMA)
34513014Shelge 	if (c & UURDB_ERROR)
34613014Shelge 		uuc->tu_state = TUS_RCVERR;
34713014Shelge 	else {
34813014Shelge 		if (uuc->tu_rcnt) {
34913014Shelge 			*uuc->tu_rbptr++ = c;
35013014Shelge 			if (--uuc->tu_rcnt)
35113014Shelge 				return;
35213014Shelge 		}
35313014Shelge 	}
35413014Shelge #endif
35513014Shelge 
35613014Shelge 	/*
35713014Shelge 	 * Switch on the tu_state of the transfer.
35813014Shelge 	 */
35913014Shelge 	switch(uuc->tu_state) {
36013014Shelge 
36113014Shelge 	/*
36213014Shelge 	 * A data error occured in uudma
36313014Shelge 	 * (either overrun or break)
36413014Shelge 	 */
36513014Shelge 	case TUS_RCVERR:
36613156Shelge 		if ((c & UURDB_ORUN) == 0)
36713156Shelge 			printf("uu%d: break received, transfer restarted\n",
36813834Ssam 			    data->pk_unit);
369*14091Shelge #ifdef UUDEBUG
370*14091Shelge 		else
371*14091Shelge 			printf("uu%d: data overrun, recovered\n",
372*14091Shelge 			    data->pk_unit);
373*14091Shelge #endif
37413156Shelge 		uuc->tu_serrs++;
37513014Shelge 		uu_restart(ctlr, ui);
37613014Shelge 		break;
37711876Shelge 
37811876Shelge 	/*
37911876Shelge 	 * If we get an unexpected "continue",
38011876Shelge 	 * start all over again...
38111876Shelge 	 */
38212937Shelge 	case TUS_INIT2:
38312937Shelge 		uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
38412937Shelge 		uuc->tu_flag = 0;
38512332Shelge 		wakeup((caddr_t)uuc);
38612857Shelge 		uustart(ui);
38711876Shelge 		break;
38811876Shelge 
38911876Shelge 	/*
39011876Shelge 	 * Only transition from this state
39111876Shelge 	 * is on a "continue", so if we don't
39211876Shelge 	 * get it, reset the world.
39311876Shelge 	 */
39412937Shelge 	case TUS_WAIT:			/* waiting for continue */
39512332Shelge 		switch(c) {
39612332Shelge 		case TUF_CONT:  /* got the expected continue */
39712937Shelge 			uuc->tu_flag = 0;
39812332Shelge 			data->pk_flag = TUF_DATA;
39912937Shelge 			data->pk_mcount = MIN(128, uuc->tu_count);
40012332Shelge 			data->pk_chksum =
40112937Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
40212332Shelge 				(int)data->pk_mcount);
40312937Shelge 			uuc->tu_state = TUS_SENDH;
40412937Shelge 			uuc->tu_wbptr = (u_char *)data;
40512937Shelge 			uuc->tu_wcnt = 2;
40612857Shelge 			uuxintr(ctlr);
40711876Shelge 			break;
40812332Shelge 
40912332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
41012937Shelge 			uuc->tu_state = TUS_GET;
41112937Shelge 			uuc->tu_rbptr = (u_char *)data;
41213014Shelge 			uuc->tu_rcnt = sizeof (*data) - 1;
41312937Shelge 			uuc->tu_flag = 1;
41412332Shelge 			uuaddr->tcs = 0;
41513014Shelge 			*uuc->tu_rbptr++ = c & UUDB_DMASK;
41613014Shelge 			break;
41712332Shelge 
41812332Shelge 		case TUF_INITF:
41912857Shelge 			uureset(ctlr);
42012332Shelge 			break;
42112332Shelge 
42212332Shelge 		default:        /* something random...bad news */
42312937Shelge 			uuc->tu_state = TUS_INIT1;
42412332Shelge 			break;
42511876Shelge 		}
42611876Shelge 		break;
42711876Shelge 
42812937Shelge 	case TUS_SENDW:
42912937Shelge 		if (c != TUF_CONT && c != TUF_INITF)
43011876Shelge 			goto bad;
43113014Shelge 		uu_restart(ctlr, ui);
43211876Shelge 		break;
43311876Shelge 
43411876Shelge 	/*
43511876Shelge 	 * Got header, now get data; amount to
43611896Shelge 	 * fetch is included in packet.
43713014Shelge 	 * (data packets are handled entirely
43813014Shelge 	 * in uudma)
43911876Shelge 	 */
44012937Shelge 	case TUS_GETH:
44113156Shelge #ifndef UUDMA
44213156Shelge 		if (data->pk_flag == TUF_DATA)
44313156Shelge 			uuc->tu_rbptr = (u_char *)uuc->tu_addr;
44413156Shelge #endif
44512937Shelge 		uuc->tu_rcnt = data->pk_mcount;
44612937Shelge 		uuc->tu_state = TUS_GETD;
44711876Shelge 		break;
44811876Shelge 
44911876Shelge 	/*
45011876Shelge 	 * Got the data, now fetch the checksum.
45111876Shelge 	 */
45212937Shelge 	case TUS_GETD:
45312937Shelge 		uuc->tu_rbptr = (u_char *)&data->pk_chksum;
45412937Shelge 		uuc->tu_rcnt = sizeof (data->pk_chksum);
45512937Shelge 		uuc->tu_state = TUS_GETC;
45611876Shelge 		break;
45711876Shelge 
45812937Shelge 	case TUS_GETC:
45911876Shelge 		/* got entire packet */
46012332Shelge 		if (data->pk_chksum !=
46112937Shelge 		    tuchk(*((short *)data), (u_short *)
46213014Shelge 		     (data->pk_flag == TUF_DATA ?
46313156Shelge 		     (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
46412332Shelge 		     (int)data->pk_mcount))
46513014Shelge 	case TUS_CHKERR:
46612937Shelge 			uuc->tu_cerrs++;
46713014Shelge 	case TUS_GET:
46812332Shelge 		if (data->pk_flag == TUF_DATA) {
46911876Shelge 			/* data packet, advance to next */
47012937Shelge 			uuc->tu_addr += data->pk_mcount;
47112937Shelge 			uuc->tu_count -= data->pk_mcount;
47212937Shelge 			uuc->tu_state = TUS_GETH;
47312937Shelge 			uuc->tu_rbptr = (u_char *)data;	/* next packet */
47412937Shelge 			uuc->tu_rcnt = 2;
47512332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
47611876Shelge 			/* end packet, idle and reenable transmitter */
47712937Shelge 			uuc->tu_state = TUS_IDLE;
47812937Shelge 			uuc->tu_flag = 0;
47912937Shelge 			uuaddr->tcs = UUCS_INTR;
48012937Shelge 			if ((bp = uutab->b_actf) == NULL) {
48113156Shelge 				printf("uu%d: no bp, active %d\n",
48213834Ssam 				    data->pk_unit, uitab[ctlr].b_active);
48312857Shelge 				uustart(ui);
48411876Shelge 				return;
48511876Shelge 			}
486*14091Shelge 			unit = UNIT(bp->b_dev);
48712332Shelge 			if (data->pk_mod > 1) {        /* hard error */
48813014Shelge 				printf("uu%d: hard error bn%d,", unit,
48913834Ssam 				    bp->b_blkno);
490*14091Shelge 				printf(" pk_mod 0%o\n", data->pk_mod&0xff);
49111876Shelge 				bp->b_flags |= B_ERROR;
49212937Shelge 				uuc->tu_herrs++;
493*14091Shelge 			} else if (data->pk_mod)	/* soft error */
49412937Shelge 				uuc->tu_serrs++;
49512332Shelge 			uutab->b_active = NULL;
496*14091Shelge 			uutab->b_actf = bp->b_actf;
49712937Shelge 			bp->b_resid = uuc->tu_count;
49811876Shelge 			if ((bp->b_flags&B_READ) == 0)
499*14091Shelge 				tu_vee(&uu_pcnt[unit]);
50011876Shelge 			iodone(bp);
50112857Shelge 			uustart(ui);
50211876Shelge 		} else {
50313156Shelge 			/*
50413156Shelge 			 * Neither data nor end: data was lost
505*14091Shelge 			 * somehow, flush and restart the transfer.
50613156Shelge 			 */
507*14091Shelge 			uuaddr->rcs = 0;
50813014Shelge 			uu_restart(ctlr, ui);
50913156Shelge 			uuc->tu_serrs++;
51011876Shelge 		}
51111876Shelge 		break;
51211876Shelge 
51312937Shelge 	case TUS_IDLE:
51412937Shelge 	case TUS_INIT1:
51511876Shelge 		break;
51611876Shelge 
51711876Shelge 	default:
51811876Shelge bad:
51911876Shelge 		if (c == TUF_INITF) {
52013156Shelge 			printf("uu%d protocol error, state=", data->pk_unit);
52112937Shelge 			printstate(uuc->tu_state);
52211876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
52312332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
52412332Shelge 			uutab->b_active = NULL;
52512332Shelge 			if (bp = uutab->b_actf) {
52611876Shelge 				bp->b_flags |= B_ERROR;
527*14091Shelge 				uutab->b_actf = bp->b_actf;
52811876Shelge 				if ((bp->b_flags&B_READ) == 0)
529*14091Shelge 					tu_vee(&uu_pcnt[unit]);
53011876Shelge 				iodone(bp);
53111876Shelge 			}
53212937Shelge 			uuc->tu_state = TUS_INIT1;
53311876Shelge 		} else {
53412332Shelge 			printf("uu%d receive state error, state=",
53513156Shelge 				data->pk_unit);
53612937Shelge 			printstate(uuc->tu_state);
53713014Shelge 			printf(", byte=%x\n", c & 0xff);
53811876Shelge #ifdef notdef
53912937Shelge 			uuc->tu_state = TUS_INIT1;
54011876Shelge #endif
54112332Shelge 			wakeup((caddr_t)uuc);
54211876Shelge 		}
54311876Shelge 	}
54411876Shelge }
54511876Shelge 
54612937Shelge 
54712937Shelge /*
54811876Shelge  * TU58 transmitter interrupt
54911876Shelge  */
55012332Shelge uuxintr(ctlr)
55112332Shelge 	int ctlr;
55211876Shelge {
55313014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
55412857Shelge 	register struct uudevice *uuaddr;
55512332Shelge 	register struct packet *data;
55612857Shelge 	struct uba_device *ui = uudinfo[ctlr];
55712332Shelge 	int c;
55811876Shelge 
55912857Shelge 	data = &uudata[ctlr];
56012857Shelge 	uuaddr = (struct uudevice *) ui->ui_addr;
56111876Shelge top:
562*14091Shelge 	if (uuc->tu_wcnt > 0) {
56311876Shelge 		/* still stuff to send, send one byte */
56412332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
56511876Shelge 			;
56612937Shelge 		uuaddr->tdb = *uuc->tu_wbptr++;
56712937Shelge 		uuc->tu_wcnt--;
56811876Shelge 		return;
56911876Shelge 	}
57011876Shelge 
57111876Shelge 	/*
57211876Shelge 	 * Last message byte was sent out.
57312937Shelge 	 * Switch on tu_state of transfer.
57411876Shelge 	 */
57512937Shelge 	switch(uuc->tu_state) {
57611876Shelge 
57711876Shelge 	/*
57811876Shelge 	 * Two nulls have been sent, remove break, and send inits
57911876Shelge 	 */
58012937Shelge 	case TUS_INIT1:
581*14091Shelge 		uuc->tu_flag = 0;
58212332Shelge 		uuaddr->tcs = UUCS_INTR;
58312937Shelge 		uuc->tu_state = TUS_INIT2;
58412937Shelge 		uuc->tu_wbptr = uuinit;
58512937Shelge 		uuc->tu_wcnt = sizeof (uuinit);
58611876Shelge 		goto top;
58711876Shelge 
58811876Shelge 	/*
58911876Shelge 	 * Inits have been sent, wait for a continue msg.
59011876Shelge 	 */
59112937Shelge 	case TUS_INIT2:
59212857Shelge 		c = uuaddr->rdb;	/* prevent overrun error */
59312332Shelge 		uuaddr->rcs = UUCS_INTR;
59412937Shelge 		uuc->tu_flag = 1;
59511876Shelge 		break;
59611876Shelge 
59711876Shelge 	/*
59811876Shelge 	 * Read cmd packet sent, get ready for data
59911876Shelge 	 */
60012937Shelge 	case TUS_SENDR:
60112937Shelge 		uuc->tu_state = TUS_GETH;
60212937Shelge 		uuc->tu_rbptr = (u_char *)data;
60312937Shelge 		uuc->tu_rcnt = 2;
60412937Shelge 		uuc->tu_flag = 1;
605*14091Shelge 		uuaddr->tcs = 0;
60612937Shelge 		uuaddr->rcs = UUCS_INTR;
60711876Shelge 		break;
60811876Shelge 
60911876Shelge 	/*
61011876Shelge 	 * Write cmd packet sent, wait for continue
61111876Shelge 	 */
61212937Shelge 	case TUS_SENDW:
61312937Shelge 		uuc->tu_state = TUS_WAIT;
61412937Shelge 		uuc->tu_flag = 1;
61512332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
61611876Shelge 			printf("NO IE\n");
61712332Shelge 			uuaddr->rcs = UUCS_INTR;
61811876Shelge 		}
61911876Shelge 		break;
62011876Shelge 
62111876Shelge 	/*
62211876Shelge 	 * Header sent, send data.
62311876Shelge 	 */
62412937Shelge 	case TUS_SENDH:
62512937Shelge 		uuc->tu_state = TUS_SENDD;
62612937Shelge 		uuc->tu_wbptr = (u_char *)uuc->tu_addr;
62712937Shelge 		uuc->tu_wcnt = data->pk_mcount;
62811876Shelge 		goto top;
62911876Shelge 
63011876Shelge 	/*
63111876Shelge 	 * Data sent, follow with checksum.
63211876Shelge 	 */
63312937Shelge 	case TUS_SENDD:
63412937Shelge 		uuc->tu_state = TUS_SENDC;
63512937Shelge 		uuc->tu_wbptr = (u_char *)&data->pk_chksum;
636*14091Shelge 		uuc->tu_wcnt = 2;
63711876Shelge 		goto top;
63811876Shelge 
63911876Shelge 	/*
64011876Shelge 	 * Checksum sent, wait for continue.
64111876Shelge 	 */
64212937Shelge 	case TUS_SENDC:
64311876Shelge 		/*
64412937Shelge 		 * Update buffer address and count.
64511876Shelge 		 */
64612937Shelge 		uuc->tu_addr += data->pk_mcount;
64712937Shelge 		uuc->tu_count -= data->pk_mcount;
648*14091Shelge 		if (uuc->tu_count > 0) {
64912937Shelge 			uuc->tu_state = TUS_WAIT;
65012937Shelge 			uuc->tu_flag = 1;
65111876Shelge 			break;
65211876Shelge 		}
65311876Shelge 
65411876Shelge 		/*
65511876Shelge 		 * End of transmission, get ready for end packet.
65611876Shelge 		 */
65712937Shelge 		uuc->tu_state = TUS_GET;
65812937Shelge 		uuc->tu_rbptr = (u_char *)data;
65912937Shelge 		uuc->tu_rcnt = sizeof (*data);
66012937Shelge 		uuc->tu_flag = 1;
661*14091Shelge 		uuaddr->tcs = 0;
66211876Shelge 		break;
66311876Shelge 
66411876Shelge 	/*
66512332Shelge 	 * Random interrupt
66611876Shelge 	 */
66713156Shelge 	case TUS_IDLE:		/* stray interrupt? */
66813156Shelge 
66911876Shelge 	default:
67011876Shelge 		break;
67111876Shelge 	}
67212937Shelge }
67312937Shelge 
67412937Shelge uuwatch()
67512937Shelge {
67613014Shelge 	register struct uu_softc *uuc;
67712937Shelge 	register struct uudevice *uuaddr;
67812937Shelge 	struct uba_device *ui;
67912937Shelge 	struct buf *bp, *uutab;
68012937Shelge 	int s, ctlr, active = 0;
68112937Shelge 
68212937Shelge 	for (ctlr=0; ctlr<NUU; ctlr++) {
68312937Shelge 		int i;
68412937Shelge 
68512937Shelge 		uuc = &uu_softc[ctlr];
686*14091Shelge 
687*14091Shelge 		if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
688*14091Shelge 			active++;
689*14091Shelge 		if (uuc->tu_flag == 0)
690*14091Shelge 			/*
691*14091Shelge 			 * If no read is in progress
692*14091Shelge 			 * just skip
693*14091Shelge 			 */
694*14091Shelge 			continue;
695*14091Shelge 
69612937Shelge 		ui = uudinfo[ctlr];
69712937Shelge 		uuaddr = (struct uudevice *)ui->ui_addr;
69812937Shelge 		uutab = &uitab[ctlr];
699*14091Shelge 		if (uuc->tu_flag++ < 40)
70012937Shelge 			continue;
70113156Shelge 		printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
702*14091Shelge #ifdef UUDEBUG
70312937Shelge 		printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt,
70413156Shelge 		       uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr,
70513156Shelge 		       uuc->tu_count);
70613834Ssam #endif
707*14091Shelge 		s = splx(UUIPL);
70812937Shelge 		uuc->tu_flag = 0;
70912937Shelge 		i = uuaddr->rdb;		/* dummy */
71012937Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
71112937Shelge 		uuaddr->tcs = UUCS_INTR;
71212937Shelge 		uuc->tu_state = TUS_IDLE;
71312937Shelge 		if (!uutab->b_active) {
71412937Shelge 			wakeup((caddr_t)uuc);
71512937Shelge 			goto retry;
71612937Shelge 		}
71712937Shelge 		if (++uutab->b_errcnt <= 1) {
71812937Shelge 			uustart(ui);
71912937Shelge 			goto retry;
72012937Shelge 		}
72112937Shelge 		if (bp = uutab->b_actf) {
72212937Shelge 			bp->b_flags |= B_ERROR;
72312937Shelge 			if ((bp->b_flags&B_READ) == 0)
724*14091Shelge 				tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
72512937Shelge 			iodone(bp);
72612937Shelge 		}
72712937Shelge retry:
72812937Shelge 		(void) splx(s);
72911876Shelge 	}
73012937Shelge 	if (active)
73112937Shelge 		timeout(uuwatch, (caddr_t)0, hz);
73212937Shelge 	else
73312937Shelge 		uuwstart = 0;
73412937Shelge 	return;
73511876Shelge }
73611876Shelge 
73712937Shelge #if !defined(VAX750) && !defined(VAX730)
73811876Shelge /*
73911876Shelge  * Compute checksum TU58 fashion
74011876Shelge  */
74111876Shelge #ifdef lint
74212937Shelge tuchk(word, cp, n)
74311876Shelge 	register word;
74411876Shelge 	register unsigned short *cp;
74511876Shelge 	int n;
74611876Shelge {
74711876Shelge 	register int c = n >> 1;
74811876Shelge 	register long temp;
74911876Shelge 
75011876Shelge 	do {
75111876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
75211876Shelge 		word += temp;
75311876Shelge 	} while (--c > 0);
75411876Shelge 	if (n & 1)
75511876Shelge 		word += *(unsigned char *)cp;
75611876Shelge 	while (word & 0xffff0000)
75711876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
75811876Shelge 	return (word);
75911876Shelge }
76011876Shelge #else
76112937Shelge tuchk(word0, wp, n)
76211896Shelge 	register int word0;			/* r11 */
76311896Shelge 	register char *wp;			/* r10 */
76411896Shelge 	register int n;				/* r9 */
76511876Shelge {
76611876Shelge 	asm("loop:");
76711896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
76811896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
76911876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
77011896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
77111896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
77211896Shelge 	asm("	addw2	r10,r11");		/* add it in */
77311896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
77411876Shelge 	asm("ok:");
77511896Shelge 	asm("	movl	r11,r0");		/* return sum */
77611876Shelge }
77711876Shelge #endif
77811876Shelge 
779*14091Shelge /*
780*14091Shelge  * Make sure this incredibly slow device
781*14091Shelge  * doesn't eat up all the buffers in the
782*14091Shelge  * system by putting the requesting process
783*14091Shelge  * (remember: this device is 'single-user')
784*14091Shelge  * to sleep if the write-behind queue grows
785*14091Shelge  * larger than NUUQ.
786*14091Shelge  */
78712937Shelge tu_pee(cp)
788*14091Shelge 	char *cp;
78912332Shelge {
79012332Shelge 	register int s;
79112332Shelge 
79212857Shelge 	s = splx(UUIPL);
793*14091Shelge 	if (++(*cp) > NUUQ)
79412332Shelge 		sleep(cp, PRIBIO);
79512332Shelge 	splx(s);
79612332Shelge }
79712332Shelge 
79812937Shelge tu_vee(cp)
799*14091Shelge 	char *cp;
80012332Shelge {
80112332Shelge 	register int s;
80212332Shelge 
80312857Shelge 	s = splx(UUIPL);
804*14091Shelge 	if (--(*cp) <= NUUQ)
80512332Shelge 		wakeup(cp);
80611876Shelge 	splx(s);
80711876Shelge }
80811876Shelge #endif
80912332Shelge 
81012937Shelge uuioctl(dev, cmd, data, flag)
81112937Shelge 	dev_t dev;
81212937Shelge 	caddr_t data;
81312937Shelge {
81412937Shelge 	/*
81513156Shelge 	 * add code to wind/rewind cassette here
81612937Shelge 	 */
81712937Shelge 	return (ENXIO);
81812937Shelge }
81912937Shelge 
82013014Shelge uu_restart(ctlr, ui)
82113014Shelge 	int ctlr;
82213014Shelge 	struct uba_device *ui;
82313014Shelge {
82413014Shelge 	uureset(ctlr);
82513014Shelge 	timeout(uustart, (caddr_t)ui, hz * 3);
82613014Shelge }
827*14091Shelge 
828*14091Shelge #endif
829