xref: /csrg-svn/sys/vax/uba/uu.c (revision 11896)
1*11896Shelge /*	uu.c	4.2	83/04/10	*/
211876Shelge 
3*11896Shelge #include "uu->h"
4*11896Shelge #if NDL > 0
511876Shelge /*
6*11896Shelge  * TU58 DECtape II/DL11 device driver
711876Shelge  *
8*11896Shelge  * 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
11*11896Shelge  * errors are checked for.
1211876Shelge  */
13*11896Shelge 
14*11896Shelge /*
15*11896Shelge  * TODO:
16*11896Shelge  * -	Split the uu structure into a per controller
17*11896Shelge  * 	part and a per drive part.
18*11896Shelge  */
19*11896Shelge 
2011876Shelge #include "../h/param.h"
2111876Shelge #include "../h/systm.h"
2211876Shelge #include "../h/buf.h"
2311876Shelge #include "../h/conf.h"
2411876Shelge #include "../h/dir.h"
25*11896Shelge #include "../h/kernel.h"
26*11896Shelge #include "../h/errno.h"
27*11896Shelge #include "../h/uio.h"
2811876Shelge #include "../h/user.h"
29*11896Shelge #include "../h/file.h"
3011876Shelge 
3111876Shelge #include "../vax/cpu.h"
3211876Shelge #include "../vax/mtpr.h"
33*11896Shelge #include "../vaxuba/ubavar.h"
34*11896Shelge #include "../vaxuba/ubareg.h"
35*11896Shelge #include "../vaxuba/uureg.h"
3611876Shelge 
37*11896Shelge #define	printd	if(uudebug) printf
3811876Shelge #ifdef	printd
39*11896Shelge int	uudebug;	/* printd */
4011876Shelge #endif	printd
4111876Shelge 
42*11896Shelge #if	!defined(MRSP) || lint
4311876Shelge #define	MRSP	(cpu != VAX_750)
4411876Shelge #endif
4511876Shelge #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
46*11896Shelge #define	WRV     02              /* bit in minor dev => write w. read verify */
47*11896Shelge #define	NDPC	02		/* # drives per controller */
4811876Shelge 
4911876Shelge /*
5011876Shelge  * Structure of a command packet
5111876Shelge  */
5211876Shelge struct packet {
5311876Shelge 	u_char	pk_flag;	/* indicates packet type (cmd, data, etc.) */
5411876Shelge 	u_char	pk_mcount;	/* length of packet (bytes) */
5511876Shelge 	u_char	pk_op;		/* operation to perform (read, write, etc.) */
5611876Shelge 	u_char	pk_mod;		/* modifier for op or returned status */
5711876Shelge 	u_char	pk_unit;	/* unit number */
5811876Shelge 	u_char	pk_sw;		/* switches */
5911876Shelge 	u_short	pk_seq;		/* sequence number, always zero */
6011876Shelge 	u_short	pk_count;	/* requested byte count for read or write */
6111876Shelge 	u_short	pk_block;	/* block number for read, write, or seek */
6211876Shelge 	u_short	pk_chksum;	/* checksum, by words with end around carry */
6311876Shelge };
6411876Shelge 
65*11896Shelge struct packet uucmd[NDL];	/* a command sent to the TU58 */
66*11896Shelge struct packet uudata[NDL];	/* a command or data returned from TU58 */
6711876Shelge 
6811876Shelge /*
69*11896Shelge  * per controller state information
7011876Shelge  */
71*11896Shelge struct uu_ctlr {
72*11896Shelge 	u_char	*uu_rbptr;	/* pointer to buffer for read */
73*11896Shelge 	int	uu_rcnt;	/* how much to read */
74*11896Shelge 	u_char	*uu_wbptr;	/* pointer to buffer for write */
75*11896Shelge 	int	uu_wcnt;	/* how much to write */
76*11896Shelge 	int	uu_state;	/* current uu_state of tansfer operation */
77*11896Shelge 	int	uu_flag;	/* read in progress flag */
78*11896Shelge 	char	*uu_addr;	/* real buffer data address */
79*11896Shelge 	int	uu_count;	/* real requested count */
80*11896Shelge 	int	uu_serrs;	/* count of soft errors */
81*11896Shelge 	int	uu_cerrs;	/* count of checksum errors */
82*11896Shelge 	int	uu_herrs;	/* count of hard errors */
83*11896Shelge 	char    uu_dopen[NDPC];	/* drive is open */
84*11896Shelge } uu_ctlr[NDL];
8511876Shelge 
8611876Shelge /*
87*11896Shelge  * controller states
8811876Shelge  */
89*11896Shelge #define	UUS_INIT1	0	/* sending nulls */
90*11896Shelge #define	UUS_INIT2	1	/* sending inits */
91*11896Shelge #define	UUS_IDLE	2	/* initialized, no transfer in progress */
92*11896Shelge #define	UUS_SENDH	3	/* sending header */
93*11896Shelge #define	UUS_SENDD	4	/* sending data */
94*11896Shelge #define	UUS_SENDC	5	/* sending checksum */
95*11896Shelge #define	UUS_SENDR	6	/* sending read command packet */
96*11896Shelge #define	UUS_SENDW	7	/* sending write command packet */
97*11896Shelge #define	UUS_GETH	8	/* reading header */
98*11896Shelge #define	UUS_GETD	9	/* reading data */
99*11896Shelge #define	UUS_GETC	10	/* reading checksum */
100*11896Shelge #define	UUS_GET		11	/* reading an entire packet */
101*11896Shelge #define	UUS_WAIT	12	/* waiting for continue */
10211876Shelge 
103*11896Shelge #define	UUS_NSTATES	13
104*11896Shelge char *uustates[UUS_NSTATES] = {
10511876Shelge 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
10611876Shelge 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT"
10711876Shelge };
10811876Shelge #define	printstate(state) \
109*11896Shelge 	if ((state) < UUS_NSTATES) \
110*11896Shelge 		printf("%s", uustates[(state)]); \
11111876Shelge 	else \
11211876Shelge 		printf("%d", (state));
11311876Shelge 
11411876Shelge /*
11511876Shelge  * Packet Flags
11611876Shelge  */
11711876Shelge #define	TUF_DATA	1		/* data packet */
11811876Shelge #define	TUF_CMD		2		/* command packet */
11911876Shelge #define	TUF_INITF	4		/* initialize */
12011876Shelge #define	TUF_CONT	020		/* continue */
12111876Shelge #define	TUF_XOFF	023		/* flow control */
12211876Shelge 
12311876Shelge /*
12411876Shelge  * Op Codes
12511876Shelge  */
126*11896Shelge #define	TUOP_NOOP	0		/* no operation */
12711876Shelge #define	TUOP_INIT	1		/* initialize */
12811876Shelge #define	TUOP_READ	2		/* read block */
12911876Shelge #define	TUOP_WRITE	3		/* write block */
13011876Shelge #define	TUOP_SEEK	5		/* seek to block */
131*11896Shelge #define	TUOP_DIAGNOSE	7		/* run micro-diagnostics */
13211876Shelge #define	TUOP_END	0100		/* end packet */
13311876Shelge 
13411876Shelge /*
13511876Shelge  * Mod Flags
13611876Shelge  */
13711876Shelge #define TUMD_WRV        1               /* write with read verify */
13811876Shelge 
13911876Shelge /*
14011876Shelge  * Switches
14111876Shelge  */
14211876Shelge #define	TUSW_MRSP	010		/* use Modified RSP */
14311876Shelge 
144*11896Shelge u_char	uunull[2] = { 0, 0 };	/* nulls to send for initialization */
145*11896Shelge u_char	uuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
14611876Shelge 
147*11896Shelge struct	uba_device	*uudinfo[NUU];
148*11896Shelge struct	uba_ctlr	*uuminfo[NDL];
149*11896Shelge 
150*11896Shelge int uuprobe(), uuslave(), uuattach(), uurintr(), uuxintr(), uuwatch();
151*11896Shelge u_short uustd[] = { 0176500, 0 };
152*11896Shelge struct uba_driver dldriver =
153*11896Shelge     { uuprobe, uuslave, uuattach, uudgo, uustd, "uu", uudinfo, "dl", uuminfo };
154*11896Shelge 
155*11896Shelge int	uuwstart;
156*11896Shelge 
15711876Shelge /*ARGSUSED*/
158*11896Shelge uuprobe(reg)
159*11896Shelge 	caddr_t reg;
16011876Shelge {
161*11896Shelge 	register int br, cvec;			/* value result */
162*11896Shelge 	struct uudevice *uuaddr = (struct uudevice *)reg;
163*11896Shelge 	int i;
16411876Shelge 
16511876Shelge #ifdef lint
166*11896Shelge 	br = 0; cvec = br; br = cvec;
167*11896Shelge 	uurintr(0); uuxintr(0);
16811876Shelge #endif
169*11896Shelge 	uuaddr->rcs = UUCS_INTR;
170*11896Shelge 	uuaddr->tdb = TUF_INITF;
171*11896Shelge 	DELAY(10000);
172*11896Shelge 	i = uuaddr->rdb;
173*11896Shelge 	uuaddr->rcs = 0;
174*11896Shelge 	return(sizeof (*uuaddr));
175*11896Shelge }
176*11896Shelge 
177*11896Shelge uuslave(ui, reg);
178*11896Shelge 	struct uba_device *ui;
179*11896Shelge 	caddr_t reg;
180*11896Shelge {
181*11896Shelge 	return (ui->ui_slave == 0 || ui->ui_slave == 1);
182*11896Shelge }
183*11896Shelge 
184*11896Shelge /*ARGSUSED*/
185*11896Shelge uuattach(ui)
186*11896Shelge 	struct uba_device *ui;
187*11896Shelge {
188*11896Shelge 
189*11896Shelge }
190*11896Shelge 
191*11896Shelge /*ARGSUSED1*/
192*11896Shelge uuopen(dev, flag)
193*11896Shelge 	dev_t dev;
194*11896Shelge 	int flag;
195*11896Shelge {
196*11896Shelge 	register struct uba_device *ui;
197*11896Shelge 	register struct uu_ctlr *uuc;
198*11896Shelge 	register struct uudevice *uuaddr;
199*11896Shelge 	register struct uba_ctlr *um;
200*11896Shelge 	int ctlr, unit = minor(dev), s;
201*11896Shelge 
202*11896Shelge 	if (unit >= NUU || (ui = uudinfo[unit]) == 0 || ui->ui_alive == 0)
20311876Shelge 		return (ENXIO);
204*11896Shelge 	um = ui->ui_mi;
205*11896Shelge 	ctlr = um->um_ctlr;
206*11896Shelge 	uuc = &uu_ctlr[ctlr];
207*11896Shelge 	if (uuc->uu_dopen[unit%NDPC])
208*11896Shelge 		return (EBUSY);
209*11896Shelge 	if (uuwstart++ == 0)
210*11896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
211*11896Shelge 
212*11896Shelge 	uuc->uu_dopen[unit%NDPC]++;
213*11896Shelge 	uuaddr = (struct uudevice *)ui->ui_mi->um_addr;
214*11896Shelge 	s = spl5();
21511876Shelge 	/*
216*11896Shelge 	 * If the unit already initialized,
21711876Shelge 	 * just enable interrupts and return.
21811876Shelge 	 */
219*11896Shelge 	if (uu->uu_state == TUS_IDLE) {
220*11896Shelge 		uuaddr->rcs = UUCS_INTR;
22111876Shelge 		splx(s);
22211876Shelge 		return (0);
22311876Shelge 	}
22411876Shelge 
22511876Shelge 	/*
22611876Shelge 	 * Must initialize, reset the cassette
22711876Shelge 	 * and wait for things to settle down.
22811876Shelge 	 */
229*11896Shelge 	uureset(ctlr);
230*11896Shelge 	sleep((caddr_t)uuc, PZERO+1);
231*11896Shelge 	um->um_tab.b_active = NULL;
232*11896Shelge 	if (uu->uu_state != TUS_IDLE) {
233*11896Shelge 		uu->uu_state = TUS_INIT1;
234*11896Shelge 		uu->uu_dopen[unit%NDPC] = 0;
235*11896Shelge 		uu->uu_rcnt = uu->uu_wcnt = 0;
236*11896Shelge 		uuaddr->rcs = 0;
237*11896Shelge 		uuaddr->tcs = 0;
238*11896Shelge 		splx(s);
239*11896Shelge 		return (ENXIO);
24011876Shelge 	}
24111876Shelge 	splx(s);
24211876Shelge 	return (0);
24311876Shelge }
24411876Shelge 
245*11896Shelge uuclose(dev, flag)
246*11896Shelge 	dev_t dev;
247*11896Shelge 	int flag;
24811876Shelge {
249*11896Shelge 	register struct uba_ctlr *um = uudinfo[minor(dev)]->ui_mi;
250*11896Shelge 	register struct uudevice *uuaddr;
251*11896Shelge 	register struct uu_ctlr *uuc;
25211876Shelge 
253*11896Shelge 	if (um->um_tab.b_active == 0) {
254*11896Shelge 		uuaddr = (struct uudevice *)um->um_addr;
255*11896Shelge 		uuaddr->rcs = 0;
256*11896Shelge 		uuwstart--;
25711876Shelge 	}
258*11896Shelge 	uuc = &uu_ctlr[um->um_ctlr];
259*11896Shelge 	if (uuc->uu_serrs + uuc->uu_cerrs + uuc->uu_herrs != 0) {
26011876Shelge 		/*
26111876Shelge 		 * A tu58 is like nothing ever seen before;
26211876Shelge 		 * I guess this is appropriate then...
26311876Shelge 		 */
26411876Shelge 		uprintf(
265*11896Shelge 		   "uu%d: %d soft errors, %d chksum errors, %d hard errors\n",
266*11896Shelge 		    minor(dev), uuc->uu_serrs, uuc->uu_cerrs, uuc->uu_herrs);
267*11896Shelge 		    uuc->uu_serrs = uuc->uu_cerrs = uuc->uu_herrs = 0;
26811876Shelge 	}
269*11896Shelge 	uuc->uu_dopen[minor(dev)%NDPC] = 0;
27011876Shelge }
27111876Shelge 
272*11896Shelge uureset(ctlr)
273*11896Shelge 	int ctlr;
27411876Shelge {
275*11896Shelge 	register struct uu_ctlr *uuc = uu_ctlr[ctlr];
276*11896Shelge 	register struct packet *cmd = uucmd[ctlr];
277*11896Shelge 	register struct uudevice *uuaddr;
278*11896Shelge 	struct uba_ctlr *um = uuminfo[ctlr];
27911876Shelge 
280*11896Shelge 	um->um_tab.b_active++;
281*11896Shelge 	uuc->uu_state = TUS_INIT1;
282*11896Shelge 	uuc->uu_wbptr = uunull;
283*11896Shelge 	uuc->uu_wcnt = sizeof (uunull);
284*11896Shelge 	cmd->pk_flag = TUF_CMD;
285*11896Shelge 	cmd->pk_mcount = sizeof (uucmd) - 4;
286*11896Shelge 	cmd->pk_mod = 0;
287*11896Shelge 	cmd->pk_seq = 0;
288*11896Shelge 	cmd->pk_sw = MRSP ? TUSW_MRSP : 0;
289*11896Shelge 	uuaddr = (struct uudevice *)um->um_addr;
290*11896Shelge 	uuaddr->rcs = 0;
291*11896Shelge 	uuaddr->tcs = UUCS_INTR | UUCS_BREAK;
292*11896Shelge 	uuxintr(ctlr);				/* start output */
29311876Shelge }
29411876Shelge 
29511876Shelge /*
29611876Shelge  * Strategy routine for block I/O
29711876Shelge  */
298*11896Shelge uustrategy(bp)
29911876Shelge 	register struct buf *bp;
30011876Shelge {
301*11896Shelge 	register struct buf *dp;
302*11896Shelge 	struct uba_device *ui;
303*11896Shelge 	struct uu_ctlr *uuc;
304*11896Shelge 	int s, unit = minor(bp->b_dev);
30511876Shelge 
306*11896Shelge 	if (unit > NUU)
307*11896Shelge 		goto bad;
308*11896Shelge 	if (bp->b_blkno >= NTUBLK)
309*11896Shelge 		goto bad;
310*11896Shelge 	ui = uudinfo[unit];
311*11896Shelge 	if (ui == 0 || ui->ui_alive == 0)
312*11896Shelge 		goto bad;
313*11896Shelge 	uuc = &uu_ctlr[ui->ui_mi->um_ctlr];
314*11896Shelge 	s = spl5();
315*11896Shelge 	bp->b_cylin = bp->b_blkno;
316*11896Shelge 	dp = &uuutab[unit];
317*11896Shelge 	disksort(dp, bp);
318*11896Shelge 	if (dp->b_active == 0) {
319*11896Shelge 		uuustart(ui);
320*11896Shelge 		bp = &ui->ui_mi->um_tab;
321*11896Shelge 		if (bp->b_actf && bp->b_active == 0)
322*11896Shelge 			uustart(ui->ui_mi);
32311876Shelge 	}
32411876Shelge 	splx(s);
325*11896Shelge 	return;
326*11896Shelge 
327*11896Shelge bad:
328*11896Shelge 	bp->b_flags |= B_ERROR;
329*11896Shelge 	iodone(bp);
330*11896Shelge 	return;
33111876Shelge }
33211876Shelge 
33311876Shelge /*
334*11896Shelge  * Unit start routine.
335*11896Shelge  * Put this unit on the ready queue for the controller
336*11896Shelge  */
337*11896Shelge uuustart(ui)
338*11896Shelge 	register struct uba_device *ui;
339*11896Shelge {
340*11896Shelge 	struct buf *dp = &uuutab[ui->ui_unit];
341*11896Shelge 	struct uba_ctlr *um = ui->ui_mi;
342*11896Shelge 
343*11896Shelge 	dp->b_forw = NULL;
344*11896Shelge 	if (um->um_tab.b_actf == NULL)
345*11896Shelge 		um->um_tab.b_actf = dp;
346*11896Shelge 	else
347*11896Shelge 		um->um_tab.b_actl->b_forw = dp;
348*11896Shelge 	um->um_tab.b_actl = dp;
349*11896Shelge 	dp->b_active++;
350*11896Shelge }
351*11896Shelge /*
35211876Shelge  * Start the transfer
35311876Shelge  */
354*11896Shelge uustart(um)
355*11896Shelge 	register struct uba_ctlr *um;
35611876Shelge {
357*11896Shelge 	register struct uudevice *uuaddr;
35811876Shelge 	register struct buf *bp;
359*11896Shelge 	register struct uu_ctlr *uuc;
360*11896Shelge 	struct buf *dp;
361*11896Shelge 	struct packet *cmd;
362*11896Shelge 	int unit;
36311876Shelge 
364*11896Shelge loop:
365*11896Shelge 	if ((dp = um->um_tab.b_actf) == NULL)
36611876Shelge 		return;
367*11896Shelge 	if ((bp = dp->b_actf) == NULL) {
368*11896Shelge 		um->um_tab.b_actf = dp->b_forw;
369*11896Shelge 		goto loop;
370*11896Shelge 	}
371*11896Shelge 	unit = minor(bp->b_dev);
372*11896Shelge 	uuc = &uu_ctlr[um->um_ctlr];
373*11896Shelge 	cmd = &uucmd[um->um_ctlr];
374*11896Shelge 	if (uuc->uu_state != TUS_IDLE) {
375*11896Shelge 		uureset(um->um_ctlr);
37611876Shelge 		return;
37711876Shelge 	}
378*11896Shelge 	um->um_tab.b_active++;
379*11896Shelge 	uuaddr = (struct uudevice *)um->um_addr;
380*11896Shelge 	cmd->pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
381*11896Shelge 	cmd->pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
38211876Shelge 	    TUMD_WRV : 0;
383*11896Shelge 	cmd->pk_unit = (minor(bp->b_dev)&DNUM);
384*11896Shelge 	cmd->pk_sw = MRSP ? TUSW_MRSP : 0;
385*11896Shelge 	cmd->pk_count = uu->uu_count = bp->b_bcount;
386*11896Shelge 	cmd->pk_block = bp->b_blkno;
387*11896Shelge 	cmd->pk_chksum =
388*11896Shelge 	    uuchk(*((short *)&cmd), (u_short *)&cmd.pk_op,
389*11896Shelge 		(int)cmd.pk_mcount);
390*11896Shelge 	uuc->uu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
391*11896Shelge 	uuc->uu_addr = bp->b_un.b_addr;
392*11896Shelge 	uuc->uu_count = bp->b_bcount;
393*11896Shelge 	uuc->uu_wbptr = (u_char *)&uucmd;
394*11896Shelge 	uuc->uu_wcnt = sizeof (uucmd);
395*11896Shelge 	uuxintr(um->um_ctlr);
39611876Shelge }
39711876Shelge 
39811876Shelge /*
39911876Shelge  * TU58 receiver interrupt
40011876Shelge  */
401*11896Shelge uurintr()
40211876Shelge {
40311876Shelge 	register struct buf *bp;
40411876Shelge 	register int c;
40511876Shelge 
40611876Shelge 	c = mfpr(CSRD)&0xff;		/* get the char, clear the interrupt */
40711876Shelge 	if (MRSP) {
40811876Shelge 		while ((mfpr(CSTS)&READY) == 0)
40911876Shelge 			;
41011876Shelge 		mtpr(CSTD, TUF_CONT);	/* ACK */
41111876Shelge 	}
412*11896Shelge 	if (uu->uu_rcnt) {		/* still waiting for data? */
413*11896Shelge 		*uu->uu_rbptr++ = c;	/* yup, put it there */
414*11896Shelge 		if (--uu->uu_rcnt)	/* decrement count, any left? */
41511876Shelge 			return;		/* get some more */
41611876Shelge 	}
41711876Shelge 
41811876Shelge 	/*
41911876Shelge 	 * We got all the data we were expecting for now,
420*11896Shelge 	 * switch on the uu_state of the transfer.
42111876Shelge 	 */
422*11896Shelge 	switch(uu->uu_state) {
42311876Shelge 
42411876Shelge 	/*
42511876Shelge 	 * If we get an unexpected "continue",
42611876Shelge 	 * start all over again...
42711876Shelge 	 */
42811876Shelge 	case TUS_INIT2:
429*11896Shelge 		uu->uu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
430*11896Shelge 		uu->uu_flag = 0;
431*11896Shelge 		wakeup((caddr_t)&uu);
432*11896Shelge 		uustart();
43311876Shelge 		break;
43411876Shelge 
43511876Shelge 	/*
43611876Shelge 	 * Only transition from this state
43711876Shelge 	 * is on a "continue", so if we don't
43811876Shelge 	 * get it, reset the world.
43911876Shelge 	 */
44011876Shelge 	case TUS_WAIT:			/* waiting for continue */
44111876Shelge 		if (c != TUF_CONT) {
442*11896Shelge 			uu->uu_state = TUS_INIT1;
44311876Shelge 			break;
44411876Shelge 		}
445*11896Shelge 		uu->uu_flag = 0;
446*11896Shelge 		uudata.pk_flag = TUF_DATA;
447*11896Shelge 		uudata.pk_mcount = MIN(128, uu->uu_count);
448*11896Shelge 		uudata.pk_chksum =
449*11896Shelge 		    uuchk(*((short *)&uudata), (u_short *)uu->uu_addr,
450*11896Shelge 			(int)uudata.pk_mcount);
451*11896Shelge 		uu->uu_state = TUS_SENDH;
452*11896Shelge 		uu->uu_wbptr = (u_char *)&uudata;
453*11896Shelge 		uu->uu_wcnt = 2;
454*11896Shelge 		uuxintr();
45511876Shelge 		break;
45611876Shelge 
45711876Shelge 	case TUS_SENDW:
45811876Shelge 		if (c != TUF_CONT)
45911876Shelge 			goto bad;
460*11896Shelge 		uureset();
46111876Shelge 		break;
46211876Shelge 
46311876Shelge 	/*
46411876Shelge 	 * Got header, now get data; amount to
465*11896Shelge 	 * fetch is included in packet.
46611876Shelge 	 */
46711876Shelge 	case TUS_GETH:
468*11896Shelge 		if (uudata.pk_flag == TUF_DATA)
469*11896Shelge 			uu->uu_rbptr = (u_char *)uu->uu_addr;
470*11896Shelge 		uu->uu_rcnt = uudata.pk_mcount;
471*11896Shelge 		uu->uu_state = TUS_GETD;
47211876Shelge 		break;
47311876Shelge 
47411876Shelge 	/*
47511876Shelge 	 * Got the data, now fetch the checksum.
47611876Shelge 	 */
47711876Shelge 	case TUS_GETD:
478*11896Shelge 		uu->uu_rbptr = (u_char *)&uudata.pk_chksum;
479*11896Shelge 		uu->uu_rcnt = sizeof (uudata.pk_chksum);
480*11896Shelge 		uu->uu_state = TUS_GETC;
48111876Shelge 		break;
48211876Shelge 
48311876Shelge 	case TUS_GET:
48411876Shelge 	case TUS_GETC:
48511876Shelge 		/* got entire packet */
48611876Shelge #ifdef notdef
487*11896Shelge 		if (uudata.pk_chksum !=
488*11896Shelge 		    uuchk(*((short *)&uudata), (u_short *)
489*11896Shelge 		     (uudata.pk_flag == TUF_DATA ? uu->uu_addr : &uudata.pk_op),
490*11896Shelge 		     (int)uudata.pk_mcount))
491*11896Shelge 			uu->uu_cerrs++;
49211876Shelge #endif
493*11896Shelge 		if (uudata.pk_flag == TUF_DATA) {
49411876Shelge 			/* data packet, advance to next */
495*11896Shelge 			uu->uu_addr += uudata.pk_mcount;
496*11896Shelge 			uu->uu_count -= uudata.pk_mcount;
497*11896Shelge 			uu->uu_state = TUS_GETH;
498*11896Shelge 			uu->uu_rbptr = (u_char *)&uudata; /* next packet */
499*11896Shelge 			uu->uu_rcnt = 2;
500*11896Shelge 		} else if (uudata.pk_flag==TUF_CMD && uudata.pk_op==TUOP_END) {
50111876Shelge 			/* end packet, idle and reenable transmitter */
502*11896Shelge 			uu->uu_state = TUS_IDLE;
503*11896Shelge 			uu->uu_flag = 0;
50411876Shelge 			mtpr(CSTS, IE);
50511876Shelge 			printd("ON ");
506*11896Shelge 			if ((bp = uutab.b_actf) == NULL) {
507*11896Shelge 				printf("uu: no bp, active %d\n",uutab.b_active);
508*11896Shelge 				uustart();
50911876Shelge 				return;
51011876Shelge 			}
511*11896Shelge 			if (uudata.pk_mod > 1) {        /* hard error */
51211876Shelge 				bp->b_flags |= B_ERROR;
513*11896Shelge 				uu->uu_herrs++;
514*11896Shelge 				harderr(bp, "uu");
515*11896Shelge 				printf("  pk_mod %o\n", uudata.pk_mod&0377);
516*11896Shelge 			} else if (uudata.pk_mod != 0)	/* soft error */
517*11896Shelge 				uu->uu_serrs++;
518*11896Shelge 			uutab.b_active = NULL;
519*11896Shelge 			uutab.b_actf = bp->av_forw;
520*11896Shelge 			bp->b_resid = uu->uu_count;
52111876Shelge 			if ((bp->b_flags&B_READ) == 0)
522*11896Shelge 				uu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
52311876Shelge 			iodone(bp);
524*11896Shelge 			uustart();
52511876Shelge 		} else {
52611876Shelge 			printf("neither data nor end: %o %o\n",
527*11896Shelge 			    uudata.pk_flag&0xff, uudata.pk_op&0xff);
52811876Shelge 			mtpr(CSRS, 0);		/* flush the rest */
529*11896Shelge 			uu->uu_state = TUS_INIT1;
53011876Shelge 		}
53111876Shelge 		break;
53211876Shelge 
53311876Shelge 	case TUS_IDLE:
53411876Shelge 	case TUS_INIT1:
53511876Shelge 		break;
53611876Shelge 
53711876Shelge 	default:
53811876Shelge bad:
53911876Shelge 		if (c == TUF_INITF) {
540*11896Shelge 			printf("uu protocol error, state=");
541*11896Shelge 			printstate(uu->uu_state);
54211876Shelge 			printf(", op=%x, cnt=%d, block=%d\n",
543*11896Shelge 			    uucmd.pk_op, uucmd.pk_count, uucmd.pk_block);
544*11896Shelge 			uutab.b_active = NULL;
545*11896Shelge 			if (bp = uutab.b_actf) {
54611876Shelge 				bp->b_flags |= B_ERROR;
547*11896Shelge 				uutab.b_actf = bp->av_forw;
54811876Shelge 				if ((bp->b_flags&B_READ) == 0)
549*11896Shelge 					uu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
55011876Shelge 				iodone(bp);
55111876Shelge 			}
552*11896Shelge 			uu->uu_state = TUS_INIT1;
55311876Shelge 		} else {
554*11896Shelge 			printf("uu receive state error, state=");
55511876Shelge 			printf(", byte=%x\n", c);
55611876Shelge #ifdef notdef
557*11896Shelge 			uu->uu_state = TUS_INIT1; */
55811876Shelge #endif
559*11896Shelge 			wakeup((caddr_t)&uu);
56011876Shelge 		}
56111876Shelge 	}
56211876Shelge }
56311876Shelge 
56411876Shelge /*
56511876Shelge  * TU58 transmitter interrupt
56611876Shelge  */
567*11896Shelge uuxintr()
56811876Shelge {
56911876Shelge 
57011876Shelge top:
571*11896Shelge 	if (uu->uu_wcnt) {
57211876Shelge 		/* still stuff to send, send one byte */
57311876Shelge 		while ((mfpr(CSTS) & READY) == 0)
57411876Shelge 			;
575*11896Shelge 		mtpr(CSTD, *uu->uu_wbptr++);
576*11896Shelge 		uu->uu_wcnt--;
57711876Shelge 		return;
57811876Shelge 	}
57911876Shelge 
58011876Shelge 	/*
58111876Shelge 	 * Last message byte was sent out.
582*11896Shelge 	 * Switch on uu_state of transfer.
58311876Shelge 	 */
584*11896Shelge 	if (uudebug) {
585*11896Shelge 		printf("uuxintr: state=");
586*11896Shelge 		printstate(uu->uu_state);
58711876Shelge 	}
588*11896Shelge 	switch(uu->uu_state) {
58911876Shelge 
59011876Shelge 	/*
59111876Shelge 	 * Two nulls have been sent, remove break, and send inits
59211876Shelge 	 */
59311876Shelge 	case TUS_INIT1:
59411876Shelge 		mtpr(CSTS, IE);
59511876Shelge 		printd("ON2 ");
596*11896Shelge 		uu->uu_state = TUS_INIT2;
597*11896Shelge 		uu->uu_wbptr = uuinit;
598*11896Shelge 		uu->uu_wcnt = sizeof (uuinit);
59911876Shelge 		goto top;
60011876Shelge 
60111876Shelge 	/*
60211876Shelge 	 * Inits have been sent, wait for a continue msg.
60311876Shelge 	 */
60411876Shelge 	case TUS_INIT2:
60511876Shelge 		(void) mfpr(CSRD);
60611876Shelge 		mtpr(CSRS, IE);
607*11896Shelge 		uu->uu_flag = 1;
60811876Shelge 		break;
60911876Shelge 
61011876Shelge 	case TUS_IDLE:		/* stray interrupt? */
61111876Shelge 		break;
61211876Shelge 
61311876Shelge 	/*
61411876Shelge 	 * Read cmd packet sent, get ready for data
61511876Shelge 	 */
61611876Shelge 	case TUS_SENDR:
617*11896Shelge 		uu->uu_state = TUS_GETH;
618*11896Shelge 		uu->uu_rbptr = (u_char *)&uudata;
619*11896Shelge 		uu->uu_rcnt = 2;
620*11896Shelge 		uu->uu_flag = 1;
62111876Shelge 		mtpr(CSTS, 0);	/* disable transmitter interrupts */
62211876Shelge 		printd("OFF ");
62311876Shelge 		break;
62411876Shelge 
62511876Shelge 	/*
62611876Shelge 	 * Write cmd packet sent, wait for continue
62711876Shelge 	 */
62811876Shelge 	case TUS_SENDW:
629*11896Shelge 		uu->uu_state = TUS_WAIT;
630*11896Shelge 		uu->uu_flag = 1;
63111876Shelge 		if ((mfpr(CSRS)&IE) == 0) {
63211876Shelge 			printf("NO IE\n");
63311876Shelge 			mtpr(CSRS, IE);
63411876Shelge 		}
63511876Shelge 		break;
63611876Shelge 
63711876Shelge 	/*
63811876Shelge 	 * Header sent, send data.
63911876Shelge 	 */
64011876Shelge 	case TUS_SENDH:
641*11896Shelge 		uu->uu_state = TUS_SENDD;
642*11896Shelge 		uu->uu_wbptr = (u_char *)uu->uu_addr;
643*11896Shelge 		uu->uu_wcnt = uudata.pk_mcount;
64411876Shelge 		goto top;
64511876Shelge 
64611876Shelge 	/*
64711876Shelge 	 * Data sent, follow with checksum.
64811876Shelge 	 */
64911876Shelge 	case TUS_SENDD:
650*11896Shelge 		uu->uu_state = TUS_SENDC;
651*11896Shelge 		uu->uu_wbptr = (u_char *)&uudata.pk_chksum;
652*11896Shelge 		uu->uu_wcnt = sizeof uudata.pk_chksum;
65311876Shelge 		goto top;
65411876Shelge 
65511876Shelge 	/*
65611876Shelge 	 * Checksum sent, wait for continue.
65711876Shelge 	 */
65811876Shelge 	case TUS_SENDC:
65911876Shelge 		/*
66011876Shelge 		 * Updata buffer address and count.
66111876Shelge 		 */
662*11896Shelge 		uu->uu_addr += uudata.pk_mcount;
663*11896Shelge 		uu->uu_count -= uudata.pk_mcount;
664*11896Shelge 		if (uu->uu_count) {
665*11896Shelge 			uu->uu_state = TUS_WAIT;
666*11896Shelge 			uu->uu_flag = 1;
66711876Shelge 			break;
66811876Shelge 		}
66911876Shelge 
67011876Shelge 		/*
67111876Shelge 		 * End of transmission, get ready for end packet.
67211876Shelge 		 */
673*11896Shelge 		uu->uu_state = TUS_GET;
674*11896Shelge 		uu->uu_rbptr = (u_char *)&uudata;
675*11896Shelge 		uu->uu_rcnt = sizeof (uudata);
676*11896Shelge 		uu->uu_flag = 1;
67711876Shelge 		mtpr(CSTS, 0);
67811876Shelge 		printd("OFF2 ");
67911876Shelge 		break;
68011876Shelge 
68111876Shelge 	/*
68211876Shelge 	 * Random interrupt, probably from MRSP ACK
68311876Shelge 	 */
68411876Shelge 	default:
68511876Shelge 		break;
68611876Shelge 	}
687*11896Shelge 	if (uudebug) {
688*11896Shelge 		printd("  new uu_state=");
689*11896Shelge 		printstate(uu->uu_state);
69011876Shelge 	}
69111876Shelge }
69211876Shelge 
69311876Shelge /*
69411876Shelge  * Compute checksum TU58 fashion
69511876Shelge  */
69611876Shelge #ifdef lint
697*11896Shelge uuchk(word, cp, n)
69811876Shelge 	register word;
69911876Shelge 	register unsigned short *cp;
70011876Shelge 	int n;
70111876Shelge {
70211876Shelge 	register int c = n >> 1;
70311876Shelge 	register long temp;
70411876Shelge 
70511876Shelge 	do {
70611876Shelge 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
70711876Shelge 		word += temp;
70811876Shelge 	} while (--c > 0);
70911876Shelge 	if (n & 1)
71011876Shelge 		word += *(unsigned char *)cp;
71111876Shelge 	while (word & 0xffff0000)
71211876Shelge 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
71311876Shelge 	return (word);
71411876Shelge }
71511876Shelge #else
716*11896Shelge uuchk(word0, wp, n)
717*11896Shelge 	register int word0;			/* r11 */
718*11896Shelge 	register char *wp;			/* r10 */
719*11896Shelge 	register int n;				/* r9 */
72011876Shelge {
72111876Shelge 	asm("loop:");
722*11896Shelge 	asm("	addw2	(r10)+,r11");		/* add a word to sum */
723*11896Shelge 	asm("	adwc	$0,r11");		/* add in carry, end-around */
72411876Shelge 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
725*11896Shelge 	asm("	blbc	r9,ok");		/* odd byte count? */
726*11896Shelge 	asm("	movzbw	(r10),r10");		/* yes, get last byte */
727*11896Shelge 	asm("	addw2	r10,r11");		/* add it in */
728*11896Shelge 	asm("	adwc	$0,r11");		/* and the carry */
72911876Shelge 	asm("ok:");
730*11896Shelge 	asm("	movl	r11,r0");		/* return sum */
73111876Shelge }
73211876Shelge #endif
73311876Shelge 
734*11896Shelge uuwatch()
73511876Shelge {
73611876Shelge 	register int s;
73711876Shelge 	register struct buf *bp;
73811876Shelge 
739*11896Shelge 	if (uutimer == 0) {
740*11896Shelge 		uu->uu_flag = 0;
74111876Shelge 		return;
74211876Shelge 	}
743*11896Shelge 	if (uu->uu_flag)
744*11896Shelge 		uu->uu_flag++;
745*11896Shelge 	if (uu->uu_flag <= 40) {
746*11896Shelge 		timeout(uuwatch, (caddr_t)0, hz);
74711876Shelge 		return;
74811876Shelge 	}
749*11896Shelge 	printf("uu: read stalled\n");
750*11896Shelge 	printf("%X %X %X %X %X %X %X %X\n", uu->uu_rbptr, uu->uu_rcnt,
751*11896Shelge 		uu->uu_wbptr, uu->uu_wcnt, uu->uu_state, uu->uu_flag,
752*11896Shelge 		uu->uu_addr, uu->uu_count);
753*11896Shelge 	uu->uu_flag = 0;
75411876Shelge 	s = splx(TUIPL);
75511876Shelge 	(void) mfpr(CSRD);
75611876Shelge 	mtpr(CSRS, IE);		/* in case we were flushing */
75711876Shelge 	mtpr(CSTS, IE);
758*11896Shelge 	uu->uu_state = TUS_IDLE;
759*11896Shelge 	if (!uutab.b_active) {
760*11896Shelge 		wakeup((caddr_t)&uu);
76111876Shelge 		goto retry;
76211876Shelge 	}
763*11896Shelge 	if (++uutab.b_errcnt <= 1) {
764*11896Shelge 		uustart();
76511876Shelge 		goto retry;
76611876Shelge 	}
767*11896Shelge 	if (bp = uutab.b_actf) {
76811876Shelge 		bp->b_flags |= B_ERROR;
76911876Shelge 		if ((bp->b_flags&B_READ) == 0)
770*11896Shelge 			uu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
77111876Shelge 		iodone(bp);
77211876Shelge 	}
77311876Shelge retry:
77411876Shelge 	splx(s);
775*11896Shelge 	timeout(uuwatch, (caddr_t)0, hz);
77611876Shelge }
77711876Shelge #endif
778