xref: /original-bsd/sys/vax/vax/tu.c (revision 8ac030d2)
1 /*	tu.c	4.12	82/11/13	*/
2 
3 #if defined(VAX750) || defined(VAX730)
4 /*
5  * TU58 DECtape II device driver
6  *
7  * This driver controls the console TU58s on a VAX-11/750 or VAX-11/730.
8  * It could be easily modified for a Unibus TU58.  The TU58
9  * is treated as a block device (only).  Error detection and
10  * recovery is almost non-existant.  It is assumed that the
11  * TU58 will follow the RSP protocol exactly, very few protocol
12  * errors are checked for.  It is assumed that the 750 uses standard
13  * RSP while the 730 uses Modified RSP (MRSP).  At the time when 750's
14  * are converted to MRSP (by replacing EPROMS in the TU58), the tests
15  * based on MRSP can be removed.
16  */
17 #include "../h/param.h"
18 #include "../h/systm.h"
19 #include "../h/buf.h"
20 #include "../h/conf.h"
21 #include "../h/dir.h"
22 #include "../h/user.h"
23 
24 #include "../vax/cpu.h"
25 #include "../vax/mtpr.h"
26 
27 #define	printd	if(tudebug) printf
28 #ifdef	printd
29 int	tudebug;	/* printd */
30 #endif	printd
31 
32 #define	NTU	((cpu == VAX_750) ? 1 : 2)
33 #define DNUM    01      /* mask for drive number (should match NTU) */
34 #if !defined(MRSP) || lint
35 #define	MRSP	(cpu != VAX_750)
36 #endif
37 #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
38 #define WRV     02              /* bit in minor dev => write w. read verify */
39 #define NTUQ    2               /* # of blocks which can be queued up */
40 #define	TUIPL	((cpu == VAX_750) ? 0x17 : 0x14)
41 
42 /*
43  * Device register bits
44  */
45 #define	READY	0200		/* transmitter ready */
46 #define	DONE	0200		/* receiver done */
47 #define	IE	0100		/* interrupt enable */
48 #define	BREAK	1		/* send break */
49 
50 /*
51  * Structure of a command packet
52  */
53 struct packet {
54 	u_char	pk_flag;	/* indicates packet type (cmd, data, etc.) */
55 	u_char	pk_mcount;	/* length of packet (bytes) */
56 	u_char	pk_op;		/* operation to perform (read, write, etc.) */
57 	u_char	pk_mod;		/* modifier for op or returned status */
58 	u_char	pk_unit;	/* unit number */
59 	u_char	pk_sw;		/* switches */
60 	u_short	pk_seq;		/* sequence number, always zero */
61 	u_short	pk_count;	/* requested byte count for read or write */
62 	u_short	pk_block;	/* block number for read, write, or seek */
63 	u_short	pk_chksum;	/* checksum, by words with end around carry */
64 };
65 
66 struct packet tucmd;		/* a command sent to the TU58 */
67 struct packet tudata;		/* a command or data returned from TU58 */
68 
69 /*
70  * State information
71  */
72 struct tu {
73 	u_char	*tu_rbptr;	/* pointer to buffer for read */
74 	int	tu_rcnt;	/* how much to read */
75 	u_char	*tu_wbptr;	/* pointer to buffer for write */
76 	int	tu_wcnt;	/* how much to write */
77 	int	tu_state;	/* current tu_state of tansfer operation */
78 	int	tu_flag;	/* read in progress flag */
79 	char	*tu_addr;	/* real buffer data address */
80 	int	tu_count;	/* real requested count */
81 	int	tu_serrs;	/* count of soft errors */
82 	int	tu_cerrs;	/* count of checksum errors */
83 	int	tu_herrs;	/* count of hard errors */
84 	char    tu_dopen[2];	/* drive is open */
85 } tu;
86 
87 /*
88  * States
89  */
90 #define	TUS_INIT1	0	/* sending nulls */
91 #define	TUS_INIT2	1	/* sending inits */
92 #define	TUS_IDLE	2	/* initialized, no transfer in progress */
93 #define	TUS_SENDH	3	/* sending header */
94 #define	TUS_SENDD	4	/* sending data */
95 #define	TUS_SENDC	5	/* sending checksum */
96 #define	TUS_SENDR	6	/* sending read command packet */
97 #define	TUS_SENDW	7	/* sending write command packet */
98 #define	TUS_GETH	8	/* reading header */
99 #define	TUS_GETD	9	/* reading data */
100 #define	TUS_GETC	10	/* reading checksum */
101 #define	TUS_GET		11	/* reading an entire packet */
102 #define	TUS_WAIT	12	/* waiting for continue */
103 
104 #define	TUS_NSTATES	13
105 char *tustates[TUS_NSTATES] = {
106 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
107 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT"
108 };
109 #define	printstate(state) \
110 	if ((state) < TUS_NSTATES) \
111 		printf("%s", tustates[(state)]); \
112 	else \
113 		printf("%d", (state));
114 
115 /*
116  * Packet Flags
117  */
118 #define	TUF_DATA	1		/* data packet */
119 #define	TUF_CMD		2		/* command packet */
120 #define	TUF_INITF	4		/* initialize */
121 #define	TUF_CONT	020		/* continue */
122 #define	TUF_XOFF	023		/* flow control */
123 
124 /*
125  * Op Codes
126  */
127 #define	TUOP_INIT	1		/* initialize */
128 #define	TUOP_READ	2		/* read block */
129 #define	TUOP_WRITE	3		/* write block */
130 #define	TUOP_SEEK	5		/* seek to block */
131 #define TUOP_DIAGNOSE	7		/* run micro-diagnostics */
132 #define	TUOP_END	0100		/* end packet */
133 
134 /*
135  * Mod Flags
136  */
137 #define TUMD_WRV        1               /* write with read verify */
138 
139 /*
140  * Switches
141  */
142 #define	TUSW_MRSP	010		/* use Modified RSP */
143 
144 u_char	tunull[2] = { 0, 0 };	/* nulls to send for initialization */
145 u_char	tuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
146 static char pcnt[2];            /* pee/vee counters */
147 int	tutimer = 0;
148 struct buf tutab;		/* I/O queue header */
149 
150 /*
151  * Open the TU58
152  */
153 /*ARGSUSED*/
154 tuopen(dev, flag)
155 {
156 	extern int tuwatch();
157 	register s;
158 
159 #ifdef lint
160 	turintr(); tuwintr();
161 #endif
162 	if ((minor(dev)&DNUM) >= NTU || tu.tu_dopen[minor(dev)&DNUM])
163 		return (ENXIO);
164 	if (tutimer == 0) {
165 		tutimer++;
166 		timeout(tuwatch, (caddr_t)0, hz);
167 	}
168 	tu.tu_dopen[minor(dev)&DNUM]++;
169 	s = splx(TUIPL);
170 	/*
171 	 * If the cassette's already initialized,
172 	 * just enable interrupts and return.
173 	 */
174 	if (tu.tu_state == TUS_IDLE) {
175 		mtpr(CSRS, IE);
176 		splx(s);
177 		return (0);
178 	}
179 
180 	/*
181 	 * Must initialize, reset the cassette
182 	 * and wait for things to settle down.
183 	 */
184 	tureset();
185 	sleep((caddr_t)&tu, PZERO+1);
186 	tutab.b_active = NULL;
187 	if (tu.tu_state != TUS_IDLE) {
188 		u.u_error = ENXIO;
189 		tu.tu_state = TUS_INIT1;
190 		tu.tu_dopen[minor(dev)&DNUM] = 0;
191 		tu.tu_rcnt = tu.tu_wcnt = 0;
192 		mtpr(CSTS, 0);
193 		mtpr(CSRS, 0);
194 	}
195 	splx(s);
196 	return (0);
197 }
198 
199 /*
200  * Close the TU58
201  */
202 tuclose(dev)
203 {
204 
205 	if (tutab.b_active == 0) {
206 		mtpr(CSRS, 0);
207 		tutimer = 0;
208 	}
209 	if (tu.tu_serrs + tu.tu_cerrs + tu.tu_herrs != 0) {
210 		/*
211 		 * A tu58 is like nothing ever seen before;
212 		 * I guess this is appropriate then...
213 		 */
214 		uprintf(
215 		   "tu%d: %d soft errors, %d chksum errors, %d hard errors\n",
216 			minor(dev), tu.tu_serrs, tu.tu_cerrs, tu.tu_herrs);
217 		tu.tu_serrs = tu.tu_cerrs = tu.tu_herrs = 0;
218 	}
219 	tu.tu_dopen[minor(dev)&DNUM] = 0;
220 }
221 
222 /*
223  * Reset the TU58
224  */
225 tureset()
226 {
227 
228 	tu.tu_state = TUS_INIT1;
229 	tu.tu_wbptr = tunull;
230 	tu.tu_wcnt = sizeof (tunull);
231 	tucmd.pk_flag = TUF_CMD;
232 	tucmd.pk_mcount = sizeof (tucmd) - 4;
233 	tucmd.pk_mod = 0;
234 	tucmd.pk_seq = 0;
235 	tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
236 	tutab.b_active++;
237 	mtpr(CSRS, 0);
238 	mtpr(CSTS, IE|BREAK);
239 	tuxintr();		/* start output */
240 }
241 
242 /*
243  * Strategy routine for block I/O
244  */
245 tustrategy(bp)
246 	register struct buf *bp;
247 {
248 	register int s;
249 
250 	if (bp->b_blkno >= NTUBLK) {
251 		bp->b_flags |= B_ERROR;
252 		iodone(bp);
253 		return;
254 	}
255 	if ((bp->b_flags&B_READ) == 0)
256 		tu_pee(&pcnt[minor(bp->b_dev)&DNUM]);
257 	bp->av_forw = NULL;
258 	s = splx(TUIPL);
259 	if (tutab.b_actf == NULL)
260 		tutab.b_actf = bp;
261 	else
262 		tutab.b_actl->av_forw = bp;
263 	tutab.b_actl = bp;
264 	if (tutab.b_active == NULL)
265 		tustart();
266 	splx(s);
267 }
268 
269 /*
270  * Start the transfer
271  */
272 tustart()
273 {
274 	register struct buf *bp;
275 
276 	if ((bp = tutab.b_actf) == NULL)
277 		return;
278 	if (tu.tu_state != TUS_IDLE) {
279 		tureset();
280 		return;
281 	}
282 	tutab.b_active++;
283 	tutab.b_errcnt = 0;
284 	tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
285 	tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
286 	    TUMD_WRV : 0;
287 	tucmd.pk_unit = (minor(bp->b_dev)&DNUM);
288 	tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
289 	tucmd.pk_count = tu.tu_count = bp->b_bcount;
290 	tucmd.pk_block = bp->b_blkno;
291 	tucmd.pk_chksum =
292 	    tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
293 		(int)tucmd.pk_mcount);
294 	tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
295 	tu.tu_addr = bp->b_un.b_addr;
296 	tu.tu_count = bp->b_bcount;
297 	tu.tu_wbptr = (u_char *)&tucmd;
298 	tu.tu_wcnt = sizeof (tucmd);
299 	tuxintr();
300 }
301 
302 /*
303  * TU58 receiver interrupt
304  */
305 turintr()
306 {
307 	register struct buf *bp;
308 	register int c;
309 
310 	c = mfpr(CSRD)&0xff;		/* get the char, clear the interrupt */
311 	if (MRSP) {
312 		while ((mfpr(CSTS)&READY) == 0)
313 			;
314 		mtpr(CSTD, TUF_CONT);	/* ACK */
315 	}
316 	if (tu.tu_rcnt) {		/* still waiting for data? */
317 		*tu.tu_rbptr++ = c;	/* yup, put it there */
318 		if (--tu.tu_rcnt)	/* decrement count, any left? */
319 			return;		/* get some more */
320 	}
321 
322 	/*
323 	 * We got all the data we were expecting for now,
324 	 * switch on the tu_state of the transfer.
325 	 */
326 	switch(tu.tu_state) {
327 
328 	/*
329 	 * If we get an unexpected "continue",
330 	 * start all over again...
331 	 */
332 	case TUS_INIT2:
333 		tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
334 		tu.tu_flag = 0;
335 		wakeup((caddr_t)&tu);
336 		tustart();
337 		break;
338 
339 	/*
340 	 * Only transition from this state
341 	 * is on a "continue", so if we don't
342 	 * get it, reset the world.
343 	 */
344 	case TUS_WAIT:			/* waiting for continue */
345 		if (c != TUF_CONT) {
346 			tu.tu_state = TUS_INIT1;
347 			break;
348 		}
349 		tu.tu_flag = 0;
350 		tudata.pk_flag = TUF_DATA;
351 		tudata.pk_mcount = MIN(128, tu.tu_count);
352 		tudata.pk_chksum =
353 		    tuchk(*((short *)&tudata), (u_short *)tu.tu_addr,
354 			(int)tudata.pk_mcount);
355 		tu.tu_state = TUS_SENDH;
356 		tu.tu_wbptr = (u_char *)&tudata;
357 		tu.tu_wcnt = 2;
358 		tuxintr();
359 		break;
360 
361 	case TUS_SENDW:
362 		if (c != TUF_CONT)
363 			goto bad;
364 		tureset();
365 		break;
366 
367 	/*
368 	 * Got header, now get data; amount to
369 	 * fetch is include in packet.
370 	 */
371 	case TUS_GETH:
372 		if (tudata.pk_flag == TUF_DATA)
373 			tu.tu_rbptr = (u_char *)tu.tu_addr;
374 		tu.tu_rcnt = tudata.pk_mcount;
375 		tu.tu_state = TUS_GETD;
376 		break;
377 
378 	/*
379 	 * Got the data, now fetch the checksum.
380 	 */
381 	case TUS_GETD:
382 		tu.tu_rbptr = (u_char *)&tudata.pk_chksum;
383 		tu.tu_rcnt = sizeof (tudata.pk_chksum);
384 		tu.tu_state = TUS_GETC;
385 		break;
386 
387 	case TUS_GET:
388 	case TUS_GETC:
389 		/* got entire packet */
390 #ifdef notdef
391 		if (tudata.pk_chksum !=
392 		    tuchk(*((short *)&tudata), (u_short *)
393 		     (tudata.pk_flag == TUF_DATA ? tu.tu_addr : &tudata.pk_op),
394 		     (int)tudata.pk_mcount))
395 			tu.tu_cerrs++;
396 #endif
397 		if (tudata.pk_flag == TUF_DATA) {
398 			/* data packet, advance to next */
399 			tu.tu_addr += tudata.pk_mcount;
400 			tu.tu_count -= tudata.pk_mcount;
401 			tu.tu_state = TUS_GETH;
402 			tu.tu_rbptr = (u_char *)&tudata; /* next packet */
403 			tu.tu_rcnt = 2;
404 		} else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
405 			/* end packet, idle and reenable transmitter */
406 			tu.tu_state = TUS_IDLE;
407 			tu.tu_flag = 0;
408 			mtpr(CSTS, IE);
409 			printd("ON ");
410 			if ((bp = tutab.b_actf) == NULL) {
411 				printf("tu: no bp, active %d\n",tutab.b_active);
412 				tustart();
413 				return;
414 			}
415 			if (tudata.pk_mod > 1) {        /* hard error */
416 				bp->b_flags |= B_ERROR;
417 				tu.tu_herrs++;
418 				harderr(bp, "tu");
419 				printf("  pk_mod %o\n", tudata.pk_mod&0377);
420 			} else if (tudata.pk_mod != 0)	/* soft error */
421 				tu.tu_serrs++;
422 			tutab.b_active = NULL;
423 			tutab.b_actf = bp->av_forw;
424 			bp->b_resid = tu.tu_count;
425 			if ((bp->b_flags&B_READ) == 0)
426 				tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
427 			iodone(bp);
428 			tustart();
429 		} else {
430 			printf("neither data nor end: %o %o\n",
431 			    tudata.pk_flag&0xff, tudata.pk_op&0xff);
432 			mtpr(CSRS, 0);		/* flush the rest */
433 			tu.tu_state = TUS_INIT1;
434 		}
435 		break;
436 
437 	case TUS_IDLE:
438 	case TUS_INIT1:
439 		break;
440 
441 	default:
442 bad:
443 		if (c == TUF_INITF) {
444 			printf("tu protocol error, state=");
445 			printstate(tu.tu_state);
446 			printf(", op=%x, cnt=%d, block=%d\n",
447 			    tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
448 			tutab.b_active = NULL;
449 			if (bp = tutab.b_actf) {
450 				bp->b_flags |= B_ERROR;
451 				tutab.b_actf = bp->av_forw;
452 				if ((bp->b_flags&B_READ) == 0)
453 					tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
454 				iodone(bp);
455 			}
456 			tu.tu_state = TUS_INIT1;
457 		} else {
458 			printf("tu receive state error, state=");
459 			printf(", byte=%x\n", c);
460 #ifdef notdef
461 			tu.tu_state = TUS_INIT1; */
462 #endif
463 			wakeup((caddr_t)&tu);
464 		}
465 	}
466 }
467 
468 /*
469  * TU58 transmitter interrupt
470  */
471 tuxintr()
472 {
473 
474 top:
475 	if (tu.tu_wcnt) {
476 		/* still stuff to send, send one byte */
477 		while ((mfpr(CSTS) & READY) == 0)
478 			;
479 		mtpr(CSTD, *tu.tu_wbptr++);
480 		tu.tu_wcnt--;
481 		return;
482 	}
483 
484 	/*
485 	 * Last message byte was sent out.
486 	 * Switch on tu_state of transfer.
487 	 */
488 	if (tudebug) {
489 		printf("tuxintr: state=");
490 		printstate(tu.tu_state);
491 	}
492 	switch(tu.tu_state) {
493 
494 	/*
495 	 * Two nulls have been sent, remove break, and send inits
496 	 */
497 	case TUS_INIT1:
498 		mtpr(CSTS, IE);
499 		printd("ON2 ");
500 		tu.tu_state = TUS_INIT2;
501 		tu.tu_wbptr = tuinit;
502 		tu.tu_wcnt = sizeof (tuinit);
503 		goto top;
504 
505 	/*
506 	 * Inits have been sent, wait for a continue msg.
507 	 */
508 	case TUS_INIT2:
509 		(void) mfpr(CSRD);
510 		mtpr(CSRS, IE);
511 		tu.tu_flag = 1;
512 		break;
513 
514 	case TUS_IDLE:		/* stray interrupt? */
515 		break;
516 
517 	/*
518 	 * Read cmd packet sent, get ready for data
519 	 */
520 	case TUS_SENDR:
521 		tu.tu_state = TUS_GETH;
522 		tu.tu_rbptr = (u_char *)&tudata;
523 		tu.tu_rcnt = 2;
524 		tu.tu_flag = 1;
525 		mtpr(CSTS, 0);	/* disable transmitter interrupts */
526 		printd("OFF ");
527 		break;
528 
529 	/*
530 	 * Write cmd packet sent, wait for continue
531 	 */
532 	case TUS_SENDW:
533 		tu.tu_state = TUS_WAIT;
534 		tu.tu_flag = 1;
535 		if ((mfpr(CSRS)&IE) == 0) {
536 			printf("NO IE\n");
537 			mtpr(CSRS, IE);
538 		}
539 		break;
540 
541 	/*
542 	 * Header sent, send data.
543 	 */
544 	case TUS_SENDH:
545 		tu.tu_state = TUS_SENDD;
546 		tu.tu_wbptr = (u_char *)tu.tu_addr;
547 		tu.tu_wcnt = tudata.pk_mcount;
548 		goto top;
549 
550 	/*
551 	 * Data sent, follow with checksum.
552 	 */
553 	case TUS_SENDD:
554 		tu.tu_state = TUS_SENDC;
555 		tu.tu_wbptr = (u_char *)&tudata.pk_chksum;
556 		tu.tu_wcnt = sizeof tudata.pk_chksum;
557 		goto top;
558 
559 	/*
560 	 * Checksum sent, wait for continue.
561 	 */
562 	case TUS_SENDC:
563 		/*
564 		 * Updata buffer address and count.
565 		 */
566 		tu.tu_addr += tudata.pk_mcount;
567 		tu.tu_count -= tudata.pk_mcount;
568 		if (tu.tu_count) {
569 			tu.tu_state = TUS_WAIT;
570 			tu.tu_flag = 1;
571 			break;
572 		}
573 
574 		/*
575 		 * End of transmission, get ready for end packet.
576 		 */
577 		tu.tu_state = TUS_GET;
578 		tu.tu_rbptr = (u_char *)&tudata;
579 		tu.tu_rcnt = sizeof (tudata);
580 		tu.tu_flag = 1;
581 		mtpr(CSTS, 0);
582 		printd("OFF2 ");
583 		break;
584 
585 	/*
586 	 * Random interrupt, probably from MRSP ACK
587 	 */
588 	default:
589 		break;
590 	}
591 	if (tudebug) {
592 		printd("  new tu_state=");
593 		printstate(tu.tu_state);
594 	}
595 }
596 
597 /*
598  * Compute checksum TU58 fashion
599  */
600 #ifdef lint
601 tuchk(word, cp, n)
602 	register word;
603 	register unsigned short *cp;
604 	int n;
605 {
606 	register int c = n >> 1;
607 	register long temp;
608 
609 	do {
610 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
611 		word += temp;
612 	} while (--c > 0);
613 	if (n & 1)
614 		word += *(unsigned char *)cp;
615 	while (word & 0xffff0000)
616 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
617 	return (word);
618 }
619 #else
620 tuchk(word0, wp, n)
621 	register int word0;	/* r11 */
622 	register char *wp;	/* r10 */
623 	register int n;		/* r9 */
624 {
625 	asm("loop:");
626 	asm("	addw2	(r10)+,r11");	/* add a word to sum */
627 	asm("	adwc	$0,r11");	/* add in carry, end-around */
628 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
629 	asm("	blbc	r9,ok");	/* odd byte count? */
630 	asm("	movzbw	(r10),r10");	/* yes, get last byte */
631 	asm("	addw2	r10,r11");	/* add it in */
632 	asm("	adwc	$0,r11");	/* and the carry */
633 	asm("ok:");
634 	asm("	movl	r11,r0");	/* return sum */
635 }
636 #endif
637 
638 tuwatch()
639 {
640 	register int s;
641 	register struct buf *bp;
642 
643 	if (tutimer == 0) {
644 		tu.tu_flag = 0;
645 		return;
646 	}
647 	if (tu.tu_flag)
648 		tu.tu_flag++;
649 	if (tu.tu_flag <= 40) {
650 		timeout(tuwatch, (caddr_t)0, hz);
651 		return;
652 	}
653 	printf("tu: read stalled\n");
654 	printf("%X %X %X %X %X %X %X %X\n", tu.tu_rbptr, tu.tu_rcnt,
655 		tu.tu_wbptr, tu.tu_wcnt, tu.tu_state, tu.tu_flag,
656 		tu.tu_addr, tu.tu_count);
657 	tu.tu_flag = 0;
658 	s = splx(TUIPL);
659 	(void) mfpr(CSRD);
660 	mtpr(CSRS, IE);		/* in case we were flushing */
661 	mtpr(CSTS, IE);
662 	tu.tu_state = TUS_IDLE;
663 	if (!tutab.b_active) {
664 		wakeup((caddr_t)&tu);
665 		goto retry;
666 	}
667 	if (++tutab.b_errcnt <= 1) {
668 		tustart();
669 		goto retry;
670 	}
671 	if (bp = tutab.b_actf) {
672 		bp->b_flags |= B_ERROR;
673 		if ((bp->b_flags&B_READ) == 0)
674 			tu_vee(&pcnt[minor(bp->b_dev)&DNUM]);
675 		iodone(bp);
676 	}
677 retry:
678 	splx(s);
679 	timeout(tuwatch, (caddr_t)0, hz);
680 }
681 
682 tu_pee(cp)
683 	char *cp;
684 {
685 	register int s;
686 
687 	s = splx(TUIPL);
688 	if (++(*cp) > NTUQ)
689 		sleep(cp, PRIBIO);
690 	splx(s);
691 }
692 
693 tu_vee(cp)
694 	char *cp;
695 {
696 	register int s;
697 
698 	s = splx(TUIPL);
699 	if (--(*cp) <= NTUQ)
700 		wakeup(cp);
701 	splx(s);
702 }
703 #endif
704