Commit | Line | Data |
---|---|---|
e6dd5973 | 1 | /* @(#)if_hdh.c 6.2 (Berkeley) %G% */ |
a0c9a57d MK |
2 | |
3 | ||
4 | /************************************************************************\ | |
5 | ||
6 | ________________________________________________________ | |
7 | / \ | |
8 | | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | | |
9 | | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | | |
10 | | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | | |
11 | | AAAA AAAA CCCC CCCC | | |
12 | | AAAA AAAA CCCC CCCC | | |
13 | | AAAA AAAA CCCC CCCC | | |
14 | | AAAA AAAA CCCC CCCC | | |
15 | | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | | |
16 | | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | | |
17 | | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | | |
18 | \________________________________________________________/ | |
19 | ||
20 | Copyright (c) 1984 by Advanced Computer Communications | |
21 | 720 Santa Barbara Street, Santa Barbara, California 93101 | |
22 | (805) 963-9431 | |
23 | ||
24 | This software may be duplicated and used on systems | |
25 | which are licensed to run U.C. Berkeley versions of | |
26 | the UNIX operating system. Any duplication of any | |
27 | part of this software must include a copy of ACC's | |
28 | copyright notice. | |
29 | ||
30 | ||
31 | File: | |
32 | if_hdh.c | |
33 | ||
34 | Author: | |
35 | Art Berggreen | |
36 | ||
37 | Project: | |
38 | 4.2BSD HDH | |
39 | ||
40 | Function: | |
41 | Device specific driver for IF-11/HDH under 4.2BSD | |
42 | networking code. | |
43 | ||
44 | Revision History: | |
45 | 31-Aug-1984: V1.0 - First Implementation. A.B. | |
46 | 6-Nov-1984: V1.1 - Supress extra "LINE DOWN" msgs. A.B. | |
47 | 13-Jan-1984: V1.2 - Add conditionals for TWG. A.B. | |
48 | ||
49 | \************************************************************************/ | |
50 | ||
51 | ||
52 | ||
53 | ||
54 | /* $Header$ */ | |
55 | ||
56 | #include "hdh.h" | |
57 | #ifdef NHDH > 0 | |
58 | ||
59 | /* | |
60 | * | |
61 | * ACC IF-11/HDH interface | |
62 | * | |
63 | */ | |
64 | ||
65 | #include "../machine/pte.h" | |
66 | ||
e6dd5973 MK |
67 | #include "param.h" |
68 | #include "systm.h" | |
69 | #include "mbuf.h" | |
70 | #include "buf.h" | |
71 | #include "protosw.h" | |
72 | #include "socket.h" | |
73 | #include "vmmac.h" | |
a0c9a57d MK |
74 | |
75 | #include "../net/if.h" | |
76 | #include "../netimp/if_imp.h" | |
77 | ||
78 | #include "../vax/cpu.h" | |
79 | #include "../vax/mtpr.h" | |
a0c9a57d MK |
80 | #include "../vaxuba/ubareg.h" |
81 | #include "../vaxuba/ubavar.h" | |
82 | ||
e6dd5973 MK |
83 | #include "if_hdhreg.h" |
84 | #include "if_uba.h" | |
85 | ||
a0c9a57d MK |
86 | int hdhprobe(), hdhattach(), hdhrint(), hdhxint(); |
87 | struct uba_device *hdhinfo[NHDH]; | |
88 | u_short hdhstd[] = { 0 }; | |
89 | struct uba_driver hdhdriver = | |
90 | { hdhprobe, 0, hdhattach, 0, hdhstd, "hdh", hdhinfo }; | |
91 | ||
92 | #define HDHUNIT(x) minor(x) | |
93 | ||
94 | int hdhinit(), hdhstart(), hdhreset(); | |
95 | ||
96 | /* | |
97 | * "Lower half" of IMP interface driver. | |
98 | * | |
99 | * Each IMP interface is handled by a common module which handles | |
100 | * the IMP-host protocol and a hardware driver which manages the | |
101 | * hardware specific details of talking with the IMP. | |
102 | * | |
103 | * The hardware portion of the IMP driver handles DMA and related | |
104 | * management of UNIBUS resources. The IMP protocol module interprets | |
105 | * contents of these messages and "controls" the actions of the | |
106 | * hardware module during IMP resets, but not, for instance, during | |
107 | * UNIBUS resets. | |
108 | * | |
109 | * The two modules are coupled at "attach time", and ever after, | |
110 | * through the imp interface structure. Higher level protocols, | |
111 | * e.g. IP, interact with the IMP driver, rather than the HDH. | |
112 | */ | |
113 | ||
114 | #define NHDHCH 2 /* no. of FDX channels for HDH */ | |
115 | #define SUPR 0 /* supervisor channel */ | |
116 | #define DATA 1 /* data channel */ | |
117 | #define HDHSUPR 0 /* supervisor read */ | |
118 | #define HDHSUPW 1 /* supervisor write */ | |
119 | #define HDHDATR 2 /* data read */ | |
120 | #define HDHDATW 3 /* data write */ | |
121 | ||
122 | #define HDH_UP 2 /* HDH protocol is up */ | |
123 | #define HDH_STARTED 1 /* HDH has been initialized */ | |
124 | ||
125 | #define HCBUSY 1 /* HDH HDX channel busy flag */ | |
126 | ||
127 | /* | |
128 | /* The IF-11/HDH has four independent dath flow channels between the | |
129 | /* front-end and the host. Two are used for reading and writing | |
130 | /* control messages and two are used for data flow. Each IF-11/HDH | |
131 | /* has a device dependent data structure (hdh_softc) which contains | |
132 | /* an array of four channel dependent structures (hdh_chan) to maintain | |
133 | /* the context of each channel. Channel structures can be linked into | |
134 | /* a queue of I/O requests pending for the hardware interface. | |
135 | /* UNIBUS mapping resources are allocated for each channel pair. | |
136 | */ | |
137 | ||
138 | struct hdh_chan { /* HDH HDX channel structure */ | |
139 | struct hdh_chan *hc_next; /* link for Start I/O queuing */ | |
140 | char hc_chan; /* HDX chan number */ | |
141 | char hc_adx; /* extended UNIBUS address bits */ | |
142 | short hc_addr; /* lower UNIBUS address bits */ | |
143 | short hc_cnt; /* byte count */ | |
144 | char hc_func; /* UMC I/O function */ | |
145 | char hc_sbfc; /* UMC I/O subfunction */ | |
146 | short hc_flags; /* status flags */ | |
147 | }; | |
148 | ||
149 | struct hdh_sioq { /* Start I/O queue head structure */ | |
150 | struct hdh_chan *sioq_head; /* pointer to queue head */ | |
151 | struct hdh_chan *sioq_tail; /* pointer to queue tail */ | |
152 | }; | |
153 | ||
154 | struct hdh_softc { /* HDH device dependent structure */ | |
155 | struct ifnet *hdh_if; /* pointer to IMP's ifnet struct */ | |
156 | struct impcb *hdh_ic; /* data structure shared with IMP */ | |
157 | struct ifuba hdh_ifuba[NHDHCH]; /* UNIBUS resources */ | |
158 | struct hdh_chan hdh_chan[2*NHDHCH]; /* HDX HDH channels */ | |
159 | struct hdh_sioq hdh_sioq; /* start i/o queue */ | |
160 | short hdh_flags; /* various status conditions */ | |
161 | } hdh_softc[NHDH]; | |
162 | ||
163 | ||
164 | /* | |
165 | * Normally, code goes here to cause the device to interrupt to determine its | |
166 | * interrupt vector. However, since the UMC must be told its vector in order | |
167 | * to interrupt, we allocate and return an unused vector and initialize the | |
168 | * UMC. | |
169 | */ | |
170 | hdhprobe(reg) | |
171 | caddr_t reg; | |
172 | { | |
173 | register int br, cvec; | |
174 | struct hdhregs *addr = (struct hdhregs *)reg; | |
175 | #ifdef lint | |
176 | br = 0; cvec = br; br = cvec; | |
177 | #endif | |
178 | ||
179 | br = 0x15; /* priority 21 (5 on UNIBUS) */ | |
180 | ||
181 | #ifdef HDHDEBUG | |
182 | cvec = 0270; /* use constant for now ... */ | |
183 | #else | |
184 | ||
185 | #ifdef VAXVMS /* if VMS */ | |
186 | cvec = 0270; /* we can't allocate vectors */ | |
187 | #else | |
188 | cvec = (uba_hd[numuba].uh_lastiv -= 4); /* available vector */ | |
189 | #endif VAXVMS | |
190 | ||
191 | #endif HDHDEBUG | |
192 | ||
193 | addr->ioini = (char) 0; /* init UMC regs */ | |
194 | addr->staack = (char) 0; /* pass vector */ | |
195 | addr->ionmi = (char) 0; /* and kick UMC */ | |
196 | addr->iochn = (char) (cvec >> 2); | |
197 | addr->csr = (short) HDH_RST; | |
198 | addr->csr = (short) (HDH_IEN|HDH_DMA|HDH_WRT); /* set enables */ | |
199 | DELAY(5000); /* give the UMC some time */ | |
200 | return(1); | |
201 | } | |
202 | ||
203 | /* | |
204 | * Call the IMP module to allow it to set up its internal | |
205 | * state, then tie the two modules together by setting up | |
206 | * the back pointers to common data structures. | |
207 | */ | |
208 | hdhattach(ui) | |
209 | struct uba_device *ui; | |
210 | { | |
211 | register struct hdh_softc *sc = &hdh_softc[ui->ui_unit]; | |
212 | register struct impcb *ip; | |
213 | struct ifimpcb { | |
214 | struct ifnet ifimp_if; | |
215 | struct impcb ifimp_impcb; | |
216 | } *ifimp; | |
217 | ||
218 | if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0) | |
e6dd5973 | 219 | return;; |
a0c9a57d MK |
220 | sc->hdh_if = &ifimp->ifimp_if; |
221 | ip = &ifimp->ifimp_impcb; | |
222 | sc->hdh_ic = ip; | |
223 | ip->ic_init = hdhinit; | |
224 | ip->ic_start = hdhstart; | |
225 | sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT; | |
226 | } | |
227 | ||
228 | /* | |
229 | * Reset interface after UNIBUS reset. | |
230 | */ | |
231 | hdhreset(unit, uban) | |
232 | int unit, uban; | |
233 | { | |
234 | register struct uba_device *ui = hdhinfo[unit]; | |
235 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
236 | ||
237 | #ifdef HDHDEBUG | |
238 | printf("HDH RESET\n"); | |
239 | #endif HDHDEBUG | |
240 | ||
241 | if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0) | |
242 | || (ui->ui_ubanum != uban)) | |
243 | return; | |
244 | printf(" hdh%d", unit); | |
e6dd5973 MK |
245 | sc->hdh_if->if_flags &= ~IFF_RUNNING; |
246 | sc->hdh_flags = 0; | |
a0c9a57d MK |
247 | (*sc->hdh_if->if_init)(unit); |
248 | } | |
249 | ||
250 | /* | |
251 | * Initialize the imp interface. | |
252 | */ | |
253 | ||
254 | static char init_blk[] = | |
255 | { | |
256 | HDHINIT, /* SYSINIT opcode */ | |
257 | HDHRQUP & 0xff, /* control code (LSB) */ | |
258 | (HDHRQUP>>8) & 0xff, /* control code (MSB) */ | |
259 | 10, /* command extension len */ | |
260 | 0, /* loopback mode (off) */ | |
261 | 3, /* our address (3=DTE) */ | |
262 | 1, /* their address (1=DCE) */ | |
263 | 3, /* frame ack t1 timeout */ | |
264 | 3, /* poll ack timeout */ | |
265 | 30, /* adm wait timeout */ | |
266 | 3, /* rej wait timeout */ | |
267 | 10, /* max retries */ | |
268 | 3, /* watchdog timeout */ | |
269 | 0xaa /* baud rate (0xaa=38.4KB) */ | |
270 | /* (output on RS-232 pin 24, */ | |
271 | /* send/receive timing is always */ | |
272 | /* taken from pins 15/17) */ | |
273 | }; | |
274 | ||
275 | hdhinit(unit) | |
276 | int unit; | |
277 | { | |
278 | register struct hdh_softc *sc; | |
279 | register struct hdhregs *addr; | |
280 | register struct uba_device *ui; | |
281 | register struct umc_chan *up; | |
282 | register struct mbuf *m, *n; | |
283 | int i, s, ubano; | |
284 | ||
285 | #ifdef HDHDEBUG | |
286 | printf("HDH INIT\n"); | |
287 | #endif HDHDEBUG | |
288 | ||
289 | if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL | |
290 | || ui->ui_alive == 0) { | |
291 | printf("hdh%d: not alive\n", unit); | |
292 | return(0); | |
293 | } | |
294 | addr = (struct hdhregs *)ui->ui_addr; | |
295 | sc = &hdh_softc[unit]; | |
296 | ||
e6dd5973 | 297 | if (sc->hdh_flags & HDH_STARTED) |
a0c9a57d | 298 | return(1); |
a0c9a57d MK |
299 | |
300 | /* | |
301 | * Alloc uba resources | |
302 | */ | |
303 | for(i=0;i<NHDHCH;i++) { | |
304 | if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0, | |
305 | (int)btoc(IMPMTU)) == 0) { | |
306 | printf("hdh%d: cannot get chan %d uba resources\n", | |
307 | unit, i); | |
308 | ui->ui_alive = 0; | |
309 | return(0); | |
310 | } | |
311 | } | |
312 | ||
e6dd5973 | 313 | sc->hdh_if->if_flags |= IFF_RUNNING; |
a0c9a57d MK |
314 | sc->hdh_flags = HDH_STARTED; |
315 | ||
316 | /* | |
317 | * hang a supervisor read (for line status) | |
318 | */ | |
319 | hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB); | |
320 | ||
321 | /* | |
322 | * hang a data read | |
323 | */ | |
324 | hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR); | |
325 | ||
326 | /* | |
327 | * bring up line to IMP | |
328 | */ | |
329 | ||
330 | snd_supr(unit, init_blk, sizeof(init_blk)); | |
331 | ||
332 | return(1); | |
333 | } | |
334 | ||
335 | /* | |
336 | * Start an output operation on an mbuf. | |
337 | */ | |
338 | hdhstart(dev) | |
339 | dev_t dev; | |
340 | { | |
341 | int unit = HDHUNIT(dev); | |
342 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
343 | register struct mbuf *m; | |
344 | int len; | |
345 | ||
346 | /* | |
347 | * If output isn't active, attempt to | |
348 | * start sending a new packet. | |
349 | */ | |
350 | ||
351 | if (sc->hdh_ic->ic_oactive) { | |
352 | printf("hdh%d: start on active unit\n", unit); | |
353 | return; | |
354 | } | |
355 | ||
356 | if ((sc->hdh_flags & HDH_UP) == 0) { | |
357 | sc->hdh_ic->ic_oactive = 0; /* Link not up, can't xmit */ | |
358 | return; | |
359 | } | |
360 | ||
361 | IF_DEQUEUE(&sc->hdh_if->if_snd, m); | |
362 | if (m == 0) { | |
363 | sc->hdh_ic->ic_oactive = 0; | |
364 | return; | |
365 | } | |
366 | ||
367 | len = if_wubaput(&sc->hdh_ifuba[DATA], m); /* copy data to mapped mem */ | |
368 | sc->hdh_ic->ic_oactive = 1; | |
369 | ||
370 | hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS); | |
371 | } | |
372 | ||
373 | /* | |
374 | * Start i/o operation on a UMC logical channel | |
375 | */ | |
376 | hdh_iorq(unit, lcn, len, func) | |
377 | int unit, lcn, len, func; | |
378 | { | |
379 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
380 | register struct hdh_chan *hc = &sc->hdh_chan[lcn]; | |
381 | register int info, s; | |
382 | ||
383 | /* | |
384 | * If channel is busy (shouldn't be), drop. | |
385 | */ | |
386 | if (hc->hc_flags & HCBUSY) { | |
387 | printf("hdh%d: channel busy lcn=%d\n", unit, lcn); | |
388 | return; | |
389 | } | |
390 | ||
391 | /* get appropriate UNIBUS mapping info */ | |
392 | ||
393 | if (lcn & 1) /* read or write? */ | |
394 | info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info; | |
395 | else | |
396 | info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info; | |
397 | ||
398 | /* set channel info */ | |
399 | ||
400 | hc->hc_flags |= HCBUSY; | |
401 | hc->hc_chan = lcn; | |
402 | hc->hc_adx = (char)((info & 0x30000) >> 12); | |
403 | hc->hc_addr = (unsigned short)(info & 0xffff); | |
404 | hc->hc_cnt = len; | |
405 | hc->hc_func = (char)func; | |
406 | hc->hc_sbfc = 0; | |
407 | ||
408 | s = splimp(); | |
409 | /* | |
410 | * If UMC comm regs busy, queue start i/o for later. | |
411 | */ | |
412 | if (sc->hdh_sioq.sioq_head) { | |
413 | (sc->hdh_sioq.sioq_tail)->hc_next = hc; | |
414 | sc->hdh_sioq.sioq_tail = hc; | |
415 | hc->hc_next = 0; | |
416 | splx(s); | |
417 | return; | |
418 | } | |
419 | ||
420 | /* start i/o on channel now */ | |
421 | ||
422 | sc->hdh_sioq.sioq_head = hc; | |
423 | sc->hdh_sioq.sioq_tail = hc; | |
424 | hc->hc_next = 0; | |
425 | start_chn(unit); | |
426 | splx(s); | |
427 | } | |
428 | ||
429 | start_chn(unit) | |
430 | int unit; | |
431 | { | |
432 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
433 | register struct hdh_chan *hc = sc->hdh_sioq.sioq_head; | |
434 | register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; | |
435 | ||
436 | /* | |
437 | * Set up comm regs. | |
438 | */ | |
439 | addr->iochn = hc->hc_chan; | |
440 | addr->ioadx = hc->hc_adx; | |
441 | addr->ioadl = hc->hc_addr; | |
442 | addr->iocnt = hc->hc_cnt; | |
443 | addr->iofcn = hc->hc_func; | |
444 | addr->iosbf = hc->hc_sbfc; | |
445 | addr->ioini = 1; | |
446 | ||
447 | /* signal UMC if necessary */ | |
448 | ||
449 | if (!(addr->ionmi)) { | |
450 | addr->ionmi = 1; | |
451 | addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; | |
452 | } | |
453 | } | |
454 | ||
455 | /* | |
456 | * IF-11/HDH interrupt handler | |
457 | */ | |
458 | hdhintr(unit) | |
459 | int unit; | |
460 | { | |
461 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
462 | register struct hdh_chan *hc; | |
463 | register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr; | |
464 | register struct mbuf *m; | |
465 | int lcn, type, cc, cnt, s; | |
466 | ||
467 | /* | |
468 | * Check for hardware errors. | |
469 | */ | |
470 | if (addr->csr & HDH_UER) { | |
471 | printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS); | |
472 | addr->csr = 0; /* disable i/f */ | |
473 | return; | |
474 | } | |
475 | /* | |
476 | * Get logical channel info. | |
477 | */ | |
478 | if ((lcn = addr->stachn) >= (NHDHCH*2)) { | |
479 | printf("hdh%d: unknown channel lcn=%d\n", unit, lcn); | |
480 | return; | |
481 | } | |
482 | ||
483 | hc = &sc->hdh_chan[lcn]; | |
484 | ||
485 | type = addr->statyp; | |
486 | cc = addr->stacc; | |
487 | cnt = hc->hc_cnt - addr->stacnt; | |
488 | ||
489 | /* Figure out what kind of interrupt it was */ | |
490 | ||
491 | switch(type) { | |
492 | ||
493 | case HDHSACK: /* start i/o accepted */ | |
494 | if (hc != sc->hdh_sioq.sioq_head) { | |
495 | printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n", | |
496 | unit, lcn, hc, sc->hdh_sioq.sioq_head); | |
497 | return; | |
498 | } | |
499 | ||
500 | /* try to start any queued i/o request */ | |
501 | ||
502 | if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) { | |
503 | start_chn(unit); | |
504 | } | |
505 | break; | |
506 | ||
507 | case HDHDONE: /* i/o completion */ | |
508 | switch (cc) { | |
509 | ||
510 | case HDHIOCABT: | |
511 | printf("hdh%d: I/O abort ", unit); | |
512 | goto daterr; | |
513 | ||
514 | case HDHIOCERR: | |
515 | printf("hdh%d: program error ", unit); | |
516 | goto daterr; | |
517 | ||
518 | case HDHIOCOVR: | |
519 | printf("hdh%d: overrun error ", unit); | |
520 | goto daterr; | |
521 | ||
522 | case HDHIOCUBE: | |
523 | printf("hdh%d: NXM timeout or UB parity error ", unit); | |
524 | ||
525 | daterr: | |
526 | printf("lcn=%d func=%x\n", lcn, hc->hc_func); | |
527 | if (hc->hc_func & HDHRDB) | |
528 | sc->hdh_if->if_ierrors++; | |
529 | else | |
530 | sc->hdh_if->if_oerrors++; | |
531 | } | |
532 | ||
533 | hc->hc_flags &= ~HCBUSY; | |
534 | ||
535 | /* was it supervisor or data traffic? */ | |
536 | ||
537 | if (lcn > HDHSUPW) | |
538 | hdh_data(unit, lcn, cc, cnt); | |
539 | else | |
540 | hdh_supr(unit, lcn, cc, cnt); | |
541 | ||
542 | } | |
543 | ||
544 | /* | |
545 | * Ack the interrupt | |
546 | */ | |
547 | addr->staack = 1; | |
548 | if (!(addr->ionmi)) { | |
549 | addr->ionmi = 1; | |
550 | addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI; | |
551 | } | |
552 | } | |
553 | ||
554 | /* | |
555 | * data channel interrupt completion handler | |
556 | */ | |
557 | hdh_data(unit, lcn, cc, rcnt) | |
558 | int unit, lcn, cc, rcnt; | |
559 | { | |
560 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
561 | register struct hdh_chan *hc = &sc->hdh_chan[lcn]; | |
562 | register struct mbuf *m; | |
563 | ||
564 | ||
565 | /* was it read or write? */ | |
566 | ||
567 | if (hc->hc_func & HDHRDB) { | |
568 | if (cc == HDHIOCOK) { | |
569 | /* | |
570 | * Queue good packet for input | |
571 | */ | |
572 | sc->hdh_if->if_ipackets++; | |
e6dd5973 MK |
573 | m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0, |
574 | sc->hdh_if); | |
a0c9a57d MK |
575 | impinput(unit, m); |
576 | } | |
577 | ||
578 | /* hang a new data read */ | |
579 | ||
580 | hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR); | |
581 | ||
582 | } else { | |
583 | /* | |
584 | * fire up next output | |
585 | */ | |
586 | sc->hdh_if->if_opackets++; | |
587 | sc->hdh_ic->ic_oactive = 0; | |
588 | hdhstart(unit); | |
589 | } | |
590 | } | |
591 | ||
592 | /* | |
593 | * supervisor channel interrupt completion handler | |
594 | */ | |
595 | hdh_supr(unit, lcn, cc, rcnt) | |
596 | int unit, lcn, cc, rcnt; | |
597 | { | |
598 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
599 | register struct hdh_chan *hc = &sc->hdh_chan[lcn]; | |
600 | register struct uba_device *ui; | |
601 | short *p; | |
602 | int i; | |
603 | ||
604 | ||
605 | /* was it read or write? */ | |
606 | ||
607 | if (hc->hc_func & HDHRDB) { | |
608 | if (cc == HDHIOCOK) { | |
609 | p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr); | |
610 | ||
611 | /* figure out what kind of supervisor message */ | |
612 | ||
613 | switch (*p) { | |
614 | ||
615 | case HDHIACK: | |
616 | case HDHLNACK: | |
617 | break; | |
618 | ||
619 | case HDHLNUP: | |
620 | printf("hdh%d: LINE UP\n", unit); | |
621 | sc->hdh_flags |= HDH_UP; | |
622 | hdhstart(unit); | |
623 | break; | |
624 | ||
625 | case HDHLNDN: | |
626 | if (sc->hdh_flags & HDH_UP) | |
627 | printf("hdh%d: LINE DOWN\n", unit); | |
628 | sc->hdh_flags &= ~HDH_UP; | |
629 | break; | |
630 | ||
631 | case HDHLOOP: | |
632 | break; | |
633 | ||
634 | case HDHSQERR: | |
635 | printf("hdh%d: HOST SEQUENCE ERROR\n", unit); | |
636 | break; | |
637 | ||
638 | case HDHSQRCV: | |
639 | printf("hdh%d: IMP SEQUENCE ERROR\n", unit); | |
640 | break; | |
641 | ||
642 | case HDHDTERR: | |
643 | printf("hdh%d: HOST DATA ERROR\n", unit); | |
644 | break; | |
645 | ||
646 | case HDHTIMO: | |
647 | printf("hdh%d: TIMEOUT\n", unit); | |
648 | break; | |
649 | ||
650 | default: | |
651 | printf("hdh%d: supervisor error, code=%x\n", | |
652 | unit, *p); | |
653 | } | |
654 | } | |
655 | ||
656 | /* hang a new supr read */ | |
657 | ||
658 | hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR); | |
659 | } | |
660 | } | |
661 | ||
662 | snd_supr(unit, msg, len) | |
663 | int unit, len; | |
664 | char *msg; | |
665 | { | |
666 | register struct hdh_softc *sc = &hdh_softc[unit]; | |
667 | register struct hdh_chan *hc = &sc->hdh_chan[HDHSUPW]; | |
668 | register struct mbuf *m; | |
669 | register char *p; | |
670 | register int cnt; | |
671 | ||
672 | if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) { | |
673 | printf("hdh%d: cannot get supervisor cmnd buffer\n", unit); | |
674 | return(0); | |
675 | } | |
676 | ||
677 | cnt = len; | |
678 | m->m_len = len; | |
679 | p = mtod(m, char *); | |
680 | ||
681 | while(cnt--) *p++ = *msg++; | |
682 | ||
683 | cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m); | |
684 | ||
685 | hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS); | |
686 | ||
687 | return(1); | |
688 | } | |
689 | ||
690 | #endif NHDH |