xref: /csrg-svn/sys/vax/uba/uu.c (revision 12332)
1*12332Shelge /*	uu.c	4.3	83/05/08	*/
211876Shelge 
3*12332Shelge #include "uu.h"
411896Shelge #if NDL > 0
511876Shelge /*
611896Shelge  * TU58 DECtape II/DL11 device driver
7*12332Shelge  * (based on a driver written by Mike Obrien @ RAND)
811876Shelge  *
911896Shelge  * The TU58 * is treated as a block device (only).  Error detection and
1011876Shelge  * recovery is almost non-existant.  It is assumed that the
1111876Shelge  * TU58 will follow the RSP protocol exactly, very few protocol
1211896Shelge  * errors are checked for.
1311876Shelge  */
1411896Shelge 
15*12332Shelge #include "../machine/pte.h"
1611896Shelge 
1711876Shelge #include "../h/param.h"
1811876Shelge #include "../h/systm.h"
1911876Shelge #include "../h/buf.h"
2011876Shelge #include "../h/conf.h"
21*12332Shelge #include "../h/time.h"
2211896Shelge #include "../h/kernel.h"
2311896Shelge #include "../h/errno.h"
2411896Shelge #include "../h/uio.h"
2511896Shelge #include "../h/file.h"
2611876Shelge 
2711876Shelge #include "../vax/cpu.h"
28*12332Shelge #include "../vax/nexus.h"
29*12332Shelge 
3011896Shelge #include "../vaxuba/ubavar.h"
3111896Shelge #include "../vaxuba/ubareg.h"
3211896Shelge #include "../vaxuba/uureg.h"
3311876Shelge 
34*12332Shelge #define	printd	if (uudebug) printf
3511876Shelge #ifdef	printd
36*12332Shelge int	uudebug;		/* printd */
3711876Shelge #endif	printd
3811876Shelge 
3911876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
4011896Shelge #define	WRV     02              /* bit in minor dev => write w. read verify */
41*12332Shelge #define	NDPC	02		/* drives per controller */
42*12332Shelge #define	NUU	NDPC * NDL	/* number of drives */
43*12332Shelge #define	DNUM	01		/* mask for drive number */
44*12332Shelge #define	NTUQ	02		/* # of block which can be queued up */
4511876Shelge 
4611876Shelge /*
4711876Shelge  * Structure of a command packet
4811876Shelge  */
4911876Shelge struct packet {
5011876Shelge 	u_char	pk_flag;	/* indicates packet type (cmd, data, etc.) */
5111876Shelge 	u_char	pk_mcount;	/* length of packet (bytes) */
5211876Shelge 	u_char	pk_op;		/* operation to perform (read, write, etc.) */
5311876Shelge 	u_char	pk_mod;		/* modifier for op or returned status */
5411876Shelge 	u_char	pk_unit;	/* unit number */
5511876Shelge 	u_char	pk_sw;		/* switches */
5611876Shelge 	u_short	pk_seq;		/* sequence number, always zero */
5711876Shelge 	u_short	pk_count;	/* requested byte count for read or write */
5811876Shelge 	u_short	pk_block;	/* block number for read, write, or seek */
5911876Shelge 	u_short	pk_chksum;	/* checksum, by words with end around carry */
6011876Shelge };
6111876Shelge 
6211896Shelge struct packet uucmd[NDL];	/* a command sent to the TU58 */
6311896Shelge struct packet uudata[NDL];	/* a command or data returned from TU58 */
6411876Shelge 
6511876Shelge /*
6611896Shelge  * per controller state information
6711876Shelge  */
6811896Shelge struct uu_ctlr {
6911896Shelge 	u_char	*uu_rbptr;	/* pointer to buffer for read */
7011896Shelge 	int	uu_rcnt;	/* how much to read */
7111896Shelge 	u_char	*uu_wbptr;	/* pointer to buffer for write */
7211896Shelge 	int	uu_wcnt;	/* how much to write */
7311896Shelge 	int	uu_state;	/* current uu_state of tansfer operation */
7411896Shelge 	int	uu_flag;	/* read in progress flag */
7511896Shelge 	char	*uu_addr;	/* real buffer data address */
7611896Shelge 	int	uu_count;	/* real requested count */
7711896Shelge 	int	uu_serrs;	/* count of soft errors */
7811896Shelge 	int	uu_cerrs;	/* count of checksum errors */
7911896Shelge 	int	uu_herrs;	/* count of hard errors */
8011896Shelge 	char    uu_dopen[NDPC];	/* drive is open */
8111896Shelge } uu_ctlr[NDL];
8211876Shelge 
8311876Shelge /*
8411896Shelge  * controller states
8511876Shelge  */
8611896Shelge #define	UUS_INIT1	0	/* sending nulls */
8711896Shelge #define	UUS_INIT2	1	/* sending inits */
8811896Shelge #define	UUS_IDLE	2	/* initialized, no transfer in progress */
8911896Shelge #define	UUS_SENDH	3	/* sending header */
9011896Shelge #define	UUS_SENDD	4	/* sending data */
9111896Shelge #define	UUS_SENDC	5	/* sending checksum */
9211896Shelge #define	UUS_SENDR	6	/* sending read command packet */
9311896Shelge #define	UUS_SENDW	7	/* sending write command packet */
9411896Shelge #define	UUS_GETH	8	/* reading header */
9511896Shelge #define	UUS_GETD	9	/* reading data */
9611896Shelge #define	UUS_GETC	10	/* reading checksum */
9711896Shelge #define	UUS_GET		11	/* reading an entire packet */
9811896Shelge #define	UUS_WAIT	12	/* waiting for continue */
9911876Shelge 
10011896Shelge #define	UUS_NSTATES	13
10111896Shelge char *uustates[UUS_NSTATES] = {
10211876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
10311876Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT"
10411876Shelge };
105*12332Shelge 
106*12332Shelge #define	UNIT(dev)	(minor(dev)&DNUM)
10711876Shelge #define	printstate(state) \
10811896Shelge 	if ((state) < UUS_NSTATES) \
10911896Shelge 		printf("%s", uustates[(state)]); \
11011876Shelge 	else \
11111876Shelge 		printf("%d", (state));
11211876Shelge 
11311876Shelge /*
11411876Shelge  * Packet Flags
11511876Shelge  */
11611876Shelge #define	TUF_DATA	1		/* data packet */
11711876Shelge #define	TUF_CMD		2		/* command packet */
11811876Shelge #define	TUF_INITF	4		/* initialize */
11911876Shelge #define	TUF_CONT	020		/* continue */
12011876Shelge #define	TUF_XOFF	023		/* flow control */
12111876Shelge 
12211876Shelge /*
12311876Shelge  * Op Codes
12411876Shelge  */
12511896Shelge #define	TUOP_NOOP	0		/* no operation */
12611876Shelge #define	TUOP_INIT	1		/* initialize */
12711876Shelge #define	TUOP_READ	2		/* read block */
12811876Shelge #define	TUOP_WRITE	3		/* write block */
12911876Shelge #define	TUOP_SEEK	5		/* seek to block */
13011896Shelge #define	TUOP_DIAGNOSE	7		/* run micro-diagnostics */
13111876Shelge #define	TUOP_END	0100		/* end packet */
13211876Shelge 
13311876Shelge /*
13411876Shelge  * Mod Flags
13511876Shelge  */
13611876Shelge #define TUMD_WRV        1               /* write with read verify */
13711876Shelge 
13811876Shelge /*
13911876Shelge  * Switches
14011876Shelge  */
14111876Shelge 
14211896Shelge u_char	uunull[2] = { 0, 0 };	/* nulls to send for initialization */
14311896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
14411876Shelge 
14511896Shelge struct	uba_device	*uudinfo[NUU];
14611896Shelge struct	uba_ctlr	*uuminfo[NDL];
14711896Shelge 
148*12332Shelge int uuprobe(), uuslave(), uuattach(), uudgo(), uurintr(), uuxintr(), uuwatch();
14911896Shelge u_short uustd[] = { 0176500, 0 };
15011896Shelge struct uba_driver dldriver =
151*12332Shelge     { uuprobe, uuslave, uuattach, uudgo, uustd, "uu", uudinfo, "uu", uuminfo };
15211896Shelge 
15311896Shelge int	uuwstart;
154*12332Shelge static char pcnt[2];			/* pee/vee counters */
15511896Shelge 
15611876Shelge /*ARGSUSED*/
15711896Shelge uuprobe(reg)
15811896Shelge 	caddr_t reg;
15911876Shelge {
16011896Shelge 	register int br, cvec;			/* value result */
16111896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
16211896Shelge 	int i;
16311876Shelge 
16411876Shelge #ifdef lint
16511896Shelge 	br = 0; cvec = br; br = cvec;
16611896Shelge 	uurintr(0); uuxintr(0);
16711876Shelge #endif
16811896Shelge 	uuaddr->rcs = UUCS_INTR;
16911896Shelge 	uuaddr->tdb = TUF_INITF;
17011896Shelge 	DELAY(10000);
17111896Shelge 	i = uuaddr->rdb;
17211896Shelge 	uuaddr->rcs = 0;
17311896Shelge 	return(sizeof (*uuaddr));
17411896Shelge }
17511896Shelge 
176*12332Shelge uuslave(ui, reg)
17711896Shelge 	struct uba_device *ui;
17811896Shelge 	caddr_t reg;
17911896Shelge {
18011896Shelge 	return (ui->ui_slave == 0 || ui->ui_slave == 1);
18111896Shelge }
18211896Shelge 
18311896Shelge /*ARGSUSED*/
18411896Shelge uuattach(ui)
18511896Shelge 	struct uba_device *ui;
18611896Shelge {
187*12332Shelge 	/* no local state to set up */
18811896Shelge }
18911896Shelge 
19011896Shelge /*ARGSUSED1*/
19111896Shelge uuopen(dev, flag)
19211896Shelge 	dev_t dev;
19311896Shelge 	int flag;
19411896Shelge {
19511896Shelge 	register struct uba_device *ui;
19611896Shelge 	register struct uu_ctlr *uuc;
19711896Shelge 	register struct uudevice *uuaddr;
19811896Shelge 	register struct uba_ctlr *um;
199*12332Shelge 	int ctlr, unit = UNIT(dev), s;
20011896Shelge 
20111896Shelge 	if (unit >= NUU || (ui = uudinfo[unit]) == 0 || ui->ui_alive == 0)
20211876Shelge 		return (ENXIO);
20311896Shelge 	um = ui->ui_mi;
20411896Shelge 	ctlr = um->um_ctlr;
20511896Shelge 	uuc = &uu_ctlr[ctlr];
206*12332Shelge 	if (uuc->uu_dopen[unit&DNUM])
20711896Shelge 		return (EBUSY);
20811896Shelge 	if (uuwstart++ == 0)
20911896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
21011896Shelge 
211*12332Shelge 	uuc->uu_dopen[unit&DNUM]++;
212*12332Shelge 	uuaddr = (struct uudevice *)um->um_addr;
21311896Shelge 	s = spl5();
21411876Shelge 	/*
21511896Shelge 	 * If the unit already initialized,
21611876Shelge 	 * just enable interrupts and return.
21711876Shelge 	 */
218*12332Shelge 	if (uuc->uu_state == UUS_IDLE) {
21911896Shelge 		uuaddr->rcs = UUCS_INTR;
22011876Shelge 		splx(s);
22111876Shelge 		return (0);
22211876Shelge 	}
22311876Shelge 
22411876Shelge 	/*
22511876Shelge 	 * Must initialize, reset the cassette
22611876Shelge 	 * and wait for things to settle down.
22711876Shelge 	 */
22811896Shelge 	uureset(ctlr);
22911896Shelge 	sleep((caddr_t)uuc, PZERO+1);
23011896Shelge 	um->um_tab.b_active = NULL;
231*12332Shelge 	if (uuc->uu_state != UUS_IDLE) {
232*12332Shelge 		uuc->uu_state = UUS_INIT1;
233*12332Shelge 		uuc->uu_dopen[unit&DNUM] = 0;
234*12332Shelge 		uuc->uu_rcnt = uuc->uu_wcnt = 0;
23511896Shelge 		uuaddr->rcs = 0;
23611896Shelge 		uuaddr->tcs = 0;
23711896Shelge 		splx(s);
23811896Shelge 		return (ENXIO);
23911876Shelge 	}
24011876Shelge 	splx(s);
24111876Shelge 	return (0);
24211876Shelge }
24311876Shelge 
24411896Shelge uuclose(dev, flag)
24511896Shelge 	dev_t dev;
24611896Shelge 	int flag;
24711876Shelge {
248*12332Shelge 	register struct uba_ctlr *um = uudinfo[UNIT(dev)]->ui_mi;
24911896Shelge 	register struct uu_ctlr *uuc;
25011876Shelge 
251*12332Shelge 	uuwstart--;
25211896Shelge 	uuc = &uu_ctlr[um->um_ctlr];
25311896Shelge 	if (uuc->uu_serrs + uuc->uu_cerrs + uuc->uu_herrs != 0) {
25411876Shelge 		/*
25511876Shelge 		 * A tu58 is like nothing ever seen before;
25611876Shelge 		 * I guess this is appropriate then...
25711876Shelge 		 */
25811876Shelge 		uprintf(
25911896Shelge 		   "uu%d: %d soft errors, %d chksum errors, %d hard errors\n",
260*12332Shelge 		    UNIT(dev), uuc->uu_serrs, uuc->uu_cerrs, uuc->uu_herrs);
26111896Shelge 		    uuc->uu_serrs = uuc->uu_cerrs = uuc->uu_herrs = 0;
26211876Shelge 	}
263*12332Shelge 	uuc->uu_dopen[UNIT(dev)] = 0;
26411876Shelge }
26511876Shelge 
26611896Shelge uureset(ctlr)
26711896Shelge 	int ctlr;
26811876Shelge {
269*12332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
270*12332Shelge 	register struct packet *cmd = &uucmd[ctlr];
27111896Shelge 	struct uba_ctlr *um = uuminfo[ctlr];
272*12332Shelge 	register struct uudevice *uuaddr = (struct uudevice *)um->um_addr;
27311876Shelge 
27411896Shelge 	um->um_tab.b_active++;
275*12332Shelge 	uuc->uu_state = UUS_INIT1;
27611896Shelge 	uuc->uu_wbptr = uunull;
27711896Shelge 	uuc->uu_wcnt = sizeof (uunull);
27811896Shelge 	cmd->pk_flag = TUF_CMD;
279*12332Shelge 	cmd->pk_mcount = sizeof (*cmd) - 4;
28011896Shelge 	cmd->pk_mod = 0;
28111896Shelge 	cmd->pk_seq = 0;
282*12332Shelge 	cmd->pk_sw = 0;
28311896Shelge 	uuaddr->rcs = 0;
28411896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
28511896Shelge 	uuxintr(ctlr);				/* start output */
28611876Shelge }
28711876Shelge 
288*12332Shelge uudgo()
289*12332Shelge {
290*12332Shelge }
291*12332Shelge 
29211876Shelge /*
29311876Shelge  * Strategy routine for block I/O
29411876Shelge  */
29511896Shelge uustrategy(bp)
29611876Shelge 	register struct buf *bp;
29711876Shelge {
298*12332Shelge 	register struct buf *uutab;
29911896Shelge 	struct uba_device *ui;
300*12332Shelge 	int s, unit = UNIT(bp->b_dev);
30111876Shelge 
30211896Shelge 	if (unit > NUU)
30311896Shelge 		goto bad;
30411896Shelge 	if (bp->b_blkno >= NTUBLK)
30511896Shelge 		goto bad;
30611896Shelge 	ui = uudinfo[unit];
30711896Shelge 	if (ui == 0 || ui->ui_alive == 0)
30811896Shelge 		goto bad;
309*12332Shelge 	uutab = &ui->ui_mi->um_tab;	/* one request queue per controller */
310*12332Shelge 	if ((bp->b_flags&B_READ) == 0)
311*12332Shelge 		uu_pee(&pcnt[UNIT(bp->b_dev)]);
31211896Shelge 	s = spl5();
313*12332Shelge 	bp->av_forw = NULL;
314*12332Shelge 	if (uutab->b_actf == NULL)
315*12332Shelge 		uutab->b_actf = bp;
316*12332Shelge 	else
317*12332Shelge 		uutab->b_actl->av_forw = bp;
318*12332Shelge 	uutab->b_actl = bp;
319*12332Shelge 	if (uutab->b_active == 0)
320*12332Shelge 		uustart(ui->ui_mi);
32111876Shelge 	splx(s);
32211896Shelge 	return;
32311896Shelge 
32411896Shelge bad:
32511896Shelge 	bp->b_flags |= B_ERROR;
326*12332Shelge 	bp->b_error = ENXIO;
32711896Shelge 	iodone(bp);
32811896Shelge 	return;
32911876Shelge }
33011876Shelge 
33111876Shelge /*
33211876Shelge  * Start the transfer
33311876Shelge  */
33411896Shelge uustart(um)
33511896Shelge 	register struct uba_ctlr *um;
33611876Shelge {
33711876Shelge 	register struct buf *bp;
33811896Shelge 	register struct uu_ctlr *uuc;
33911896Shelge 	struct packet *cmd;
340*12332Shelge 	int ctlr;
34111876Shelge 
342*12332Shelge 	bp = um->um_tab.b_actf;
343*12332Shelge 	if (bp == NULL)
34411876Shelge 		return;
345*12332Shelge 	ctlr = um->um_ctlr;
346*12332Shelge 	uuc = &uu_ctlr[ctlr];
347*12332Shelge 	cmd = &uucmd[ctlr];
348*12332Shelge 	if (uuc->uu_state != UUS_IDLE) {
349*12332Shelge 		uureset(ctlr);
35011876Shelge 		return;
35111876Shelge 	}
35211896Shelge 	um->um_tab.b_active++;
35311896Shelge 	cmd->pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
35411896Shelge 	cmd->pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
35511876Shelge 	    TUMD_WRV : 0;
356*12332Shelge 	cmd->pk_unit = UNIT(bp->b_dev);
357*12332Shelge 	cmd->pk_sw = 0;
358*12332Shelge 	cmd->pk_count = uuc->uu_count = bp->b_bcount;
35911896Shelge 	cmd->pk_block = bp->b_blkno;
36011896Shelge 	cmd->pk_chksum =
361*12332Shelge 	    uuchk(*((short *)cmd), (u_short *)&cmd->pk_op,
362*12332Shelge 		(int)cmd->pk_mcount);
363*12332Shelge 	uuc->uu_state = bp->b_flags&B_READ ? UUS_SENDR : UUS_SENDW;
36411896Shelge 	uuc->uu_addr = bp->b_un.b_addr;
36511896Shelge 	uuc->uu_count = bp->b_bcount;
366*12332Shelge 	uuc->uu_wbptr = (u_char *)cmd;
367*12332Shelge 	uuc->uu_wcnt = sizeof (*cmd);
368*12332Shelge 	uuxintr(ctlr);
36911876Shelge }
37011876Shelge 
37111876Shelge /*
37211876Shelge  * TU58 receiver interrupt
37311876Shelge  */
374*12332Shelge uurintr(ctlr)
375*12332Shelge 	int ctlr;
37611876Shelge {
377*12332Shelge 	struct uba_ctlr *um = uuminfo[ctlr];
378*12332Shelge 	register struct buf *bp = um->um_tab.b_actf;
379*12332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
380*12332Shelge 	register struct uudevice *uuaddr = (struct uudevice *)um->um_addr;
381*12332Shelge 	register struct buf *uutab = &um->um_tab;
382*12332Shelge 	struct packet *data, *cmd;
383*12332Shelge 	int c;
38411876Shelge 
385*12332Shelge 	if (!uutab->b_active)
386*12332Shelge 		return;
387*12332Shelge 	cmd = &uucmd[ctlr];
388*12332Shelge 	c = uuaddr->rdb;
389*12332Shelge 	if (c & UURDB_ERROR) {
390*12332Shelge 		if (c & UURDB_ORUN) {
391*12332Shelge 			printf("data overrun, ");
392*12332Shelge 			goto bad;
393*12332Shelge 		} else {
394*12332Shelge 			printf("uu%d: break received, device reset, state=",
395*12332Shelge 				UNIT(bp->b_dev));
396*12332Shelge 			printstate(uuc->uu_state);
397*12332Shelge 			uureset(ctlr);
398*12332Shelge 			printf("\n");
399*12332Shelge 			return;
400*12332Shelge 		}
40111876Shelge 	}
402*12332Shelge top:
403*12332Shelge 	c &= 0xff;
404*12332Shelge 	if (uuc->uu_rcnt) {		/* still waiting for data? */
405*12332Shelge 		*uuc->uu_rbptr++ = c;	/* yup, put it there */
406*12332Shelge 		if (--uuc->uu_rcnt)	/* decrement count, any left? */
40711876Shelge 			return;		/* get some more */
40811876Shelge 	}
409*12332Shelge 	data = &uudata[ctlr];
41011876Shelge 
41111876Shelge 	/*
41211876Shelge 	 * We got all the data we were expecting for now,
41311896Shelge 	 * switch on the uu_state of the transfer.
41411876Shelge 	 */
415*12332Shelge 	switch(uuc->uu_state) {
41611876Shelge 
41711876Shelge 	/*
41811876Shelge 	 * If we get an unexpected "continue",
41911876Shelge 	 * start all over again...
42011876Shelge 	 */
421*12332Shelge 	case UUS_INIT2:
422*12332Shelge 		uuc->uu_state = c == TUF_CONT ? UUS_IDLE : UUS_INIT1;
423*12332Shelge 		uuc->uu_flag = 0;
424*12332Shelge 		wakeup((caddr_t)uuc);
425*12332Shelge 		uustart(um);
42611876Shelge 		break;
42711876Shelge 
42811876Shelge 	/*
42911876Shelge 	 * Only transition from this state
43011876Shelge 	 * is on a "continue", so if we don't
43111876Shelge 	 * get it, reset the world.
43211876Shelge 	 */
433*12332Shelge 	case UUS_WAIT:			/* waiting for continue */
434*12332Shelge 		switch(c) {
435*12332Shelge 		case TUF_CONT:  /* got the expected continue */
436*12332Shelge 			uuc->uu_flag = 0;
437*12332Shelge 			data->pk_flag = TUF_DATA;
438*12332Shelge 			data->pk_mcount = MIN(128, uuc->uu_count);
439*12332Shelge 			data->pk_chksum =
440*12332Shelge 			    tuchk(*((short *)data), (caddr_t)uuc->uu_addr,
441*12332Shelge 				(int)data->pk_mcount);
442*12332Shelge 			uuc->uu_state = UUS_SENDH;
443*12332Shelge 			uuc->uu_wbptr = (u_char *)data;
444*12332Shelge 			uuc->uu_wcnt = 2;
445*12332Shelge 			tuxintr();
44611876Shelge 			break;
447*12332Shelge 
448*12332Shelge 		case TUF_CMD:   /* sending us an END packet...error */
449*12332Shelge 			uuc->uu_state = UUS_GET;
450*12332Shelge 			uuc->uu_rbptr = (u_char *) data;
451*12332Shelge 			uuc->uu_rcnt = sizeof (*data);
452*12332Shelge 			uuc->uu_flag = 1;
453*12332Shelge 			uuaddr->tcs = 0;
454*12332Shelge 			goto top;
455*12332Shelge 
456*12332Shelge 		case TUF_INITF:
457*12332Shelge 			tureset();
458*12332Shelge 			break;
459*12332Shelge 
460*12332Shelge 		default:        /* something random...bad news */
461*12332Shelge 			uuc->uu_state = UUS_INIT1;
462*12332Shelge 			break;
46311876Shelge 		}
46411876Shelge 		break;
46511876Shelge 
466*12332Shelge 	case UUS_SENDW:
46711876Shelge 		if (c != TUF_CONT)
46811876Shelge 			goto bad;
469*12332Shelge 		uureset(ctlr);
47011876Shelge 		break;
47111876Shelge 
47211876Shelge 	/*
47311876Shelge 	 * Got header, now get data; amount to
47411896Shelge 	 * fetch is included in packet.
47511876Shelge 	 */
476*12332Shelge 	case UUS_GETH:
477*12332Shelge 		if (data->pk_flag == TUF_DATA)
478*12332Shelge 			uuc->uu_rbptr = (u_char *)uuc->uu_addr;
479*12332Shelge 		uuc->uu_rcnt = data->pk_mcount;
480*12332Shelge 		uuc->uu_state = UUS_GETD;
48111876Shelge 		break;
48211876Shelge 
48311876Shelge 	/*
48411876Shelge 	 * Got the data, now fetch the checksum.
48511876Shelge 	 */
486*12332Shelge 	case UUS_GETD:
487*12332Shelge 		uuc->uu_rbptr = (u_char *)&data->pk_chksum;
488*12332Shelge 		uuc->uu_rcnt = sizeof (data->pk_chksum);
489*12332Shelge 		uuc->uu_state = UUS_GETC;
49011876Shelge 		break;
49111876Shelge 
492*12332Shelge 	case UUS_GET:
493*12332Shelge 	case UUS_GETC:
49411876Shelge 		/* got entire packet */
49511876Shelge #ifdef notdef
496*12332Shelge 		if (data->pk_chksum !=
497*12332Shelge 		    uuchk(*((short *)data), (u_short *)
498*12332Shelge 		     (data->pk_flag == TUF_DATA ? uuc->uu_addr : &data->pk_op),
499*12332Shelge 		     (int)data->pk_mcount))
500*12332Shelge 			uuc->uu_cerrs++;
50111876Shelge #endif
502*12332Shelge 		if (data->pk_flag == TUF_DATA) {
50311876Shelge 			/* data packet, advance to next */
504*12332Shelge 			uuc->uu_addr += data->pk_mcount;
505*12332Shelge 			uuc->uu_count -= data->pk_mcount;
506*12332Shelge 			uuc->uu_state = UUS_GETH;
507*12332Shelge 			uuc->uu_rbptr = (u_char *)data;	/* next packet */
508*12332Shelge 			uuc->uu_rcnt = 2;
509*12332Shelge 		} else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) {
51011876Shelge 			/* end packet, idle and reenable transmitter */
511*12332Shelge 			uuc->uu_state = UUS_IDLE;
512*12332Shelge 			uuc->uu_flag = 0;
513*12332Shelge 			uuaddr->rcs = UUCS_INTR;
51411876Shelge 			printd("ON ");
515*12332Shelge 			if (bp == NULL) {
516*12332Shelge 				printf("uu: no bp active\n");
517*12332Shelge 				uustart(um);
51811876Shelge 				return;
51911876Shelge 			}
520*12332Shelge 			if (data->pk_mod > 1) {        /* hard error */
52111876Shelge 				bp->b_flags |= B_ERROR;
522*12332Shelge 				uuc->uu_herrs++;
52311896Shelge 				harderr(bp, "uu");
524*12332Shelge 				printf(" pk_mod %o\n", data->pk_mod&0xff);
525*12332Shelge 			} else if (data->pk_mod != 0)	/* soft error */
526*12332Shelge 				uuc->uu_serrs++;
527*12332Shelge 			uutab->b_active = NULL;
528*12332Shelge 			uutab->b_actf = bp->av_forw;
529*12332Shelge 			bp->b_resid = uuc->uu_count;
53011876Shelge 			if ((bp->b_flags&B_READ) == 0)
531*12332Shelge 				uu_vee(&pcnt[UNIT(bp->b_dev)]);
53211876Shelge 			iodone(bp);
533*12332Shelge 			uustart(um);
53411876Shelge 		} else {
53511876Shelge 			printf("neither data nor end: %o %o\n",
536*12332Shelge 			    data->pk_flag&0xff, data->pk_op&0xff);
537*12332Shelge 			uuaddr->rcs = 0;		/* flush the rest */
538*12332Shelge 			uuc->uu_state = UUS_INIT1;
53911876Shelge 		}
54011876Shelge 		break;
54111876Shelge 
542*12332Shelge 	case UUS_IDLE:
543*12332Shelge 	case UUS_INIT1:
54411876Shelge 		break;
54511876Shelge 
54611876Shelge 	default:
54711876Shelge bad:
54811876Shelge 		if (c == TUF_INITF) {
549*12332Shelge 			printf("uu%d protocol error, state=", UNIT(bp->b_dev));
550*12332Shelge 			printstate(uuc->uu_state);
55111876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
552*12332Shelge 			    cmd->pk_op, cmd->pk_count, cmd->pk_block);
553*12332Shelge 			uutab->b_active = NULL;
554*12332Shelge 			if (bp = uutab->b_actf) {
55511876Shelge 				bp->b_flags |= B_ERROR;
556*12332Shelge 				uutab->b_actf = bp->av_forw;
55711876Shelge 				if ((bp->b_flags&B_READ) == 0)
558*12332Shelge 					uu_vee(&pcnt[UNIT(bp->b_dev)]);
55911876Shelge 				iodone(bp);
56011876Shelge 			}
561*12332Shelge 			uuc->uu_state = UUS_INIT1;
56211876Shelge 		} else {
563*12332Shelge 			printf("uu%d receive state error, state=",
564*12332Shelge 				UNIT(bp->b_dev));
565*12332Shelge 			printstate(uuc->uu_state);
56611876Shelge 			printf(", byte=%x\n", c);
56711876Shelge #ifdef notdef
568*12332Shelge 			uuc->uu_state = UUS_INIT1; */
56911876Shelge #endif
570*12332Shelge 			wakeup((caddr_t)uuc);
57111876Shelge 		}
57211876Shelge 	}
57311876Shelge }
57411876Shelge 
57511876Shelge /*
57611876Shelge  * TU58 transmitter interrupt
57711876Shelge  */
578*12332Shelge uuxintr(ctlr)
579*12332Shelge 	int ctlr;
58011876Shelge {
581*12332Shelge 	register struct uu_ctlr *uuc = &uu_ctlr[ctlr];
582*12332Shelge 	register struct uudevice *uuaddr =
583*12332Shelge 				(struct uudevice *) uuminfo[ctlr]->um_addr;
584*12332Shelge 	register struct packet *data;
585*12332Shelge 	int c;
58611876Shelge 
58711876Shelge top:
588*12332Shelge 	if (uuc->uu_wcnt) {
58911876Shelge 		/* still stuff to send, send one byte */
590*12332Shelge 		while ((uuaddr->tcs & UUCS_READY) == 0)
59111876Shelge 			;
592*12332Shelge 		uuaddr->tdb = *uuc->uu_wbptr++;
593*12332Shelge 		uuc->uu_wcnt--;
59411876Shelge 		return;
59511876Shelge 	}
596*12332Shelge 	data = &uudata[ctlr];
59711876Shelge 
59811876Shelge 	/*
59911876Shelge 	 * Last message byte was sent out.
60011896Shelge 	 * Switch on uu_state of transfer.
60111876Shelge 	 */
60211896Shelge 	if (uudebug) {
60311896Shelge 		printf("uuxintr: state=");
604*12332Shelge 		printstate(uuc->uu_state);
60511876Shelge 	}
606*12332Shelge 	switch(uuc->uu_state) {
60711876Shelge 
60811876Shelge 	/*
60911876Shelge 	 * Two nulls have been sent, remove break, and send inits
61011876Shelge 	 */
611*12332Shelge 	case UUS_INIT1:
612*12332Shelge 		uuaddr->tcs = UUCS_INTR;
61311876Shelge 		printd("ON2 ");
614*12332Shelge 		uuc->uu_state = UUS_INIT2;
615*12332Shelge 		uuc->uu_wbptr = uuinit;
616*12332Shelge 		uuc->uu_wcnt = sizeof (uuinit);
61711876Shelge 		goto top;
61811876Shelge 
61911876Shelge 	/*
62011876Shelge 	 * Inits have been sent, wait for a continue msg.
62111876Shelge 	 */
622*12332Shelge 	case UUS_INIT2:
623*12332Shelge 		c = uuaddr->rdb;		/* not used */
624*12332Shelge 		uuaddr->rcs = UUCS_INTR;
625*12332Shelge 		uuc->uu_flag = 1;
62611876Shelge 		break;
62711876Shelge 
628*12332Shelge 	case UUS_IDLE:		/* stray interrupt? */
62911876Shelge 		break;
63011876Shelge 
63111876Shelge 	/*
63211876Shelge 	 * Read cmd packet sent, get ready for data
63311876Shelge 	 */
634*12332Shelge 	case UUS_SENDR:
635*12332Shelge 		uuc->uu_state = UUS_GETH;
636*12332Shelge 		uuc->uu_rbptr = (u_char *)data;
637*12332Shelge 		uuc->uu_rcnt = 2;
638*12332Shelge 		uuc->uu_flag = 1;
639*12332Shelge 		uuaddr->tcs = 0;	/* disable transmitter interrupts */
64011876Shelge 		printd("OFF ");
64111876Shelge 		break;
64211876Shelge 
64311876Shelge 	/*
64411876Shelge 	 * Write cmd packet sent, wait for continue
64511876Shelge 	 */
646*12332Shelge 	case UUS_SENDW:
647*12332Shelge 		uuc->uu_state = UUS_WAIT;
648*12332Shelge 		uuc->uu_flag = 1;
649*12332Shelge 		if ((uuaddr->rcs&UUCS_INTR) == 0) {
65011876Shelge 			printf("NO IE\n");
651*12332Shelge 			uuaddr->rcs = UUCS_INTR;
65211876Shelge 		}
65311876Shelge 		break;
65411876Shelge 
65511876Shelge 	/*
65611876Shelge 	 * Header sent, send data.
65711876Shelge 	 */
658*12332Shelge 	case UUS_SENDH:
659*12332Shelge 		uuc->uu_state = UUS_SENDD;
660*12332Shelge 		uuc->uu_wbptr = (u_char *)uuc->uu_addr;
661*12332Shelge 		uuc->uu_wcnt = data->pk_mcount;
66211876Shelge 		goto top;
66311876Shelge 
66411876Shelge 	/*
66511876Shelge 	 * Data sent, follow with checksum.
66611876Shelge 	 */
667*12332Shelge 	case UUS_SENDD:
668*12332Shelge 		uuc->uu_state = UUS_SENDC;
669*12332Shelge 		uuc->uu_wbptr = (u_char *)&data->pk_chksum;
670*12332Shelge 		uuc->uu_wcnt = sizeof (data->pk_chksum);
67111876Shelge 		goto top;
67211876Shelge 
67311876Shelge 	/*
67411876Shelge 	 * Checksum sent, wait for continue.
67511876Shelge 	 */
676*12332Shelge 	case UUS_SENDC:
67711876Shelge 		/*
67811876Shelge 		 * Updata buffer address and count.
67911876Shelge 		 */
680*12332Shelge 		uuc->uu_addr += data->pk_mcount;
681*12332Shelge 		uuc->uu_count -= data->pk_mcount;
682*12332Shelge 		if (uuc->uu_count) {
683*12332Shelge 			uuc->uu_state = UUS_WAIT;
684*12332Shelge 			uuc->uu_flag = 1;
68511876Shelge 			break;
68611876Shelge 		}
68711876Shelge 
68811876Shelge 		/*
68911876Shelge 		 * End of transmission, get ready for end packet.
69011876Shelge 		 */
691*12332Shelge 		uuc->uu_state = UUS_GET;
692*12332Shelge 		uuc->uu_rbptr = (u_char *)data;
693*12332Shelge 		uuc->uu_rcnt = sizeof (*data);
694*12332Shelge 		uuc->uu_flag = 1;
695*12332Shelge 		uuaddr->tcs = 0;		/* disable transm. interrupts */
69611876Shelge 		printd("OFF2 ");
69711876Shelge 		break;
69811876Shelge 
69911876Shelge 	/*
700*12332Shelge 	 * Random interrupt
70111876Shelge 	 */
70211876Shelge 	default:
70311876Shelge 		break;
70411876Shelge 	}
70511896Shelge 	if (uudebug) {
70611896Shelge 		printd("  new uu_state=");
707*12332Shelge 		printstate(uuc->uu_state);
70811876Shelge 	}
70911876Shelge }
71011876Shelge 
71111876Shelge /*
71211876Shelge  * Compute checksum TU58 fashion
71311876Shelge  */
71411876Shelge #ifdef lint
71511896Shelge uuchk(word, cp, n)
71611876Shelge 	register word;
71711876Shelge 	register unsigned short *cp;
71811876Shelge 	int n;
71911876Shelge {
72011876Shelge 	register int c = n >> 1;
72111876Shelge 	register long temp;
72211876Shelge 
72311876Shelge 	do {
72411876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
72511876Shelge 		word += temp;
72611876Shelge 	} while (--c > 0);
72711876Shelge 	if (n & 1)
72811876Shelge 		word += *(unsigned char *)cp;
72911876Shelge 	while (word & 0xffff0000)
73011876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
73111876Shelge 	return (word);
73211876Shelge }
73311876Shelge #else
73411896Shelge uuchk(word0, wp, n)
73511896Shelge 	register int word0;			/* r11 */
73611896Shelge 	register char *wp;			/* r10 */
73711896Shelge 	register int n;				/* r9 */
73811876Shelge {
73911876Shelge 	asm("loop:");
74011896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
74111896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
74211876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
74311896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
74411896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
74511896Shelge 	asm("	addw2	r10,r11");		/* add it in */
74611896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
74711876Shelge 	asm("ok:");
74811896Shelge 	asm("	movl	r11,r0");		/* return sum */
74911876Shelge }
75011876Shelge #endif
75111876Shelge 
75211896Shelge uuwatch()
75311876Shelge {
754*12332Shelge 	register struct uu_ctlr *uuc;
755*12332Shelge 	register struct uudevice *uuaddr;
756*12332Shelge 	struct uba_ctlr *um;
757*12332Shelge 	struct buf *bp, *uutab;
758*12332Shelge 	int s;
75911876Shelge 
760*12332Shelge 	if (uuwstart == 0)
76111876Shelge 		return;
762*12332Shelge 	for (s=0; s<NDL; s++) {
763*12332Shelge 		int i;
764*12332Shelge 
765*12332Shelge 		uuc = &uu_ctlr[s];
766*12332Shelge 		um = uuminfo[s];
767*12332Shelge 		if (uuc->uu_flag)
768*12332Shelge 			uuc->uu_flag++;
769*12332Shelge 		if (uuc->uu_flag <= 40)
770*12332Shelge 			continue;
771*12332Shelge 		printf("uu%d: read stalled\n", s);
772*12332Shelge 		printf("%X %X %X %X %X %X %X %X\n", uuc->uu_rbptr, uuc->uu_rcnt,
773*12332Shelge 		       uuc->uu_wbptr, uuc->uu_wcnt, uuc->uu_state, uuc->uu_flag,
774*12332Shelge 		       uuc->uu_addr, uuc->uu_count);
775*12332Shelge 		uuc->uu_flag = 0;
776*12332Shelge 		uuaddr = (struct uudevice *)um->um_addr;
777*12332Shelge 		uutab = &um->um_tab;
778*12332Shelge 		i = uuaddr->rdb;		/* dummy */
779*12332Shelge 		uuaddr->rcs = UUCS_INTR;	/* in case we were flushing */
780*12332Shelge 		uuaddr->tcs = UUCS_INTR;
781*12332Shelge 		uuc->uu_state = UUS_IDLE;
782*12332Shelge 		if (!uutab->b_active) {
783*12332Shelge 			wakeup((caddr_t)uuc);
784*12332Shelge 			continue;
785*12332Shelge 		}
786*12332Shelge 		if (++uutab->b_errcnt <= 1) {
787*12332Shelge 			uustart(um);
788*12332Shelge 			continue;
789*12332Shelge 		}
790*12332Shelge 		if (bp = uutab->b_actf) {
791*12332Shelge 			bp->b_flags |= B_ERROR;
792*12332Shelge 			if ((bp->b_flags&B_READ) == 0)
793*12332Shelge 				uu_vee(&pcnt[UNIT(bp->b_dev)]);
794*12332Shelge 			iodone(bp);
795*12332Shelge 		}
79611876Shelge 	}
797*12332Shelge 	timeout(uuwatch, (caddr_t)0, hz);
798*12332Shelge 	return;
799*12332Shelge }
800*12332Shelge 
801*12332Shelge uu_pee(cp)
802*12332Shelge char *cp;
803*12332Shelge {
804*12332Shelge 	register int s;
805*12332Shelge 
806*12332Shelge 	s = spl5();
807*12332Shelge 	if (++(*cp) > NTUQ) {
808*12332Shelge 		sleep(cp, PRIBIO);
80911876Shelge 	}
810*12332Shelge 	splx(s);
811*12332Shelge }
812*12332Shelge 
813*12332Shelge uu_vee(cp)
814*12332Shelge char *cp;
815*12332Shelge {
816*12332Shelge 	register int s;
817*12332Shelge 
818*12332Shelge 	s = spl5();
819*12332Shelge 	if (--(*cp) <= NTUQ) {
820*12332Shelge 		wakeup(cp);
82111876Shelge 	}
82211876Shelge 	splx(s);
82311876Shelge }
82411876Shelge #endif
825*12332Shelge 
826