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