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