Commit | Line | Data |
---|---|---|
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 | |
40 | int 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 | */ | |
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 | ||
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 |
81 | struct packet tucmd; /* a command sent to the TU58 */ |
82 | struct packet tudata; /* a command or data returned from TU58 */ | |
83 | ||
406ddcbe BJ |
84 | char *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 | |
89 | u_char tunull[2] = { 0, 0 }; /* nulls to send for initialization */ | |
90 | u_char tuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */ | |
6eca79b2 | 91 | static char tu_pcnt[2]; /* pee/vee counters */ |
4ba2674e | 92 | int tutimer = 0; |
c8d599e6 | 93 | int tuwake(); |
6eca79b2 | 94 | struct buf tutab; /* I/O queue header */ |
4ba2674e BJ |
95 | |
96 | /* | |
97 | * Open the TU58 | |
98 | */ | |
89b8a44c | 99 | /*ARGSUSED*/ |
4ba2674e BJ |
100 | tuopen(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 | 147 | ok: |
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 |
157 | tuclose(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 | ||
190 | tuwake(bp) | |
191 | struct buf *bp; | |
192 | { | |
8011f5df | 193 | wakeup((caddr_t)bp); |
4ba2674e BJ |
194 | } |
195 | ||
196 | /* | |
197 | * Reset the TU58 | |
198 | */ | |
4ba2674e BJ |
199 | tureset() |
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 | 219 | tustrategy(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 |
246 | tustart() |
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 |
282 | turintr() |
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 | 411 | tus_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 | 462 | bad: |
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 |
494 | tuxintr() |
495 | { | |
89b8a44c BJ |
496 | |
497 | top: | |
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 |
624 | tuchk(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 | 643 | tuchk(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 | |
661 | tuwatch() | |
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 | } | |
703 | retry: | |
704 | splx(s); | |
4ba2674e BJ |
705 | timeout(tuwatch, (caddr_t)0, hz); |
706 | } | |
6269134b SL |
707 | |
708 | tu_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 | ||
719 | tu_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 | |
730 | tu_restart() | |
731 | { | |
732 | tureset(); | |
ec3f5209 | 733 | timeout(tustart, (caddr_t)0, hz * 3); |
15e42b2e | 734 | } |
c8d599e6 | 735 | |
c3a6f569 | 736 | #endif |