BSD 4_3_Reno release
[unix-history] / usr / src / sys / vax / tu.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
1c15e888 6 * @(#)tu.c 7.4 (Berkeley) 4/12/90
da7c5cc6 7 */
4ba2674e 8
10f66600 9#if defined(VAX750) || defined(VAX730)
4ba2674e
BJ
10/*
11 * TU58 DECtape II device driver
12 *
4ec5f6fa
SL
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
15e42b2e 15 * recovery is not extensive, but sufficient for most situations. It is
4ec5f6fa
SL
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.
15e42b2e
HS
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.
195c9f34 22 *
c8d599e6
HS
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*****
4ba2674e 26 */
1884f3f6
JB
27#include "param.h"
28#include "systm.h"
29#include "buf.h"
30#include "conf.h"
1884f3f6
JB
31#include "user.h"
32#include "kernel.h"
cd3da95f 33
1884f3f6
JB
34#include "cpu.h"
35#include "mtpr.h"
36#include "rsp.h"
02a37dd4 37
4ba2674e
BJ
38#define printd if(tudebug) printf
39#ifdef printd
40int tudebug; /* printd */
41#endif printd
42
6269134b 43#define NTU ((cpu == VAX_750) ? 1 : 2)
15e42b2e 44#define DNUM 01 /* mask for drive number (should match NTU) */
4ba2674e 45#define NTUBLK 512 /* number of blocks on a TU58 cassette */
6269134b
SL
46#define WRV 02 /* bit in minor dev => write w. read verify */
47#define NTUQ 2 /* # of blocks which can be queued up */
8011f5df 48#define spltu() ((cpu == VAX_750) ? spl7() : spl4())
4ba2674e 49
c8d599e6
HS
50#ifndef MRSP
51#define MRSP (cpu != VAX_750)
52#endif
53
15e42b2e
HS
54/*
55 * State information
56 */
57struct 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
4ba2674e
BJ
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
4ba2674e
BJ
81struct packet tucmd; /* a command sent to the TU58 */
82struct packet tudata; /* a command or data returned from TU58 */
83
406ddcbe
BJ
84char *tustates[TUS_NSTATES] = {
85 "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
15e42b2e 86 "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
406ddcbe 87};
4ba2674e
BJ
88
89u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */
90u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */
6eca79b2 91static char tu_pcnt[2]; /* pee/vee counters */
4ba2674e 92int tutimer = 0;
c8d599e6 93int tuwake();
6eca79b2 94struct buf tutab; /* I/O queue header */
4ba2674e
BJ
95
96/*
97 * Open the TU58
98 */
89b8a44c 99/*ARGSUSED*/
4ba2674e
BJ
100tuopen(dev, flag)
101{
102 extern int tuwatch();
2311123d 103 register s;
298c05ad 104 int error;
4ba2674e 105
89b8a44c
BJ
106#ifdef lint
107 turintr(); tuwintr();
108#endif
c8d599e6 109 if ((minor(dev)&DNUM) >= NTU)
2d876e2a 110 return (ENXIO);
c8d599e6
HS
111 if (tu.tu_dopen[minor(dev)&DNUM])
112 return (EBUSY);
113 if (tutimer++ == 0)
4ba2674e 114 timeout(tuwatch, (caddr_t)0, hz);
c8d599e6 115
8011f5df 116 s = spltu();
c8d599e6 117 tu.tu_dopen[minor(dev)&DNUM]++;
406ddcbe
BJ
118 /*
119 * If the cassette's already initialized,
120 * just enable interrupts and return.
121 */
122 if (tu.tu_state == TUS_IDLE) {
4ba2674e 123 mtpr(CSRS, IE);
15e42b2e 124 goto ok;
406ddcbe
BJ
125 }
126
127 /*
128 * Must initialize, reset the cassette
129 * and wait for things to settle down.
130 */
131 tureset();
298c05ad
KS
132 if (error = tsleep((caddr_t)&tu, (PZERO + 1) | PCATCH,
133 devopn, 0)) {
134 splx(s);
135 return (error);
136 }
406ddcbe
BJ
137 tutab.b_active = NULL;
138 if (tu.tu_state != TUS_IDLE) {
406ddcbe
BJ
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);
15e42b2e
HS
144 splx(s);
145 return (EIO);
406ddcbe 146 }
15e42b2e 147ok:
2311123d 148 splx(s);
2d876e2a 149 return (0);
4ba2674e
BJ
150}
151
152/*
c8d599e6
HS
153 * Close the TU58, but make sure all
154 * outstanding i/o is complete first..
4ba2674e 155 */
f3149b5f 156/* ARGSUSED */
c8d599e6
HS
157tuclose(dev, flag)
158 dev_t dev;
159 int flag;
4ba2674e 160{
c8d599e6
HS
161 int s, unit = minor(dev);
162 struct buf *bp, *last = NULL;
89b8a44c 163
8011f5df 164 s = spltu();
c8d599e6
HS
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]) {
4ba2674e 183 tutimer = 0;
c8d599e6
HS
184 mtpr(CSRS, 0);
185 tu.tu_flag = 0;
4ba2674e 186 }
c8d599e6
HS
187 splx(s);
188}
189
190tuwake(bp)
191 struct buf *bp;
192{
8011f5df 193 wakeup((caddr_t)bp);
4ba2674e
BJ
194}
195
196/*
197 * Reset the TU58
198 */
4ba2674e
BJ
199tureset()
200{
89b8a44c 201
c8d599e6 202 mtpr(CSRS, 0);
406ddcbe
BJ
203 tu.tu_state = TUS_INIT1;
204 tu.tu_wbptr = tunull;
205 tu.tu_wcnt = sizeof (tunull);
4ba2674e 206 tucmd.pk_flag = TUF_CMD;
406ddcbe 207 tucmd.pk_mcount = sizeof (tucmd) - 4;
4ba2674e
BJ
208 tucmd.pk_mod = 0;
209 tucmd.pk_seq = 0;
c8d599e6 210 tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
4ba2674e 211 tutab.b_active++;
195c9f34
HS
212 mtpr(CSTS, IE | BREAK);
213 tuxintr(); /* start output */
4ba2674e
BJ
214}
215
216/*
217 * Strategy routine for block I/O
218 */
4ba2674e 219tustrategy(bp)
89b8a44c 220 register struct buf *bp;
4ba2674e 221{
2311123d 222 register int s;
89b8a44c 223
406ddcbe 224 if (bp->b_blkno >= NTUBLK) {
4ba2674e
BJ
225 bp->b_flags |= B_ERROR;
226 iodone(bp);
227 return;
228 }
6269134b 229 if ((bp->b_flags&B_READ) == 0)
6eca79b2 230 tu_pee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
4ba2674e 231 bp->av_forw = NULL;
8011f5df 232 s = spltu();
4ba2674e
BJ
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();
2311123d 240 splx(s);
4ba2674e
BJ
241}
242
243/*
244 * Start the transfer
245 */
4ba2674e
BJ
246tustart()
247{
248 register struct buf *bp;
c8d599e6 249 int s;
4ba2674e 250
4ba2674e
BJ
251 if ((bp = tutab.b_actf) == NULL)
252 return;
8011f5df 253 s = spltu();
406ddcbe 254 if (tu.tu_state != TUS_IDLE) {
4ba2674e 255 tureset();
c8d599e6 256 splx(s);
4ba2674e
BJ
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;
6269134b
SL
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);
c8d599e6 265 tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
406ddcbe 266 tucmd.pk_count = tu.tu_count = bp->b_bcount;
4ba2674e 267 tucmd.pk_block = bp->b_blkno;
89b8a44c 268 tucmd.pk_chksum =
6e7edb25 269 tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
89b8a44c 270 (int)tucmd.pk_mcount);
406ddcbe
BJ
271 tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
272 tu.tu_addr = bp->b_un.b_addr;
406ddcbe
BJ
273 tu.tu_wbptr = (u_char *)&tucmd;
274 tu.tu_wcnt = sizeof (tucmd);
4ba2674e 275 tuxintr();
c8d599e6 276 splx(s);
4ba2674e
BJ
277}
278
279/*
280 * TU58 receiver interrupt
281 */
4ba2674e
BJ
282turintr()
283{
284 register struct buf *bp;
285 register int c;
286
15e42b2e 287 c = mfpr(CSRD)&0xff;
c8d599e6
HS
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 }
4ba2674e
BJ
297 }
298
299 /*
15e42b2e 300 * Switch on the state of the transfer.
406ddcbe
BJ
301 */
302 switch(tu.tu_state) {
303
15e42b2e
HS
304 /*
305 * Probably an overrun error,
306 * cannot happen if MRSP is used
307 */
308 case TUS_RCVERR:
c8d599e6
HS
309 mtpr(CSRS, 0); /* flush */
310 printf("overrun error, transfer restarted\n"); /* DEBUG */
15e42b2e
HS
311 tu.tu_serrs++;
312 tu_restart();
313 break;
15e42b2e 314
406ddcbe
BJ
315 /*
316 * If we get an unexpected "continue",
317 * start all over again...
4ba2674e 318 */
406ddcbe
BJ
319 case TUS_INIT2:
320 tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
321 tu.tu_flag = 0;
4ba2674e
BJ
322 wakeup((caddr_t)&tu);
323 tustart();
324 break;
325
406ddcbe
BJ
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 */
132e5956
HS
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 =
8011f5df 338 tuchk(*((short *)&tudata), (u_short *)tu.tu_addr,
132e5956
HS
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;
15e42b2e 349 tu.tu_rcnt = sizeof (tudata) - 1;
132e5956
HS
350 tu.tu_flag = 1;
351 mtpr (CSTS, 0);
15e42b2e
HS
352 *tu.tu_rbptr = c;
353 break;
132e5956
HS
354
355 case TUF_INITF:
356 tureset();
357 break;
358
359 default: /* something random...bad news */
406ddcbe 360 tu.tu_state = TUS_INIT1;
4ba2674e
BJ
361 break;
362 }
4ba2674e
BJ
363 break;
364
406ddcbe 365 case TUS_SENDW:
132e5956 366 if (c != TUF_CONT && c != TUF_INITF)
6269134b 367 goto bad;
406ddcbe
BJ
368 tureset();
369 break;
6269134b 370
406ddcbe
BJ
371 /*
372 * Got header, now get data; amount to
15e42b2e 373 * fetch is included in packet.
406ddcbe
BJ
374 */
375 case TUS_GETH:
c8d599e6 376 if (MRSP && (tudata.pk_flag == TUF_DATA))
406ddcbe
BJ
377 tu.tu_rbptr = (u_char *)tu.tu_addr;
378 tu.tu_rcnt = tudata.pk_mcount;
379 tu.tu_state = TUS_GETD;
4ba2674e
BJ
380 break;
381
406ddcbe
BJ
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;
4ba2674e
BJ
389 break;
390
c8d599e6
HS
391 case TUS_CHKERR: /* from tudma only */
392 tu.tu_cerrs++;
393 goto tus_get;
394
406ddcbe 395 case TUS_GET:
c8d599e6
HS
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
406ddcbe
BJ
403 case TUS_GETC:
404 /* got entire packet */
89b8a44c 405 if (tudata.pk_chksum !=
6e7edb25 406 tuchk(*((short *)&tudata), (u_short *)
15e42b2e
HS
407 (tudata.pk_flag == TUF_DATA ?
408 (u_short *) tu.tu_addr : (u_short *)&tudata.pk_op),
89b8a44c 409 (int)tudata.pk_mcount))
406ddcbe 410 tu.tu_cerrs++;
c8d599e6 411tus_get:
89b8a44c
BJ
412 if (tudata.pk_flag == TUF_DATA) {
413 /* data packet, advance to next */
406ddcbe
BJ
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;
89b8a44c
BJ
419 } else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
420 /* end packet, idle and reenable transmitter */
406ddcbe
BJ
421 tu.tu_state = TUS_IDLE;
422 tu.tu_flag = 0;
89b8a44c 423 mtpr(CSTS, IE);
4ba2674e
BJ
424 printd("ON ");
425 if ((bp = tutab.b_actf) == NULL) {
15e42b2e
HS
426 printf("tu%d: no bp, active %d\n",
427 tudata.pk_unit, tutab.b_active);
4ba2674e
BJ
428 tustart();
429 return;
430 }
6269134b 431 if (tudata.pk_mod > 1) { /* hard error */
4ba2674e 432 bp->b_flags |= B_ERROR;
406ddcbe 433 tu.tu_herrs++;
15e42b2e
HS
434 printf("tu%d: hard error bn%d,",
435 minor(bp->b_dev)&DNUM, bp->b_blkno);
6269134b 436 printf(" pk_mod %o\n", tudata.pk_mod&0377);
0b9e4041 437 } else if (tudata.pk_mod != 0) /* soft error */
406ddcbe 438 tu.tu_serrs++;
4ba2674e
BJ
439 tutab.b_active = NULL;
440 tutab.b_actf = bp->av_forw;
406ddcbe 441 bp->b_resid = tu.tu_count;
6269134b 442 if ((bp->b_flags&B_READ) == 0)
6eca79b2 443 tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
4ba2674e
BJ
444 iodone(bp);
445 tustart();
446 } else {
15e42b2e
HS
447 /*
448 * Neither data nor end: data was lost
449 * somehow, restart the transfer
450 */
4ba2674e 451 mtpr(CSRS, 0); /* flush the rest */
15e42b2e
HS
452 tu_restart();
453 tu.tu_serrs++;
4ba2674e
BJ
454 }
455 break;
456
406ddcbe
BJ
457 case TUS_IDLE:
458 case TUS_INIT1:
4ba2674e
BJ
459 break;
460
89b8a44c 461 default:
406ddcbe 462bad:
4ba2674e 463 if (c == TUF_INITF) {
15e42b2e
HS
464 printf("tu%d protocol error, state=",
465 (int)tudata.pk_unit);
406ddcbe
BJ
466 printstate(tu.tu_state);
467 printf(", op=%x, cnt=%d, block=%d\n",
89b8a44c 468 tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
4ba2674e
BJ
469 tutab.b_active = NULL;
470 if (bp = tutab.b_actf) {
471 bp->b_flags |= B_ERROR;
472 tutab.b_actf = bp->av_forw;
6269134b 473 if ((bp->b_flags&B_READ) == 0)
6eca79b2 474 tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
4ba2674e
BJ
475 iodone(bp);
476 }
406ddcbe 477 tu.tu_state = TUS_INIT1;
4ba2674e 478 } else {
15e42b2e
HS
479 printf("tu%d: receive state error, state=",
480 (int)tudata.pk_unit);
b2f88be3 481 printstate(tu.tu_state);
15e42b2e 482 printf(", byte=%x\n", c & 0xff);
c8d599e6
HS
483 if (tutab.b_actf)
484 tu_restart();
485 else
486 wakeup((caddr_t)&tu);
4ba2674e
BJ
487 }
488 }
489}
490
491/*
492 * TU58 transmitter interrupt
493 */
4ba2674e
BJ
494tuxintr()
495{
89b8a44c
BJ
496
497top:
406ddcbe 498 if (tu.tu_wcnt) {
89b8a44c 499 /* still stuff to send, send one byte */
4ba2674e
BJ
500 while ((mfpr(CSTS) & READY) == 0)
501 ;
406ddcbe
BJ
502 mtpr(CSTD, *tu.tu_wbptr++);
503 tu.tu_wcnt--;
4ba2674e
BJ
504 return;
505 }
506
507 /*
508 * Last message byte was sent out.
132e5956 509 * Switch on state of transfer.
4ba2674e 510 */
406ddcbe
BJ
511 if (tudebug) {
512 printf("tuxintr: state=");
513 printstate(tu.tu_state);
514 }
515 switch(tu.tu_state) {
89b8a44c 516
406ddcbe
BJ
517 /*
518 * Two nulls have been sent, remove break, and send inits
519 */
520 case TUS_INIT1:
4ba2674e
BJ
521 mtpr(CSTS, IE);
522 printd("ON2 ");
406ddcbe
BJ
523 tu.tu_state = TUS_INIT2;
524 tu.tu_wbptr = tuinit;
525 tu.tu_wcnt = sizeof (tuinit);
4ba2674e
BJ
526 goto top;
527
406ddcbe
BJ
528 /*
529 * Inits have been sent, wait for a continue msg.
530 */
531 case TUS_INIT2:
89b8a44c 532 (void) mfpr(CSRD);
4ba2674e 533 mtpr(CSRS, IE);
406ddcbe 534 tu.tu_flag = 1;
4ba2674e
BJ
535 break;
536
406ddcbe
BJ
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;
4ba2674e
BJ
545 mtpr(CSTS, 0); /* disable transmitter interrupts */
546 printd("OFF ");
547 break;
548
406ddcbe
BJ
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;
4ba2674e
BJ
555 if ((mfpr(CSRS)&IE) == 0) {
556 printf("NO IE\n");
557 mtpr(CSRS, IE);
558 }
559 break;
560
406ddcbe
BJ
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;
4ba2674e
BJ
568 goto top;
569
406ddcbe
BJ
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;
4ba2674e
BJ
577 goto top;
578
406ddcbe
BJ
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;
4ba2674e 592 }
406ddcbe
BJ
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 ");
4ba2674e
BJ
603 break;
604
406ddcbe
BJ
605 /*
606 * Random interrupt, probably from MRSP ACK
607 */
c8d599e6 608 case TUS_IDLE:
15e42b2e 609
406ddcbe 610 default:
4ba2674e 611 break;
15e42b2e 612
4ba2674e 613 }
406ddcbe
BJ
614 if (tudebug) {
615 printd(" new tu_state=");
616 printstate(tu.tu_state);
617 }
4ba2674e
BJ
618}
619
620/*
621 * Compute checksum TU58 fashion
4ba2674e 622 */
0b9e4041 623#ifdef lint
6269134b
SL
624tuchk(word, cp, n)
625 register word;
626 register unsigned short *cp;
6e7edb25 627 int n;
6269134b 628{
6e7edb25 629 register int c = n >> 1;
6269134b
SL
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;
0b9e4041
BJ
638 while (word & 0xffff0000)
639 word = (word & 0xffff) + ((word >> 16) & 0xffff);
6269134b
SL
640 return (word);
641}
642#else
4ba2674e 643tuchk(word0, wp, n)
0b9e4041 644 register int word0; /* r11 */
8011f5df 645 register u_short *wp; /* r10 */
0b9e4041 646 register int n; /* r9 */
4ba2674e
BJ
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}
6269134b 659#endif
4ba2674e
BJ
660
661tuwatch()
662{
663 register int s;
664 register struct buf *bp;
665
c8d599e6
HS
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);
4ba2674e
BJ
671 return;
672 }
c8d599e6 673 if (tu.tu_flag++ <= 40) {
406ddcbe
BJ
674 timeout(tuwatch, (caddr_t)0, hz);
675 return;
676 }
15e42b2e 677 printf("tu%d: read stalled\n", tudata.pk_unit);
c8d599e6 678#ifdef TUDEBUG
406ddcbe
BJ
679 printf("%X %X %X %X %X %X %X %X\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);
4ec5f6fa 682#endif
8011f5df 683 s = spltu();
15e42b2e 684 tu.tu_flag = 0;
406ddcbe
BJ
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;
4ba2674e 692 }
406ddcbe
BJ
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)
6eca79b2 700 tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
406ddcbe
BJ
701 iodone(bp);
702 }
703retry:
704 splx(s);
4ba2674e
BJ
705 timeout(tuwatch, (caddr_t)0, hz);
706}
6269134b
SL
707
708tu_pee(cp)
406ddcbe 709 char *cp;
6269134b
SL
710{
711 register int s;
712
8011f5df 713 s = spltu();
406ddcbe 714 if (++(*cp) > NTUQ)
6269134b 715 sleep(cp, PRIBIO);
6269134b
SL
716 splx(s);
717}
718
719tu_vee(cp)
406ddcbe 720 char *cp;
6269134b
SL
721{
722 register int s;
723
8011f5df 724 s = spltu();
406ddcbe 725 if (--(*cp) <= NTUQ)
6269134b 726 wakeup(cp);
6269134b
SL
727 splx(s);
728}
15e42b2e
HS
729
730tu_restart()
731{
732 tureset();
ec3f5209 733 timeout(tustart, (caddr_t)0, hz * 3);
15e42b2e 734}
c8d599e6 735
c3a6f569 736#endif