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