|
|
1.1 root 1: /* @(#)if_hdh.c 7.5 (Berkeley) 5/26/88 */
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 "param.h"
67: #include "systm.h"
68: #include "mbuf.h"
69: #include "buf.h"
70: #include "protosw.h"
71: #include "socket.h"
72: #include "vmmac.h"
73:
74: #include "../machine/pte.h"
75:
76: #include "../net/if.h"
77: #include "../netimp/if_imp.h"
78:
79: #include "../vax/cpu.h"
80: #include "../vax/mtpr.h"
81: #include "../vaxuba/ubareg.h"
82: #include "../vaxuba/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: */
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: */
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: */
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:
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: */
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: */
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:
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: */
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: */
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: */
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:
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.