|
|
1.1 root 1: /* @(#)if_hdh.c 7.1 (Berkeley) 6/5/86 */
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:
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"
74:
75: #include "../net/if.h"
76: #include "../netimp/if_imp.h"
77:
78: #include "../vax/cpu.h"
79: #include "../vax/mtpr.h"
80: #include "../vaxuba/ubareg.h"
81: #include "../vaxuba/ubavar.h"
82:
83: #include "if_hdhreg.h"
84: #include "if_uba.h"
85:
86: int hdhprobe(), hdhattach(), hdhintr();
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: 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: struct uba_device *ui;
211: {
212: register struct hdh_softc *sc = &hdh_softc[ui->ui_unit];
213: register struct impcb *ip;
214: struct ifimpcb {
215: struct ifnet ifimp_if;
216: struct impcb ifimp_impcb;
217: } *ifimp;
218:
219: if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0)
220: return;;
221: sc->hdh_if = &ifimp->ifimp_if;
222: ip = &ifimp->ifimp_impcb;
223: sc->hdh_ic = ip;
224: ip->ic_init = hdhinit;
225: ip->ic_start = hdhstart;
226: sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT;
227: }
228:
229: /*
230: * Reset interface after UNIBUS reset.
231: */
232: hdhreset(unit, uban)
233: int unit, uban;
234: {
235: register struct uba_device *ui = hdhinfo[unit];
236: register struct hdh_softc *sc = &hdh_softc[unit];
237:
238: #ifdef HDHDEBUG
239: printf("HDH RESET\n");
240: #endif HDHDEBUG
241:
242: if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0)
243: || (ui->ui_ubanum != uban))
244: return;
245: printf(" hdh%d", unit);
246: sc->hdh_if->if_flags &= ~IFF_RUNNING;
247: sc->hdh_flags = 0;
248: (*sc->hdh_if->if_init)(unit);
249: }
250:
251: /*
252: * Initialize the imp interface.
253: */
254:
255: static char init_blk[] =
256: {
257: HDHINIT, /* SYSINIT opcode */
258: HDHRQUP & 0xff, /* control code (LSB) */
259: (HDHRQUP>>8) & 0xff, /* control code (MSB) */
260: 10, /* command extension len */
261: 0, /* loopback mode (off) */
262: 3, /* our address (3=DTE) */
263: 1, /* their address (1=DCE) */
264: 3, /* frame ack t1 timeout */
265: 3, /* poll ack timeout */
266: 30, /* adm wait timeout */
267: 3, /* rej wait timeout */
268: 10, /* max retries */
269: 3, /* watchdog timeout */
270: 0xaa /* baud rate (0xaa=38.4KB) */
271: /* (output on RS-232 pin 24, */
272: /* send/receive timing is always */
273: /* taken from pins 15/17) */
274: };
275:
276: hdhinit(unit)
277: int unit;
278: {
279: register struct hdh_softc *sc;
280: register struct uba_device *ui;
281: int i;
282:
283: #ifdef HDHDEBUG
284: printf("HDH INIT\n");
285: #endif HDHDEBUG
286:
287: if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
288: || ui->ui_alive == 0) {
289: printf("hdh%d: not alive\n", unit);
290: return(0);
291: }
292: sc = &hdh_softc[unit];
293:
294: if (sc->hdh_flags & HDH_STARTED)
295: return(1);
296:
297: /*
298: * Alloc uba resources
299: */
300: for(i=0;i<NHDHCH;i++) {
301: if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
302: (int)btoc(IMPMTU)) == 0) {
303: printf("hdh%d: cannot get chan %d uba resources\n",
304: unit, i);
305: ui->ui_alive = 0;
306: return(0);
307: }
308: }
309:
310: sc->hdh_if->if_flags |= IFF_RUNNING;
311: sc->hdh_flags = HDH_STARTED;
312:
313: /*
314: * hang a supervisor read (for line status)
315: */
316: hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB);
317:
318: /*
319: * hang a data read
320: */
321: hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR);
322:
323: /*
324: * bring up line to IMP
325: */
326:
327: snd_supr(unit, init_blk, sizeof(init_blk));
328:
329: return(1);
330: }
331:
332: /*
333: * Start an output operation on an mbuf.
334: */
335: hdhstart(dev)
336: dev_t dev;
337: {
338: int unit = HDHUNIT(dev);
339: register struct hdh_softc *sc = &hdh_softc[unit];
340: register struct mbuf *m;
341: int len;
342:
343: /*
344: * If output isn't active, attempt to
345: * start sending a new packet.
346: */
347:
348: if (sc->hdh_ic->ic_oactive) {
349: printf("hdh%d: start on active unit\n", unit);
350: return;
351: }
352:
353: if ((sc->hdh_flags & HDH_UP) == 0) {
354: sc->hdh_ic->ic_oactive = 0; /* Link not up, can't xmit */
355: return;
356: }
357:
358: IF_DEQUEUE(&sc->hdh_if->if_snd, m);
359: if (m == 0) {
360: sc->hdh_ic->ic_oactive = 0;
361: return;
362: }
363:
364: len = if_wubaput(&sc->hdh_ifuba[DATA], m); /* copy data to mapped mem */
365: sc->hdh_ic->ic_oactive = 1;
366:
367: hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
368: }
369:
370: /*
371: * Start i/o operation on a UMC logical channel
372: */
373: hdh_iorq(unit, lcn, len, func)
374: int unit, lcn, len, func;
375: {
376: register struct hdh_softc *sc = &hdh_softc[unit];
377: register struct hdh_chan *hc = &sc->hdh_chan[lcn];
378: register int info, s;
379:
380: /*
381: * If channel is busy (shouldn't be), drop.
382: */
383: if (hc->hc_flags & HCBUSY) {
384: printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
385: return;
386: }
387:
388: /* get appropriate UNIBUS mapping info */
389:
390: if (lcn & 1) /* read or write? */
391: info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
392: else
393: info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
394:
395: /* set channel info */
396:
397: hc->hc_flags |= HCBUSY;
398: hc->hc_chan = lcn;
399: hc->hc_adx = (char)((info & 0x30000) >> 12);
400: hc->hc_addr = (unsigned short)(info & 0xffff);
401: hc->hc_cnt = len;
402: hc->hc_func = (char)func;
403: hc->hc_sbfc = 0;
404:
405: s = splimp();
406: /*
407: * If UMC comm regs busy, queue start i/o for later.
408: */
409: if (sc->hdh_sioq.sioq_head) {
410: (sc->hdh_sioq.sioq_tail)->hc_next = hc;
411: sc->hdh_sioq.sioq_tail = hc;
412: hc->hc_next = 0;
413: splx(s);
414: return;
415: }
416:
417: /* start i/o on channel now */
418:
419: sc->hdh_sioq.sioq_head = hc;
420: sc->hdh_sioq.sioq_tail = hc;
421: hc->hc_next = 0;
422: start_chn(unit);
423: splx(s);
424: }
425:
426: start_chn(unit)
427: int unit;
428: {
429: register struct hdh_softc *sc = &hdh_softc[unit];
430: register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
431: register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
432:
433: /*
434: * Set up comm regs.
435: */
436: addr->iochn = hc->hc_chan;
437: addr->ioadx = hc->hc_adx;
438: addr->ioadl = hc->hc_addr;
439: addr->iocnt = hc->hc_cnt;
440: addr->iofcn = hc->hc_func;
441: addr->iosbf = hc->hc_sbfc;
442: addr->ioini = 1;
443:
444: /* signal UMC if necessary */
445:
446: if (!(addr->ionmi)) {
447: addr->ionmi = 1;
448: addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
449: }
450: }
451:
452: /*
453: * IF-11/HDH interrupt handler
454: */
455: hdhintr(unit)
456: int unit;
457: {
458: register struct hdh_softc *sc = &hdh_softc[unit];
459: register struct hdh_chan *hc;
460: register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
461: int lcn, type, cc, cnt;
462:
463: /*
464: * Check for hardware errors.
465: */
466: if (addr->csr & HDH_UER) {
467: printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
468: addr->csr = 0; /* disable i/f */
469: return;
470: }
471: /*
472: * Get logical channel info.
473: */
474: if ((lcn = addr->stachn) >= (NHDHCH*2)) {
475: printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
476: return;
477: }
478:
479: hc = &sc->hdh_chan[lcn];
480:
481: type = addr->statyp;
482: cc = addr->stacc;
483: cnt = hc->hc_cnt - addr->stacnt;
484:
485: /* Figure out what kind of interrupt it was */
486:
487: switch(type) {
488:
489: case HDHSACK: /* start i/o accepted */
490: if (hc != sc->hdh_sioq.sioq_head) {
491: printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
492: unit, lcn, hc, sc->hdh_sioq.sioq_head);
493: return;
494: }
495:
496: /* try to start any queued i/o request */
497:
498: if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
499: start_chn(unit);
500: }
501: break;
502:
503: case HDHDONE: /* i/o completion */
504: switch (cc) {
505:
506: case HDHIOCABT:
507: printf("hdh%d: I/O abort ", unit);
508: goto daterr;
509:
510: case HDHIOCERR:
511: printf("hdh%d: program error ", unit);
512: goto daterr;
513:
514: case HDHIOCOVR:
515: printf("hdh%d: overrun error ", unit);
516: goto daterr;
517:
518: case HDHIOCUBE:
519: printf("hdh%d: NXM timeout or UB parity error ", unit);
520:
521: daterr:
522: printf("lcn=%d func=%x\n", lcn, hc->hc_func);
523: if (hc->hc_func & HDHRDB)
524: sc->hdh_if->if_ierrors++;
525: else
526: sc->hdh_if->if_oerrors++;
527: }
528:
529: hc->hc_flags &= ~HCBUSY;
530:
531: /* was it supervisor or data traffic? */
532:
533: if (lcn > HDHSUPW)
534: hdh_data(unit, lcn, cc, cnt);
535: else
536: hdh_supr(unit, lcn, cc);
537:
538: }
539:
540: /*
541: * Ack the interrupt
542: */
543: addr->staack = 1;
544: if (!(addr->ionmi)) {
545: addr->ionmi = 1;
546: addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
547: }
548: }
549:
550: /*
551: * data channel interrupt completion handler
552: */
553: hdh_data(unit, lcn, cc, rcnt)
554: int unit, lcn, cc, rcnt;
555: {
556: register struct hdh_softc *sc = &hdh_softc[unit];
557: register struct hdh_chan *hc = &sc->hdh_chan[lcn];
558: register struct mbuf *m;
559:
560:
561: /* was it read or write? */
562:
563: if (hc->hc_func & HDHRDB) {
564: if (cc == HDHIOCOK) {
565: /*
566: * Queue good packet for input
567: */
568: sc->hdh_if->if_ipackets++;
569: m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
570: sc->hdh_if);
571: impinput(unit, m);
572: }
573:
574: /* hang a new data read */
575:
576: hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR);
577:
578: } else {
579: /*
580: * fire up next output
581: */
582: sc->hdh_if->if_opackets++;
583: sc->hdh_ic->ic_oactive = 0;
584: hdhstart(unit);
585: }
586: }
587:
588: /*
589: * supervisor channel interrupt completion handler
590: */
591: hdh_supr(unit, lcn, cc)
592: int unit, lcn, cc;
593: {
594: register struct hdh_softc *sc = &hdh_softc[unit];
595: register struct hdh_chan *hc = &sc->hdh_chan[lcn];
596: short *p;
597:
598:
599: /* was it read or write? */
600:
601: if (hc->hc_func & HDHRDB) {
602: if (cc == HDHIOCOK) {
603: p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
604:
605: /* figure out what kind of supervisor message */
606:
607: switch (*p) {
608:
609: case HDHIACK:
610: case HDHLNACK:
611: break;
612:
613: case HDHLNUP:
614: printf("hdh%d: LINE UP\n", unit);
615: sc->hdh_flags |= HDH_UP;
616: hdhstart(unit);
617: break;
618:
619: case HDHLNDN:
620: if (sc->hdh_flags & HDH_UP)
621: printf("hdh%d: LINE DOWN\n", unit);
622: sc->hdh_flags &= ~HDH_UP;
623: break;
624:
625: case HDHLOOP:
626: break;
627:
628: case HDHSQERR:
629: printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
630: break;
631:
632: case HDHSQRCV:
633: printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
634: break;
635:
636: case HDHDTERR:
637: printf("hdh%d: HOST DATA ERROR\n", unit);
638: break;
639:
640: case HDHTIMO:
641: printf("hdh%d: TIMEOUT\n", unit);
642: break;
643:
644: default:
645: printf("hdh%d: supervisor error, code=%x\n",
646: unit, *p);
647: }
648: }
649:
650: /* hang a new supr read */
651:
652: hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR);
653: }
654: }
655:
656: snd_supr(unit, msg, len)
657: int unit, len;
658: char *msg;
659: {
660: register struct hdh_softc *sc = &hdh_softc[unit];
661: register struct mbuf *m;
662: register char *p;
663: register int cnt;
664:
665: if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
666: printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
667: return;
668: }
669:
670: cnt = len;
671: m->m_len = len;
672: p = mtod(m, char *);
673:
674: while(cnt--) *p++ = *msg++;
675:
676: cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
677:
678: hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
679: }
680: #endif NHDH
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.