xref: /csrg-svn/sys/vax/uba/uu.c (revision 13014)
1*13014Shelge /*	uu.c	4.6	83/06/11	*/
211876Shelge 
312332Shelge #include "uu.h"
412857Shelge #if NUU > 0
511876Shelge /*
611896Shelge  * TU58 DECtape II/DL11 device driver
711876Shelge  *
811896Shelge  * The TU58 * is treated as a block device (only).  Error detection and
911876Shelge  * recovery is almost non-existant.  It is assumed that the
1011876Shelge  * TU58 will follow the RSP protocol exactly, very few protocol
1111896Shelge  * errors are checked for.
1211876Shelge  */
1311896Shelge 
1412332Shelge #include "../machine/pte.h"
1511896Shelge 
1611876Shelge #include "../h/param.h"
1711876Shelge #include "../h/systm.h"
1811876Shelge #include "../h/buf.h"
1911876Shelge #include "../h/conf.h"
2012332Shelge #include "../h/time.h"
2111896Shelge #include "../h/kernel.h"
2211896Shelge #include "../h/errno.h"
2311896Shelge #include "../h/uio.h"
2411896Shelge #include "../h/file.h"
2511876Shelge 
2611876Shelge #include "../vax/cpu.h"
2712332Shelge #include "../vax/nexus.h"
2812937Shelge #include "../vax/rsp.h"
2912332Shelge 
3011896Shelge #include "../vaxuba/ubavar.h"
3111896Shelge #include "../vaxuba/ubareg.h"
3211896Shelge #include "../vaxuba/uureg.h"
3311876Shelge 
3411876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
3512857Shelge #define	WRV     01              /* bit in minor dev => write w. read verify */
3612332Shelge #define	NDPC	02		/* drives per controller */
3712857Shelge #define	NUX	NDPC * NUU	/* number of drives */
3812332Shelge #define	NTUQ	02		/* # of block which can be queued up */
3912857Shelge #define	UMASK	01		/* unit number mask */
4012937Shelge #define UUIPL	0x14		/* ipl level to use */
4111876Shelge 
4212857Shelge struct packet uucmd[NUU];	/* a command sent to the TU58 */
4312857Shelge struct packet uudata[NUU];	/* a command or data returned from TU58 */
4412857Shelge struct buf uitab[NUU];		/* buffer queue headers */
4511876Shelge 
4611876Shelge /*
4712937Shelge  * Driver soft carrier structure
4811876Shelge  */
4912937Shelge struct uu_softc {
5012937Shelge 	u_char	*tu_rbptr;	/* pointer to buffer for read */
5112937Shelge 	int	tu_rcnt;	/* how much to read */
5212937Shelge 	u_char	*tu_wbptr;	/* pointer to buffer for write */
5312937Shelge 	int	tu_wcnt;	/* how much to write */
5412937Shelge 	int	tu_state;	/* current state of tansfer operation */
5512937Shelge 	int	tu_flag;	/* read in progress flag */
5612937Shelge 	char	*tu_addr;	/* real buffer data address */
5712937Shelge 	int	tu_count;	/* real requested count */
5812937Shelge 	int	tu_serrs;	/* count of soft errors */
5912937Shelge 	int	tu_cerrs;	/* count of checksum errors */
6012937Shelge 	int	tu_herrs;	/* count of hard errors */
6112937Shelge 	char    tu_dopen[2];	/* drive is open */
62*13014Shelge } uu_softc[NUU];
6311876Shelge 
6412937Shelge #if defined(VAX750) || defined(VAX730)
6512937Shelge extern char *tustates[];
6612937Shelge #else
6712937Shelge char *tustates[TUS_NSTATES] = {
6811876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
69*13014Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
7011876Shelge };
7112937Shelge #endif
7212332Shelge 
7312857Shelge #define	UNIT(dev)	(minor(dev)>>1)
7411876Shelge 
7511896Shelge u_char	uunull[2] = { 0, 0 };	/* nulls to send for initialization */
7611896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
7711876Shelge 
7811896Shelge struct	uba_device	*uudinfo[NUU];
7911896Shelge 
8012857Shelge int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
8112857Shelge u_short uustd[] = { 0176500 };
8212857Shelge struct uba_driver uudriver =
8312857Shelge     { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
8411896Shelge 
8511896Shelge int	uuwstart;
8612937Shelge static char pcnt[NUX];			/* pee/vee counters, one per drive */
8711896Shelge 
8811876Shelge /*ARGSUSED*/
8911896Shelge uuprobe(reg)
9011896Shelge 	caddr_t reg;
9111876Shelge {
9211896Shelge 	register int br, cvec;			/* value result */
9311896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
9411876Shelge 
9511876Shelge #ifdef lint
9611896Shelge 	br = 0; cvec = br; br = cvec;
9711896Shelge 	uurintr(0); uuxintr(0);
9811876Shelge #endif
9912857Shelge 	uuaddr->tcs = UUCS_INTR;
10012857Shelge 	DELAY(1000);
10112857Shelge 	uuaddr->tcs = 0;
10212857Shelge 	cvec -= 4;		/* since we are using the xmitter intrpt */
10311896Shelge 	return(sizeof (*uuaddr));
10411896Shelge }
10511896Shelge 
10611896Shelge uuattach(ui)
10712857Shelge 	register struct uba_device *ui;
10811896Shelge {
10911896Shelge }
11011896Shelge 
11111896Shelge /*ARGSUSED1*/
11211896Shelge uuopen(dev, flag)
11311896Shelge 	dev_t dev;
11411896Shelge 	int flag;
11511896Shelge {
11611896Shelge 	register struct uba_device *ui;
117*13014Shelge 	register struct uu_softc *uuc;
11811896Shelge 	register struct uudevice *uuaddr;
11912332Shelge 	int ctlr, unit = UNIT(dev), s;
12011896Shelge 
12112857Shelge 	ctlr = unit / NDPC;
12212857Shelge 	if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
12311876Shelge 		return (ENXIO);
12412937Shelge 	uuc = &uu_softc[ctlr];
12512937Shelge 	if (uuc->tu_dopen[unit&UMASK])
12611896Shelge 		return (EBUSY);
12711896Shelge 	if (uuwstart++ == 0)
12811896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
12911896Shelge 
13012937Shelge 	uuc->tu_dopen[unit&UMASK]++;
13112857Shelge 	uuaddr = (struct uudevice *)ui->ui_addr;
13212857Shelge 	s = splx(UUIPL);
13311876Shelge 	/*
134*13014Shelge 	 * If the other device on this controller
135*13014Shelge 	 * is already active, just return
136*13014Shelge 	 */
137*13014Shelge 	if (uuc->tu_dopen[0] && uuc->tu_dopen[1])
138*13014Shelge 		return;
139*13014Shelge 
140*13014Shelge 	/*
14111896Shelge 	 * If the unit already initialized,
14211876Shelge 	 * just enable interrupts and return.
14311876Shelge 	 */
14412937Shelge 	if (uuc->tu_state == TUS_IDLE) {
14511896Shelge 		uuaddr->rcs = UUCS_INTR;
14612937Shelge 		goto ok;
14711876Shelge 	}
14811876Shelge 
14911876Shelge 	/*
15011876Shelge 	 * Must initialize, reset the cassette
15111876Shelge 	 * and wait for things to settle down.
15211876Shelge 	 */
15311896Shelge 	uureset(ctlr);
15411896Shelge 	sleep((caddr_t)uuc, PZERO+1);
15512857Shelge 	uitab[ctlr].b_active = NULL;
15612937Shelge 	if (uuc->tu_state != TUS_IDLE) {
15712937Shelge 		uuc->tu_state = TUS_INIT1;
15812937Shelge 		uuc->tu_dopen[unit&UMASK] = 0;
15912937Shelge 		uuc->tu_rcnt = uuc->tu_wcnt = 0;
16011896Shelge 		uuaddr->rcs = 0;
16111896Shelge 		uuaddr->tcs = 0;
16211896Shelge 		splx(s);
16312937Shelge 		return (EIO);
16411876Shelge 	}
16512937Shelge ok:
16611876Shelge 	splx(s);
16711876Shelge 	return (0);
16811876Shelge }
16911876Shelge 
17011896Shelge uuclose(dev, flag)
17111896Shelge 	dev_t dev;
17211896Shelge 	int flag;
17311876Shelge {
174*13014Shelge 	register struct uu_softc *uuc;
17512857Shelge 	int unit = UNIT(dev);
17612937Shelge 	int ctlr = unit/NDPC;
17711876Shelge 
17812937Shelge 	uuc = &uu_softc[ctlr];
17912937Shelge 	if (uuc->tu_serrs + uuc->tu_cerrs + uuc->tu_herrs != 0) {
18011876Shelge 		/*
18111876Shelge 		 * A tu58 is like nothing ever seen before;
18211876Shelge 		 * I guess this is appropriate then...
18311876Shelge 		 */
18411876Shelge 		uprintf(
18512857Shelge 		   "uu%d: %d soft errors, %d checksum errors, %d hard errors\n",
18612937Shelge 		    unit, uuc->tu_serrs, uuc->tu_cerrs, uuc->tu_herrs);
18712937Shelge 		    uuc->tu_serrs = uuc->tu_cerrs = uuc->tu_herrs = 0;
18811876Shelge 	}
18912937Shelge 	uuc->tu_dopen[unit&UMASK] = 0;
19011876Shelge }
19111876Shelge 
19211896Shelge uureset(ctlr)
19311896Shelge 	int ctlr;
19411876Shelge {
195*13014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
19612332Shelge 	register struct packet *cmd = &uucmd[ctlr];
19712857Shelge 	struct uba_device *ui = uudinfo[ctlr];
19812857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
19911876Shelge 
20012857Shelge 	uitab[ctlr].b_active++;
20112937Shelge 	uuc->tu_state = TUS_INIT1;
20212937Shelge 	uuc->tu_wbptr = uunull;
20312937Shelge 	uuc->tu_wcnt = sizeof (uunull);
20411896Shelge 	cmd->pk_flag = TUF_CMD;
20512332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
20611896Shelge 	cmd->pk_mod = 0;
20711896Shelge 	cmd->pk_seq = 0;
20812332Shelge 	cmd->pk_sw = 0;
20911896Shelge 	uuaddr->rcs = 0;
21011896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
21111896Shelge 	uuxintr(ctlr);				/* start output */
21211876Shelge }
21311876Shelge 
21411876Shelge /*
21511876Shelge  * Strategy routine for block I/O
21611876Shelge  */
21711896Shelge uustrategy(bp)
21811876Shelge 	register struct buf *bp;
21911876Shelge {
22012332Shelge 	register struct buf *uutab;
22111896Shelge 	struct uba_device *ui;
22212857Shelge 	int s, unit = UNIT(minor(bp->b_dev));
22311876Shelge 
22412857Shelge 	if (unit > NUX)
22511896Shelge 		goto bad;
22611896Shelge 	if (bp->b_blkno >= NTUBLK)
22711896Shelge 		goto bad;
22812857Shelge 	ui = uudinfo[unit/NDPC];
22911896Shelge 	if (ui == 0 || ui->ui_alive == 0)
23011896Shelge 		goto bad;
23112857Shelge 	uutab = &uitab[unit/NDPC];	/* one request queue per controller */
23212332Shelge 	if ((bp->b_flags&B_READ) == 0)
23312937Shelge 		tu_pee(&pcnt[unit]);
23412857Shelge 	s = splx(UUIPL);
23512937Shelge 	bp->av_forw = NULL;
23612332Shelge 	if (uutab->b_actf == NULL)
23712332Shelge 		uutab->b_actf = bp;
23812332Shelge 	else
23912937Shelge 		uutab->b_actl->av_forw = bp;
24012332Shelge 	uutab->b_actl = bp;
24112332Shelge 	if (uutab->b_active == 0)
24212857Shelge 		uustart(ui);
24311876Shelge 	splx(s);
24411896Shelge 	return;
24511896Shelge 
24611896Shelge bad:
24711896Shelge 	bp->b_flags |= B_ERROR;
24812332Shelge 	bp->b_error = ENXIO;
24911896Shelge 	iodone(bp);
25011896Shelge 	return;
25111876Shelge }
25211876Shelge 
25311876Shelge /*
25411876Shelge  * Start the transfer
25511876Shelge  */
25612857Shelge uustart(ui)
25712857Shelge 	register struct uba_device *ui;
25811876Shelge {
25911876Shelge 	register struct buf *bp;
260*13014Shelge 	register struct uu_softc *uuc;
26111896Shelge 	struct packet *cmd;
26212857Shelge 	int ctlr = ui->ui_unit;
26311876Shelge 
26412857Shelge 	if ((bp = uitab[ctlr].b_actf) == NULL)
26511876Shelge 		return;
26612937Shelge 	uuc = &uu_softc[ctlr];
26712332Shelge 	cmd = &uucmd[ctlr];
26812937Shelge 	if (uuc->tu_state != TUS_IDLE) {
26912332Shelge 		uureset(ctlr);
27011876Shelge 		return;
27111876Shelge 	}
27212857Shelge 	uitab[ctlr].b_active++;
27312937Shelge 	uitab[ctlr].b_errcnt = 0;
27412937Shelge 	uuc->tu_addr = bp->b_un.b_addr;
27512937Shelge 	uuc->tu_count = cmd->pk_count = bp->b_bcount;
27612937Shelge 	cmd->pk_block = bp->b_blkno;
27712937Shelge 	if (bp->b_flags&B_READ) {
27812937Shelge 		cmd->pk_op = TUOP_READ;
27912937Shelge 		cmd->pk_mod = 0;
28012937Shelge 		uuc->tu_state = TUS_SENDR;
28112937Shelge 	} else {
28212937Shelge 		cmd->pk_op = TUOP_WRITE;
28312937Shelge 		cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0;
28412937Shelge 		uuc->tu_state = TUS_SENDW;
28512937Shelge 	}
28612857Shelge 	cmd->pk_unit = UNIT(minor(bp->b_dev));
28712332Shelge 	cmd->pk_sw = 0;
28811896Shelge 	cmd->pk_chksum =
28912937Shelge 	    tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount);
29012937Shelge 	uuc->tu_wbptr = (u_char *)cmd;
29112937Shelge 	uuc->tu_wcnt = sizeof (*cmd);
29212332Shelge 	uuxintr(ctlr);
29311876Shelge }
29411876Shelge 
29511876Shelge /*
296*13014Shelge  * TU58 receiver interrupt,
297*13014Shelge  * handles whatever condition the
298*13014Shelge  * pseudo DMA routine in locore is
299*13014Shelge  * unable to handle, or, if UUDMA is
300*13014Shelge  * undefined, handle all receiver interrupt
301*13014Shelge  * processing
30211876Shelge  */
30312332Shelge uurintr(ctlr)
30412332Shelge 	int ctlr;
30511876Shelge {
30612857Shelge 	struct uba_device *ui = uudinfo[ctlr];
307*13014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
30812857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
30912857Shelge 	register struct buf *uutab = &uitab[ctlr];
31012332Shelge 	struct packet *data, *cmd;
31112937Shelge 	struct buf *bp;
31212937Shelge 	int c, unit;
31311876Shelge 
31412857Shelge 	c = uuaddr->rdb;
31512937Shelge 	data = &uudata[ctlr];
316*13014Shelge 	cmd = &uucmd[ctlr];
317*13014Shelge #if !defined(UUDMA)
318*13014Shelge 	if (c & UURDB_ERROR)
319*13014Shelge 		uuc->tu_state = TUS_RCVERR;
320*13014Shelge 	else {
321*13014Shelge 		if (uuc->tu_rcnt) {
322*13014Shelge 			*uuc->tu_rbptr++ = c;
323*13014Shelge 			if (--uuc->tu_rcnt)
324*13014Shelge 				return;
325*13014Shelge 		}
326*13014Shelge 	}
327*13014Shelge #endif
328*13014Shelge 
329*13014Shelge 	/*
330*13014Shelge 	 * Switch on the tu_state of the transfer.
331*13014Shelge 	 */
332*13014Shelge 	switch(uuc->tu_state) {
333*13014Shelge 
334*13014Shelge 	/*
335*13014Shelge 	 * A data error occured in uudma
336*13014Shelge 	 * (either overrun or break)
337*13014Shelge 	 */
338*13014Shelge 	case TUS_RCVERR:
33912937Shelge 		if (c & UURDB_ORUN)
34012937Shelge 			printf("uu(%d): data overrun, bytes left: %d",
34112937Shelge 			  ui->ui_unit,
34212937Shelge 			  uuc->tu_count + uuc->tu_rcnt - data->pk_mcount);
34312937Shelge 		else
34412937Shelge 			printf("uu(%d): break received", ui->ui_unit);
345*13014Shelge 		printf(", transfer restarted\n");
346*13014Shelge 		uu_restart(ctlr, ui);
347*13014Shelge 		break;
34811876Shelge 
34911876Shelge 	/*
35011876Shelge 	 * If we get an unexpected "continue",
35111876Shelge 	 * start all over again...
35211876Shelge 	 */
35312937Shelge 	case TUS_INIT2:
35412937Shelge 		uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
35512937Shelge 		uuc->tu_flag = 0;
35612332Shelge 		wakeup((caddr_t)uuc);
35712857Shelge 		uustart(ui);
35811876Shelge 		break;
35911876Shelge 
36011876Shelge 	/*
36111876Shelge 	 * Only transition from this state
36211876Shelge 	 * is on a "continue", so if we don't
36311876Shelge 	 * get it, reset the world.
36411876Shelge 	 */
36512937Shelge 	case TUS_WAIT:			/* waiting for continue */
36612332Shelge 		switch(c) {
36712332Shelge 		case TUF_CONT:  /* got the expected continue */
36812937Shelge 			uuc->tu_flag = 0;
36912332Shelge 			data->pk_flag = TUF_DATA;
37012937Shelge 			data->pk_mcount = MIN(128, uuc->tu_count);
37112332Shelge 			data->pk_chksum =
37212937Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->tu_addr,
37312332Shelge 				(int)data->pk_mcount);
37412937Shelge 			uuc->tu_state = TUS_SENDH;
37512937Shelge 			uuc->tu_wbptr = (u_char *)data;
37612937Shelge 			uuc->tu_wcnt = 2;
37712857Shelge 			uuxintr(ctlr);
37811876Shelge 			break;
37912332Shelge 
38012332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
38112937Shelge 			uuc->tu_state = TUS_GET;
38212937Shelge 			uuc->tu_rbptr = (u_char *)data;
383*13014Shelge 			uuc->tu_rcnt = sizeof (*data) - 1;
38412937Shelge 			uuc->tu_flag = 1;
38512332Shelge 			uuaddr->tcs = 0;
386*13014Shelge 			*uuc->tu_rbptr++ = c & UUDB_DMASK;
387*13014Shelge 			break;
38812332Shelge 
38912332Shelge 		case TUF_INITF:
39012857Shelge 			uureset(ctlr);
39112332Shelge 			break;
39212332Shelge 
39312332Shelge 		default:        /* something random...bad news */
39412937Shelge 			uuc->tu_state = TUS_INIT1;
39512332Shelge 			break;
39611876Shelge 		}
39711876Shelge 		break;
39811876Shelge 
39912937Shelge 	case TUS_SENDW:
40012937Shelge 		if (c != TUF_CONT && c != TUF_INITF)
40111876Shelge 			goto bad;
402*13014Shelge 		uu_restart(ctlr, ui);
40311876Shelge 		break;
40411876Shelge 
40511876Shelge 	/*
40611876Shelge 	 * Got header, now get data; amount to
40711896Shelge 	 * fetch is included in packet.
408*13014Shelge 	 * (data packets are handled entirely
409*13014Shelge 	 * in uudma)
41011876Shelge 	 */
41112937Shelge 	case TUS_GETH:
41212937Shelge 		uuc->tu_rcnt = data->pk_mcount;
41312937Shelge 		uuc->tu_state = TUS_GETD;
41411876Shelge 		break;
41511876Shelge 
41611876Shelge 	/*
41711876Shelge 	 * Got the data, now fetch the checksum.
41811876Shelge 	 */
41912937Shelge 	case TUS_GETD:
42012937Shelge 		uuc->tu_rbptr = (u_char *)&data->pk_chksum;
42112937Shelge 		uuc->tu_rcnt = sizeof (data->pk_chksum);
42212937Shelge 		uuc->tu_state = TUS_GETC;
42311876Shelge 		break;
42411876Shelge 
42512937Shelge 	case TUS_GETC:
42611876Shelge 		/* got entire packet */
42712332Shelge 		if (data->pk_chksum !=
42812937Shelge 		    tuchk(*((short *)data), (u_short *)
429*13014Shelge 		     (data->pk_flag == TUF_DATA ?
430*13014Shelge 		     (u_short *)  uuc->tu_addr : (u_short *)&data->pk_op),
43112332Shelge 		     (int)data->pk_mcount))
432*13014Shelge 	case TUS_CHKERR:
43312937Shelge 			uuc->tu_cerrs++;
434*13014Shelge 	case TUS_GET:
43512332Shelge 		if (data->pk_flag == TUF_DATA) {
43611876Shelge 			/* data packet, advance to next */
43712937Shelge 			uuc->tu_addr += data->pk_mcount;
43812937Shelge 			uuc->tu_count -= data->pk_mcount;
43912937Shelge 			uuc->tu_state = TUS_GETH;
44012937Shelge 			uuc->tu_rbptr = (u_char *)data;	/* next packet */
44112937Shelge 			uuc->tu_rcnt = 2;
44212332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
44311876Shelge 			/* end packet, idle and reenable transmitter */
44412937Shelge 			uuc->tu_state = TUS_IDLE;
44512937Shelge 			uuc->tu_flag = 0;
44612937Shelge 			uuaddr->tcs = UUCS_INTR;
44712937Shelge 			if ((bp = uutab->b_actf) == NULL) {
44812857Shelge 				printf("uu(%d): no bp, active %d\n",
44912937Shelge 					ui->ui_unit, uitab[ctlr].b_active);
45012857Shelge 				uustart(ui);
45111876Shelge 				return;
45211876Shelge 			}
45312937Shelge 			unit = UNIT(minor(bp->b_dev));
45412332Shelge 			if (data->pk_mod > 1) {        /* hard error */
455*13014Shelge 				printf("uu%d: hard error bn%d,", unit,
456*13014Shelge 								bp->b_blkno);
457*13014Shelge 				printf(" pk_mod %o\n", data->pk_mod&0xff);
45811876Shelge 				bp->b_flags |= B_ERROR;
45912937Shelge 				uuc->tu_herrs++;
46012332Shelge 			} else if (data->pk_mod != 0)	/* soft error */
46112937Shelge 				uuc->tu_serrs++;
46212332Shelge 			uutab->b_active = NULL;
46312937Shelge 			uutab->b_actf = bp->av_forw;
46412937Shelge 			bp->b_resid = uuc->tu_count;
46511876Shelge 			if ((bp->b_flags&B_READ) == 0)
46612937Shelge 				tu_vee(&pcnt[unit]);
46711876Shelge 			iodone(bp);
46812857Shelge 			uustart(ui);
46911876Shelge 		} else {
47011876Shelge 			printf("neither data nor end: %o %o\n",
47112332Shelge 			    data->pk_flag&0xff, data->pk_op&0xff);
47212332Shelge 			uuaddr->rcs = 0;		/* flush the rest */
47312937Shelge 			uuc->tu_state = TUS_INIT1;
474*13014Shelge 			uu_restart(ctlr, ui);
47511876Shelge 		}
47611876Shelge 		break;
47711876Shelge 
47812937Shelge 	case TUS_IDLE:
47912937Shelge 	case TUS_INIT1:
48011876Shelge 		break;
48111876Shelge 
48211876Shelge 	default:
48311876Shelge bad:
48411876Shelge 		if (c == TUF_INITF) {
48512857Shelge 			printf("uu%d protocol error, state=", unit);
48612937Shelge 			printstate(uuc->tu_state);
48711876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
48812332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
48912332Shelge 			uutab->b_active = NULL;
49012332Shelge 			if (bp = uutab->b_actf) {
49111876Shelge 				bp->b_flags |= B_ERROR;
49212937Shelge 				uutab->b_actf = bp->av_forw;
49311876Shelge 				if ((bp->b_flags&B_READ) == 0)
49412937Shelge 					tu_vee(&pcnt[unit]);
49511876Shelge 				iodone(bp);
49611876Shelge 			}
49712937Shelge 			uuc->tu_state = TUS_INIT1;
49811876Shelge 		} else {
49912332Shelge 			printf("uu%d receive state error, state=",
50012857Shelge 				unit);
50112937Shelge 			printstate(uuc->tu_state);
502*13014Shelge 			printf(", byte=%x\n", c & 0xff);
50311876Shelge #ifdef notdef
50412937Shelge 			uuc->tu_state = TUS_INIT1;
50511876Shelge #endif
50612332Shelge 			wakeup((caddr_t)uuc);
50711876Shelge 		}
50811876Shelge 	}
50911876Shelge }
51011876Shelge 
51112937Shelge 
51212937Shelge /*
51311876Shelge  * TU58 transmitter interrupt
51411876Shelge  */
51512332Shelge uuxintr(ctlr)
51612332Shelge 	int ctlr;
51711876Shelge {
518*13014Shelge 	register struct uu_softc *uuc = &uu_softc[ctlr];
51912857Shelge 	register struct uudevice *uuaddr;
52012332Shelge 	register struct packet *data;
52112857Shelge 	struct uba_device *ui = uudinfo[ctlr];
52212332Shelge 	int c;
52311876Shelge 
52412857Shelge 	data = &uudata[ctlr];
52512857Shelge 	uuaddr = (struct uudevice *) ui->ui_addr;
52611876Shelge top:
52712937Shelge 	if (uuc->tu_wcnt) {
52811876Shelge 		/* still stuff to send, send one byte */
52912332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
53011876Shelge 			;
53112937Shelge 		uuaddr->tdb = *uuc->tu_wbptr++;
53212937Shelge 		uuc->tu_wcnt--;
53311876Shelge 		return;
53411876Shelge 	}
53511876Shelge 
53611876Shelge 	/*
53711876Shelge 	 * Last message byte was sent out.
53812937Shelge 	 * Switch on tu_state of transfer.
53911876Shelge 	 */
54012937Shelge 	switch(uuc->tu_state) {
54111876Shelge 
54211876Shelge 	/*
54311876Shelge 	 * Two nulls have been sent, remove break, and send inits
54411876Shelge 	 */
54512937Shelge 	case TUS_INIT1:
54612332Shelge 		uuaddr->tcs = UUCS_INTR;
54712937Shelge 		uuc->tu_state = TUS_INIT2;
54812937Shelge 		uuc->tu_wbptr = uuinit;
54912937Shelge 		uuc->tu_wcnt = sizeof (uuinit);
55011876Shelge 		goto top;
55111876Shelge 
55211876Shelge 	/*
55311876Shelge 	 * Inits have been sent, wait for a continue msg.
55411876Shelge 	 */
55512937Shelge 	case TUS_INIT2:
55612857Shelge 		c = uuaddr->rdb;	/* prevent overrun error */
55712332Shelge 		uuaddr->rcs = UUCS_INTR;
55812937Shelge 		uuc->tu_flag = 1;
55911876Shelge 		break;
56011876Shelge 
56112937Shelge 	case TUS_IDLE:		/* stray interrupt? */
56211876Shelge 		break;
56311876Shelge 
56411876Shelge 	/*
56511876Shelge 	 * Read cmd packet sent, get ready for data
56611876Shelge 	 */
56712937Shelge 	case TUS_SENDR:
56812937Shelge 		uuc->tu_state = TUS_GETH;
56912937Shelge 		uuc->tu_rbptr = (u_char *)data;
57012937Shelge 		uuc->tu_rcnt = 2;
57112937Shelge 		uuc->tu_flag = 1;
57212332Shelge 		uuaddr->tcs = 0;	/* disable transmitter interrupts */
57312937Shelge 		uuaddr->rcs = UUCS_INTR;
57411876Shelge 		break;
57511876Shelge 
57611876Shelge 	/*
57711876Shelge 	 * Write cmd packet sent, wait for continue
57811876Shelge 	 */
57912937Shelge 	case TUS_SENDW:
58012937Shelge 		uuc->tu_state = TUS_WAIT;
58112937Shelge 		uuc->tu_flag = 1;
58212332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
58311876Shelge 			printf("NO IE\n");
58412332Shelge 			uuaddr->rcs = UUCS_INTR;
58511876Shelge 		}
58611876Shelge 		break;
58711876Shelge 
58811876Shelge 	/*
58911876Shelge 	 * Header sent, send data.
59011876Shelge 	 */
59112937Shelge 	case TUS_SENDH:
59212937Shelge 		uuc->tu_state = TUS_SENDD;
59312937Shelge 		uuc->tu_wbptr = (u_char *)uuc->tu_addr;
59412937Shelge 		uuc->tu_wcnt = data->pk_mcount;
59511876Shelge 		goto top;
59611876Shelge 
59711876Shelge 	/*
59811876Shelge 	 * Data sent, follow with checksum.
59911876Shelge 	 */
60012937Shelge 	case TUS_SENDD:
60112937Shelge 		uuc->tu_state = TUS_SENDC;
60212937Shelge 		uuc->tu_wbptr = (u_char *)&data->pk_chksum;
60312937Shelge 		uuc->tu_wcnt = sizeof (data->pk_chksum);
60411876Shelge 		goto top;
60511876Shelge 
60611876Shelge 	/*
60711876Shelge 	 * Checksum sent, wait for continue.
60811876Shelge 	 */
60912937Shelge 	case TUS_SENDC:
61011876Shelge 		/*
61112937Shelge 		 * Update buffer address and count.
61211876Shelge 		 */
61312937Shelge 		uuc->tu_addr += data->pk_mcount;
61412937Shelge 		uuc->tu_count -= data->pk_mcount;
61512937Shelge 		if (uuc->tu_count) {
61612937Shelge 			uuc->tu_state = TUS_WAIT;
61712937Shelge 			uuc->tu_flag = 1;
61811876Shelge 			break;
61911876Shelge 		}
62011876Shelge 
62111876Shelge 		/*
62211876Shelge 		 * End of transmission, get ready for end packet.
62311876Shelge 		 */
62412937Shelge 		uuc->tu_state = TUS_GET;
62512937Shelge 		uuc->tu_rbptr = (u_char *)data;
62612937Shelge 		uuc->tu_rcnt = sizeof (*data);
62712937Shelge 		uuc->tu_flag = 1;
62812332Shelge 		uuaddr->tcs = 0;		/* disable transm. interrupts */
62911876Shelge 		break;
63011876Shelge 
63111876Shelge 	/*
63212332Shelge 	 * Random interrupt
63311876Shelge 	 */
63411876Shelge 	default:
63511876Shelge 		break;
63611876Shelge 	}
63712937Shelge }
63812937Shelge 
63912937Shelge uuwatch()
64012937Shelge {
641*13014Shelge 	register struct uu_softc *uuc;
64212937Shelge 	register struct uudevice *uuaddr;
64312937Shelge 	struct uba_device *ui;
64412937Shelge 	struct buf *bp, *uutab;
64512937Shelge 	int s, ctlr, active = 0;
64612937Shelge 
64712937Shelge 	for (ctlr=0; ctlr<NUU; ctlr++) {
64812937Shelge 		int i;
64912937Shelge 
65012937Shelge 		uuc = &uu_softc[ctlr];
65112937Shelge 		ui = uudinfo[ctlr];
65212937Shelge 		uuaddr = (struct uudevice *)ui->ui_addr;
65312937Shelge 		uutab = &uitab[ctlr];
65412937Shelge 		if ((uuc->tu_dopen[0] == 0) && (uuc->tu_dopen[1] == 0) &&
65512937Shelge 		    (uutab->b_active == 0)) {
65612937Shelge 			uuc->tu_flag = 0;
65712937Shelge 			uuaddr->rcs = 0;
65812937Shelge 			continue;
65912937Shelge 		}
66012937Shelge 		active++;
66112937Shelge 		if (uuc->tu_flag)
66212937Shelge 			uuc->tu_flag++;
66312937Shelge 		if (uuc->tu_flag <= 40)
66412937Shelge 			continue;
66512937Shelge 		printf("uu(%d): read stalled\n", ctlr);
66612937Shelge 		printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt,
66712937Shelge 		       uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr, uuc->tu_count);
66812937Shelge 		uuc->tu_flag = 0;
66912937Shelge 		s = splx(UUIPL);
67012937Shelge 		i = uuaddr->rdb;		/* dummy */
67112937Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
67212937Shelge 		uuaddr->tcs = UUCS_INTR;
67312937Shelge 		uuc->tu_state = TUS_IDLE;
67412937Shelge 		if (!uutab->b_active) {
67512937Shelge 			wakeup((caddr_t)uuc);
67612937Shelge 			goto retry;
67712937Shelge 		}
67812937Shelge 		if (++uutab->b_errcnt <= 1) {
67912937Shelge 			uustart(ui);
68012937Shelge 			goto retry;
68112937Shelge 		}
68212937Shelge 		if (bp = uutab->b_actf) {
68312937Shelge 			bp->b_flags |= B_ERROR;
68412937Shelge 			if ((bp->b_flags&B_READ) == 0)
68512937Shelge 				tu_vee(&pcnt[UNIT(minor(bp->b_dev))]);
68612937Shelge 			iodone(bp);
68712937Shelge 		}
68812937Shelge retry:
68912937Shelge 		(void) splx(s);
69011876Shelge 	}
69112937Shelge 	if (active)
69212937Shelge 		timeout(uuwatch, (caddr_t)0, hz);
69312937Shelge 	else
69412937Shelge 		uuwstart = 0;
69512937Shelge 	return;
69611876Shelge }
69711876Shelge 
69812937Shelge #if !defined(VAX750) && !defined(VAX730)
69911876Shelge /*
70011876Shelge  * Compute checksum TU58 fashion
70111876Shelge  */
70211876Shelge #ifdef lint
70312937Shelge tuchk(word, cp, n)
70411876Shelge 	register word;
70511876Shelge 	register unsigned short *cp;
70611876Shelge 	int n;
70711876Shelge {
70811876Shelge 	register int c = n >> 1;
70911876Shelge 	register long temp;
71011876Shelge 
71111876Shelge 	do {
71211876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
71311876Shelge 		word += temp;
71411876Shelge 	} while (--c > 0);
71511876Shelge 	if (n & 1)
71611876Shelge 		word += *(unsigned char *)cp;
71711876Shelge 	while (word & 0xffff0000)
71811876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
71911876Shelge 	return (word);
72011876Shelge }
72111876Shelge #else
72212937Shelge tuchk(word0, wp, n)
72311896Shelge 	register int word0;			/* r11 */
72411896Shelge 	register char *wp;			/* r10 */
72511896Shelge 	register int n;				/* r9 */
72611876Shelge {
72711876Shelge 	asm("loop:");
72811896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
72911896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
73011876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
73111896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
73211896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
73311896Shelge 	asm("	addw2	r10,r11");		/* add it in */
73411896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
73511876Shelge 	asm("ok:");
73611896Shelge 	asm("	movl	r11,r0");		/* return sum */
73711876Shelge }
73811876Shelge #endif
73911876Shelge 
74012937Shelge tu_pee(cp)
74112332Shelge char *cp;
74212332Shelge {
74312332Shelge 	register int s;
74412332Shelge 
74512857Shelge 	s = splx(UUIPL);
74612332Shelge 	if (++(*cp) > NTUQ) {
74712332Shelge 		sleep(cp, PRIBIO);
74811876Shelge 	}
74912332Shelge 	splx(s);
75012332Shelge }
75112332Shelge 
75212937Shelge tu_vee(cp)
75312332Shelge char *cp;
75412332Shelge {
75512332Shelge 	register int s;
75612332Shelge 
75712857Shelge 	s = splx(UUIPL);
75812332Shelge 	if (--(*cp) <= NTUQ) {
75912332Shelge 		wakeup(cp);
76011876Shelge 	}
76111876Shelge 	splx(s);
76211876Shelge }
76311876Shelge #endif
76412332Shelge 
76512937Shelge uuioctl(dev, cmd, data, flag)
76612937Shelge 	dev_t dev;
76712937Shelge 	caddr_t data;
76812937Shelge {
76912937Shelge 	/*
77012937Shelge 	 * to be added later
77112937Shelge 	 */
77212937Shelge 	return (ENXIO);
77312937Shelge }
77412937Shelge 
77512937Shelge #endif
77612937Shelge 
777*13014Shelge uu_restart(ctlr, ui)
778*13014Shelge 	int ctlr;
779*13014Shelge 	struct uba_device *ui;
780*13014Shelge {
781*13014Shelge 	uureset(ctlr);
782*13014Shelge 	timeout(uustart, (caddr_t)ui, hz * 3);
783*13014Shelge }
784