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