xref: /csrg-svn/sys/vax/uba/uu.c (revision 12857)
1*12857Shelge /*	uu.c	4.4	83/06/01	*/
211876Shelge 
312332Shelge #include "uu.h"
4*12857Shelge #if NUU > 0
511876Shelge /*
611896Shelge  * TU58 DECtape II/DL11 device driver
711876Shelge  *
8*12857Shelge  *  ******   Warning: untested  ******
9*12857Shelge  *
1011896Shelge  * The TU58 * is treated as a block device (only).  Error detection and
1111876Shelge  * recovery is almost non-existant.  It is assumed that the
1211876Shelge  * TU58 will follow the RSP protocol exactly, very few protocol
1311896Shelge  * errors are checked for.
1411876Shelge  */
1511896Shelge 
1612332Shelge #include "../machine/pte.h"
1711896Shelge 
1811876Shelge #include "../h/param.h"
1911876Shelge #include "../h/systm.h"
2011876Shelge #include "../h/buf.h"
2111876Shelge #include "../h/conf.h"
2212332Shelge #include "../h/time.h"
2311896Shelge #include "../h/kernel.h"
2411896Shelge #include "../h/errno.h"
2511896Shelge #include "../h/uio.h"
2611896Shelge #include "../h/file.h"
2711876Shelge 
2811876Shelge #include "../vax/cpu.h"
2912332Shelge #include "../vax/nexus.h"
3012332Shelge 
3111896Shelge #include "../vaxuba/ubavar.h"
3211896Shelge #include "../vaxuba/ubareg.h"
3311896Shelge #include "../vaxuba/uureg.h"
3411876Shelge 
3512332Shelge #define	printd	if (uudebug) printf
3611876Shelge #ifdef	printd
37*12857Shelge int	uudebug = 0;		/* printd */
3811876Shelge #endif	printd
3911876Shelge 
4011876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
41*12857Shelge #define	WRV     01              /* bit in minor dev => write w. read verify */
4212332Shelge #define	NDPC	02		/* drives per controller */
43*12857Shelge #define	NUX	NDPC * NUU	/* number of drives */
4412332Shelge #define	NTUQ	02		/* # of block which can be queued up */
45*12857Shelge #define	UMASK	01		/* unit number mask */
46*12857Shelge #define UUIPL	04		/* ipl level to use */
4711876Shelge 
4811876Shelge /*
4911876Shelge  * Structure of a command packet
5011876Shelge  */
5111876Shelge struct packet {
5211876Shelge 	u_char	pk_flag;	/* indicates packet type (cmd, data, etc.) */
5311876Shelge 	u_char	pk_mcount;	/* length of packet (bytes) */
5411876Shelge 	u_char	pk_op;		/* operation to perform (read, write, etc.) */
5511876Shelge 	u_char	pk_mod;		/* modifier for op or returned status */
5611876Shelge 	u_char	pk_unit;	/* unit number */
5711876Shelge 	u_char	pk_sw;		/* switches */
5811876Shelge 	u_short	pk_seq;		/* sequence number, always zero */
5911876Shelge 	u_short	pk_count;	/* requested byte count for read or write */
6011876Shelge 	u_short	pk_block;	/* block number for read, write, or seek */
6111876Shelge 	u_short	pk_chksum;	/* checksum, by words with end around carry */
6211876Shelge };
6311876Shelge 
64*12857Shelge struct packet uucmd[NUU];	/* a command sent to the TU58 */
65*12857Shelge struct packet uudata[NUU];	/* a command or data returned from TU58 */
66*12857Shelge struct buf uitab[NUU];		/* buffer queue headers */
6711876Shelge 
6811876Shelge /*
6911896Shelge  * per controller state information
7011876Shelge  */
7111896Shelge struct uu_ctlr {
7211896Shelge 	u_char	*uu_rbptr;	/* pointer to buffer for read */
7311896Shelge 	int	uu_rcnt;	/* how much to read */
7411896Shelge 	u_char	*uu_wbptr;	/* pointer to buffer for write */
7511896Shelge 	int	uu_wcnt;	/* how much to write */
7611896Shelge 	int	uu_state;	/* current uu_state of tansfer operation */
7711896Shelge 	int	uu_flag;	/* read in progress flag */
7811896Shelge 	char	*uu_addr;	/* real buffer data address */
7911896Shelge 	int	uu_count;	/* real requested count */
8011896Shelge 	int	uu_serrs;	/* count of soft errors */
8111896Shelge 	int	uu_cerrs;	/* count of checksum errors */
8211896Shelge 	int	uu_herrs;	/* count of hard errors */
8311896Shelge 	char    uu_dopen[NDPC];	/* drive is open */
84*12857Shelge } uu_ctlr[NUU];
8511876Shelge 
8611876Shelge /*
8711896Shelge  * controller states
8811876Shelge  */
8911896Shelge #define	UUS_INIT1	0	/* sending nulls */
9011896Shelge #define	UUS_INIT2	1	/* sending inits */
9111896Shelge #define	UUS_IDLE	2	/* initialized, no transfer in progress */
9211896Shelge #define	UUS_SENDH	3	/* sending header */
9311896Shelge #define	UUS_SENDD	4	/* sending data */
9411896Shelge #define	UUS_SENDC	5	/* sending checksum */
9511896Shelge #define	UUS_SENDR	6	/* sending read command packet */
9611896Shelge #define	UUS_SENDW	7	/* sending write command packet */
9711896Shelge #define	UUS_GETH	8	/* reading header */
9811896Shelge #define	UUS_GETD	9	/* reading data */
9911896Shelge #define	UUS_GETC	10	/* reading checksum */
10011896Shelge #define	UUS_GET		11	/* reading an entire packet */
10111896Shelge #define	UUS_WAIT	12	/* waiting for continue */
10211876Shelge 
10311896Shelge #define	UUS_NSTATES	13
10411896Shelge char *uustates[UUS_NSTATES] = {
10511876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
10611876Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT"
10711876Shelge };
10812332Shelge 
109*12857Shelge #define	UNIT(dev)	(minor(dev)>>1)
11011876Shelge #define	printstate(state) \
11111896Shelge 	if ((state) < UUS_NSTATES) \
11211896Shelge 		printf("%s", uustates[(state)]); \
11311876Shelge 	else \
11411876Shelge 		printf("%d", (state));
11511876Shelge 
11611876Shelge /*
11711876Shelge  * Packet Flags
11811876Shelge  */
11911876Shelge #define	TUF_DATA	1		/* data packet */
12011876Shelge #define	TUF_CMD		2		/* command packet */
12111876Shelge #define	TUF_INITF	4		/* initialize */
12211876Shelge #define	TUF_CONT	020		/* continue */
12311876Shelge #define	TUF_XOFF	023		/* flow control */
12411876Shelge 
12511876Shelge /*
12611876Shelge  * Op Codes
12711876Shelge  */
12811896Shelge #define	TUOP_NOOP	0		/* no operation */
12911876Shelge #define	TUOP_INIT	1		/* initialize */
13011876Shelge #define	TUOP_READ	2		/* read block */
13111876Shelge #define	TUOP_WRITE	3		/* write block */
13211876Shelge #define	TUOP_SEEK	5		/* seek to block */
13311896Shelge #define	TUOP_DIAGNOSE	7		/* run micro-diagnostics */
13411876Shelge #define	TUOP_END	0100		/* end packet */
13511876Shelge 
13611876Shelge /*
13711876Shelge  * Mod Flags
13811876Shelge  */
13911876Shelge #define TUMD_WRV        1               /* write with read verify */
14011876Shelge 
14111876Shelge /*
14211876Shelge  * Switches
14311876Shelge  */
14411876Shelge 
14511896Shelge u_char	uunull[2] = { 0, 0 };	/* nulls to send for initialization */
14611896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
14711876Shelge 
14811896Shelge struct	uba_device	*uudinfo[NUU];
14911896Shelge 
150*12857Shelge int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch();
151*12857Shelge u_short uustd[] = { 0176500 };
152*12857Shelge struct uba_driver uudriver =
153*12857Shelge     { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo };
15411896Shelge 
15511896Shelge int	uuwstart;
156*12857Shelge static char pcnt[NUX];			/* pee/vee counters */
15711896Shelge 
15811876Shelge /*ARGSUSED*/
15911896Shelge uuprobe(reg)
16011896Shelge 	caddr_t reg;
16111876Shelge {
16211896Shelge 	register int br, cvec;			/* value result */
16311896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
16411896Shelge 	int i;
16511876Shelge 
16611876Shelge #ifdef lint
16711896Shelge 	br = 0; cvec = br; br = cvec;
16811896Shelge 	uurintr(0); uuxintr(0);
16911876Shelge #endif
170*12857Shelge 	uuaddr->tcs = UUCS_INTR;
171*12857Shelge 	DELAY(1000);
172*12857Shelge 	uuaddr->tcs = 0;
173*12857Shelge 	cvec -= 4;		/* since we are using the xmitter intrpt */
17411896Shelge 	return(sizeof (*uuaddr));
17511896Shelge }
17611896Shelge 
17711896Shelge uuattach(ui)
178*12857Shelge 	register struct uba_device *ui;
17911896Shelge {
18011896Shelge }
18111896Shelge 
18211896Shelge /*ARGSUSED1*/
18311896Shelge uuopen(dev, flag)
18411896Shelge 	dev_t dev;
18511896Shelge 	int flag;
18611896Shelge {
18711896Shelge 	register struct uba_device *ui;
18811896Shelge 	register struct uu_ctlr *uuc;
18911896Shelge 	register struct uudevice *uuaddr;
19012332Shelge 	int ctlr, unit = UNIT(dev), s;
19111896Shelge 
192*12857Shelge 	ctlr = unit / NDPC;
193*12857Shelge 	if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0)
19411876Shelge 		return (ENXIO);
19511896Shelge 	uuc = &uu_ctlr[ctlr];
196*12857Shelge 	if (uuc->uu_dopen[unit&UMASK])
19711896Shelge 		return (EBUSY);
19811896Shelge 	if (uuwstart++ == 0)
19911896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
20011896Shelge 
201*12857Shelge 	uuc->uu_dopen[unit&UMASK]++;
202*12857Shelge 	uuaddr = (struct uudevice *)ui->ui_addr;
203*12857Shelge 	s = splx(UUIPL);
20411876Shelge 	/*
20511896Shelge 	 * If the unit already initialized,
20611876Shelge 	 * just enable interrupts and return.
20711876Shelge 	 */
20812332Shelge 	if (uuc->uu_state == UUS_IDLE) {
20911896Shelge 		uuaddr->rcs = UUCS_INTR;
210*12857Shelge 		(void) splx(s);
21111876Shelge 		return (0);
21211876Shelge 	}
21311876Shelge 
21411876Shelge 	/*
21511876Shelge 	 * Must initialize, reset the cassette
21611876Shelge 	 * and wait for things to settle down.
21711876Shelge 	 */
21811896Shelge 	uureset(ctlr);
21911896Shelge 	sleep((caddr_t)uuc, PZERO+1);
220*12857Shelge 	uitab[ctlr].b_active = NULL;
22112332Shelge 	if (uuc->uu_state != UUS_IDLE) {
22212332Shelge 		uuc->uu_state = UUS_INIT1;
223*12857Shelge 		uuc->uu_dopen[unit&UMASK] = 0;
22412332Shelge 		uuc->uu_rcnt = uuc->uu_wcnt = 0;
22511896Shelge 		uuaddr->rcs = 0;
22611896Shelge 		uuaddr->tcs = 0;
22711896Shelge 		splx(s);
22811896Shelge 		return (ENXIO);
22911876Shelge 	}
23011876Shelge 	splx(s);
23111876Shelge 	return (0);
23211876Shelge }
23311876Shelge 
23411896Shelge uuclose(dev, flag)
23511896Shelge 	dev_t dev;
23611896Shelge 	int flag;
23711876Shelge {
23811896Shelge 	register struct uu_ctlr *uuc;
239*12857Shelge 	int unit = UNIT(dev);
24011876Shelge 
24112332Shelge 	uuwstart--;
242*12857Shelge 	uuc = &uu_ctlr[unit%NDPC];
24311896Shelge 	if (uuc->uu_serrs + uuc->uu_cerrs + uuc->uu_herrs != 0) {
24411876Shelge 		/*
24511876Shelge 		 * A tu58 is like nothing ever seen before;
24611876Shelge 		 * I guess this is appropriate then...
24711876Shelge 		 */
24811876Shelge 		uprintf(
249*12857Shelge 		   "uu%d: %d soft errors, %d checksum errors, %d hard errors\n",
250*12857Shelge 		    unit, uuc->uu_serrs, uuc->uu_cerrs, uuc->uu_herrs);
25111896Shelge 		    uuc->uu_serrs = uuc->uu_cerrs = uuc->uu_herrs = 0;
25211876Shelge 	}
253*12857Shelge 	uuc->uu_dopen[unit%NDPC] = 0;
25411876Shelge }
25511876Shelge 
25611896Shelge uureset(ctlr)
25711896Shelge 	int ctlr;
25811876Shelge {
25912332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
26012332Shelge 	register struct packet *cmd = &uucmd[ctlr];
261*12857Shelge 	struct uba_device *ui = uudinfo[ctlr];
262*12857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
26311876Shelge 
264*12857Shelge 	printf ("uureset\n");
265*12857Shelge 	uitab[ctlr].b_active++;
26612332Shelge 	uuc->uu_state = UUS_INIT1;
26711896Shelge 	uuc->uu_wbptr = uunull;
26811896Shelge 	uuc->uu_wcnt = sizeof (uunull);
26911896Shelge 	cmd->pk_flag = TUF_CMD;
27012332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
27111896Shelge 	cmd->pk_mod = 0;
27211896Shelge 	cmd->pk_seq = 0;
27312332Shelge 	cmd->pk_sw = 0;
27411896Shelge 	uuaddr->rcs = 0;
27511896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
27611896Shelge 	uuxintr(ctlr);				/* start output */
27711876Shelge }
27811876Shelge 
27911876Shelge /*
28011876Shelge  * Strategy routine for block I/O
28111876Shelge  */
28211896Shelge uustrategy(bp)
28311876Shelge 	register struct buf *bp;
28411876Shelge {
28512332Shelge 	register struct buf *uutab;
28611896Shelge 	struct uba_device *ui;
287*12857Shelge 	int s, unit = UNIT(minor(bp->b_dev));
28811876Shelge 
289*12857Shelge 	if (unit > NUX)
29011896Shelge 		goto bad;
29111896Shelge 	if (bp->b_blkno >= NTUBLK)
29211896Shelge 		goto bad;
293*12857Shelge 	ui = uudinfo[unit/NDPC];
29411896Shelge 	if (ui == 0 || ui->ui_alive == 0)
29511896Shelge 		goto bad;
296*12857Shelge 	uutab = &uitab[unit/NDPC];	/* one request queue per controller */
29712332Shelge 	if ((bp->b_flags&B_READ) == 0)
298*12857Shelge 		uu_pee(&pcnt[unit]);
299*12857Shelge 	printf("uustrat: unit=%d, bp=%x\n", unit, bp);
300*12857Shelge 	s = splx(UUIPL);
301*12857Shelge 	bp->b_forw = NULL;
30212332Shelge 	if (uutab->b_actf == NULL)
30312332Shelge 		uutab->b_actf = bp;
30412332Shelge 	else
305*12857Shelge 		uutab->b_actl->b_forw = bp;
30612332Shelge 	uutab->b_actl = bp;
30712332Shelge 	if (uutab->b_active == 0)
308*12857Shelge 		uustart(ui);
30911876Shelge 	splx(s);
31011896Shelge 	return;
31111896Shelge 
31211896Shelge bad:
31311896Shelge 	bp->b_flags |= B_ERROR;
31412332Shelge 	bp->b_error = ENXIO;
31511896Shelge 	iodone(bp);
31611896Shelge 	return;
31711876Shelge }
31811876Shelge 
31911876Shelge /*
32011876Shelge  * Start the transfer
32111876Shelge  */
322*12857Shelge uustart(ui)
323*12857Shelge 	register struct uba_device *ui;
32411876Shelge {
32511876Shelge 	register struct buf *bp;
32611896Shelge 	register struct uu_ctlr *uuc;
32711896Shelge 	struct packet *cmd;
328*12857Shelge 	int ctlr = ui->ui_unit;
32911876Shelge 
330*12857Shelge 	if ((bp = uitab[ctlr].b_actf) == NULL)
33111876Shelge 		return;
33212332Shelge 	uuc = &uu_ctlr[ctlr];
33312332Shelge 	cmd = &uucmd[ctlr];
33412332Shelge 	if (uuc->uu_state != UUS_IDLE) {
33512332Shelge 		uureset(ctlr);
33611876Shelge 		return;
33711876Shelge 	}
338*12857Shelge 	uitab[ctlr].b_active++;
33911896Shelge 	cmd->pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
34011896Shelge 	cmd->pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
34111876Shelge 	    TUMD_WRV : 0;
342*12857Shelge 	cmd->pk_unit = UNIT(minor(bp->b_dev));
34312332Shelge 	cmd->pk_sw = 0;
34412332Shelge 	cmd->pk_count = uuc->uu_count = bp->b_bcount;
34511896Shelge 	cmd->pk_block = bp->b_blkno;
34611896Shelge 	cmd->pk_chksum =
34712332Shelge 	    uuchk(*((short *)cmd), (u_short *)&cmd->pk_op,
34812332Shelge 		(int)cmd->pk_mcount);
34912332Shelge 	uuc->uu_state = bp->b_flags&B_READ ? UUS_SENDR : UUS_SENDW;
35011896Shelge 	uuc->uu_addr = bp->b_un.b_addr;
35111896Shelge 	uuc->uu_count = bp->b_bcount;
35212332Shelge 	uuc->uu_wbptr = (u_char *)cmd;
35312332Shelge 	uuc->uu_wcnt = sizeof (*cmd);
35412332Shelge 	uuxintr(ctlr);
35511876Shelge }
35611876Shelge 
35711876Shelge /*
35811876Shelge  * TU58 receiver interrupt
35911876Shelge  */
36012332Shelge uurintr(ctlr)
36112332Shelge 	int ctlr;
36211876Shelge {
363*12857Shelge 	struct uba_device *ui = uudinfo[ctlr];
36412332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
365*12857Shelge 	register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr;
366*12857Shelge 	register struct buf *uutab = &uitab[ctlr];
367*12857Shelge 	register struct buf *bp = uutab->b_actf;
36812332Shelge 	struct packet *data, *cmd;
369*12857Shelge 	int c, unit = UNIT(minor(bp->b_dev));
37011876Shelge 
371*12857Shelge 	c = uuaddr->rdb;
372*12857Shelge 	/*
373*12857Shelge 	 * We may have a stray interrupt, but read
374*12857Shelge 	 * the data anyway, otherwise we'll get an overrun
375*12857Shelge 	 * next time
376*12857Shelge 	 */
377*12857Shelge 	if (uutab->b_active == 0)
37812332Shelge 		return;
37912332Shelge 	cmd = &uucmd[ctlr];
38012332Shelge 	if (c & UURDB_ERROR) {
38112332Shelge 		if (c & UURDB_ORUN) {
382*12857Shelge 			printf("uu%d: data overrun (ignored)\n", unit);
38312332Shelge 		} else {
38412332Shelge 			printf("uu%d: break received, device reset, state=",
385*12857Shelge 				unit);
38612332Shelge 			printstate(uuc->uu_state);
38712332Shelge 			uureset(ctlr);
38812332Shelge 			printf("\n");
38912332Shelge 			return;
39012332Shelge 		}
39111876Shelge 	}
392*12857Shelge 	data = &uudata[ctlr];
39312332Shelge top:
39412332Shelge 	c &= 0xff;
39512332Shelge 	if (uuc->uu_rcnt) {		/* still waiting for data? */
39612332Shelge 		*uuc->uu_rbptr++ = c;	/* yup, put it there */
39712332Shelge 		if (--uuc->uu_rcnt)	/* decrement count, any left? */
39811876Shelge 			return;		/* get some more */
39911876Shelge 	}
40011876Shelge 
40111876Shelge 	/*
40211876Shelge 	 * We got all the data we were expecting for now,
40311896Shelge 	 * switch on the uu_state of the transfer.
40411876Shelge 	 */
40512332Shelge 	switch(uuc->uu_state) {
40611876Shelge 
40711876Shelge 	/*
40811876Shelge 	 * If we get an unexpected "continue",
40911876Shelge 	 * start all over again...
41011876Shelge 	 */
41112332Shelge 	case UUS_INIT2:
41212332Shelge 		uuc->uu_state = c == TUF_CONT ? UUS_IDLE : UUS_INIT1;
41312332Shelge 		uuc->uu_flag = 0;
41412332Shelge 		wakeup((caddr_t)uuc);
415*12857Shelge 		uustart(ui);
41611876Shelge 		break;
41711876Shelge 
41811876Shelge 	/*
41911876Shelge 	 * Only transition from this state
42011876Shelge 	 * is on a "continue", so if we don't
42111876Shelge 	 * get it, reset the world.
42211876Shelge 	 */
42312332Shelge 	case UUS_WAIT:			/* waiting for continue */
42412332Shelge 		switch(c) {
42512332Shelge 		case TUF_CONT:  /* got the expected continue */
42612332Shelge 			uuc->uu_flag = 0;
42712332Shelge 			data->pk_flag = TUF_DATA;
42812332Shelge 			data->pk_mcount = MIN(128, uuc->uu_count);
42912332Shelge 			data->pk_chksum =
43012332Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->uu_addr,
43112332Shelge 				(int)data->pk_mcount);
43212332Shelge 			uuc->uu_state = UUS_SENDH;
43312332Shelge 			uuc->uu_wbptr = (u_char *)data;
43412332Shelge 			uuc->uu_wcnt = 2;
435*12857Shelge 			uuxintr(ctlr);
43611876Shelge 			break;
43712332Shelge 
43812332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
43912332Shelge 			uuc->uu_state = UUS_GET;
44012332Shelge 			uuc->uu_rbptr = (u_char *) data;
44112332Shelge 			uuc->uu_rcnt = sizeof (*data);
44212332Shelge 			uuc->uu_flag = 1;
44312332Shelge 			uuaddr->tcs = 0;
44412332Shelge 			goto top;
44512332Shelge 
44612332Shelge 		case TUF_INITF:
447*12857Shelge 			uureset(ctlr);
44812332Shelge 			break;
44912332Shelge 
45012332Shelge 		default:        /* something random...bad news */
45112332Shelge 			uuc->uu_state = UUS_INIT1;
45212332Shelge 			break;
45311876Shelge 		}
45411876Shelge 		break;
45511876Shelge 
45612332Shelge 	case UUS_SENDW:
45711876Shelge 		if (c != TUF_CONT)
45811876Shelge 			goto bad;
45912332Shelge 		uureset(ctlr);
46011876Shelge 		break;
46111876Shelge 
46211876Shelge 	/*
46311876Shelge 	 * Got header, now get data; amount to
46411896Shelge 	 * fetch is included in packet.
46511876Shelge 	 */
46612332Shelge 	case UUS_GETH:
46712332Shelge 		if (data->pk_flag == TUF_DATA)
46812332Shelge 			uuc->uu_rbptr = (u_char *)uuc->uu_addr;
46912332Shelge 		uuc->uu_rcnt = data->pk_mcount;
47012332Shelge 		uuc->uu_state = UUS_GETD;
47111876Shelge 		break;
47211876Shelge 
47311876Shelge 	/*
47411876Shelge 	 * Got the data, now fetch the checksum.
47511876Shelge 	 */
47612332Shelge 	case UUS_GETD:
47712332Shelge 		uuc->uu_rbptr = (u_char *)&data->pk_chksum;
47812332Shelge 		uuc->uu_rcnt = sizeof (data->pk_chksum);
47912332Shelge 		uuc->uu_state = UUS_GETC;
48011876Shelge 		break;
48111876Shelge 
48212332Shelge 	case UUS_GET:
48312332Shelge 	case UUS_GETC:
48411876Shelge 		/* got entire packet */
48511876Shelge #ifdef notdef
48612332Shelge 		if (data->pk_chksum !=
48712332Shelge 		    uuchk(*((short *)data), (u_short *)
48812332Shelge 		     (data->pk_flag == TUF_DATA ? uuc->uu_addr : &data->pk_op),
48912332Shelge 		     (int)data->pk_mcount))
49012332Shelge 			uuc->uu_cerrs++;
49111876Shelge #endif
49212332Shelge 		if (data->pk_flag == TUF_DATA) {
49311876Shelge 			/* data packet, advance to next */
49412332Shelge 			uuc->uu_addr += data->pk_mcount;
49512332Shelge 			uuc->uu_count -= data->pk_mcount;
49612332Shelge 			uuc->uu_state = UUS_GETH;
49712332Shelge 			uuc->uu_rbptr = (u_char *)data;	/* next packet */
49812332Shelge 			uuc->uu_rcnt = 2;
49912332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
50011876Shelge 			/* end packet, idle and reenable transmitter */
50112332Shelge 			uuc->uu_state = UUS_IDLE;
50212332Shelge 			uuc->uu_flag = 0;
50312332Shelge 			uuaddr->rcs = UUCS_INTR;
50411876Shelge 			printd("ON ");
50512332Shelge 			if (bp == NULL) {
506*12857Shelge 				printf("uu(%d): no bp, active %d\n",
507*12857Shelge 					uitab[ctlr].b_active);
508*12857Shelge 				uustart(ui);
50911876Shelge 				return;
51011876Shelge 			}
51112332Shelge 			if (data->pk_mod > 1) {        /* hard error */
51211876Shelge 				bp->b_flags |= B_ERROR;
51312332Shelge 				uuc->uu_herrs++;
51411896Shelge 				harderr(bp, "uu");
51512332Shelge 				printf(" pk_mod %o\n", data->pk_mod&0xff);
51612332Shelge 			} else if (data->pk_mod != 0)	/* soft error */
51712332Shelge 				uuc->uu_serrs++;
51812332Shelge 			uutab->b_active = NULL;
519*12857Shelge 			uutab->b_actf = bp->b_forw;
52012332Shelge 			bp->b_resid = uuc->uu_count;
52111876Shelge 			if ((bp->b_flags&B_READ) == 0)
522*12857Shelge 				uu_vee(&pcnt[unit]);
52311876Shelge 			iodone(bp);
524*12857Shelge 			uustart(ui);
52511876Shelge 		} else {
52611876Shelge 			printf("neither data nor end: %o %o\n",
52712332Shelge 			    data->pk_flag&0xff, data->pk_op&0xff);
52812332Shelge 			uuaddr->rcs = 0;		/* flush the rest */
52912332Shelge 			uuc->uu_state = UUS_INIT1;
53011876Shelge 		}
53111876Shelge 		break;
53211876Shelge 
53312332Shelge 	case UUS_IDLE:
53412332Shelge 	case UUS_INIT1:
53511876Shelge 		break;
53611876Shelge 
53711876Shelge 	default:
53811876Shelge bad:
53911876Shelge 		if (c == TUF_INITF) {
540*12857Shelge 			printf("uu%d protocol error, state=", unit);
54112332Shelge 			printstate(uuc->uu_state);
54211876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
54312332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
54412332Shelge 			uutab->b_active = NULL;
54512332Shelge 			if (bp = uutab->b_actf) {
54611876Shelge 				bp->b_flags |= B_ERROR;
547*12857Shelge 				uutab->b_actf = bp->b_forw;
54811876Shelge 				if ((bp->b_flags&B_READ) == 0)
549*12857Shelge 					uu_vee(&pcnt[unit]);
55011876Shelge 				iodone(bp);
55111876Shelge 			}
55212332Shelge 			uuc->uu_state = UUS_INIT1;
55311876Shelge 		} else {
55412332Shelge 			printf("uu%d receive state error, state=",
555*12857Shelge 				unit);
55612332Shelge 			printstate(uuc->uu_state);
55711876Shelge 			printf(", byte=%x\n", c);
55811876Shelge #ifdef notdef
559*12857Shelge 			uuc->uu_state = UUS_INIT1;
56011876Shelge #endif
56112332Shelge 			wakeup((caddr_t)uuc);
56211876Shelge 		}
56311876Shelge 	}
56411876Shelge }
56511876Shelge 
56611876Shelge /*
56711876Shelge  * TU58 transmitter interrupt
56811876Shelge  */
56912332Shelge uuxintr(ctlr)
57012332Shelge 	int ctlr;
57111876Shelge {
57212332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
573*12857Shelge 	register struct uudevice *uuaddr;
57412332Shelge 	register struct packet *data;
575*12857Shelge 	struct uba_device *ui = uudinfo[ctlr];
57612332Shelge 	int c;
57711876Shelge 
578*12857Shelge 	data = &uudata[ctlr];
579*12857Shelge 	uuaddr = (struct uudevice *) ui->ui_addr;
58011876Shelge top:
58112332Shelge 	if (uuc->uu_wcnt) {
58211876Shelge 		/* still stuff to send, send one byte */
58312332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
58411876Shelge 			;
58512332Shelge 		uuaddr->tdb = *uuc->uu_wbptr++;
58612332Shelge 		uuc->uu_wcnt--;
58711876Shelge 		return;
58811876Shelge 	}
58911876Shelge 
59011876Shelge 	/*
59111876Shelge 	 * Last message byte was sent out.
59211896Shelge 	 * Switch on uu_state of transfer.
59311876Shelge 	 */
59411896Shelge 	if (uudebug) {
59511896Shelge 		printf("uuxintr: state=");
59612332Shelge 		printstate(uuc->uu_state);
59711876Shelge 	}
59812332Shelge 	switch(uuc->uu_state) {
59911876Shelge 
60011876Shelge 	/*
60111876Shelge 	 * Two nulls have been sent, remove break, and send inits
60211876Shelge 	 */
60312332Shelge 	case UUS_INIT1:
60412332Shelge 		uuaddr->tcs = UUCS_INTR;
60511876Shelge 		printd("ON2 ");
60612332Shelge 		uuc->uu_state = UUS_INIT2;
60712332Shelge 		uuc->uu_wbptr = uuinit;
60812332Shelge 		uuc->uu_wcnt = sizeof (uuinit);
60911876Shelge 		goto top;
61011876Shelge 
61111876Shelge 	/*
61211876Shelge 	 * Inits have been sent, wait for a continue msg.
61311876Shelge 	 */
61412332Shelge 	case UUS_INIT2:
615*12857Shelge 		c = uuaddr->rdb;	/* prevent overrun error */
61612332Shelge 		uuaddr->rcs = UUCS_INTR;
61712332Shelge 		uuc->uu_flag = 1;
61811876Shelge 		break;
61911876Shelge 
62012332Shelge 	case UUS_IDLE:		/* stray interrupt? */
62111876Shelge 		break;
62211876Shelge 
62311876Shelge 	/*
62411876Shelge 	 * Read cmd packet sent, get ready for data
62511876Shelge 	 */
62612332Shelge 	case UUS_SENDR:
62712332Shelge 		uuc->uu_state = UUS_GETH;
62812332Shelge 		uuc->uu_rbptr = (u_char *)data;
62912332Shelge 		uuc->uu_rcnt = 2;
63012332Shelge 		uuc->uu_flag = 1;
63112332Shelge 		uuaddr->tcs = 0;	/* disable transmitter interrupts */
63211876Shelge 		printd("OFF ");
63311876Shelge 		break;
63411876Shelge 
63511876Shelge 	/*
63611876Shelge 	 * Write cmd packet sent, wait for continue
63711876Shelge 	 */
63812332Shelge 	case UUS_SENDW:
63912332Shelge 		uuc->uu_state = UUS_WAIT;
64012332Shelge 		uuc->uu_flag = 1;
64112332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
64211876Shelge 			printf("NO IE\n");
64312332Shelge 			uuaddr->rcs = UUCS_INTR;
64411876Shelge 		}
64511876Shelge 		break;
64611876Shelge 
64711876Shelge 	/*
64811876Shelge 	 * Header sent, send data.
64911876Shelge 	 */
65012332Shelge 	case UUS_SENDH:
65112332Shelge 		uuc->uu_state = UUS_SENDD;
65212332Shelge 		uuc->uu_wbptr = (u_char *)uuc->uu_addr;
65312332Shelge 		uuc->uu_wcnt = data->pk_mcount;
65411876Shelge 		goto top;
65511876Shelge 
65611876Shelge 	/*
65711876Shelge 	 * Data sent, follow with checksum.
65811876Shelge 	 */
65912332Shelge 	case UUS_SENDD:
66012332Shelge 		uuc->uu_state = UUS_SENDC;
66112332Shelge 		uuc->uu_wbptr = (u_char *)&data->pk_chksum;
66212332Shelge 		uuc->uu_wcnt = sizeof (data->pk_chksum);
66311876Shelge 		goto top;
66411876Shelge 
66511876Shelge 	/*
66611876Shelge 	 * Checksum sent, wait for continue.
66711876Shelge 	 */
66812332Shelge 	case UUS_SENDC:
66911876Shelge 		/*
67011876Shelge 		 * Updata buffer address and count.
67111876Shelge 		 */
67212332Shelge 		uuc->uu_addr += data->pk_mcount;
67312332Shelge 		uuc->uu_count -= data->pk_mcount;
67412332Shelge 		if (uuc->uu_count) {
67512332Shelge 			uuc->uu_state = UUS_WAIT;
67612332Shelge 			uuc->uu_flag = 1;
67711876Shelge 			break;
67811876Shelge 		}
67911876Shelge 
68011876Shelge 		/*
68111876Shelge 		 * End of transmission, get ready for end packet.
68211876Shelge 		 */
68312332Shelge 		uuc->uu_state = UUS_GET;
68412332Shelge 		uuc->uu_rbptr = (u_char *)data;
68512332Shelge 		uuc->uu_rcnt = sizeof (*data);
68612332Shelge 		uuc->uu_flag = 1;
68712332Shelge 		uuaddr->tcs = 0;		/* disable transm. interrupts */
68811876Shelge 		printd("OFF2 ");
68911876Shelge 		break;
69011876Shelge 
69111876Shelge 	/*
69212332Shelge 	 * Random interrupt
69311876Shelge 	 */
69411876Shelge 	default:
69511876Shelge 		break;
69611876Shelge 	}
69711896Shelge 	if (uudebug) {
69811896Shelge 		printd("  new uu_state=");
69912332Shelge 		printstate(uuc->uu_state);
700*12857Shelge 		printf("\n");
70111876Shelge 	}
70211876Shelge }
70311876Shelge 
70411876Shelge /*
70511876Shelge  * Compute checksum TU58 fashion
70611876Shelge  */
70711876Shelge #ifdef lint
70811896Shelge uuchk(word, cp, n)
70911876Shelge 	register word;
71011876Shelge 	register unsigned short *cp;
71111876Shelge 	int n;
71211876Shelge {
71311876Shelge 	register int c = n >> 1;
71411876Shelge 	register long temp;
71511876Shelge 
71611876Shelge 	do {
71711876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
71811876Shelge 		word += temp;
71911876Shelge 	} while (--c > 0);
72011876Shelge 	if (n & 1)
72111876Shelge 		word += *(unsigned char *)cp;
72211876Shelge 	while (word & 0xffff0000)
72311876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
72411876Shelge 	return (word);
72511876Shelge }
72611876Shelge #else
72711896Shelge uuchk(word0, wp, n)
72811896Shelge 	register int word0;			/* r11 */
72911896Shelge 	register char *wp;			/* r10 */
73011896Shelge 	register int n;				/* r9 */
73111876Shelge {
73211876Shelge 	asm("loop:");
73311896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
73411896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
73511876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
73611896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
73711896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
73811896Shelge 	asm("	addw2	r10,r11");		/* add it in */
73911896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
74011876Shelge 	asm("ok:");
74111896Shelge 	asm("	movl	r11,r0");		/* return sum */
74211876Shelge }
74311876Shelge #endif
74411876Shelge 
74511896Shelge uuwatch()
74611876Shelge {
74712332Shelge 	register struct uu_ctlr *uuc;
74812332Shelge 	register struct uudevice *uuaddr;
749*12857Shelge 	struct uba_device *ui;
75012332Shelge 	struct buf *bp, *uutab;
75112332Shelge 	int s;
75211876Shelge 
75312332Shelge 	if (uuwstart == 0)
75411876Shelge 		return;
755*12857Shelge 	for (s=0; s<NUU; s++) {
75612332Shelge 		int i;
75712332Shelge 
75812332Shelge 		uuc = &uu_ctlr[s];
759*12857Shelge 		ui = uudinfo[s];
76012332Shelge 		if (uuc->uu_flag)
76112332Shelge 			uuc->uu_flag++;
76212332Shelge 		if (uuc->uu_flag <= 40)
76312332Shelge 			continue;
76412332Shelge 		printf("uu%d: read stalled\n", s);
76512332Shelge 		printf("%X %X %X %X %X %X %X %X\n", uuc->uu_rbptr, uuc->uu_rcnt,
76612332Shelge 		       uuc->uu_wbptr, uuc->uu_wcnt, uuc->uu_state, uuc->uu_flag,
76712332Shelge 		       uuc->uu_addr, uuc->uu_count);
76812332Shelge 		uuc->uu_flag = 0;
769*12857Shelge 		uuaddr = (struct uudevice *)ui->ui_addr;
770*12857Shelge 		uutab = &uitab[s];
77112332Shelge 		i = uuaddr->rdb;		/* dummy */
77212332Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
77312332Shelge 		uuaddr->tcs = UUCS_INTR;
77412332Shelge 		uuc->uu_state = UUS_IDLE;
77512332Shelge 		if (!uutab->b_active) {
77612332Shelge 			wakeup((caddr_t)uuc);
77712332Shelge 			continue;
77812332Shelge 		}
77912332Shelge 		if (++uutab->b_errcnt <= 1) {
780*12857Shelge 			uustart(ui);
78112332Shelge 			continue;
78212332Shelge 		}
78312332Shelge 		if (bp = uutab->b_actf) {
78412332Shelge 			bp->b_flags |= B_ERROR;
78512332Shelge 			if ((bp->b_flags&B_READ) == 0)
786*12857Shelge 				uu_vee(&pcnt[UNIT(minor(bp->b_dev))]);
78712332Shelge 			iodone(bp);
78812332Shelge 		}
78911876Shelge 	}
79012332Shelge 	timeout(uuwatch, (caddr_t)0, hz);
79112332Shelge 	return;
79212332Shelge }
79312332Shelge 
794*12857Shelge 
795*12857Shelge uuioctl(dev, cmd, data, flag)
796*12857Shelge 	dev_t dev;
797*12857Shelge 	caddr_t data;
798*12857Shelge {
799*12857Shelge 	/*
800*12857Shelge 	 * to be added later
801*12857Shelge 	 */
802*12857Shelge 	return (ENXIO);
803*12857Shelge }
804*12857Shelge 
80512332Shelge uu_pee(cp)
80612332Shelge char *cp;
80712332Shelge {
80812332Shelge 	register int s;
80912332Shelge 
810*12857Shelge 	s = splx(UUIPL);
81112332Shelge 	if (++(*cp) > NTUQ) {
81212332Shelge 		sleep(cp, PRIBIO);
81311876Shelge 	}
81412332Shelge 	splx(s);
81512332Shelge }
81612332Shelge 
81712332Shelge uu_vee(cp)
81812332Shelge char *cp;
81912332Shelge {
82012332Shelge 	register int s;
82112332Shelge 
822*12857Shelge 	s = splx(UUIPL);
82312332Shelge 	if (--(*cp) <= NTUQ) {
82412332Shelge 		wakeup(cp);
82511876Shelge 	}
82611876Shelge 	splx(s);
82711876Shelge }
82811876Shelge #endif
82912332Shelge 
830