xref: /csrg-svn/sys/vax/uba/uu.c (revision 25521)
123359Smckusick /*
223359Smckusick  * Copyright (c) 1982 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*25521Stef  *	@(#)uu.c	6.4 (Berkeley) 11/22/85
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 
3012332Shelge #include "../machine/pte.h"
3111896Shelge 
3217084Sbloom #include "param.h"
3317084Sbloom #include "systm.h"
3417084Sbloom #include "buf.h"
3517084Sbloom #include "conf.h"
3617084Sbloom #include "time.h"
3717084Sbloom #include "kernel.h"
3817084Sbloom #include "errno.h"
3917084Sbloom #include "file.h"
4011876Shelge 
4111876Shelge #include "../vax/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();
96*25521Stef 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*/
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 
12211896Shelge uuattach(ui)
12312857Shelge 	register struct uba_device *ui;
12411896Shelge {
12511896Shelge }
12611896Shelge 
12711896Shelge /*ARGSUSED1*/
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;
13512332Shelge 	int ctlr, unit = UNIT(dev), s;
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);
17011896Shelge 	sleep((caddr_t)uuc, PZERO+1);
17112857Shelge 	uitab[ctlr].b_active = NULL;
17212937Shelge 	if (uuc->tu_state != TUS_IDLE) {
17312937Shelge 		uuc->tu_state = TUS_INIT1;
17412937Shelge 		uuc->tu_dopen[unit&UMASK] = 0;
17512937Shelge 		uuc->tu_rcnt = uuc->tu_wcnt = 0;
17611896Shelge 		uuaddr->rcs = 0;
17711896Shelge 		uuaddr->tcs = 0;
17811896Shelge 		splx(s);
17912937Shelge 		return (EIO);
18011876Shelge 	}
18112937Shelge ok:
18211876Shelge 	splx(s);
18311876Shelge 	return (0);
18411876Shelge }
18511876Shelge 
18614091Shelge /*
18714091Shelge  * Wait for all outstanding IO on this drive
18814091Shelge  * complete, before closing. If both drives on
18914091Shelge  * this controller are idle, mark the controller
19014091Shelge  * `inactive'.
19114091Shelge  */
19214091Shelge 
19311896Shelge uuclose(dev, flag)
19411896Shelge 	dev_t dev;
19511896Shelge 	int flag;
19611876Shelge {
19714091Shelge 	int s, unit = UNIT(dev);
19814091Shelge 	register struct uu_softc *uuc = &uu_softc[unit/NDPC];
19914091Shelge 	struct buf *bp, *last = NULL;
20014091Shelge 	struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr;
20111876Shelge 
20214091Shelge 	s = splx(UUIPL);
20314091Shelge 	while (uu_pcnt[unit])
20414091Shelge 		sleep(&uu_pcnt[unit], PRIBIO);
20514091Shelge 	/*
20614091Shelge 	 * No more writes are pending, scan the
20714091Shelge 	 * buffer queue for oustanding reads from
20814091Shelge 	 * this unit.
20914091Shelge 	 */
21014152Shelge 	for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) {
21114091Shelge 		if (bp->b_dev == dev)
21214091Shelge 			last = bp;
21314152Shelge 	}
21414152Shelge 	if (last) {
21514152Shelge 		last->b_flags |= B_CALL;
21614152Shelge 		last->b_iodone = uuwake;
21714152Shelge 		sleep((caddr_t)last, PRIBIO);
21814152Shelge 	}
21914091Shelge 	uuc->tu_dopen[unit&UMASK] = 0;
22014091Shelge 	if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) {
22114091Shelge 		uuc->tu_flag = 0;
22214091Shelge 		uuaddr->rcs = 0;
22314091Shelge 	}
22414091Shelge 	splx(s);
22511876Shelge }
22611876Shelge 
22714152Shelge uuwake(bp)
22814152Shelge 	struct buf *bp;
22914152Shelge {
23014152Shelge 	wakeup(bp);
23114152Shelge }
23214152Shelge 
23311896Shelge uureset(ctlr)
23411896Shelge 	int ctlr;
23511876Shelge {
23613014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
23712332Shelge 	register struct packet *cmd = &uucmd[ctlr];
23812857Shelge 	struct uba_device *ui = uudinfo[ctlr];
23912857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
24011876Shelge 
24112857Shelge 	uitab[ctlr].b_active++;
24212937Shelge 	uuc->tu_state = TUS_INIT1;
24312937Shelge 	uuc->tu_wbptr = uunull;
24412937Shelge 	uuc->tu_wcnt = sizeof (uunull);
24514091Shelge 	uuc->tu_rcnt = 0;
24611896Shelge 	cmd->pk_flag = TUF_CMD;
24712332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
24811896Shelge 	cmd->pk_mod = 0;
24911896Shelge 	cmd->pk_seq = 0;
25012332Shelge 	cmd->pk_sw = 0;
25111896Shelge 	uuaddr->rcs = 0;
25211896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
25311896Shelge 	uuxintr(ctlr);				/* start output */
25411876Shelge }
25511876Shelge 
25611876Shelge /*
25711876Shelge  * Strategy routine for block I/O
25811876Shelge  */
25911896Shelge uustrategy(bp)
26011876Shelge 	register struct buf *bp;
26111876Shelge {
26212332Shelge 	register struct buf *uutab;
26311896Shelge 	struct uba_device *ui;
26414091Shelge 	int s, unit = UNIT(bp->b_dev);
26511876Shelge 
26614091Shelge 	if ((unit > NUX) || (bp->b_blkno >= NTUBLK))
26711896Shelge 		goto bad;
26812857Shelge 	ui = uudinfo[unit/NDPC];
26911896Shelge 	if (ui == 0 || ui->ui_alive == 0)
27011896Shelge 		goto bad;
27112857Shelge 	uutab = &uitab[unit/NDPC];	/* one request queue per controller */
27213156Shelge 	s = splx(UUIPL);
27312332Shelge 	if ((bp->b_flags&B_READ) == 0)
27414091Shelge 		tu_pee(&uu_pcnt[unit]);
27514091Shelge 	bp->b_actf = NULL;
27612332Shelge 	if (uutab->b_actf == NULL)
27712332Shelge 		uutab->b_actf = bp;
27812332Shelge 	else
27914091Shelge 		uutab->b_actl->b_actf = bp;
28012332Shelge 	uutab->b_actl = bp;
28112332Shelge 	if (uutab->b_active == 0)
28212857Shelge 		uustart(ui);
28311876Shelge 	splx(s);
28411896Shelge 	return;
28511896Shelge 
28611896Shelge bad:
28711896Shelge 	bp->b_flags |= B_ERROR;
28812332Shelge 	bp->b_error = ENXIO;
28911896Shelge 	iodone(bp);
29011896Shelge 	return;
29111876Shelge }
29211876Shelge 
29311876Shelge /*
29411876Shelge  * Start the transfer
29511876Shelge  */
29612857Shelge uustart(ui)
29712857Shelge 	register struct uba_device *ui;
29811876Shelge {
29911876Shelge 	register struct buf *bp;
30013014Shelge 	register struct uu_softc *uuc;
30111896Shelge 	struct packet *cmd;
30214152Shelge 	int ctlr = ui->ui_unit, s;
30311876Shelge 
30412857Shelge 	if ((bp = uitab[ctlr].b_actf) == NULL)
30511876Shelge 		return;
30614152Shelge 	s = splx(UUIPL);
30712937Shelge 	uuc = &uu_softc[ctlr];
30812937Shelge 	if (uuc->tu_state != TUS_IDLE) {
30912332Shelge 		uureset(ctlr);
31014152Shelge 		splx(s);
31111876Shelge 		return;
31211876Shelge 	}
31314091Shelge 	cmd = &uucmd[ctlr];
31412857Shelge 	uitab[ctlr].b_active++;
31512937Shelge 	uitab[ctlr].b_errcnt = 0;
31612937Shelge 	uuc->tu_addr = bp->b_un.b_addr;
31712937Shelge 	uuc->tu_count = cmd->pk_count = bp->b_bcount;
31812937Shelge 	cmd->pk_block = bp->b_blkno;
31912937Shelge 	if (bp->b_flags&B_READ) {
32012937Shelge 		cmd->pk_op = TUOP_READ;
32112937Shelge 		cmd->pk_mod = 0;
32212937Shelge 		uuc->tu_state = TUS_SENDR;
32312937Shelge 	} else {
32412937Shelge 		cmd->pk_op = TUOP_WRITE;
32512937Shelge 		cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
32612937Shelge 		uuc->tu_state = TUS_SENDW;
32712937Shelge 	}
32814091Shelge 	cmd->pk_unit = UNIT(bp->b_dev)&UMASK;
32912332Shelge 	cmd->pk_sw = 0;
33011896Shelge 	cmd->pk_chksum =
33112937Shelge 	    tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
33212937Shelge 	uuc->tu_wbptr = (u_char *)cmd;
33312937Shelge 	uuc->tu_wcnt = sizeof (*cmd);
33412332Shelge 	uuxintr(ctlr);
33514152Shelge 	splx(s);
33611876Shelge }
33711876Shelge 
33811876Shelge /*
33914091Shelge  * TU58 receiver interrupt, handles whatever condition the
34014091Shelge  * pseudo DMA routine in locore is unable to handle,
34114091Shelge  * or, if UUDMA is undefined, handle all receiver interrupt
34214091Shelge  * processing.
34311876Shelge  */
34412332Shelge uurintr(ctlr)
34512332Shelge 	int ctlr;
34611876Shelge {
34712857Shelge 	struct uba_device *ui = uudinfo[ctlr];
34813014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
34912857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
35012857Shelge 	register struct buf *uutab = &uitab[ctlr];
35112332Shelge 	struct packet *data, *cmd;
35212937Shelge 	struct buf *bp;
35312937Shelge 	int c, unit;
35411876Shelge 
35512857Shelge 	c = uuaddr->rdb;
35612937Shelge 	data = &uudata[ctlr];
35713014Shelge 	cmd = &uucmd[ctlr];
35813014Shelge #if !defined(UUDMA)
35913014Shelge 	if (c & UURDB_ERROR)
36013014Shelge 		uuc->tu_state = TUS_RCVERR;
36113014Shelge 	else {
36213014Shelge 		if (uuc->tu_rcnt) {
36313014Shelge 			*uuc->tu_rbptr++ = c;
36413014Shelge 			if (--uuc->tu_rcnt)
36513014Shelge 				return;
36613014Shelge 		}
36713014Shelge 	}
36813014Shelge #endif
36913014Shelge 
37013014Shelge 	/*
37113014Shelge 	 * Switch on the tu_state of the transfer.
37213014Shelge 	 */
37313014Shelge 	switch(uuc->tu_state) {
37413014Shelge 
37513014Shelge 	/*
37613014Shelge 	 * A data error occured in uudma
37713014Shelge 	 * (either overrun or break)
37813014Shelge 	 */
37913014Shelge 	case TUS_RCVERR:
38013156Shelge 		if ((c & UURDB_ORUN) == 0)
38113156Shelge 			printf("uu%d: break received, transfer restarted\n",
38213834Ssam 			    data->pk_unit);
38314091Shelge #ifdef UUDEBUG
38414091Shelge 		else
38514091Shelge 			printf("uu%d: data overrun, recovered\n",
38614091Shelge 			    data->pk_unit);
38714091Shelge #endif
38813156Shelge 		uuc->tu_serrs++;
38913014Shelge 		uu_restart(ctlr, ui);
39013014Shelge 		break;
39111876Shelge 
39211876Shelge 	/*
39311876Shelge 	 * If we get an unexpected "continue",
39411876Shelge 	 * start all over again...
39511876Shelge 	 */
39612937Shelge 	case TUS_INIT2:
39712937Shelge 		uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
39812937Shelge 		uuc->tu_flag = 0;
39912332Shelge 		wakeup((caddr_t)uuc);
40012857Shelge 		uustart(ui);
40111876Shelge 		break;
40211876Shelge 
40311876Shelge 	/*
40411876Shelge 	 * Only transition from this state
40511876Shelge 	 * is on a "continue", so if we don't
40611876Shelge 	 * get it, reset the world.
40711876Shelge 	 */
40812937Shelge 	case TUS_WAIT:			/* waiting for continue */
40912332Shelge 		switch(c) {
41012332Shelge 		case TUF_CONT:  /* got the expected continue */
41112937Shelge 			uuc->tu_flag = 0;
41212332Shelge 			data->pk_flag = TUF_DATA;
41312937Shelge 			data->pk_mcount = MIN(128, uuc->tu_count);
41412332Shelge 			data->pk_chksum =
41512937Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
41612332Shelge 				(int)data->pk_mcount);
41712937Shelge 			uuc->tu_state = TUS_SENDH;
41812937Shelge 			uuc->tu_wbptr = (u_char *)data;
41912937Shelge 			uuc->tu_wcnt = 2;
42012857Shelge 			uuxintr(ctlr);
42111876Shelge 			break;
42212332Shelge 
42312332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
42412937Shelge 			uuc->tu_state = TUS_GET;
42512937Shelge 			uuc->tu_rbptr = (u_char *)data;
42613014Shelge 			uuc->tu_rcnt = sizeof (*data) - 1;
42712937Shelge 			uuc->tu_flag = 1;
42812332Shelge 			uuaddr->tcs = 0;
42913014Shelge 			*uuc->tu_rbptr++ = c & UUDB_DMASK;
43013014Shelge 			break;
43112332Shelge 
43212332Shelge 		case TUF_INITF:
43312857Shelge 			uureset(ctlr);
43412332Shelge 			break;
43512332Shelge 
43612332Shelge 		default:        /* something random...bad news */
43712937Shelge 			uuc->tu_state = TUS_INIT1;
43812332Shelge 			break;
43911876Shelge 		}
44011876Shelge 		break;
44111876Shelge 
44212937Shelge 	case TUS_SENDW:
44312937Shelge 		if (c != TUF_CONT && c != TUF_INITF)
44411876Shelge 			goto bad;
44513014Shelge 		uu_restart(ctlr, ui);
44611876Shelge 		break;
44711876Shelge 
44811876Shelge 	/*
44911876Shelge 	 * Got header, now get data; amount to
45011896Shelge 	 * fetch is included in packet.
45113014Shelge 	 * (data packets are handled entirely
45213014Shelge 	 * in uudma)
45311876Shelge 	 */
45412937Shelge 	case TUS_GETH:
45513156Shelge #ifndef UUDMA
45613156Shelge 		if (data->pk_flag == TUF_DATA)
45713156Shelge 			uuc->tu_rbptr = (u_char *)uuc->tu_addr;
45813156Shelge #endif
45912937Shelge 		uuc->tu_rcnt = data->pk_mcount;
46012937Shelge 		uuc->tu_state = TUS_GETD;
46111876Shelge 		break;
46211876Shelge 
46311876Shelge 	/*
46411876Shelge 	 * Got the data, now fetch the checksum.
46511876Shelge 	 */
46612937Shelge 	case TUS_GETD:
46712937Shelge 		uuc->tu_rbptr = (u_char *)&data->pk_chksum;
46812937Shelge 		uuc->tu_rcnt = sizeof (data->pk_chksum);
46912937Shelge 		uuc->tu_state = TUS_GETC;
47011876Shelge 		break;
47111876Shelge 
47212937Shelge 	case TUS_GETC:
47311876Shelge 		/* got entire packet */
47412332Shelge 		if (data->pk_chksum !=
47512937Shelge 		    tuchk(*((short *)data), (u_short *)
47613014Shelge 		     (data->pk_flag == TUF_DATA ?
47713156Shelge 		     (u_short *) uuc->tu_addr : (u_short *)&data->pk_op),
47812332Shelge 		     (int)data->pk_mcount))
47913014Shelge 	case TUS_CHKERR:
48012937Shelge 			uuc->tu_cerrs++;
48113014Shelge 	case TUS_GET:
48212332Shelge 		if (data->pk_flag == TUF_DATA) {
48311876Shelge 			/* data packet, advance to next */
48412937Shelge 			uuc->tu_addr += data->pk_mcount;
48512937Shelge 			uuc->tu_count -= data->pk_mcount;
48612937Shelge 			uuc->tu_state = TUS_GETH;
48712937Shelge 			uuc->tu_rbptr = (u_char *)data;	/* next packet */
48812937Shelge 			uuc->tu_rcnt = 2;
48912332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
49011876Shelge 			/* end packet, idle and reenable transmitter */
49112937Shelge 			uuc->tu_state = TUS_IDLE;
49212937Shelge 			uuc->tu_flag = 0;
49312937Shelge 			uuaddr->tcs = UUCS_INTR;
49412937Shelge 			if ((bp = uutab->b_actf) == NULL) {
49513156Shelge 				printf("uu%d: no bp, active %d\n",
49613834Ssam 				    data->pk_unit, uitab[ctlr].b_active);
49712857Shelge 				uustart(ui);
49811876Shelge 				return;
49911876Shelge 			}
50014091Shelge 			unit = UNIT(bp->b_dev);
50112332Shelge 			if (data->pk_mod > 1) {        /* hard error */
50213014Shelge 				printf("uu%d: hard error bn%d,", unit,
50313834Ssam 				    bp->b_blkno);
50414091Shelge 				printf(" pk_mod 0%o\n", data->pk_mod&0xff);
50511876Shelge 				bp->b_flags |= B_ERROR;
50612937Shelge 				uuc->tu_herrs++;
50714091Shelge 			} else if (data->pk_mod)	/* soft error */
50812937Shelge 				uuc->tu_serrs++;
50912332Shelge 			uutab->b_active = NULL;
51014091Shelge 			uutab->b_actf = bp->b_actf;
51112937Shelge 			bp->b_resid = uuc->tu_count;
51211876Shelge 			if ((bp->b_flags&B_READ) == 0)
51314091Shelge 				tu_vee(&uu_pcnt[unit]);
51411876Shelge 			iodone(bp);
51512857Shelge 			uustart(ui);
51611876Shelge 		} else {
51713156Shelge 			/*
51813156Shelge 			 * Neither data nor end: data was lost
51914091Shelge 			 * somehow, flush and restart the transfer.
52013156Shelge 			 */
52114091Shelge 			uuaddr->rcs = 0;
52213014Shelge 			uu_restart(ctlr, ui);
52313156Shelge 			uuc->tu_serrs++;
52411876Shelge 		}
52511876Shelge 		break;
52611876Shelge 
52712937Shelge 	case TUS_IDLE:
52812937Shelge 	case TUS_INIT1:
52911876Shelge 		break;
53011876Shelge 
53111876Shelge 	default:
53211876Shelge bad:
53311876Shelge 		if (c == TUF_INITF) {
53413156Shelge 			printf("uu%d protocol error, state=", data->pk_unit);
53512937Shelge 			printstate(uuc->tu_state);
53611876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
53712332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
53812332Shelge 			uutab->b_active = NULL;
53912332Shelge 			if (bp = uutab->b_actf) {
54011876Shelge 				bp->b_flags |= B_ERROR;
54114091Shelge 				uutab->b_actf = bp->b_actf;
54211876Shelge 				if ((bp->b_flags&B_READ) == 0)
54314091Shelge 					tu_vee(&uu_pcnt[unit]);
54411876Shelge 				iodone(bp);
54511876Shelge 			}
54612937Shelge 			uuc->tu_state = TUS_INIT1;
54711876Shelge 		} else {
54812332Shelge 			printf("uu%d receive state error, state=",
54913156Shelge 				data->pk_unit);
55012937Shelge 			printstate(uuc->tu_state);
55113014Shelge 			printf(", byte=%x\n", c & 0xff);
55211876Shelge #ifdef notdef
55312937Shelge 			uuc->tu_state = TUS_INIT1;
55411876Shelge #endif
55512332Shelge 			wakeup((caddr_t)uuc);
55611876Shelge 		}
55711876Shelge 	}
55811876Shelge }
55911876Shelge 
56012937Shelge 
56112937Shelge /*
56211876Shelge  * TU58 transmitter interrupt
56311876Shelge  */
56412332Shelge uuxintr(ctlr)
56512332Shelge 	int ctlr;
56611876Shelge {
56713014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
56812857Shelge 	register struct uudevice *uuaddr;
56912332Shelge 	register struct packet *data;
57012857Shelge 	struct uba_device *ui = uudinfo[ctlr];
57112332Shelge 	int c;
57211876Shelge 
57312857Shelge 	data = &uudata[ctlr];
57412857Shelge 	uuaddr = (struct uudevice *) ui->ui_addr;
57511876Shelge top:
57614091Shelge 	if (uuc->tu_wcnt > 0) {
57711876Shelge 		/* still stuff to send, send one byte */
57812332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
57911876Shelge 			;
58012937Shelge 		uuaddr->tdb = *uuc->tu_wbptr++;
58112937Shelge 		uuc->tu_wcnt--;
58211876Shelge 		return;
58311876Shelge 	}
58411876Shelge 
58511876Shelge 	/*
58611876Shelge 	 * Last message byte was sent out.
58712937Shelge 	 * Switch on tu_state of transfer.
58811876Shelge 	 */
58912937Shelge 	switch(uuc->tu_state) {
59011876Shelge 
59111876Shelge 	/*
59211876Shelge 	 * Two nulls have been sent, remove break, and send inits
59311876Shelge 	 */
59412937Shelge 	case TUS_INIT1:
59514091Shelge 		uuc->tu_flag = 0;
59612332Shelge 		uuaddr->tcs = UUCS_INTR;
59712937Shelge 		uuc->tu_state = TUS_INIT2;
59812937Shelge 		uuc->tu_wbptr = uuinit;
59912937Shelge 		uuc->tu_wcnt = sizeof (uuinit);
60011876Shelge 		goto top;
60111876Shelge 
60211876Shelge 	/*
60311876Shelge 	 * Inits have been sent, wait for a continue msg.
60411876Shelge 	 */
60512937Shelge 	case TUS_INIT2:
60612857Shelge 		c = uuaddr->rdb;	/* prevent overrun error */
60712332Shelge 		uuaddr->rcs = UUCS_INTR;
60812937Shelge 		uuc->tu_flag = 1;
60911876Shelge 		break;
61011876Shelge 
61111876Shelge 	/*
61211876Shelge 	 * Read cmd packet sent, get ready for data
61311876Shelge 	 */
61412937Shelge 	case TUS_SENDR:
61512937Shelge 		uuc->tu_state = TUS_GETH;
61612937Shelge 		uuc->tu_rbptr = (u_char *)data;
61712937Shelge 		uuc->tu_rcnt = 2;
61812937Shelge 		uuc->tu_flag = 1;
61914091Shelge 		uuaddr->tcs = 0;
62012937Shelge 		uuaddr->rcs = UUCS_INTR;
62111876Shelge 		break;
62211876Shelge 
62311876Shelge 	/*
62411876Shelge 	 * Write cmd packet sent, wait for continue
62511876Shelge 	 */
62612937Shelge 	case TUS_SENDW:
62712937Shelge 		uuc->tu_state = TUS_WAIT;
62812937Shelge 		uuc->tu_flag = 1;
62912332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
63011876Shelge 			printf("NO IE\n");
63112332Shelge 			uuaddr->rcs = UUCS_INTR;
63211876Shelge 		}
63311876Shelge 		break;
63411876Shelge 
63511876Shelge 	/*
63611876Shelge 	 * Header sent, send data.
63711876Shelge 	 */
63812937Shelge 	case TUS_SENDH:
63912937Shelge 		uuc->tu_state = TUS_SENDD;
64012937Shelge 		uuc->tu_wbptr = (u_char *)uuc->tu_addr;
64112937Shelge 		uuc->tu_wcnt = data->pk_mcount;
64211876Shelge 		goto top;
64311876Shelge 
64411876Shelge 	/*
64511876Shelge 	 * Data sent, follow with checksum.
64611876Shelge 	 */
64712937Shelge 	case TUS_SENDD:
64812937Shelge 		uuc->tu_state = TUS_SENDC;
64912937Shelge 		uuc->tu_wbptr = (u_char *)&data->pk_chksum;
65014091Shelge 		uuc->tu_wcnt = 2;
65111876Shelge 		goto top;
65211876Shelge 
65311876Shelge 	/*
65411876Shelge 	 * Checksum sent, wait for continue.
65511876Shelge 	 */
65612937Shelge 	case TUS_SENDC:
65711876Shelge 		/*
65812937Shelge 		 * Update buffer address and count.
65911876Shelge 		 */
66012937Shelge 		uuc->tu_addr += data->pk_mcount;
66112937Shelge 		uuc->tu_count -= data->pk_mcount;
66214091Shelge 		if (uuc->tu_count > 0) {
66312937Shelge 			uuc->tu_state = TUS_WAIT;
66412937Shelge 			uuc->tu_flag = 1;
66511876Shelge 			break;
66611876Shelge 		}
66711876Shelge 
66811876Shelge 		/*
66911876Shelge 		 * End of transmission, get ready for end packet.
67011876Shelge 		 */
67112937Shelge 		uuc->tu_state = TUS_GET;
67212937Shelge 		uuc->tu_rbptr = (u_char *)data;
67312937Shelge 		uuc->tu_rcnt = sizeof (*data);
67412937Shelge 		uuc->tu_flag = 1;
67514091Shelge 		uuaddr->tcs = 0;
67611876Shelge 		break;
67711876Shelge 
67811876Shelge 	/*
67912332Shelge 	 * Random interrupt
68011876Shelge 	 */
68113156Shelge 	case TUS_IDLE:		/* stray interrupt? */
68213156Shelge 
68311876Shelge 	default:
68411876Shelge 		break;
68511876Shelge 	}
68612937Shelge }
68712937Shelge 
68812937Shelge uuwatch()
68912937Shelge {
69013014Shelge 	register struct uu_softc *uuc;
69112937Shelge 	register struct uudevice *uuaddr;
69212937Shelge 	struct uba_device *ui;
69312937Shelge 	struct buf *bp, *uutab;
69412937Shelge 	int s, ctlr, active = 0;
69512937Shelge 
69612937Shelge 	for (ctlr=0; ctlr<NUU; ctlr++) {
69712937Shelge 		int i;
69812937Shelge 
69912937Shelge 		uuc = &uu_softc[ctlr];
70014091Shelge 
70114091Shelge 		if (uuc->tu_dopen[0] || uuc->tu_dopen[1])
70214091Shelge 			active++;
70314091Shelge 		if (uuc->tu_flag == 0)
70414091Shelge 			/*
70514091Shelge 			 * If no read is in progress
70614091Shelge 			 * just skip
70714091Shelge 			 */
70814091Shelge 			continue;
70914091Shelge 
71012937Shelge 		ui = uudinfo[ctlr];
71112937Shelge 		uuaddr = (struct uudevice *)ui->ui_addr;
71212937Shelge 		uutab = &uitab[ctlr];
71314091Shelge 		if (uuc->tu_flag++ < 40)
71412937Shelge 			continue;
71513156Shelge 		printf("uu%d: read stalled\n", uudata[ctlr].pk_unit);
71614091Shelge #ifdef UUDEBUG
71712937Shelge 		printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt,
71813156Shelge 		       uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr,
71913156Shelge 		       uuc->tu_count);
72013834Ssam #endif
72114091Shelge 		s = splx(UUIPL);
72212937Shelge 		uuc->tu_flag = 0;
72312937Shelge 		i = uuaddr->rdb;		/* dummy */
72412937Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
72512937Shelge 		uuaddr->tcs = UUCS_INTR;
72612937Shelge 		uuc->tu_state = TUS_IDLE;
72712937Shelge 		if (!uutab->b_active) {
72812937Shelge 			wakeup((caddr_t)uuc);
72912937Shelge 			goto retry;
73012937Shelge 		}
73112937Shelge 		if (++uutab->b_errcnt <= 1) {
73212937Shelge 			uustart(ui);
73312937Shelge 			goto retry;
73412937Shelge 		}
73512937Shelge 		if (bp = uutab->b_actf) {
73612937Shelge 			bp->b_flags |= B_ERROR;
73712937Shelge 			if ((bp->b_flags&B_READ) == 0)
73814091Shelge 				tu_vee(&uu_pcnt[UNIT(bp->b_dev)]);
73912937Shelge 			iodone(bp);
74012937Shelge 		}
74112937Shelge retry:
74212937Shelge 		(void) splx(s);
74311876Shelge 	}
74412937Shelge 	if (active)
74512937Shelge 		timeout(uuwatch, (caddr_t)0, hz);
74612937Shelge 	else
74712937Shelge 		uuwstart = 0;
74812937Shelge 	return;
74911876Shelge }
75011876Shelge 
75112937Shelge #if !defined(VAX750) && !defined(VAX730)
75211876Shelge /*
75311876Shelge  * Compute checksum TU58 fashion
75411876Shelge  */
75511876Shelge #ifdef lint
75612937Shelge tuchk(word, cp, n)
75711876Shelge 	register word;
75811876Shelge 	register unsigned short *cp;
75911876Shelge 	int n;
76011876Shelge {
76111876Shelge 	register int c = n >> 1;
76211876Shelge 	register long temp;
76311876Shelge 
76411876Shelge 	do {
76511876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
76611876Shelge 		word += temp;
76711876Shelge 	} while (--c > 0);
76811876Shelge 	if (n & 1)
76911876Shelge 		word += *(unsigned char *)cp;
77011876Shelge 	while (word & 0xffff0000)
77111876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
77211876Shelge 	return (word);
77311876Shelge }
77411876Shelge #else
77512937Shelge tuchk(word0, wp, n)
77611896Shelge 	register int word0;			/* r11 */
77711896Shelge 	register char *wp;			/* r10 */
77811896Shelge 	register int n;				/* r9 */
77911876Shelge {
78011876Shelge 	asm("loop:");
78111896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
78211896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
78311876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
78411896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
78511896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
78611896Shelge 	asm("	addw2	r10,r11");		/* add it in */
78711896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
78811876Shelge 	asm("ok:");
78911896Shelge 	asm("	movl	r11,r0");		/* return sum */
79011876Shelge }
79111876Shelge #endif
79211876Shelge 
79314091Shelge /*
79414091Shelge  * Make sure this incredibly slow device
79514091Shelge  * doesn't eat up all the buffers in the
79614091Shelge  * system by putting the requesting process
79714091Shelge  * (remember: this device is 'single-user')
79814091Shelge  * to sleep if the write-behind queue grows
79914091Shelge  * larger than NUUQ.
80014091Shelge  */
80112937Shelge tu_pee(cp)
80214091Shelge 	char *cp;
80312332Shelge {
80412332Shelge 	register int s;
80512332Shelge 
80612857Shelge 	s = splx(UUIPL);
80714091Shelge 	if (++(*cp) > NUUQ)
80812332Shelge 		sleep(cp, PRIBIO);
80912332Shelge 	splx(s);
81012332Shelge }
81112332Shelge 
81212937Shelge tu_vee(cp)
81314091Shelge 	char *cp;
81412332Shelge {
81512332Shelge 	register int s;
81612332Shelge 
81712857Shelge 	s = splx(UUIPL);
81814091Shelge 	if (--(*cp) <= NUUQ)
81912332Shelge 		wakeup(cp);
82011876Shelge 	splx(s);
82111876Shelge }
82211876Shelge #endif
82312332Shelge 
82412937Shelge uuioctl(dev, cmd, data, flag)
82512937Shelge 	dev_t dev;
82612937Shelge 	caddr_t data;
82712937Shelge {
82812937Shelge 	/*
82913156Shelge 	 * add code to wind/rewind cassette here
83012937Shelge 	 */
83112937Shelge 	return (ENXIO);
83212937Shelge }
83312937Shelge 
83413014Shelge uu_restart(ctlr, ui)
83513014Shelge 	int ctlr;
83613014Shelge 	struct uba_device *ui;
83713014Shelge {
83813014Shelge 	uureset(ctlr);
83913014Shelge 	timeout(uustart, (caddr_t)ui, hz * 3);
84013014Shelge }
84114091Shelge 
84214091Shelge #endif
843