Commit | Line | Data |
---|---|---|
586a8972 MK |
1 | /* |
2 | * Datakit driver | |
3 | * DR11C version without KMC | |
4 | * | |
5 | * uses mbufs for transmission | |
6 | * | |
7 | * SCCSID[] = "@(#)dkit_dr.c 1.5 Garage 84/04/11" | |
8 | */ | |
9 | ||
10 | #include "dkitdr.h" | |
11 | #if NDKITDR>0 | |
12 | #include "datakit.h" | |
13 | ||
b28b3a13 KB |
14 | #include "../include/pte.h" |
15 | #include "sys/param.h" | |
16 | #include "sys/time.h" | |
17 | #include "sys/kernel.h" | |
18 | #include "sys/buf.h" | |
19 | #include "sys/mbuf.h" | |
20 | #include "sys/errno.h" | |
21 | #include "sys/socket.h" | |
22 | #include "sys/syslog.h" | |
23 | #include "net/if.h" | |
24 | #include "../uba/ubareg.h" | |
25 | #include "../uba/ubavar.h" | |
586a8972 MK |
26 | |
27 | #include "dk.h" | |
28 | #include "dkit.h" | |
29 | #include "dkdr.h" | |
30 | ||
31 | ||
32 | #define PKBHOG 64 /* max temp buffers per channel */ | |
33 | #define DKNPKB (200+4*NDATAKIT) | |
34 | #define DKNSTB 10 | |
35 | ||
36 | struct dkchan dkit[NDATAKIT]; | |
37 | extern int dk_nchan; | |
38 | ||
39 | int dkdr_npk = DKNPKB; | |
40 | struct dkpkbufr dk_pkbuf[DKNPKB]; | |
41 | ||
42 | int dkdr_nstat = DKNSTB; | |
43 | struct dkstat dkdr_stat[DKNSTB]; | |
44 | ||
45 | int dkattached = 0; /* Is it really there? */ | |
46 | ||
47 | #ifdef KALYPSO | |
48 | #define URPDEBUG 5000 | |
49 | #else | |
50 | #define URPDEBUG 500 | |
51 | #endif | |
52 | ||
53 | #ifdef URPDEBUG | |
54 | int dkurpdebug = 0; | |
55 | #define URPTRACE(chan, chr, Dkp) if (dkurpdebug == (chan)) \ | |
56 | dkurptrace(chr, Dkp); | |
57 | #endif | |
58 | ||
59 | /* | |
60 | * structure of data in first mbuf on chain (type DKM_HDR) | |
61 | * | |
62 | */ | |
63 | struct mpacket { | |
64 | short mp_len; /* Total length left */ | |
65 | char mp_ctl; /* Control character */ | |
66 | int mp_eob; /* Send end-of-block indicator */ | |
67 | int (*mp_endfcn)(); /* End-action function */ | |
68 | caddr_t mp_endparm; /* Parameter to above function */ | |
69 | }; | |
70 | ||
71 | /* | |
72 | * dr11-c bit definitions | |
73 | */ | |
74 | #define DKTENAB 0100 /* transmit interrupt enable */ | |
75 | #define DKRENAB 040 /* receiver interrupt enable */ | |
76 | #define ENABS 0140 /* both enables */ | |
77 | #define DKCOM 03 /* dr11-c command bits */ | |
78 | #define DKTDONE 0200 /* transmit done bit */ | |
79 | #define DKRDONE 0100000 /* receiver done bit */ | |
80 | #define DKMARK 01000 /* start of packet bit */ | |
81 | #define DKOVF 040000 /* receiver overflow bit (in drin) */ | |
82 | #define DKDATA 0400 /* bit 9 ... indicates non-control */ | |
83 | ||
84 | #define DKCHUNK 16 /* packet size */ | |
85 | ||
86 | /* | |
87 | * dr11c commands | |
88 | */ | |
89 | #define D_OSEQ 0 | |
90 | #define D_READ 1 | |
91 | #define D_WRITE 2 | |
92 | #define D_XPACK 3 | |
93 | ||
94 | /* | |
95 | * error control protocol definitions | |
96 | */ | |
97 | #define SEQ 0010 /* 8 sequence numbers to end trailers */ | |
98 | #define ECHO 0020 /* 8 echoes, data given to host */ | |
99 | #define REJ 0030 /* 8 rejections, transmission error */ | |
100 | #define ACK 0040 /* first of 8 acks, correct reception */ | |
101 | #define BOT 0050 /* normal beginning of trailer */ | |
102 | #define BOTM 0051 /* trailer with more data to follow */ | |
103 | #define BOTS 0052 /* seq update algorithm on this trailer */ | |
104 | #define SOI 0053 /* start of interrupt trailer */ | |
105 | #define EOI 0054 /* end of interrupt trailer */ | |
106 | #define ENQ 0055 /* xmitter request flow/error status */ | |
107 | #define CHECK 0056 /* xmitter request error status */ | |
108 | #define INITREQ 0057 /* request initialization */ | |
109 | #define INIT0 0060 /* disable trailer processing */ | |
110 | #define INIT1 0061 /* enable trailer processing */ | |
111 | #define AINIT 0062 /* response to INIT0/INIT1 */ | |
112 | ||
113 | #define DKBMASK 03 /* this xmitter has window size of 4, */ | |
114 | /* #define DKBLOCK 60 /* each message is 60 bytes */ | |
115 | #define DKBLOCK 28 /* each message is 60 bytes */ | |
116 | ||
117 | ||
118 | /* | |
119 | * some commonly used macros | |
120 | */ | |
121 | ||
122 | ||
123 | ||
124 | struct dkpkbufr *dk_Sfree; | |
125 | extern int dkdr_npk; | |
126 | extern struct dkpkbufr dk_pkbuf[]; | |
127 | ||
128 | int dknopkb = 1 ; /* Counter for 'no dkpkbufr' condition. */ | |
129 | int dkstray; /* number of stray interrupts since last timeout */ | |
130 | int dkdrlostint; /* Number of lost receiver interrupts */ | |
131 | int dkdisabled; /* flag to indicate that DK interface has been disabled | |
132 | due to stray interrupts, etc. */ | |
133 | #define MAX_STRAY 10 /* maximum number of stray interrupts | |
134 | before temporarily disabling DK interrupts */ | |
135 | ||
136 | /* | |
137 | * dr11c device registers | |
138 | */ | |
139 | struct rdevice { | |
140 | short dkcsr; | |
141 | short dko; | |
142 | short dki; | |
143 | }; | |
144 | ||
145 | extern int dkdr_nstat; | |
146 | extern struct dkstat dkdr_stat[]; | |
147 | ||
148 | static char Hstat, Tstat; | |
149 | ||
150 | #define DKADDR ((struct rdevice *) dkitdrdinfo[0]->ui_addr) | |
151 | ||
152 | ||
153 | /* | |
154 | * Intermediate level command codes | |
155 | */ | |
156 | #define KS_SEND 20 | |
157 | #define KS_RDB 21 | |
158 | #define KS_EOI 22 | |
159 | #define KS_CNTL 23 | |
160 | #define KS_ERR 24 | |
161 | ||
162 | ||
163 | ||
164 | int dkdebug = 512 ; | |
165 | int dkactive ; | |
166 | ||
167 | static int timeron; | |
168 | ||
169 | ||
170 | int dkitdrprobe(), dkitdrattach(); | |
171 | struct uba_device *dkitdrdinfo[1]; | |
172 | u_short dkitdrstd[] = { 0 }; | |
173 | struct uba_driver dkitdrdriver = | |
174 | { dkitdrprobe, 0, dkitdrattach, 0, dkitdrstd, "dkitdr", dkitdrdinfo }; | |
175 | ||
176 | dkitdrprobe(reg) | |
177 | caddr_t reg; | |
178 | { | |
179 | register int br, cvec; /* value-result */ | |
180 | register struct rdevice *draddr = (struct rdevice *) reg; | |
181 | register int i, c; | |
182 | ||
183 | #ifdef lint | |
184 | br = 0; cvec = br; br = cvec; | |
185 | dkdrrint(0); dkdrxint(0); | |
186 | #endif | |
187 | draddr->dkcsr = D_READ; | |
188 | for (i = 0; i < 1024; i++) | |
189 | if (draddr->dkcsr & DKRDONE) c = draddr->dki; | |
190 | else break; | |
191 | #ifdef lint | |
192 | c = c; | |
193 | #endif | |
194 | draddr->dkcsr = D_WRITE; | |
195 | draddr->dko = DKMARK | (dk_nchan-1); /* pack on 511 */ | |
196 | draddr->dkcsr = D_XPACK + DKTENAB; | |
197 | draddr->dko = 0; | |
198 | DELAY(10000); | |
199 | draddr->dkcsr = 0; | |
200 | return(sizeof(struct rdevice)); | |
201 | } | |
202 | ||
203 | /*ARGSUSED*/ | |
204 | dkitdrattach(ui) | |
205 | struct uba_device *ui; | |
206 | { | |
207 | dkattached = 1; | |
208 | ||
209 | #if defined(INET) && NDKI>0 | |
210 | dkiattach(); | |
211 | #endif | |
212 | } | |
213 | ||
214 | ||
215 | static | |
216 | dk_init() | |
217 | { | |
218 | register struct rdevice *raddr = DKADDR; | |
219 | register s ; | |
220 | /* | |
221 | * At attach time for the hardware device | |
222 | * initialize and check things out to the | |
223 | * (grumble) limited extent that is possible. | |
224 | */ | |
225 | ||
226 | s = spl5() ; | |
227 | Hstat = Tstat = 0 ; | |
228 | dkdisabled = 0; | |
229 | dkstray = 0; | |
230 | { | |
231 | register struct dkchan *dkp ; | |
232 | ||
233 | for (dkp = &dkit[0]; dkp < &dkit[dk_nchan]; dkp++) { | |
234 | dkp->dk_rlen = 0 ; | |
235 | dkp->dk_xlen = 0 ; | |
236 | dkp->dk_X = XM_OFF; | |
237 | dkp->dk_rq = NULL ; | |
238 | dkp->dk_outq.ifq_len = 0; | |
239 | dkp->dk_outq.ifq_maxlen = 20; | |
240 | dkp->dk_outq.ifq_drops = 0; | |
241 | dkp->dk_outq.ifq_head = NULL; | |
242 | dkp->dk_outq.ifq_tail = NULL; | |
243 | } | |
244 | } { register struct dkpkbufr *pkb ; | |
245 | ||
246 | for (pkb = &dk_pkbuf[1]; pkb < &dk_pkbuf[dkdr_npk-1]; pkb++) { | |
247 | pkb->Pnext = pkb + 1 ; | |
248 | } | |
249 | dk_pkbuf[dkdr_npk-1].Pnext = NULL ; | |
250 | dk_Sfree = &dk_pkbuf[1] ; | |
251 | dk_pkbuf[0].Pnext = NULL ; | |
252 | } { | |
253 | register int seq, i, c ; | |
254 | ||
255 | raddr->dkcsr = D_OSEQ ; | |
256 | raddr->dko = 0 ; /* clears all FIFO's */ | |
257 | seq = 0 ; | |
258 | while (raddr->dkcsr & DKTDONE) { | |
259 | seq += (((raddr->dki)>>10) & 017) + 2 ; | |
260 | if (seq > 100) { | |
261 | dkreport(KS_ERR, 0, 1, 0, 1) ; | |
262 | splx(s) ; | |
263 | return -EIO ; | |
264 | } | |
265 | } | |
266 | raddr->dkcsr = D_READ; | |
267 | for (i = 0; i < 1024; i++) | |
268 | if (raddr->dkcsr & DKRDONE) c = raddr->dki; | |
269 | else break; | |
270 | #ifdef lint | |
271 | c = c; | |
272 | #endif | |
273 | } | |
274 | raddr->dkcsr = ENABS ; | |
275 | if(!timeron){ | |
276 | dk_timeout(); | |
277 | timeron++; | |
278 | } | |
279 | ||
280 | splx(s) ; | |
281 | dkactive = 1 ; | |
282 | ||
283 | ||
284 | return 0 ; | |
285 | } | |
286 | ||
287 | /*ARGSUSED*/ | |
288 | dkitreset(uban) | |
289 | int uban; | |
290 | { | |
291 | register struct rdevice *raddr ; | |
292 | ||
293 | raddr = DKADDR; | |
294 | raddr->dkcsr = ENABS; | |
295 | log(LOG_ERR, " dkit_dr%d", 0); | |
296 | } | |
297 | ||
298 | dk_open(chan, supfcn) | |
299 | register chan ; | |
300 | int (*supfcn)() ; | |
301 | { | |
302 | register struct dkchan *dkp; | |
303 | register s ; | |
304 | extern dkkint() ; | |
305 | static firsttime = 1; | |
306 | static init; | |
307 | extern int commchan; | |
308 | ||
309 | if (chan >= dk_nchan || !dkattached) | |
310 | return -ENXIO ; | |
311 | if (firsttime) { | |
312 | if ((init = dk_init()) < 0) return init; | |
313 | firsttime = 0; | |
314 | } | |
315 | dkp = &dkit[chan] ; | |
316 | s = spl5() ; | |
317 | /* | |
318 | * Channel 0 (0-3 in ISN) is reserved for maintenance. | |
319 | * An open on channel 0 is interpreted as a request | |
320 | * for an unused channel. Channel 1 (4 in ISN or RADIAN) | |
321 | * is the common supervisory channel. | |
322 | */ | |
323 | if (chan == 0) { | |
324 | chan = commchan+1 ; /* Start above commchan */ | |
325 | while (1) { | |
326 | dkp = &dkit[chan] ; | |
327 | if (dkp->dk_state == 0) | |
328 | break ; | |
329 | chan++ ; | |
330 | if (chan >= dk_nchan) { | |
331 | splx(s) ; | |
332 | return -EADDRNOTAVAIL ; | |
333 | } | |
334 | } | |
335 | } | |
336 | ||
337 | ||
338 | /* | |
339 | * Finish setting up dkp struct. | |
340 | */ | |
341 | if ((dkp->dk_state & DK_OPEN) ==0) { | |
342 | if (chan > dkdebug) | |
343 | log(LOG_ERR, "dkopen %d: %x\n", chan, supfcn) ; | |
344 | dkp->dk_S = 1 ; | |
345 | dkp->dk_R = 0 ; | |
346 | dkp->dk_X = 0 ; | |
347 | dkp->dk_A = 0 ; | |
348 | dkp->dk_rejcnt = 0; | |
349 | dkp->dk_srejcnt = 0; | |
350 | dkp->dk_ackrejcnt = 0; | |
351 | dkp->dk_enqcnt = 0; | |
352 | dksend(chan, INIT1) ; | |
353 | flushall(dkp, 0); | |
354 | dkp->dk_state &= ~DK_LINGR ; | |
355 | dkp->dk_state |= DK_OPEN; | |
356 | } | |
357 | dkp->dk_supfcn = supfcn ; | |
358 | splx(s) ; | |
359 | return chan ; | |
360 | } | |
361 | ||
362 | ||
363 | /* | |
364 | * Close a channel: | |
365 | */ | |
366 | ||
367 | dk_close(chan) | |
368 | { | |
369 | register struct dkchan *dkp; | |
370 | register s ; | |
371 | ||
372 | s = spl5() ; | |
373 | if (chan > dkdebug) | |
374 | log(LOG_ERR, "dkclose %d\n", chan) ; | |
375 | dkp = &dkit[chan] ; | |
376 | if (chan == 0) { | |
377 | if (!dkattached) return -ENXIO; | |
378 | for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) { | |
379 | if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV)) { | |
380 | dkp->dk_state |= DK_RESET ; | |
381 | flushall(dkp, 0) ; | |
382 | } | |
383 | } | |
384 | dkactive = 0 ; | |
385 | splx(s); | |
386 | return dk_init() ; | |
387 | } else { | |
388 | dkp->dk_state |= DK_OPEN ; | |
389 | flushall(dkp, 0) ; | |
390 | dkp->dk_state = DK_LINGR ; | |
391 | dkp->dk_X = XM_OFF; | |
392 | dkp->dk_trmode = 0 ; | |
393 | } | |
394 | splx(s) ; | |
395 | return 0; | |
396 | } | |
397 | ||
398 | /* | |
399 | * Close phase 2 - mark available for reassignment | |
400 | */ | |
401 | dk_free(chan) | |
402 | { | |
403 | if (chan > dkdebug) | |
404 | log(LOG_ERR, "dkfree %d\n", chan) ; | |
405 | dkit[chan].dk_state &= ~DK_LINGR ; | |
406 | } | |
407 | ||
408 | ||
409 | /* | |
410 | * Reset a channel | |
411 | * prevents further I/O until close | |
412 | */ | |
413 | dk_reset(chan) | |
414 | { | |
415 | register struct dkchan *dkp ; | |
416 | register s ; | |
417 | ||
418 | if (chan > dkdebug) | |
419 | log(LOG_ERR, "dkreset %d\n", chan) ; | |
420 | s = spl5() ; | |
421 | dkp = &dkit[chan] ; | |
422 | dkp->dk_state |= DK_RESET ; | |
423 | flushall(dkp, 0) ; | |
424 | splx(s) ; | |
425 | } | |
426 | ||
427 | ||
428 | ||
429 | /* | |
430 | * Xmit a short control (interrupt) packet | |
431 | */ | |
432 | dk_xint(chan, intr) | |
433 | { | |
434 | register struct rdevice *raddr ; | |
435 | register s ; | |
436 | register struct dkchan *dkp ; | |
437 | ||
438 | dkp = &dkit[chan] ; | |
439 | if (chan == 0 || dkp->dk_X < XM_INIT) | |
440 | return -1 ; | |
441 | s = spl5() ; | |
442 | if (chan > dkdebug) | |
443 | log(LOG_ERR, "dkxint %d: %o %o\n", chan, (intr & 0377), ((intr >>8)&0377)) ; | |
444 | raddr = DKADDR ; | |
445 | raddr->dkcsr = D_WRITE ; | |
446 | raddr->dko = chan | DKMARK ; | |
447 | raddr->dko = SOI ; | |
448 | raddr->dko = (intr & 0377) | DKDATA ; | |
449 | raddr->dko = ((intr >> 8) & 0377) | DKDATA ; | |
450 | raddr->dko = EOI ; | |
451 | raddr->dkcsr = D_XPACK ; | |
452 | raddr->dko = 0 ; | |
453 | if(dkdisabled) | |
454 | raddr->dko = 0; | |
455 | else | |
456 | raddr->dko = ENABS; | |
457 | splx(s) ; | |
458 | return 0 ; | |
459 | } | |
460 | ||
461 | ||
462 | /* | |
463 | * Adjust window size | |
464 | */ | |
465 | dk_winsize(chan, win) | |
466 | struct diocxwin win; | |
467 | { | |
468 | return EINVAL; /* For now... */ | |
469 | } | |
470 | ||
471 | ||
472 | /* | |
473 | * Xmit data on a channel | |
474 | * NOTE * * * * * | |
475 | * Although it is never checked here, buffer addresses | |
476 | * in this version of the driver must be kernel addressable. | |
477 | */ | |
478 | dk_xmit(chan, m, eob, ctlchar, endfcn, endparm) | |
479 | struct mbuf *m ; | |
480 | int (*endfcn)() ; | |
481 | caddr_t endparm ; | |
482 | { | |
483 | register struct dkchan *dkp ; | |
484 | register struct mpacket *mbp ; | |
485 | register struct mbuf *mb; | |
486 | int s ; | |
487 | ||
488 | s = spl5() ; | |
489 | dkp = &dkit[chan] ; | |
490 | if ((dkp->dk_state & DK_RESET) || (mb = m_get(M_DONTWAIT,DKMT_HDR)) == NULL) { | |
491 | m_freem(m); | |
492 | splx(s) ; | |
493 | return 0 ; | |
494 | } | |
495 | ||
496 | if (ctlchar == '\001') eob = 0; | |
497 | mb->m_len = 0; | |
498 | mbp = mtod(mb, struct mpacket *); | |
499 | mbp->mp_endfcn = endfcn ; | |
500 | mbp->mp_endparm = endparm ; | |
501 | mbp->mp_eob = eob; | |
502 | mb->m_next = m; | |
503 | ||
504 | mbp->mp_len = 0; | |
505 | while (m) { | |
506 | #ifdef notdef | |
507 | if (m->m_type != DKMT_DATA && m->m_type != DKMT_CTL) { | |
508 | log(LOG_ERR, "dk_xmit %d: got type %x\n", chan, m->m_type); | |
509 | m_freem(mb); | |
510 | return 0; | |
511 | } | |
512 | #endif | |
513 | mbp->mp_len += m->m_len; | |
514 | m = m->m_next; | |
515 | } | |
516 | ||
517 | if ((ctlchar & 0300) == 0100) { | |
518 | register struct mbuf *n = mb, *mc; | |
519 | ||
520 | mc = m_get(M_DONTWAIT, DKMT_CTL); | |
521 | if (mc == NULL) { | |
522 | m_freem(mb); | |
523 | splx(s); | |
524 | return 0; | |
525 | } | |
526 | *mtod(mc, char *) = ctlchar; | |
527 | mc->m_len = 1; | |
528 | ||
529 | /* Append it -- can't use m_cat because type field counts */ | |
530 | while (n->m_next) n = n->m_next; | |
531 | n->m_next = mc; | |
532 | mbp->mp_len++; | |
533 | ctlchar = 0; | |
534 | } | |
535 | mbp->mp_ctl = ctlchar; | |
536 | ||
537 | if ((dkp->dk_state & DK_BUSY) == 0) { | |
538 | dkp->dk_state |= DK_BUSY ; | |
539 | dkp->dk_curout = mb; | |
540 | dkp->dk_xlen = mbp->mp_len ; | |
541 | if (chan > dkdebug) | |
542 | log(LOG_ERR, "xmit %d: %x len %d\n", chan, | |
543 | mb->m_next, mbp->mp_len) ; | |
544 | dkxmit(dkp, chan, 2) ; | |
545 | splx(s) ; | |
546 | return dkp->dk_state ; | |
547 | } | |
548 | if (IF_QFULL(&dkp->dk_outq)) { | |
549 | IF_DROP(&dkp->dk_outq); | |
550 | m_freem(mb); | |
551 | } | |
552 | else | |
553 | IF_ENQUEUE(&dkp->dk_outq, mb); | |
554 | splx(s) ; | |
555 | return dkp->dk_state ; | |
556 | } | |
557 | ||
558 | /* | |
559 | * Receive into a block buffer | |
560 | */ | |
561 | dk_recv(chan, addr, len, mode, endfcn, endparm) | |
562 | caddr_t addr ; | |
563 | int (*endfcn)() ; | |
564 | caddr_t endparm ; | |
565 | { | |
566 | register struct dkchan *dkp ; | |
567 | register s ; | |
568 | ||
569 | if (addr == 0) { | |
570 | log(LOG_ERR, "dk_recv: channel %d endfcn %x: invalid address specification\n", chan, endfcn); | |
571 | return 0; | |
572 | } | |
573 | ||
574 | s = spl5() ; | |
575 | dkp = &dkit[chan] ; | |
576 | if (dkp->dk_state & (DK_RCV | DK_RESET)) { | |
577 | splx(s) ; | |
578 | return 0 ; | |
579 | } | |
580 | dkp->dk_state |= DK_RCV ; | |
581 | dkp->dk_endfcn = endfcn ; | |
582 | dkp->dk_endparm = endparm ; | |
583 | dkp->dk_rmode = mode ; | |
584 | dkp->dk_rlen = len ; | |
585 | dkp->dk_raddr = (caddr_t)addr ; | |
586 | if (chan > dkdebug) | |
587 | log(LOG_ERR, "dkrecv %d: %x len %d mode %o\n", chan, (caddr_t)addr, len, mode) ; | |
588 | dkrcv(dkp, chan, 2) ; | |
589 | splx(s) ; | |
590 | return dkp->dk_state ; | |
591 | } | |
592 | ||
593 | ||
594 | dk_rabort(chan, nendfcn, nendparm) | |
595 | int (*nendfcn)() ; | |
596 | caddr_t nendparm ; | |
597 | { | |
598 | register struct dkchan *dkp ; | |
599 | register s ; | |
600 | ||
601 | dkp = &dkit[chan] ; | |
602 | s = spl5() ; | |
603 | if (dkp->dk_state & DK_RCV) { | |
604 | dkp->dk_state &= ~DK_RCV ; | |
605 | if (dkp->dk_rlen) { | |
606 | if (chan > dkdebug) | |
607 | log(LOG_ERR, "rcvabo %d: rlen %d\n", chan, dkp->dk_rlen) ; | |
608 | (*nendfcn)(nendparm, chan, dkp->dk_rlen, DKR_ABORT, 0) ; | |
609 | } | |
610 | dkp->dk_rlen = 0 ; | |
611 | } | |
612 | splx(s) ; | |
613 | return dkp->dk_state ; | |
614 | } | |
615 | ||
616 | ||
617 | ||
618 | dk_status(chan) | |
619 | { | |
620 | if (chan >= dk_nchan) | |
621 | return 0 ; | |
622 | return dkit[chan].dk_state ; | |
623 | } | |
624 | ||
625 | ||
626 | dk_timeout() | |
627 | { | |
628 | register struct rdevice *raddr; | |
629 | register struct dkchan *dkp; | |
630 | register chan ; | |
631 | int s = spl5(); | |
632 | ||
633 | chan = 0 ; | |
634 | for (dkp = &dkit[0]; dkp < &dkit[dk_nchan]; dkp++) { | |
635 | if (dkp->dk_X != XM_OFF) { | |
636 | if (dkp->dk_X == 0) | |
637 | dksend(chan, INIT1) ; | |
638 | else | |
639 | if (dkp->dk_S != ((dkp->dk_R + 1) & 07)) { | |
640 | if (dkp->dk_X & XM_ENQ) { | |
641 | dksend(chan, ENQ) ; | |
642 | dkp->dk_X &= ~XM_REJ ; | |
643 | dkp->dk_enqcnt++; | |
644 | URPTRACE(chan, ENQ, dkp); | |
645 | } | |
646 | else dkp->dk_X |= XM_ENQ; | |
647 | } | |
648 | } | |
649 | chan++ ; | |
650 | } | |
651 | ||
652 | dkstray = 0; | |
653 | if(dkdisabled){ | |
654 | if(dkdisabled++ > 10){ | |
655 | /* try re-enabling interrupts */ | |
656 | dkdisabled = 0; | |
657 | log(LOG_ERR, "re-enabling DK interface\n"); | |
658 | raddr = DKADDR; | |
659 | raddr->dkcsr = ENABS; | |
660 | } | |
661 | } | |
662 | else { | |
663 | /* Look for lost interrupts */ | |
664 | if (raddr->dkcsr < 0) { | |
665 | dkdrlostint++; | |
666 | dkdrxint(0); | |
667 | } | |
668 | } | |
669 | ||
670 | timeout(dk_timeout, (caddr_t) 0, 1*hz); | |
671 | splx(s); | |
672 | } | |
673 | ||
674 | dk_cmd(chan, cmd) | |
675 | { | |
676 | register struct dkchan *dkp ; | |
677 | int s = spl5(); | |
678 | ||
679 | if (chan > dkdebug) | |
680 | log(LOG_ERR, "dkcmd %d: %o\n", chan, cmd) ; | |
681 | dkp = &dkit[chan] ; | |
682 | if (cmd & DKC_XINIT) { | |
683 | dkp->dk_X = dkp->dk_R = dkp->dk_A = 0 ; | |
684 | dkp->dk_S = 1 ; | |
685 | dksend(chan, INIT1) ; | |
686 | } | |
687 | if (cmd & DKC_FLUSH) { | |
688 | flushall(dkp, -1) ; | |
689 | } | |
690 | if (cmd & DKC_SPND) | |
691 | dkp->dk_state |= DK_SPND ; | |
692 | if (cmd & DKC_RSME) { | |
693 | dkp->dk_state &= ~DK_SPND ; | |
694 | dkxmit(dkp, chan, 2) ; | |
695 | } | |
696 | splx(s); | |
697 | } | |
698 | ||
699 | ||
700 | static | |
701 | flushall(dkp, rwflag) | |
702 | register struct dkchan *dkp ; | |
703 | { | |
704 | register s ; | |
705 | struct mpacket *mbp; | |
706 | ||
707 | s = spl5() ; | |
708 | if ((dkp->dk_state & DK_RCV) && (rwflag >= 0)) { | |
709 | dkp->dk_state &= ~DK_RCV ; | |
710 | if (dkp->dk_endfcn) | |
711 | (*dkp->dk_endfcn)(dkp->dk_endparm, dkp-dkit, dkp->dk_rlen, DKR_ABORT, 0) ; | |
712 | dkp->dk_rlen = 0 ; | |
713 | } | |
714 | if ((dkp->dk_state & DK_BUSY) && (rwflag <= 0)) { | |
715 | register struct mbuf *m ; | |
716 | ||
717 | dkp->dk_xlen = 0; | |
718 | if (dkp->dk_curout) { | |
719 | mbp = mtod(dkp->dk_curout, struct mpacket *); | |
720 | if (mbp->mp_endfcn) | |
721 | (mbp->mp_endfcn)(mbp->mp_endparm, dkp-dkit); | |
722 | m_freem(dkp->dk_curout); | |
723 | dkp->dk_curout = NULL; | |
724 | } | |
725 | while (1) { | |
726 | IF_DEQUEUE(&dkp->dk_outq, m); | |
727 | if (!m) break; | |
728 | mbp = mtod(m, struct mpacket *); | |
729 | if (mbp->mp_endfcn) | |
730 | (mbp->mp_endfcn)(mbp->mp_endparm, dkp-dkit); | |
731 | m_freem(m); | |
732 | } | |
733 | dkp->dk_state &= ~DK_BUSY ; | |
734 | } | |
735 | if ((dkp->dk_state & DK_OPEN) && (rwflag >= 0)) { | |
736 | register struct dkpkbufr *dbp ; | |
737 | ||
738 | dkp->dk_rlen = 0 ; | |
739 | dkp->dk_xlen = 0 ; | |
740 | dkp->dk_C = 0 ; | |
741 | while (dbp = dkp->dk_rq) { | |
742 | dkp->dk_rq = dbp->Pnext ; | |
743 | dbp->Pnext = dk_Sfree ; | |
744 | dk_Sfree = dbp ; | |
745 | } | |
746 | while (dbp = dkp->dk_rb) { | |
747 | dkp->dk_rb = dbp->Pnext ; | |
748 | dbp->Pnext = dk_Sfree ; | |
749 | dk_Sfree = dbp ; | |
750 | } | |
751 | } | |
752 | splx(s) ; | |
753 | } | |
754 | ||
755 | ||
756 | /* | |
757 | * Routine to handle completion status | |
758 | */ | |
759 | static | |
760 | dkkint() | |
761 | { | |
762 | register struct dkchan *dkp; | |
763 | register struct dkstat *sp; | |
764 | register chan; | |
765 | struct mbuf *m ,*om; | |
766 | struct mpacket *mbp; | |
767 | static char *cmpltype[] = {"send", "rdb", "eoi", "cntl", "err"}; | |
768 | ||
769 | while (Tstat != Hstat) { | |
770 | sp = &dkdr_stat[Hstat]; | |
771 | chan = sp->k_chan; | |
772 | dkp = &dkit[chan]; | |
773 | if (sp->k_chan > dkdebug) { | |
774 | if (sp->k_type >= KS_SEND && sp->k_type <= KS_ERR) | |
775 | log(LOG_ERR, "dkdone: type %s chan %d info %o-%o\n", | |
776 | cmpltype[sp->k_type-KS_SEND], | |
777 | sp->k_chan, sp->k_info1, sp->k_info2) ; | |
778 | else log(LOG_ERR, "dkdone: type %d chan %d info %o-%o\n", | |
779 | sp->k_type, sp->k_chan, sp->k_info1, sp->k_info2) ; | |
780 | } | |
781 | if (Hstat==dkdr_nstat-1) Hstat=0; else Hstat++; | |
782 | switch(sp->k_type) { | |
783 | case KS_CNTL: | |
784 | if (dkp->dk_supfcn) | |
785 | (*dkp->dk_supfcn)(chan, sp->k_info1) ; | |
786 | break ; | |
787 | case KS_EOI: | |
788 | break ; | |
789 | case KS_SEND: | |
790 | om = dkp->dk_curout ; | |
791 | if (om == NULL) { | |
792 | log(LOG_ERR, "dkk: xbufout\n"); | |
793 | break; | |
794 | } | |
795 | IF_DEQUEUE(&dkp->dk_outq, m); | |
796 | if (m == NULL) { | |
797 | dkp->dk_state &= ~DK_BUSY; | |
798 | dkp->dk_curout = NULL; | |
799 | } else { | |
800 | dkp->dk_curout = m; | |
801 | mbp = mtod(m, struct mpacket *); | |
802 | dkp->dk_xlen = mbp->mp_len ; | |
803 | if (chan > dkdebug) | |
804 | log(LOG_ERR, "xmiti %d: %x len %d\n", chan, | |
805 | m->m_next, mbp->mp_len) ; | |
806 | dkxmit(dkp, chan, 0) ; | |
807 | } | |
808 | mbp = mtod(om, struct mpacket *); | |
809 | if (mbp->mp_endfcn != NULL) | |
810 | (mbp->mp_endfcn)(mbp->mp_endparm, chan) ; | |
811 | m_freem(om); | |
812 | break; | |
813 | case KS_RDB: | |
814 | dkp->dk_state &= ~(DK_RCV|DK_RCVQ) ; | |
815 | if (sp->k_info2 == DKR_TIME && dkp->dk_rlen == 0) | |
816 | break ; /* another coming later */ | |
817 | if (dkp->dk_rlen) { | |
818 | sp->k_info1 = dkp->dk_rlen ; | |
819 | dkp->dk_rlen = 0 ; | |
820 | } | |
821 | if (dkp->dk_endfcn != NULL) | |
822 | (*dkp->dk_endfcn)(dkp->dk_endparm, dkp-dkit, sp->k_info1, sp->k_info2&0377, | |
823 | (sp->k_info2>>8)&0377) ; | |
824 | break; | |
825 | case KS_ERR: | |
826 | log(LOG_ERR, "err in dkit.c: chan - %d, code - %o\n", | |
827 | chan, sp->k_info1); | |
828 | break; | |
829 | } /* end switch */ | |
830 | ||
831 | } /* end while */ | |
832 | } | |
833 | ||
834 | ||
835 | ||
836 | ||
837 | ||
838 | ||
839 | ||
840 | /* static */ | |
841 | int dkxmitpanic = 0; | |
842 | ||
843 | dkxmit(dkp, stechan, intrpt) | |
844 | struct dkchan *dkp ; | |
845 | { | |
846 | register struct rdevice *raddr ; | |
847 | register char *ptr ; | |
848 | register struct mbuf *m; | |
849 | register int wtype; | |
850 | short pklen ; | |
851 | short mlen, unacked ; | |
852 | short blklen ; | |
853 | unsigned short totlen ; | |
854 | struct mpacket *mbp ; | |
855 | #ifdef notdef | |
856 | short scheck ; | |
857 | #endif | |
858 | ||
859 | if( dkp->dk_curout == NULL || stechan ==0 ) | |
860 | return ; | |
861 | mbp = mtod(dkp->dk_curout, struct mpacket *); | |
862 | raddr = DKADDR ; | |
863 | if ((dkp->dk_S & DKBMASK) == (dkp->dk_R & DKBMASK) || (dkp->dk_state & DK_SPND)) | |
864 | goto ctlchk ; | |
865 | if ((dkp->dk_xlen || ((mbp->mp_ctl & 0200) == 0)) && dkp->dk_X < XM_INIT) | |
866 | goto ctlchk ; | |
867 | #ifdef notdef | |
868 | if ((dkp->dk_S & DKBMASK) == ((dkp->dk_R + 1) & DKBMASK)) | |
869 | scheck = 0 ; | |
870 | else | |
871 | scheck = 1 ; | |
872 | #endif | |
873 | ||
874 | unacked = ((dkp->dk_S - dkp->dk_A - 1) & 07) * DKBLOCK ; | |
875 | mlen = MIN(unacked, dkp->dk_xlen) ; | |
876 | totlen = dkp->dk_xlen - mlen; | |
877 | if (totlen == 0) | |
878 | goto ctlchk ; | |
879 | ||
880 | /* Skip over stuff sent but not acked */ | |
881 | for (m = dkp->dk_curout->m_next; m && (mlen > 0); m = m->m_next) | |
882 | if (mlen > m->m_len) mlen -= m->m_len; | |
883 | else break; | |
884 | ||
885 | while (totlen && ((dkp->dk_S ^ dkp->dk_R) & DKBMASK)) { | |
886 | if (dkxmitpanic) panic("dkxmit -- panic 1"); | |
887 | blklen = MIN (totlen, DKBLOCK) ; | |
888 | pklen = 0 ; | |
889 | raddr->dkcsr = D_WRITE ; | |
890 | raddr->dko = stechan | DKMARK ; | |
891 | while (blklen) { | |
892 | if (dkxmitpanic) panic("dkxmit -- panic 2"); | |
893 | if (m == NULL) panic("dkxmit mlen"); | |
894 | ptr = mtod(m, char *) + mlen; | |
895 | mlen = MIN(blklen, m->m_len - mlen); | |
896 | blklen -= mlen; | |
897 | wtype = (m->m_type == DKMT_CTL ? 0 : DKDATA); | |
898 | while (mlen--) { | |
899 | if (dkxmitpanic) panic("dkxmit -- panic 3"); | |
900 | raddr->dko = (*ptr++ & 0377) | wtype ; | |
901 | pklen++ ; | |
902 | if ((pklen & (DKCHUNK-1)) == 0) { | |
903 | raddr->dkcsr = D_XPACK ; | |
904 | raddr->dko = 0 ; | |
905 | raddr->dkcsr = D_WRITE ; | |
906 | raddr->dko = stechan|DKMARK ; | |
907 | } | |
908 | } | |
909 | if (ptr == (mtod(m, char *) + m->m_len)) { | |
910 | m = m->m_next; | |
911 | mlen = 0; | |
912 | } | |
913 | else mlen = ptr - mtod(m, char *); | |
914 | } | |
915 | blklen = MIN (totlen, DKBLOCK) ; | |
916 | if ((pklen & (DKCHUNK-1)) > (DKCHUNK-4)) { | |
917 | raddr->dkcsr = D_XPACK ; | |
918 | raddr->dko = 0 ; | |
919 | raddr->dkcsr = D_WRITE ; | |
920 | raddr->dko = stechan|DKMARK ; | |
921 | } | |
922 | if (blklen == totlen && mbp->mp_eob) | |
923 | raddr->dko = BOT ; | |
924 | else | |
925 | raddr->dko = BOTM ; | |
926 | raddr->dko = (blklen & 0377) | DKDATA ; | |
927 | raddr->dko = ((blklen>>8) & 0377) | DKDATA ; | |
928 | raddr->dko = SEQ + dkp->dk_S ; | |
929 | raddr->dkcsr = D_XPACK ; | |
930 | raddr->dko = 0 ; | |
931 | URPTRACE(stechan, SEQ + dkp->dk_S, dkp); | |
932 | dkp->dk_S++ ; | |
933 | dkp->dk_S &= 07 ; | |
934 | totlen -= blklen ; | |
935 | } | |
936 | #ifdef notdef | |
937 | if (totlen == 0 && dkp->dk_xlen && scheck) { | |
938 | raddr->dkcsr = D_WRITE ; | |
939 | raddr->dko = stechan|DKMARK ; | |
940 | raddr->dko = CHECK ; | |
941 | raddr->dkcsr = D_XPACK ; | |
942 | raddr->dko = 0 ; | |
943 | URPTRACE(stechan, CHECK, dkp); | |
944 | } | |
945 | #endif | |
946 | ctlchk: | |
947 | if (mbp->mp_ctl & 0200) { | |
948 | raddr->dkcsr = D_WRITE ; | |
949 | raddr->dko = stechan|DKMARK ; | |
950 | raddr->dko = mbp->mp_ctl & 0377 ; | |
951 | raddr->dkcsr = D_XPACK ; | |
952 | raddr->dko = 0 ; | |
953 | mbp->mp_ctl = 0 ; | |
954 | if (dkp->dk_xlen == 0) | |
955 | dkreport(KS_SEND, stechan, 0, 0, intrpt) ; | |
956 | } | |
957 | if(dkdisabled) | |
958 | raddr->dkcsr = 0; | |
959 | else | |
960 | raddr->dkcsr = ENABS ; | |
961 | } | |
962 | ||
963 | ||
964 | static | |
965 | dkrcv(dkp, stechan, intrpt) | |
966 | struct dkchan *dkp ; | |
967 | { | |
968 | register char *ptr1 ; | |
969 | register char *ptr2 ; | |
970 | register len ; | |
971 | short final ; | |
972 | short hibits ; | |
973 | struct dkpkbufr *pkb ; | |
974 | short tlen ; | |
975 | ||
976 | if ((dkp->dk_rlen == 0) || (dkp->dk_rq == NULL)) | |
977 | return ; | |
978 | final = 0 ; | |
979 | tlen = 0 ; | |
980 | while (final == 0 && (pkb = dkp->dk_rq)) { | |
981 | if (dkp->dk_rlen == 0) | |
982 | final |= DKR_FULL ; | |
983 | ptr1 = &pkb->Pdata[0] ; | |
984 | ptr2 = dkp->dk_raddr ; | |
985 | len = MIN(pkb->Plen, dkp->dk_rlen) ; | |
986 | hibits = pkb->Phibits ; | |
987 | while (len--) { | |
988 | if (hibits < 0) | |
989 | break ; | |
990 | hibits <<= 1 ; | |
991 | *ptr2++ = *ptr1++ ; | |
992 | } | |
993 | len = ptr2 - dkp->dk_raddr ; | |
994 | tlen += len ; | |
995 | dkp->dk_rlen -= len ; | |
996 | dkp->dk_raddr = ptr2 ; | |
997 | if ((pkb->Plen -= len) && hibits < 0) { | |
998 | final |= ((*ptr1++ & 0377) << 8) | DKR_CNTL ; | |
999 | hibits <<= 1 ; | |
1000 | pkb->Plen-- ; | |
1001 | } | |
1002 | if (len = pkb->Plen) { | |
1003 | ptr2 = &pkb->Pdata[0] ; | |
1004 | while (len--) | |
1005 | *ptr2++ = *ptr1++ ; | |
1006 | pkb->Phibits = hibits ; | |
1007 | } | |
1008 | while (pkb && (pkb->Plen == 0)) { | |
1009 | if ((pkb->Pseq & 0370) == ACK) { | |
1010 | pkb->Pseq += ECHO - ACK ; | |
1011 | final |= dkp->dk_rmode & DKR_BLOCK ; | |
1012 | } | |
1013 | if (pkb->Pseq) { | |
1014 | dksend(stechan, pkb->Pseq) ; | |
1015 | dkp->dk_C = pkb->Pseq ; | |
1016 | } | |
1017 | dkp->dk_rq = pkb->Pnext ; | |
1018 | pkb->Pnext = dk_Sfree ; | |
1019 | dk_Sfree = pkb ; | |
1020 | pkb = dkp->dk_rq ; | |
1021 | } | |
1022 | } | |
1023 | if (tlen && (dkp->dk_rmode & DKR_TIME)) | |
1024 | final |= DKR_TIME ; | |
1025 | if (dkp->dk_rlen == 0) | |
1026 | final |= DKR_FULL ; | |
1027 | if (final && (final != DKR_TIME || ((dkp->dk_state & DK_RCVQ) == 0))) { | |
1028 | dkp->dk_state |= DK_RCVQ ; | |
1029 | len = dkp->dk_rlen ; | |
1030 | if (final != DKR_TIME) | |
1031 | dkp->dk_rlen = 0 ; | |
1032 | dkreport(KS_RDB, stechan, len, final, (final == DKR_TIME)?2:intrpt) ; | |
1033 | } | |
1034 | } | |
1035 | ||
1036 | ||
1037 | ||
1038 | static | |
1039 | dksend(stechan, val) | |
1040 | { | |
1041 | register struct rdevice *raddr ; | |
1042 | register savcsr ; | |
1043 | ||
1044 | if(stechan == 0) | |
1045 | return; | |
1046 | ||
1047 | raddr = DKADDR ; | |
1048 | savcsr = raddr->dkcsr ; | |
1049 | raddr->dkcsr = D_WRITE ; | |
1050 | raddr->dko = stechan| DKMARK ; | |
1051 | raddr->dko = val ; | |
1052 | raddr->dkcsr = D_XPACK ; | |
1053 | raddr->dko = 0 ; | |
1054 | raddr->dkcsr = savcsr ; | |
1055 | } | |
1056 | ||
1057 | ||
1058 | /*ARGSUSED*/ | |
1059 | dkdrrint(dev) /* ?? */ /* needed for UNIX OS */ | |
1060 | { | |
1061 | register struct rdevice *raddr ; | |
1062 | register c ; | |
1063 | register cnt; | |
1064 | ||
1065 | #ifdef lint | |
1066 | c = 0; cnt = c; | |
1067 | #endif | |
1068 | cnt = 0; | |
1069 | raddr = DKADDR ; | |
1070 | raddr->dkcsr = D_OSEQ ; | |
1071 | if((raddr->dkcsr & DKTDONE) == 0){ | |
1072 | if(dkstray++ >= MAX_STRAY){ | |
1073 | log(LOG_ERR, "DK err 1 (Cabling?)\n"); | |
1074 | raddr->dkcsr = 0; | |
1075 | dkdisabled = 1; | |
1076 | return; | |
1077 | } | |
1078 | } | |
1079 | while (raddr->dkcsr & DKTDONE){ | |
1080 | c = raddr->dki ; | |
1081 | if(cnt++ > 65){ | |
1082 | log(LOG_ERR, "DK err 2 (Cabling?)\n"); | |
1083 | raddr->dkcsr = 0; | |
1084 | dkdisabled = 1; | |
1085 | return; | |
1086 | } | |
1087 | } | |
1088 | raddr->dkcsr = ENABS ; | |
1089 | if (Hstat != Tstat) | |
1090 | dkkint() ; | |
1091 | } | |
1092 | ||
1093 | /*ARGSUSED*/ | |
1094 | dkdrxint(dev) /* ?? */ | |
1095 | { | |
1096 | register struct rdevice *raddr ; | |
1097 | register char *ptr ; | |
1098 | struct dkchan *dkp ; | |
1099 | register c ; | |
1100 | short badpacks ; | |
1101 | struct dkpkbufr *pkb ; | |
1102 | short stechan ; | |
1103 | short len, xlen ; | |
1104 | unsigned short bitloc ; | |
1105 | ||
1106 | badpacks = 0 ; | |
1107 | raddr = DKADDR ; | |
1108 | pkb = NULL ; | |
1109 | if(raddr->dkcsr >= 0){ | |
1110 | if(dkstray++ > MAX_STRAY){ | |
1111 | log(LOG_ERR, "DK err 3 (Cabling?)\n"); | |
1112 | goto disable; | |
1113 | } | |
1114 | } | |
1115 | while (raddr->dkcsr < 0) { | |
1116 | raddr->dkcsr = D_READ ; | |
1117 | c = raddr->dki ; | |
1118 | while (raddr->dkcsr < 0 && (c & DKMARK)) { | |
1119 | c &= 0777 ; | |
1120 | if (c >= dk_nchan) { | |
1121 | if (++badpacks > 20) { | |
1122 | log(LOG_ERR, "DK err 4 (Cabling?)\n"); | |
1123 | dkreport(KS_ERR, 0, 2, 0, 1) ; | |
1124 | goto disable ; | |
1125 | } | |
1126 | break ; | |
1127 | } | |
1128 | /* discard all chl 0 packets; | |
1129 | * the LDI version of the CPM-DR and CPM-422 | |
1130 | * puts out packets on chl 0 occasionally. | |
1131 | */ | |
1132 | if(c == 0) break; | |
1133 | ||
1134 | dkp = &dkit[c] ; | |
1135 | stechan = c ; | |
1136 | qpkb: | |
1137 | if (pkb && pkb->Plen) { | |
1138 | dkrcvq(stechan, dkp, pkb, 0) ; | |
1139 | pkb = NULL ; | |
1140 | } | |
1141 | if (pkb == NULL) { | |
1142 | if ((pkb = dk_Sfree) != NULL) { | |
1143 | dk_Sfree = pkb->Pnext ; | |
1144 | pkb->Pseq = 0 ; | |
1145 | pkb->Plen = 0 ; | |
1146 | pkb->Pnext = NULL ; | |
1147 | pkb->Phibits = 0 ; | |
1148 | } else { | |
1149 | /* | |
1150 | ** Oops, no more dkpkbufr's. | |
1151 | ** Let outer loop gobble up | |
1152 | ** the entire packet. | |
1153 | ** Report to the console | |
1154 | ** every 100th occurrence. | |
1155 | */ | |
1156 | if ( dknopkb++ >= 100 ) { | |
1157 | dknopkb = 1 ; | |
1158 | dkreport(KS_ERR, 0, 3, 0, 1) ; | |
1159 | } | |
1160 | break ; | |
1161 | } | |
1162 | } | |
1163 | raddr->dkcsr = D_READ ; | |
1164 | ptr = &pkb->Pdata[0] ; | |
1165 | bitloc = 0100000 ; | |
1166 | while (raddr->dkcsr < 0 && ((c = raddr->dki) & DKMARK) == 0) | |
1167 | switch (c = c & 0777) { | |
1168 | case NULL: | |
1169 | break ; | |
1170 | case AINIT: | |
1171 | dkp->dk_X = XM_INIT ; | |
1172 | dkp->dk_R = 0 ; | |
1173 | dkp->dk_S = 1 ; | |
1174 | dkp->dk_A = 0 ; | |
1175 | dkxmit(dkp, stechan, 1) ; | |
1176 | raddr->dkcsr = D_READ ; | |
1177 | break ; | |
1178 | case INIT0: | |
1179 | dksend(stechan, AINIT) ; | |
1180 | dkp->dk_trmode = 0 ; | |
1181 | dkp->dk_C = dkp->dk_rseq = 0 ; | |
1182 | break ; | |
1183 | case INIT1: | |
1184 | dksend(stechan, AINIT) ; | |
1185 | dkp->dk_trmode = 1 ; | |
1186 | dkp->dk_C = dkp->dk_tail1 = dkp->dk_tail2 = dkp->dk_rseq = 0 ; | |
1187 | while (pkb) { | |
1188 | pkb->Pnext = dk_Sfree ; | |
1189 | dk_Sfree = pkb ; | |
1190 | if (pkb = dkp->dk_rq) | |
1191 | dkp->dk_rq = pkb->Pnext ; | |
1192 | if (pkb == NULL) | |
1193 | if (pkb = dkp->dk_rb) | |
1194 | dkp->dk_rb = pkb->Pnext ; | |
1195 | } | |
1196 | goto qpkb ; | |
1197 | case INITREQ: | |
1198 | dksend(stechan, INIT1) ; | |
1199 | dkp->dk_X = 0 ; | |
1200 | break ; | |
1201 | case ENQ: | |
1202 | dksend(stechan, dkp->dk_C) ; | |
1203 | case CHECK: | |
1204 | dksend(stechan, ACK+dkp->dk_rseq) ; | |
1205 | while (pkb) { | |
1206 | pkb->Pnext = dk_Sfree ; | |
1207 | dk_Sfree = pkb ; | |
1208 | if (pkb = dkp->dk_rb) | |
1209 | dkp->dk_rb = pkb->Pnext ; | |
1210 | } | |
1211 | dkp->dk_rblen = 0 ; | |
1212 | goto qpkb ; | |
1213 | case EOI: | |
1214 | if (dkp->dk_tail1 == ((SOI<<8)|2)) | |
1215 | dkreport(KS_EOI, stechan, dkp->dk_tail2, 0, 1) ; | |
1216 | dkp->dk_tail1 = 0 ; | |
1217 | break ; | |
1218 | default: | |
1219 | if (c & DKDATA) { | |
1220 | if (dkp->dk_tail1) { | |
1221 | dkp->dk_tail2 = ((dkp->dk_tail2 >> 8) & 0377) | (c<<8) ; | |
1222 | dkp->dk_tail1++ ; | |
1223 | if ((dkp->dk_tail1 & 0377) > 3) | |
1224 | dkp->dk_tail1 = 0 ; | |
1225 | } else { | |
1226 | *ptr++ = c & 0377 ; | |
1227 | pkb->Plen++ ; | |
1228 | bitloc >>= 1 ; | |
1229 | } | |
1230 | break ; | |
1231 | } | |
1232 | if (((c & 0770) == ECHO) || ((c & 0770) == REJ)) { | |
1233 | URPTRACE(stechan, c, dkp); | |
1234 | dkp->dk_R = c & 07 ; | |
1235 | if (((dkp->dk_S - dkp->dk_R - 1) & 07) < | |
1236 | ((dkp->dk_S - dkp->dk_A - 1) & 07)) { | |
1237 | gotack: | |
1238 | dkp->dk_X &= ~(XM_REJ | XM_ENQ); | |
1239 | xlen = dkp->dk_xlen ; | |
1240 | len = ((c - dkp->dk_A) & 07) * DKBLOCK ; | |
1241 | len = MIN(len, xlen); | |
1242 | dkp->dk_xlen -= len; | |
1243 | if (dkp->dk_curout) | |
1244 | m_adj(dkp->dk_curout->m_next, len) ; | |
1245 | dkp->dk_A = c & 07 ; | |
1246 | if (len || xlen) | |
1247 | if ((dkp->dk_xlen) == 0) | |
1248 | dkreport(KS_SEND, stechan, 0, 0, 1) ; | |
1249 | } | |
1250 | dkxmit(dkp, stechan, 1) ; | |
1251 | raddr->dkcsr = D_READ ; | |
1252 | if ((c & 0770) == REJ && ((dkp->dk_X & XM_REJ) == 0)) { | |
1253 | dkp->dk_rejcnt++; | |
1254 | gotrej: | |
1255 | dkp->dk_S = (c+1) & 07 ; | |
1256 | dkxmit(dkp, stechan, 1) ; | |
1257 | raddr->dkcsr = D_READ ; | |
1258 | dkp->dk_X |= XM_REJ ; | |
1259 | } | |
1260 | break ; | |
1261 | } | |
1262 | if ((c & 0770) == ACK) { | |
1263 | URPTRACE(stechan, c, dkp); | |
1264 | if (dkp->dk_A != (c & 07)) | |
1265 | goto gotack ; | |
1266 | if ((dkp->dk_X & XM_REJ) == 0) { | |
1267 | dkp->dk_ackrejcnt++; | |
1268 | goto gotrej ; | |
1269 | } | |
1270 | break ; | |
1271 | } | |
1272 | if ((c & 0774) == BOT) { | |
1273 | dkp->dk_tail1 = c << 8 ; | |
1274 | break ; | |
1275 | } | |
1276 | if ((c & 0770) == SEQ) { | |
1277 | pkb->Pseq = c - SEQ + ECHO ; | |
1278 | dkrcvq(stechan, dkp, pkb, 0) ; | |
1279 | if (dkp->dk_trmode) { | |
1280 | if (dkp->dk_rblen == dkp->dk_tail2 && | |
1281 | (dkp->dk_tail1 & 0377) == 2 && | |
1282 | ((dkp->dk_tail1 >> 8) & 0377) != SOI && | |
1283 | ((dkp->dk_rseq+1) & 07) == (c & 07)) { | |
1284 | dkp->dk_rseq = c & 07 ; | |
1285 | if (((dkp->dk_tail1>>8) & 0377) != BOTM) | |
1286 | pkb->Pseq += ACK - ECHO ; | |
1287 | dkrcvq(stechan, dkp, dkp->dk_rb, 1) ; | |
1288 | } else { | |
1289 | while (pkb = dkp->dk_rb) { | |
1290 | dkp->dk_rb = pkb->Pnext ; | |
1291 | pkb->Pnext = dk_Sfree ; | |
1292 | dk_Sfree = pkb ; | |
1293 | } | |
1294 | pkb = dk_Sfree ; | |
1295 | dk_Sfree = pkb->Pnext ; | |
1296 | pkb->Plen = 0 ; | |
1297 | pkb->Pnext = NULL ; | |
1298 | pkb->Pseq = REJ + dkp->dk_rseq ; | |
1299 | dkp->dk_srejcnt++; | |
1300 | if (((dkp->dk_tail1>>8) & 0377) == BOTS) { | |
1301 | dkp->dk_rseq = c & 07 ; | |
1302 | pkb->Pseq = ECHO + dkp->dk_rseq ; | |
1303 | } | |
1304 | dkrcvq(stechan, dkp, pkb, 1) ; | |
1305 | } | |
1306 | dkp->dk_rb = NULL ; | |
1307 | dkp->dk_rblen = 0 ; | |
1308 | dkp->dk_tail1 = 0 ; | |
1309 | } else | |
1310 | /* always keep seq no up to date */ | |
1311 | dkp->dk_rseq = c & 07; | |
1312 | pkb = NULL ; | |
1313 | goto qpkb ; | |
1314 | } | |
1315 | if (c & 0200) { | |
1316 | dkreport(KS_CNTL, stechan, c, 0, 1) ; | |
1317 | raddr->dkcsr = D_READ ; | |
1318 | } else { | |
1319 | *ptr++ = c & 0377 ; | |
1320 | pkb->Plen++ ; | |
1321 | pkb->Phibits |= bitloc ; | |
1322 | bitloc >>= 1 ; | |
1323 | } | |
1324 | } | |
1325 | if (pkb && pkb->Plen) { | |
1326 | dkrcvq(stechan, dkp, pkb, 0) ; | |
1327 | pkb = NULL ; | |
1328 | } | |
1329 | } | |
1330 | } | |
1331 | ||
1332 | if (pkb) { | |
1333 | if (pkb->Plen) | |
1334 | dkrcvq(stechan, dkp, pkb, 0) ; | |
1335 | else { | |
1336 | pkb->Pnext = dk_Sfree ; | |
1337 | dk_Sfree = pkb ; | |
1338 | } | |
1339 | } | |
1340 | raddr->dkcsr = ENABS ; | |
1341 | return; | |
1342 | ||
1343 | disable: | |
1344 | if(pkb){ | |
1345 | pkb->Pnext = dk_Sfree; | |
1346 | dk_Sfree = pkb; | |
1347 | } | |
1348 | raddr->dkcsr = 0; | |
1349 | dkdisabled = 1; | |
1350 | } | |
1351 | ||
1352 | dkrcvq(stechan, dkp, npkb, where) | |
1353 | register struct dkchan *dkp ; | |
1354 | struct dkpkbufr *npkb ; | |
1355 | { | |
1356 | register struct dkpkbufr *pkb ; | |
1357 | int i ; | |
1358 | ||
1359 | i = 0 ; | |
1360 | if (dkp->dk_trmode && where == 0) | |
1361 | pkb = (struct dkpkbufr *)&dkp->dk_rb ; | |
1362 | else | |
1363 | pkb = (struct dkpkbufr *)&dkp->dk_rq ; | |
1364 | ||
1365 | while (pkb->Pnext) { | |
1366 | pkb = pkb->Pnext ; | |
1367 | i++ ; | |
1368 | } | |
1369 | if ( i >= PKBHOG ) { | |
1370 | /* | |
1371 | ** This channel has too many buffers. | |
1372 | ** Do not queue any more. | |
1373 | ** Return the new buffer to the free list. | |
1374 | */ | |
1375 | npkb->Pnext = dk_Sfree ; | |
1376 | dk_Sfree = npkb ; | |
1377 | return ; | |
1378 | } | |
1379 | pkb->Pnext = npkb ; | |
1380 | ||
1381 | if (dkp->dk_trmode && where == 0) | |
1382 | dkp->dk_rblen += npkb->Plen ; | |
1383 | else | |
1384 | dkrcv(dkp, stechan, 1) ; | |
1385 | } | |
1386 | ||
1387 | ||
1388 | ||
1389 | dkreport(type, chan, info1, info2, intrpt) | |
1390 | /* intrpt parameter controlls whether the pdp-11 interrupt is called. | |
1391 | * Value 0 says no (means dkxint queued already) | |
1392 | * Value 1 says call it immediately (like from dr11c interrupt) | |
1393 | * Value 2 says to queue a call as soon as processor priority lowers | |
1394 | * (by sending a dummy packet on a channel and getting dkxint) | |
1395 | */ | |
1396 | { | |
1397 | register struct dkstat *sp; | |
1398 | ||
1399 | if ((Tstat + 1) % dkdr_nstat == Hstat) { /* room in queue? */ | |
1400 | log(LOG_ERR, "dkit_dr: No room in status queue, Channel %d\n", chan); | |
1401 | return; | |
1402 | } | |
1403 | ||
1404 | sp = &dkdr_stat[Tstat] ; | |
1405 | sp->k_chan = chan ; | |
1406 | sp->k_type = type ; | |
1407 | sp->k_info1 = info1 ; | |
1408 | sp->k_info2 = info2 ; | |
1409 | if (Tstat == dkdr_nstat-1) Tstat = 0 ; else Tstat++ ; | |
1410 | if (intrpt==1) { | |
1411 | dkkint() ; | |
1412 | } else if (intrpt==2) { | |
1413 | register struct rdevice *raddr ; | |
1414 | raddr = DKADDR ; | |
1415 | raddr->dkcsr = D_WRITE ; | |
1416 | ||
1417 | /* Chl (dk_nchan-1) is used instead of 511 because | |
1418 | * the LDI switch module will complain if we use | |
1419 | * a chl outside the range set up in its route tables. | |
1420 | */ | |
1421 | raddr->dko = (dk_nchan-1) | DKMARK ; | |
1422 | ||
1423 | /* | |
1424 | * A null is used here because it should always | |
1425 | * be ignored by the far end of the circuit. | |
1426 | */ | |
1427 | raddr->dko = 0 ; | |
1428 | ||
1429 | raddr->dkcsr = D_XPACK ; | |
1430 | raddr->dko = 0 ; | |
1431 | raddr->dkcsr = ENABS ; | |
1432 | } | |
1433 | } | |
1434 | ||
1435 | #ifdef URPDEBUG | |
1436 | struct dkurps { | |
1437 | char dku_ctl; | |
1438 | char dku_S; | |
1439 | char dku_R; | |
1440 | char dku_A; | |
1441 | } dkurps[URPDEBUG]; | |
1442 | int dkurpsize = URPDEBUG; | |
1443 | ||
1444 | struct dkurps *dkurpsp = dkurps; | |
1445 | int dkurpreset; | |
1446 | ||
1447 | dkurptrace(ctl, dkp) char ctl; register struct dkchan *dkp; | |
1448 | { | |
1449 | #ifdef lint | |
1450 | dkurpsize = dkurpsize; | |
1451 | #endif | |
1452 | if (dkurpreset) { | |
1453 | dkurpsp = dkurps; | |
1454 | dkurpreset = 0; | |
1455 | } | |
1456 | dkurpsp->dku_ctl = ctl; | |
1457 | dkurpsp->dku_S = dkp->dk_S; | |
1458 | dkurpsp->dku_R = dkp->dk_R; | |
1459 | dkurpsp->dku_A = dkp->dk_A; | |
1460 | if (++dkurpsp == dkurps+URPDEBUG) | |
1461 | dkurpsp = dkurps; | |
1462 | } | |
1463 | #endif URPDEBUG | |
1464 | #endif |