Commit | Line | Data |
---|---|---|
5f334c5b | 1 | /* uu.c 4.9 83/07/24 */ |
2a6e4a22 | 2 | |
03d12a3f | 3 | #include "uu.h" |
fc231bc6 | 4 | #if NUU > 0 |
2a6e4a22 | 5 | /* |
c3963d4e | 6 | * TU58 DECtape II/DL11 device driver |
fc231bc6 | 7 | * |
b1084c70 HS |
8 | * The TU58 is treated as a block device (only). Error detection and |
9 | * recovery is not very extensive, but sufficient to handle the most | |
5f334c5b HS |
10 | * common errors. It is assumed that the TU58 will follow the RSP |
11 | * protocol exactly, very few protocol errors are checked for. | |
12 | * | |
13 | * To reduce interrupt latency, `options UUDMA' should be specified | |
14 | * in the config file to make sure the `pseudo-DMA' code in locore.s | |
15 | * will be compiled into the system. Otherwise overrun errors will | |
16 | * occur frequently (these errors are not reported). | |
17 | * | |
18 | * TODO: | |
19 | * | |
20 | * - Add ioctl code to wind/rewind cassette | |
21 | * | |
2a6e4a22 | 22 | */ |
c3963d4e | 23 | |
03d12a3f | 24 | #include "../machine/pte.h" |
c3963d4e | 25 | |
2a6e4a22 HS |
26 | #include "../h/param.h" |
27 | #include "../h/systm.h" | |
28 | #include "../h/buf.h" | |
29 | #include "../h/conf.h" | |
03d12a3f | 30 | #include "../h/time.h" |
2a6e4a22 | 31 | #include "../h/kernel.h" |
c3963d4e | 32 | #include "../h/errno.h" |
c3963d4e | 33 | #include "../h/file.h" |
2a6e4a22 HS |
34 | |
35 | #include "../vax/cpu.h" | |
03d12a3f | 36 | #include "../vax/nexus.h" |
ecb04cd7 | 37 | #include "../vax/rsp.h" |
03d12a3f | 38 | |
c3963d4e HS |
39 | #include "../vaxuba/ubavar.h" |
40 | #include "../vaxuba/ubareg.h" | |
41 | #include "../vaxuba/uureg.h" | |
2a6e4a22 | 42 | |
2a6e4a22 | 43 | #define NTUBLK 512 /* number of blocks on a TU58 cassette */ |
fc231bc6 | 44 | #define WRV 01 /* bit in minor dev => write w. read verify */ |
03d12a3f | 45 | #define NDPC 02 /* drives per controller */ |
fc231bc6 | 46 | #define NUX NDPC * NUU /* number of drives */ |
5f334c5b | 47 | #define NUUQ 02 /* # of block which can be queued up */ |
fc231bc6 | 48 | #define UMASK 01 /* unit number mask */ |
ecb04cd7 | 49 | #define UUIPL 0x14 /* ipl level to use */ |
2a6e4a22 | 50 | |
fc231bc6 HS |
51 | struct packet uucmd[NUU]; /* a command sent to the TU58 */ |
52 | struct packet uudata[NUU]; /* a command or data returned from TU58 */ | |
53 | struct buf uitab[NUU]; /* buffer queue headers */ | |
2a6e4a22 HS |
54 | |
55 | /* | |
ecb04cd7 | 56 | * Driver soft carrier structure |
2a6e4a22 | 57 | */ |
ecb04cd7 HS |
58 | struct uu_softc { |
59 | u_char *tu_rbptr; /* pointer to buffer for read */ | |
60 | int tu_rcnt; /* how much to read */ | |
61 | u_char *tu_wbptr; /* pointer to buffer for write */ | |
62 | int tu_wcnt; /* how much to write */ | |
63 | int tu_state; /* current state of tansfer operation */ | |
64 | int tu_flag; /* read in progress flag */ | |
65 | char *tu_addr; /* real buffer data address */ | |
66 | int tu_count; /* real requested count */ | |
67 | int tu_serrs; /* count of soft errors */ | |
68 | int tu_cerrs; /* count of checksum errors */ | |
69 | int tu_herrs; /* count of hard errors */ | |
70 | char tu_dopen[2]; /* drive is open */ | |
a73ada79 | 71 | } uu_softc[NUU]; |
ecb04cd7 HS |
72 | |
73 | #if defined(VAX750) || defined(VAX730) | |
74 | extern char *tustates[]; | |
75 | #else | |
76 | char *tustates[TUS_NSTATES] = { | |
2a6e4a22 | 77 | "INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR", |
a73ada79 | 78 | "SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR" |
2a6e4a22 | 79 | }; |
ecb04cd7 | 80 | #endif |
03d12a3f | 81 | |
fc231bc6 | 82 | #define UNIT(dev) (minor(dev)>>1) |
2a6e4a22 | 83 | |
5f334c5b | 84 | u_char uunull[2] = { 0, 0 }; /* nulls to send for initialization */ |
c3963d4e HS |
85 | u_char uuinit[2] = { TUF_INITF, TUF_INITF }; /* inits to send */ |
86 | ||
87 | struct uba_device *uudinfo[NUU]; | |
c3963d4e | 88 | |
fc231bc6 HS |
89 | int uuprobe(), uuattach(), uurintr(), uuxintr(), uuwatch(); |
90 | u_short uustd[] = { 0176500 }; | |
91 | struct uba_driver uudriver = | |
92 | { uuprobe, 0, uuattach, 0, uustd, "uu", uudinfo }; | |
c3963d4e HS |
93 | |
94 | int uuwstart; | |
5f334c5b | 95 | static char uu_pcnt[NUX]; /* pee/vee counters, one per drive */ |
2a6e4a22 | 96 | |
2a6e4a22 | 97 | /*ARGSUSED*/ |
c3963d4e HS |
98 | uuprobe(reg) |
99 | caddr_t reg; | |
2a6e4a22 | 100 | { |
c3963d4e HS |
101 | register int br, cvec; /* value result */ |
102 | struct uudevice *uuaddr = (struct uudevice *)reg; | |
2a6e4a22 HS |
103 | |
104 | #ifdef lint | |
c3963d4e HS |
105 | br = 0; cvec = br; br = cvec; |
106 | uurintr(0); uuxintr(0); | |
2a6e4a22 | 107 | #endif |
fc231bc6 HS |
108 | uuaddr->tcs = UUCS_INTR; |
109 | DELAY(1000); | |
110 | uuaddr->tcs = 0; | |
111 | cvec -= 4; /* since we are using the xmitter intrpt */ | |
c3963d4e HS |
112 | return(sizeof (*uuaddr)); |
113 | } | |
114 | ||
c3963d4e | 115 | uuattach(ui) |
fc231bc6 | 116 | register struct uba_device *ui; |
c3963d4e | 117 | { |
c3963d4e HS |
118 | } |
119 | ||
120 | /*ARGSUSED1*/ | |
121 | uuopen(dev, flag) | |
122 | dev_t dev; | |
123 | int flag; | |
124 | { | |
125 | register struct uba_device *ui; | |
a73ada79 | 126 | register struct uu_softc *uuc; |
c3963d4e | 127 | register struct uudevice *uuaddr; |
03d12a3f | 128 | int ctlr, unit = UNIT(dev), s; |
c3963d4e | 129 | |
fc231bc6 HS |
130 | ctlr = unit / NDPC; |
131 | if (unit >= NUX || (ui = uudinfo[ctlr]) == 0 || ui->ui_alive == 0) | |
2a6e4a22 | 132 | return (ENXIO); |
ecb04cd7 HS |
133 | uuc = &uu_softc[ctlr]; |
134 | if (uuc->tu_dopen[unit&UMASK]) | |
c3963d4e HS |
135 | return (EBUSY); |
136 | if (uuwstart++ == 0) | |
137 | timeout(uuwatch, (caddr_t)0, hz); | |
138 | ||
ecb04cd7 | 139 | uuc->tu_dopen[unit&UMASK]++; |
fc231bc6 HS |
140 | uuaddr = (struct uudevice *)ui->ui_addr; |
141 | s = splx(UUIPL); | |
a73ada79 HS |
142 | /* |
143 | * If the other device on this controller | |
5f334c5b | 144 | * is already active, no need to initialize |
a73ada79 HS |
145 | */ |
146 | if (uuc->tu_dopen[0] && uuc->tu_dopen[1]) | |
b1084c70 | 147 | goto ok; |
a73ada79 | 148 | |
2a6e4a22 | 149 | /* |
c3963d4e | 150 | * If the unit already initialized, |
2a6e4a22 HS |
151 | * just enable interrupts and return. |
152 | */ | |
ecb04cd7 | 153 | if (uuc->tu_state == TUS_IDLE) { |
c3963d4e | 154 | uuaddr->rcs = UUCS_INTR; |
ecb04cd7 | 155 | goto ok; |
2a6e4a22 HS |
156 | } |
157 | ||
158 | /* | |
159 | * Must initialize, reset the cassette | |
160 | * and wait for things to settle down. | |
161 | */ | |
c3963d4e HS |
162 | uureset(ctlr); |
163 | sleep((caddr_t)uuc, PZERO+1); | |
fc231bc6 | 164 | uitab[ctlr].b_active = NULL; |
ecb04cd7 HS |
165 | if (uuc->tu_state != TUS_IDLE) { |
166 | uuc->tu_state = TUS_INIT1; | |
167 | uuc->tu_dopen[unit&UMASK] = 0; | |
168 | uuc->tu_rcnt = uuc->tu_wcnt = 0; | |
c3963d4e HS |
169 | uuaddr->rcs = 0; |
170 | uuaddr->tcs = 0; | |
171 | splx(s); | |
ecb04cd7 | 172 | return (EIO); |
2a6e4a22 | 173 | } |
ecb04cd7 | 174 | ok: |
2a6e4a22 HS |
175 | splx(s); |
176 | return (0); | |
177 | } | |
178 | ||
5f334c5b HS |
179 | /* |
180 | * Wait for all outstanding IO on this drive | |
181 | * complete, before closing. If both drives on | |
182 | * this controller are idle, mark the controller | |
183 | * `inactive'. | |
184 | */ | |
185 | ||
c3963d4e HS |
186 | uuclose(dev, flag) |
187 | dev_t dev; | |
188 | int flag; | |
2a6e4a22 | 189 | { |
5f334c5b HS |
190 | int s, unit = UNIT(dev); |
191 | register struct uu_softc *uuc = &uu_softc[unit/NDPC]; | |
192 | struct buf *bp, *last = NULL; | |
193 | struct uudevice *uuaddr = (struct uudevice *)uudinfo[unit/NDPC]->ui_addr; | |
c3963d4e | 194 | |
5f334c5b HS |
195 | s = splx(UUIPL); |
196 | while (uu_pcnt[unit]) | |
197 | sleep(&uu_pcnt[unit], PRIBIO); | |
198 | /* | |
199 | * No more writes are pending, scan the | |
200 | * buffer queue for oustanding reads from | |
201 | * this unit. | |
202 | */ | |
203 | for (bp = uitab[unit/NDPC].b_actf; bp; bp = bp->b_actf) | |
204 | if (bp->b_dev == dev) | |
205 | last = bp; | |
206 | if (last) | |
207 | iowait(last); | |
208 | uuc->tu_dopen[unit&UMASK] = 0; | |
209 | if (!uuc->tu_dopen[0] && !uuc->tu_dopen[1]) { | |
210 | uuc->tu_flag = 0; | |
211 | uuaddr->rcs = 0; | |
212 | /* | |
213 | * Make sure the device is left in a | |
214 | * known state.... | |
215 | */ | |
216 | if (uuc->tu_state != TUS_IDLE) | |
217 | uuc->tu_state = TUS_INIT1; | |
218 | } | |
219 | splx(s); | |
2a6e4a22 HS |
220 | } |
221 | ||
c3963d4e HS |
222 | uureset(ctlr) |
223 | int ctlr; | |
2a6e4a22 | 224 | { |
a73ada79 | 225 | register struct uu_softc *uuc = &uu_softc[ctlr]; |
03d12a3f | 226 | register struct packet *cmd = &uucmd[ctlr]; |
fc231bc6 HS |
227 | struct uba_device *ui = uudinfo[ctlr]; |
228 | register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr; | |
c3963d4e | 229 | |
fc231bc6 | 230 | uitab[ctlr].b_active++; |
ecb04cd7 HS |
231 | uuc->tu_state = TUS_INIT1; |
232 | uuc->tu_wbptr = uunull; | |
233 | uuc->tu_wcnt = sizeof (uunull); | |
5f334c5b | 234 | uuc->tu_rcnt = 0; |
c3963d4e | 235 | cmd->pk_flag = TUF_CMD; |
03d12a3f | 236 | cmd->pk_mcount = sizeof (*cmd) - 4; |
c3963d4e HS |
237 | cmd->pk_mod = 0; |
238 | cmd->pk_seq = 0; | |
03d12a3f | 239 | cmd->pk_sw = 0; |
c3963d4e HS |
240 | uuaddr->rcs = 0; |
241 | uuaddr->tcs = UUCS_INTR | UUCS_BREAK; | |
242 | uuxintr(ctlr); /* start output */ | |
2a6e4a22 HS |
243 | } |
244 | ||
245 | /* | |
246 | * Strategy routine for block I/O | |
247 | */ | |
c3963d4e | 248 | uustrategy(bp) |
2a6e4a22 HS |
249 | register struct buf *bp; |
250 | { | |
03d12a3f | 251 | register struct buf *uutab; |
c3963d4e | 252 | struct uba_device *ui; |
5f334c5b | 253 | int s, unit = UNIT(bp->b_dev); |
c3963d4e | 254 | |
5f334c5b | 255 | if ((unit > NUX) || (bp->b_blkno >= NTUBLK)) |
c3963d4e | 256 | goto bad; |
fc231bc6 | 257 | ui = uudinfo[unit/NDPC]; |
c3963d4e HS |
258 | if (ui == 0 || ui->ui_alive == 0) |
259 | goto bad; | |
fc231bc6 | 260 | uutab = &uitab[unit/NDPC]; /* one request queue per controller */ |
b1084c70 | 261 | s = splx(UUIPL); |
03d12a3f | 262 | if ((bp->b_flags&B_READ) == 0) |
5f334c5b HS |
263 | tu_pee(&uu_pcnt[unit]); |
264 | bp->b_actf = NULL; | |
03d12a3f HS |
265 | if (uutab->b_actf == NULL) |
266 | uutab->b_actf = bp; | |
267 | else | |
5f334c5b | 268 | uutab->b_actl->b_actf = bp; |
03d12a3f HS |
269 | uutab->b_actl = bp; |
270 | if (uutab->b_active == 0) | |
fc231bc6 | 271 | uustart(ui); |
2a6e4a22 | 272 | splx(s); |
c3963d4e HS |
273 | return; |
274 | ||
275 | bad: | |
276 | bp->b_flags |= B_ERROR; | |
03d12a3f | 277 | bp->b_error = ENXIO; |
c3963d4e HS |
278 | iodone(bp); |
279 | return; | |
2a6e4a22 HS |
280 | } |
281 | ||
282 | /* | |
283 | * Start the transfer | |
284 | */ | |
fc231bc6 HS |
285 | uustart(ui) |
286 | register struct uba_device *ui; | |
2a6e4a22 HS |
287 | { |
288 | register struct buf *bp; | |
a73ada79 | 289 | register struct uu_softc *uuc; |
c3963d4e | 290 | struct packet *cmd; |
fc231bc6 | 291 | int ctlr = ui->ui_unit; |
2a6e4a22 | 292 | |
fc231bc6 | 293 | if ((bp = uitab[ctlr].b_actf) == NULL) |
2a6e4a22 | 294 | return; |
ecb04cd7 | 295 | uuc = &uu_softc[ctlr]; |
ecb04cd7 | 296 | if (uuc->tu_state != TUS_IDLE) { |
03d12a3f | 297 | uureset(ctlr); |
2a6e4a22 HS |
298 | return; |
299 | } | |
5f334c5b | 300 | cmd = &uucmd[ctlr]; |
fc231bc6 | 301 | uitab[ctlr].b_active++; |
ecb04cd7 HS |
302 | uitab[ctlr].b_errcnt = 0; |
303 | uuc->tu_addr = bp->b_un.b_addr; | |
304 | uuc->tu_count = cmd->pk_count = bp->b_bcount; | |
305 | cmd->pk_block = bp->b_blkno; | |
306 | if (bp->b_flags&B_READ) { | |
307 | cmd->pk_op = TUOP_READ; | |
308 | cmd->pk_mod = 0; | |
309 | uuc->tu_state = TUS_SENDR; | |
310 | } else { | |
311 | cmd->pk_op = TUOP_WRITE; | |
312 | cmd->pk_mod = minor(bp->b_dev)&WRV ? TUMD_WRV : 0; | |
313 | uuc->tu_state = TUS_SENDW; | |
314 | } | |
5f334c5b | 315 | cmd->pk_unit = UNIT(bp->b_dev)&UMASK; |
03d12a3f | 316 | cmd->pk_sw = 0; |
c3963d4e | 317 | cmd->pk_chksum = |
ecb04cd7 HS |
318 | tuchk(*((short *)cmd), (u_short *)&cmd->pk_op, (int)cmd->pk_mcount); |
319 | uuc->tu_wbptr = (u_char *)cmd; | |
320 | uuc->tu_wcnt = sizeof (*cmd); | |
03d12a3f | 321 | uuxintr(ctlr); |
2a6e4a22 HS |
322 | } |
323 | ||
324 | /* | |
5f334c5b HS |
325 | * TU58 receiver interrupt, handles whatever condition the |
326 | * pseudo DMA routine in locore is unable to handle, | |
327 | * or, if UUDMA is undefined, handle all receiver interrupt | |
328 | * processing. | |
2a6e4a22 | 329 | */ |
03d12a3f HS |
330 | uurintr(ctlr) |
331 | int ctlr; | |
2a6e4a22 | 332 | { |
fc231bc6 | 333 | struct uba_device *ui = uudinfo[ctlr]; |
a73ada79 | 334 | register struct uu_softc *uuc = &uu_softc[ctlr]; |
fc231bc6 HS |
335 | register struct uudevice *uuaddr = (struct uudevice *)ui->ui_addr; |
336 | register struct buf *uutab = &uitab[ctlr]; | |
03d12a3f | 337 | struct packet *data, *cmd; |
ecb04cd7 HS |
338 | struct buf *bp; |
339 | int c, unit; | |
03d12a3f | 340 | |
fc231bc6 | 341 | c = uuaddr->rdb; |
ecb04cd7 | 342 | data = &uudata[ctlr]; |
a73ada79 HS |
343 | cmd = &uucmd[ctlr]; |
344 | #if !defined(UUDMA) | |
345 | if (c & UURDB_ERROR) | |
346 | uuc->tu_state = TUS_RCVERR; | |
347 | else { | |
348 | if (uuc->tu_rcnt) { | |
349 | *uuc->tu_rbptr++ = c; | |
350 | if (--uuc->tu_rcnt) | |
351 | return; | |
352 | } | |
353 | } | |
354 | #endif | |
355 | ||
356 | /* | |
357 | * Switch on the tu_state of the transfer. | |
358 | */ | |
359 | switch(uuc->tu_state) { | |
360 | ||
361 | /* | |
362 | * A data error occured in uudma | |
363 | * (either overrun or break) | |
364 | */ | |
365 | case TUS_RCVERR: | |
b1084c70 HS |
366 | if ((c & UURDB_ORUN) == 0) |
367 | printf("uu%d: break received, transfer restarted\n", | |
401769ad | 368 | data->pk_unit); |
5f334c5b HS |
369 | #ifdef UUDEBUG |
370 | else | |
371 | printf("uu%d: data overrun, recovered\n", | |
372 | data->pk_unit); | |
373 | #endif | |
b1084c70 | 374 | uuc->tu_serrs++; |
a73ada79 HS |
375 | uu_restart(ctlr, ui); |
376 | break; | |
2a6e4a22 HS |
377 | |
378 | /* | |
379 | * If we get an unexpected "continue", | |
380 | * start all over again... | |
381 | */ | |
ecb04cd7 HS |
382 | case TUS_INIT2: |
383 | uuc->tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1; | |
384 | uuc->tu_flag = 0; | |
03d12a3f | 385 | wakeup((caddr_t)uuc); |
fc231bc6 | 386 | uustart(ui); |
2a6e4a22 HS |
387 | break; |
388 | ||
389 | /* | |
390 | * Only transition from this state | |
391 | * is on a "continue", so if we don't | |
392 | * get it, reset the world. | |
393 | */ | |
ecb04cd7 | 394 | case TUS_WAIT: /* waiting for continue */ |
03d12a3f HS |
395 | switch(c) { |
396 | case TUF_CONT: /* got the expected continue */ | |
ecb04cd7 | 397 | uuc->tu_flag = 0; |
03d12a3f | 398 | data->pk_flag = TUF_DATA; |
ecb04cd7 | 399 | data->pk_mcount = MIN(128, uuc->tu_count); |
03d12a3f | 400 | data->pk_chksum = |
ecb04cd7 | 401 | tuchk(*((short *)data), (caddr_t)uuc->tu_addr, |
03d12a3f | 402 | (int)data->pk_mcount); |
ecb04cd7 HS |
403 | uuc->tu_state = TUS_SENDH; |
404 | uuc->tu_wbptr = (u_char *)data; | |
405 | uuc->tu_wcnt = 2; | |
fc231bc6 | 406 | uuxintr(ctlr); |
03d12a3f HS |
407 | break; |
408 | ||
409 | case TUF_CMD: /* sending us an END packet...error */ | |
ecb04cd7 HS |
410 | uuc->tu_state = TUS_GET; |
411 | uuc->tu_rbptr = (u_char *)data; | |
a73ada79 | 412 | uuc->tu_rcnt = sizeof (*data) - 1; |
ecb04cd7 | 413 | uuc->tu_flag = 1; |
03d12a3f | 414 | uuaddr->tcs = 0; |
a73ada79 HS |
415 | *uuc->tu_rbptr++ = c & UUDB_DMASK; |
416 | break; | |
03d12a3f HS |
417 | |
418 | case TUF_INITF: | |
fc231bc6 | 419 | uureset(ctlr); |
03d12a3f HS |
420 | break; |
421 | ||
422 | default: /* something random...bad news */ | |
ecb04cd7 | 423 | uuc->tu_state = TUS_INIT1; |
2a6e4a22 HS |
424 | break; |
425 | } | |
2a6e4a22 HS |
426 | break; |
427 | ||
ecb04cd7 HS |
428 | case TUS_SENDW: |
429 | if (c != TUF_CONT && c != TUF_INITF) | |
2a6e4a22 | 430 | goto bad; |
a73ada79 | 431 | uu_restart(ctlr, ui); |
2a6e4a22 HS |
432 | break; |
433 | ||
434 | /* | |
435 | * Got header, now get data; amount to | |
c3963d4e | 436 | * fetch is included in packet. |
a73ada79 HS |
437 | * (data packets are handled entirely |
438 | * in uudma) | |
2a6e4a22 | 439 | */ |
ecb04cd7 | 440 | case TUS_GETH: |
b1084c70 HS |
441 | #ifndef UUDMA |
442 | if (data->pk_flag == TUF_DATA) | |
443 | uuc->tu_rbptr = (u_char *)uuc->tu_addr; | |
444 | #endif | |
ecb04cd7 HS |
445 | uuc->tu_rcnt = data->pk_mcount; |
446 | uuc->tu_state = TUS_GETD; | |
2a6e4a22 HS |
447 | break; |
448 | ||
449 | /* | |
450 | * Got the data, now fetch the checksum. | |
451 | */ | |
ecb04cd7 HS |
452 | case TUS_GETD: |
453 | uuc->tu_rbptr = (u_char *)&data->pk_chksum; | |
454 | uuc->tu_rcnt = sizeof (data->pk_chksum); | |
455 | uuc->tu_state = TUS_GETC; | |
2a6e4a22 HS |
456 | break; |
457 | ||
ecb04cd7 | 458 | case TUS_GETC: |
2a6e4a22 | 459 | /* got entire packet */ |
03d12a3f | 460 | if (data->pk_chksum != |
ecb04cd7 | 461 | tuchk(*((short *)data), (u_short *) |
a73ada79 | 462 | (data->pk_flag == TUF_DATA ? |
b1084c70 | 463 | (u_short *) uuc->tu_addr : (u_short *)&data->pk_op), |
03d12a3f | 464 | (int)data->pk_mcount)) |
a73ada79 | 465 | case TUS_CHKERR: |
ecb04cd7 | 466 | uuc->tu_cerrs++; |
a73ada79 | 467 | case TUS_GET: |
03d12a3f | 468 | if (data->pk_flag == TUF_DATA) { |
2a6e4a22 | 469 | /* data packet, advance to next */ |
ecb04cd7 HS |
470 | uuc->tu_addr += data->pk_mcount; |
471 | uuc->tu_count -= data->pk_mcount; | |
472 | uuc->tu_state = TUS_GETH; | |
473 | uuc->tu_rbptr = (u_char *)data; /* next packet */ | |
474 | uuc->tu_rcnt = 2; | |
03d12a3f | 475 | } else if (data->pk_flag==TUF_CMD && data->pk_op==TUOP_END) { |
2a6e4a22 | 476 | /* end packet, idle and reenable transmitter */ |
ecb04cd7 HS |
477 | uuc->tu_state = TUS_IDLE; |
478 | uuc->tu_flag = 0; | |
479 | uuaddr->tcs = UUCS_INTR; | |
480 | if ((bp = uutab->b_actf) == NULL) { | |
b1084c70 | 481 | printf("uu%d: no bp, active %d\n", |
401769ad | 482 | data->pk_unit, uitab[ctlr].b_active); |
fc231bc6 | 483 | uustart(ui); |
2a6e4a22 HS |
484 | return; |
485 | } | |
5f334c5b | 486 | unit = UNIT(bp->b_dev); |
03d12a3f | 487 | if (data->pk_mod > 1) { /* hard error */ |
a73ada79 | 488 | printf("uu%d: hard error bn%d,", unit, |
401769ad | 489 | bp->b_blkno); |
5f334c5b | 490 | printf(" pk_mod 0%o\n", data->pk_mod&0xff); |
2a6e4a22 | 491 | bp->b_flags |= B_ERROR; |
ecb04cd7 | 492 | uuc->tu_herrs++; |
5f334c5b | 493 | } else if (data->pk_mod) /* soft error */ |
ecb04cd7 | 494 | uuc->tu_serrs++; |
03d12a3f | 495 | uutab->b_active = NULL; |
5f334c5b | 496 | uutab->b_actf = bp->b_actf; |
ecb04cd7 | 497 | bp->b_resid = uuc->tu_count; |
2a6e4a22 | 498 | if ((bp->b_flags&B_READ) == 0) |
5f334c5b | 499 | tu_vee(&uu_pcnt[unit]); |
2a6e4a22 | 500 | iodone(bp); |
fc231bc6 | 501 | uustart(ui); |
2a6e4a22 | 502 | } else { |
b1084c70 HS |
503 | /* |
504 | * Neither data nor end: data was lost | |
5f334c5b | 505 | * somehow, flush and restart the transfer. |
b1084c70 | 506 | */ |
5f334c5b | 507 | uuaddr->rcs = 0; |
a73ada79 | 508 | uu_restart(ctlr, ui); |
b1084c70 | 509 | uuc->tu_serrs++; |
2a6e4a22 HS |
510 | } |
511 | break; | |
512 | ||
ecb04cd7 HS |
513 | case TUS_IDLE: |
514 | case TUS_INIT1: | |
2a6e4a22 HS |
515 | break; |
516 | ||
517 | default: | |
518 | bad: | |
519 | if (c == TUF_INITF) { | |
b1084c70 | 520 | printf("uu%d protocol error, state=", data->pk_unit); |
ecb04cd7 | 521 | printstate(uuc->tu_state); |
2a6e4a22 | 522 | printf(", op=%x, cnt=%d, block=%d\n", |
03d12a3f HS |
523 | cmd->pk_op, cmd->pk_count, cmd->pk_block); |
524 | uutab->b_active = NULL; | |
525 | if (bp = uutab->b_actf) { | |
2a6e4a22 | 526 | bp->b_flags |= B_ERROR; |
5f334c5b | 527 | uutab->b_actf = bp->b_actf; |
2a6e4a22 | 528 | if ((bp->b_flags&B_READ) == 0) |
5f334c5b | 529 | tu_vee(&uu_pcnt[unit]); |
2a6e4a22 HS |
530 | iodone(bp); |
531 | } | |
ecb04cd7 | 532 | uuc->tu_state = TUS_INIT1; |
2a6e4a22 | 533 | } else { |
03d12a3f | 534 | printf("uu%d receive state error, state=", |
b1084c70 | 535 | data->pk_unit); |
ecb04cd7 | 536 | printstate(uuc->tu_state); |
a73ada79 | 537 | printf(", byte=%x\n", c & 0xff); |
2a6e4a22 | 538 | #ifdef notdef |
ecb04cd7 | 539 | uuc->tu_state = TUS_INIT1; |
2a6e4a22 | 540 | #endif |
03d12a3f | 541 | wakeup((caddr_t)uuc); |
2a6e4a22 HS |
542 | } |
543 | } | |
544 | } | |
545 | ||
ecb04cd7 | 546 | |
2a6e4a22 HS |
547 | /* |
548 | * TU58 transmitter interrupt | |
549 | */ | |
03d12a3f HS |
550 | uuxintr(ctlr) |
551 | int ctlr; | |
2a6e4a22 | 552 | { |
a73ada79 | 553 | register struct uu_softc *uuc = &uu_softc[ctlr]; |
fc231bc6 | 554 | register struct uudevice *uuaddr; |
03d12a3f | 555 | register struct packet *data; |
fc231bc6 | 556 | struct uba_device *ui = uudinfo[ctlr]; |
03d12a3f | 557 | int c; |
2a6e4a22 | 558 | |
fc231bc6 HS |
559 | data = &uudata[ctlr]; |
560 | uuaddr = (struct uudevice *) ui->ui_addr; | |
2a6e4a22 | 561 | top: |
5f334c5b | 562 | if (uuc->tu_wcnt > 0) { |
2a6e4a22 | 563 | /* still stuff to send, send one byte */ |
03d12a3f | 564 | while ((uuaddr->tcs & UUCS_READY) == 0) |
2a6e4a22 | 565 | ; |
ecb04cd7 HS |
566 | uuaddr->tdb = *uuc->tu_wbptr++; |
567 | uuc->tu_wcnt--; | |
2a6e4a22 HS |
568 | return; |
569 | } | |
570 | ||
571 | /* | |
572 | * Last message byte was sent out. | |
ecb04cd7 | 573 | * Switch on tu_state of transfer. |
2a6e4a22 | 574 | */ |
ecb04cd7 | 575 | switch(uuc->tu_state) { |
2a6e4a22 HS |
576 | |
577 | /* | |
578 | * Two nulls have been sent, remove break, and send inits | |
579 | */ | |
ecb04cd7 | 580 | case TUS_INIT1: |
5f334c5b | 581 | uuc->tu_flag = 0; |
03d12a3f | 582 | uuaddr->tcs = UUCS_INTR; |
ecb04cd7 HS |
583 | uuc->tu_state = TUS_INIT2; |
584 | uuc->tu_wbptr = uuinit; | |
585 | uuc->tu_wcnt = sizeof (uuinit); | |
2a6e4a22 HS |
586 | goto top; |
587 | ||
588 | /* | |
589 | * Inits have been sent, wait for a continue msg. | |
590 | */ | |
ecb04cd7 | 591 | case TUS_INIT2: |
fc231bc6 | 592 | c = uuaddr->rdb; /* prevent overrun error */ |
03d12a3f | 593 | uuaddr->rcs = UUCS_INTR; |
ecb04cd7 | 594 | uuc->tu_flag = 1; |
2a6e4a22 HS |
595 | break; |
596 | ||
2a6e4a22 HS |
597 | /* |
598 | * Read cmd packet sent, get ready for data | |
599 | */ | |
ecb04cd7 HS |
600 | case TUS_SENDR: |
601 | uuc->tu_state = TUS_GETH; | |
602 | uuc->tu_rbptr = (u_char *)data; | |
603 | uuc->tu_rcnt = 2; | |
604 | uuc->tu_flag = 1; | |
5f334c5b | 605 | uuaddr->tcs = 0; |
ecb04cd7 | 606 | uuaddr->rcs = UUCS_INTR; |
2a6e4a22 HS |
607 | break; |
608 | ||
609 | /* | |
610 | * Write cmd packet sent, wait for continue | |
611 | */ | |
ecb04cd7 HS |
612 | case TUS_SENDW: |
613 | uuc->tu_state = TUS_WAIT; | |
614 | uuc->tu_flag = 1; | |
03d12a3f | 615 | if ((uuaddr->rcs&UUCS_INTR) == 0) { |
2a6e4a22 | 616 | printf("NO IE\n"); |
03d12a3f | 617 | uuaddr->rcs = UUCS_INTR; |
2a6e4a22 HS |
618 | } |
619 | break; | |
620 | ||
621 | /* | |
622 | * Header sent, send data. | |
623 | */ | |
ecb04cd7 HS |
624 | case TUS_SENDH: |
625 | uuc->tu_state = TUS_SENDD; | |
626 | uuc->tu_wbptr = (u_char *)uuc->tu_addr; | |
627 | uuc->tu_wcnt = data->pk_mcount; | |
2a6e4a22 HS |
628 | goto top; |
629 | ||
630 | /* | |
631 | * Data sent, follow with checksum. | |
632 | */ | |
ecb04cd7 HS |
633 | case TUS_SENDD: |
634 | uuc->tu_state = TUS_SENDC; | |
635 | uuc->tu_wbptr = (u_char *)&data->pk_chksum; | |
5f334c5b | 636 | uuc->tu_wcnt = 2; |
2a6e4a22 HS |
637 | goto top; |
638 | ||
639 | /* | |
640 | * Checksum sent, wait for continue. | |
641 | */ | |
ecb04cd7 | 642 | case TUS_SENDC: |
2a6e4a22 | 643 | /* |
ecb04cd7 | 644 | * Update buffer address and count. |
2a6e4a22 | 645 | */ |
ecb04cd7 HS |
646 | uuc->tu_addr += data->pk_mcount; |
647 | uuc->tu_count -= data->pk_mcount; | |
5f334c5b | 648 | if (uuc->tu_count > 0) { |
ecb04cd7 HS |
649 | uuc->tu_state = TUS_WAIT; |
650 | uuc->tu_flag = 1; | |
2a6e4a22 HS |
651 | break; |
652 | } | |
653 | ||
654 | /* | |
655 | * End of transmission, get ready for end packet. | |
656 | */ | |
ecb04cd7 HS |
657 | uuc->tu_state = TUS_GET; |
658 | uuc->tu_rbptr = (u_char *)data; | |
659 | uuc->tu_rcnt = sizeof (*data); | |
660 | uuc->tu_flag = 1; | |
5f334c5b | 661 | uuaddr->tcs = 0; |
2a6e4a22 HS |
662 | break; |
663 | ||
664 | /* | |
03d12a3f | 665 | * Random interrupt |
2a6e4a22 | 666 | */ |
b1084c70 HS |
667 | case TUS_IDLE: /* stray interrupt? */ |
668 | ||
2a6e4a22 HS |
669 | default: |
670 | break; | |
671 | } | |
ecb04cd7 HS |
672 | } |
673 | ||
674 | uuwatch() | |
675 | { | |
a73ada79 | 676 | register struct uu_softc *uuc; |
ecb04cd7 HS |
677 | register struct uudevice *uuaddr; |
678 | struct uba_device *ui; | |
679 | struct buf *bp, *uutab; | |
680 | int s, ctlr, active = 0; | |
681 | ||
682 | for (ctlr=0; ctlr<NUU; ctlr++) { | |
683 | int i; | |
684 | ||
685 | uuc = &uu_softc[ctlr]; | |
5f334c5b HS |
686 | |
687 | if (uuc->tu_dopen[0] || uuc->tu_dopen[1]) | |
688 | active++; | |
689 | if (uuc->tu_flag == 0) | |
b1084c70 | 690 | /* |
5f334c5b HS |
691 | * If no read is in progress |
692 | * just skip | |
b1084c70 | 693 | */ |
ecb04cd7 | 694 | continue; |
5f334c5b HS |
695 | |
696 | ui = uudinfo[ctlr]; | |
697 | uuaddr = (struct uudevice *)ui->ui_addr; | |
698 | uutab = &uitab[ctlr]; | |
699 | if (uuc->tu_flag++ < 40) | |
ecb04cd7 | 700 | continue; |
b1084c70 | 701 | printf("uu%d: read stalled\n", uudata[ctlr].pk_unit); |
5f334c5b | 702 | #ifdef UUDEBUG |
ecb04cd7 | 703 | printf("%X %X %X %X %X %X %X\n", uuc->tu_rbptr, uuc->tu_rcnt, |
b1084c70 HS |
704 | uuc->tu_wbptr, uuc->tu_wcnt, uuc->tu_state, uuc->tu_addr, |
705 | uuc->tu_count); | |
401769ad | 706 | #endif |
ecb04cd7 | 707 | s = splx(UUIPL); |
5f334c5b | 708 | uuc->tu_flag = 0; |
ecb04cd7 HS |
709 | i = uuaddr->rdb; /* dummy */ |
710 | uuaddr->rcs = UUCS_INTR; /* in case we were flushing */ | |
711 | uuaddr->tcs = UUCS_INTR; | |
712 | uuc->tu_state = TUS_IDLE; | |
713 | if (!uutab->b_active) { | |
714 | wakeup((caddr_t)uuc); | |
715 | goto retry; | |
716 | } | |
717 | if (++uutab->b_errcnt <= 1) { | |
718 | uustart(ui); | |
719 | goto retry; | |
720 | } | |
721 | if (bp = uutab->b_actf) { | |
722 | bp->b_flags |= B_ERROR; | |
723 | if ((bp->b_flags&B_READ) == 0) | |
5f334c5b | 724 | tu_vee(&uu_pcnt[UNIT(bp->b_dev)]); |
ecb04cd7 HS |
725 | iodone(bp); |
726 | } | |
727 | retry: | |
728 | (void) splx(s); | |
2a6e4a22 | 729 | } |
ecb04cd7 HS |
730 | if (active) |
731 | timeout(uuwatch, (caddr_t)0, hz); | |
732 | else | |
733 | uuwstart = 0; | |
734 | return; | |
2a6e4a22 HS |
735 | } |
736 | ||
ecb04cd7 | 737 | #if !defined(VAX750) && !defined(VAX730) |
2a6e4a22 HS |
738 | /* |
739 | * Compute checksum TU58 fashion | |
740 | */ | |
741 | #ifdef lint | |
ecb04cd7 | 742 | tuchk(word, cp, n) |
2a6e4a22 HS |
743 | register word; |
744 | register unsigned short *cp; | |
745 | int n; | |
746 | { | |
747 | register int c = n >> 1; | |
748 | register long temp; | |
749 | ||
750 | do { | |
751 | temp = *cp++; /* temp, only because vax cc won't *r++ */ | |
752 | word += temp; | |
753 | } while (--c > 0); | |
754 | if (n & 1) | |
755 | word += *(unsigned char *)cp; | |
756 | while (word & 0xffff0000) | |
757 | word = (word & 0xffff) + ((word >> 16) & 0xffff); | |
758 | return (word); | |
759 | } | |
760 | #else | |
ecb04cd7 | 761 | tuchk(word0, wp, n) |
c3963d4e HS |
762 | register int word0; /* r11 */ |
763 | register char *wp; /* r10 */ | |
764 | register int n; /* r9 */ | |
2a6e4a22 HS |
765 | { |
766 | asm("loop:"); | |
c3963d4e HS |
767 | asm(" addw2 (r10)+,r11"); /* add a word to sum */ |
768 | asm(" adwc $0,r11"); /* add in carry, end-around */ | |
2a6e4a22 | 769 | asm(" acbl $2,$-2,r9,loop"); /* done yet? */ |
c3963d4e HS |
770 | asm(" blbc r9,ok"); /* odd byte count? */ |
771 | asm(" movzbw (r10),r10"); /* yes, get last byte */ | |
772 | asm(" addw2 r10,r11"); /* add it in */ | |
773 | asm(" adwc $0,r11"); /* and the carry */ | |
2a6e4a22 | 774 | asm("ok:"); |
c3963d4e | 775 | asm(" movl r11,r0"); /* return sum */ |
2a6e4a22 HS |
776 | } |
777 | #endif | |
778 | ||
5f334c5b HS |
779 | /* |
780 | * Make sure this incredibly slow device | |
781 | * doesn't eat up all the buffers in the | |
782 | * system by putting the requesting process | |
783 | * (remember: this device is 'single-user') | |
784 | * to sleep if the write-behind queue grows | |
785 | * larger than NUUQ. | |
786 | */ | |
ecb04cd7 | 787 | tu_pee(cp) |
5f334c5b | 788 | char *cp; |
03d12a3f HS |
789 | { |
790 | register int s; | |
791 | ||
fc231bc6 | 792 | s = splx(UUIPL); |
5f334c5b | 793 | if (++(*cp) > NUUQ) |
03d12a3f | 794 | sleep(cp, PRIBIO); |
03d12a3f HS |
795 | splx(s); |
796 | } | |
797 | ||
ecb04cd7 | 798 | tu_vee(cp) |
5f334c5b | 799 | char *cp; |
03d12a3f HS |
800 | { |
801 | register int s; | |
802 | ||
fc231bc6 | 803 | s = splx(UUIPL); |
5f334c5b | 804 | if (--(*cp) <= NUUQ) |
03d12a3f | 805 | wakeup(cp); |
2a6e4a22 | 806 | splx(s); |
2a6e4a22 HS |
807 | } |
808 | #endif | |
03d12a3f | 809 | |
ecb04cd7 HS |
810 | uuioctl(dev, cmd, data, flag) |
811 | dev_t dev; | |
812 | caddr_t data; | |
813 | { | |
814 | /* | |
b1084c70 | 815 | * add code to wind/rewind cassette here |
ecb04cd7 HS |
816 | */ |
817 | return (ENXIO); | |
818 | } | |
819 | ||
a73ada79 HS |
820 | uu_restart(ctlr, ui) |
821 | int ctlr; | |
822 | struct uba_device *ui; | |
823 | { | |
824 | uureset(ctlr); | |
825 | timeout(uustart, (caddr_t)ui, hz * 3); | |
826 | } | |
5f334c5b HS |
827 | |
828 | #endif |