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