|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Excelan Inc.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)if_ex.c 7.9 (Berkeley) 12/16/90
37: */
38:
39: #include "ex.h"
40: #if NEX > 0
41:
42: /*
43: * Excelan EXOS 204 Interface
44: *
45: * George Powers
46: * Excelan Inc.
47: */
48:
49: #include "sys/param.h"
50: #include "sys/systm.h"
51: #include "sys/mbuf.h"
52: #include "sys/buf.h"
53: #include "sys/protosw.h"
54: #include "sys/socket.h"
55: #include "sys/vmmac.h"
56: #include "sys/ioctl.h"
57: #include "sys/syslog.h"
58: #include "sys/errno.h"
59:
60: #include "net/if.h"
61: #include "net/netisr.h"
62: #include "net/route.h"
63:
64: #ifdef INET
65: #include "netinet/in.h"
66: #include "netinet/in_systm.h"
67: #include "netinet/in_var.h"
68: #include "netinet/ip.h"
69: #include "netinet/if_ether.h"
70: #endif
71:
72: #ifdef NS
73: #include "netns/ns.h"
74: #include "netns/ns_if.h"
75: #endif
76:
77: #ifdef ISO
78: #include "netiso/iso.h"
79: #include "netiso/iso_var.h"
80: extern char all_es_snpa[], all_is_snpa[];
81: #endif
82:
83: #include "../include/pte.h"
84: #include "../include/cpu.h"
85: #include "../include/mtpr.h"
86: #include "if_exreg.h"
87: #include "if_uba.h"
88: #include "../uba/ubareg.h"
89: #include "../uba/ubavar.h"
90:
91: /* #define DEBUG /* check for "impossible" events */
92:
93: #define NH2X 4 /* a sufficient number is critical */
94: #define NX2H 4 /* this is pretty arbitrary */
95: #define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */
96:
97: int exprobe(), exattach(), excdint();
98: struct uba_device *exinfo[NEX];
99: u_short exstd[] = { 0 };
100: struct uba_driver exdriver =
101: { exprobe, 0, exattach, 0, exstd, "ex", exinfo };
102: int exinit(),exstart(),ether_output(),exioctl(),exreset(),exwatch();
103: struct ex_msg *exgetcbuf();
104:
105: /*
106: * Ethernet software status per interface.
107: *
108: * Each interface is referenced by a network interface structure,
109: * xs_if, which the routing code uses to locate the interface.
110: * This structure contains the output queue for the interface, its address, ...
111: * We also have, for each interface, a UBA interface structure, which
112: * contains information about the UNIBUS resources held by the interface:
113: * map registers, buffered data paths, etc. Information is cached in this
114: * structure for use by the if_uba.c routines in running the interface
115: * efficiently.
116: */
117: struct ex_softc {
118: struct arpcom xs_ac; /* Ethernet common part */
119: #define xs_if xs_ac.ac_if /* network-visible interface */
120: #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
121: #ifdef DEBUG
122: int xs_wait;
123: #endif
124: struct ifuba xs_ifuba; /* UNIBUS resources */
125: int xs_flags; /* private flags */
126: #define EX_XPENDING 1 /* xmit rqst pending on EXOS */
127: #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */
128: #define EX_RUNNING (1<<2) /* board is running */
129: #define EX_SETADDR (1<<3) /* physaddr has been changed */
130: struct ex_msg *xs_h2xnext; /* host pointer to request queue */
131: struct ex_msg *xs_x2hnext; /* host pointer to reply queue */
132: int xs_ubaddr; /* map info for structs below */
133: #define UNIADDR(x) ((u_long)(x)&0x3FFFF)
134: #define P_UNIADDR(x) ((u_long)(x)&0x3FFF0)
135: /* the following structures are always mapped in */
136: u_short xs_h2xhdr; /* EXOS's request queue header */
137: u_short xs_x2hhdr; /* EXOS's reply queue header */
138: struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */
139: struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */
140: struct confmsg xs_cm; /* configuration message */
141: struct stat_array xs_xsa; /* EXOS writes stats here */
142: /* end mapped area */
143: #define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))
144: #define RVAL_OFF(unit, n) \
145: ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))
146: #define LVAL_OFF(unit, n) \
147: ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))
148: #define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr)
149: #define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr)
150: #define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent)
151: #define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent)
152: #define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm)
153: #define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa)
154: #define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end)
155: int xs_end; /* place holder */
156: } ex_softc[NEX];
157:
158: /*
159: * The following structure is a kludge to store a cvec value
160: * between the time exprobe is called, and exconfig.
161: */
162: struct ex_cvecs {
163: struct exdevice *xc_csraddr;
164: int xc_cvec;
165: }ex_cvecs[NEX];
166:
167: int ex_ncall = 0; /* counts calls to exprobe */
168:
169: exprobe(reg)
170: caddr_t reg;
171: {
172: register int br, cvec; /* r11, r10 value-result */
173: register struct exdevice *addr = (struct exdevice *)reg;
174: register i;
175:
176: /*
177: * We program the EXOS interrupt vector, like dmf device.
178: */
179: br = 0x15;
180: cvec = (uba_hd[numuba].uh_lastiv -= 4);
181: ex_cvecs[ex_ncall].xc_csraddr = addr;
182: ex_cvecs[ex_ncall].xc_cvec = cvec;
183: /*
184: * Reset EXOS and run self-test (guaranteed to
185: * complete within 2 seconds).
186: */
187: addr->xd_porta = EX_RESET;
188: i = 2000;
189: while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
190: DELAY(1000);
191: if ((addr->xd_portb & EX_TESTOK) == 0) {
192: printf("ex: self-test failed\n");
193: return 0;
194: }
195: #ifdef lint
196: br = br;
197: excdint(0);
198: #endif
199: ex_ncall++;
200: return (sizeof(struct exdevice));
201: }
202:
203: /*
204: * Interface exists: make available by filling in network interface
205: * record. System will initialize the interface when it is ready
206: * to accept packets. Board is temporarily configured and issues
207: * a NET_ADDRS command, only to get the Ethernet address.
208: */
209: exattach(ui)
210: register struct uba_device *ui;
211: {
212: register struct ex_softc *xs = &ex_softc[ui->ui_unit];
213: register struct ifnet *ifp = &xs->xs_if;
214: register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
215: register struct ex_msg *bp;
216: int unit = ui->ui_unit;
217: ifp->if_unit = ui->ui_unit;
218: ifp->if_name = "ex";
219: ifp->if_mtu = ETHERMTU;
220:
221: /*
222: * Temporarily map queues in order to configure EXOS
223: */
224: xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
225: INCORE_SIZE(unit), 0);
226: exconfig(ui, 0); /* without interrupts */
227: if (xs->xs_cm.cm_cc) goto badconf;
228:
229: bp = exgetcbuf(xs);
230: bp->mb_rqst = LLNET_ADDRS;
231: bp->mb_na.na_mask = READ_OBJ;
232: bp->mb_na.na_slot = PHYSSLOT;
233: bp->mb_status |= MH_EXOS;
234: addr->xd_portb = EX_NTRUPT;
235: bp = xs->xs_x2hnext;
236: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
237: ;
238: printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n",
239: ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
240: xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
241: ether_sprintf(bp->mb_na.na_addrs));
242: bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
243: sizeof (xs->xs_addr));
244:
245: ifp->if_init = exinit;
246: ifp->if_output = ether_output;
247: ifp->if_start = exstart;
248: ifp->if_ioctl = exioctl;
249: ifp->if_reset = exreset;
250: ifp->if_flags = IFF_BROADCAST;
251: xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
252: if_attach(ifp);
253: badconf:
254: ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
255: }
256:
257: /*
258: * Reset of interface after UNIBUS reset.
259: * If interface is on specified uba, reset its state.
260: */
261: exreset(unit, uban)
262: int unit, uban;
263: {
264: register struct uba_device *ui;
265:
266: if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
267: ui->ui_ubanum != uban)
268: return;
269: printf(" ex%d", unit);
270: ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
271: ex_softc[unit].xs_flags &= ~EX_RUNNING;
272: exinit(unit);
273: }
274:
275: /*
276: * Initialization of interface; clear recorded pending
277: * operations, and reinitialize UNIBUS usage.
278: * Called at boot time (with interrupts disabled?),
279: * and at ifconfig time via exioctl, with interrupts disabled.
280: */
281: exinit(unit)
282: int unit;
283: {
284: register struct ex_softc *xs = &ex_softc[unit];
285: register struct uba_device *ui = exinfo[unit];
286: register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
287: register struct ifnet *ifp = &xs->xs_if;
288: register struct ex_msg *bp;
289: int s;
290:
291: /* not yet, if address still unknown */
292: if (ifp->if_addrlist == (struct ifaddr *)0)
293: return;
294: if (xs->xs_flags & EX_RUNNING)
295: return;
296:
297: if ((ifp->if_flags & IFF_RUNNING) == 0) {
298: if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
299: sizeof (struct ether_header),
300: (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
301: printf("ex%d: can't initialize\n", unit);
302: xs->xs_if.if_flags &= ~IFF_UP;
303: return;
304: }
305: xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
306: INCORE_SIZE(unit), 0);
307: }
308: exconfig(ui, 4); /* with vectored interrupts*/
309: /*
310: * Put EXOS on the Ethernet, using NET_MODE command
311: */
312: bp = exgetcbuf(xs);
313: bp->mb_rqst = LLNET_MODE;
314: bp->mb_nm.nm_mask = WRITE_OBJ;
315: bp->mb_nm.nm_optn = 0;
316: bp->mb_nm.nm_mode = MODE_PERF;
317: bp->mb_status |= MH_EXOS;
318: addr->xd_portb = EX_NTRUPT;
319: bp = xs->xs_x2hnext;
320: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
321: ;
322: bp->mb_length = MBDATALEN;
323: bp->mb_status |= MH_EXOS; /* free up buffer */
324: addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
325: xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
326:
327: ifp->if_watchdog = exwatch;
328: ifp->if_timer = EXWATCHINTVL;
329: s = splimp(); /* are interrupts always disabled here, anyway? */
330: exhangrcv(unit); /* hang receive request */
331: xs->xs_if.if_flags |= IFF_RUNNING;
332: xs->xs_flags |= EX_RUNNING;
333: if (xs->xs_flags & EX_SETADDR)
334: ex_setaddr((u_char *)0, unit);
335: #ifdef ISO
336: ex_setmulti(all_es_snpa, unit, 1);
337: ex_setmulti(all_is_snpa, unit, 2);
338: #endif
339: (void) exstart(&xs->xs_if); /* start transmits */
340: splx(s);
341: }
342:
343: /*
344: * Reset, test, and configure EXOS. This routine assumes
345: * that message queues, etc. have already been mapped into
346: * the UBA. It is called by exinit, and should also be
347: * callable by exattach.
348: */
349: exconfig(ui, itype)
350: struct uba_device *ui;
351: int itype;
352: {
353: register int unit = ui->ui_unit;
354: register struct ex_softc *xs = &ex_softc[unit];
355: register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
356: register struct confmsg *cm = &xs->xs_cm;
357: register struct ex_msg *bp;
358: int i;
359: u_long shiftreg;
360:
361: xs->xs_flags = 0;
362: /*
363: * Reset EXOS, wait for self-test to complete
364: */
365: addr->xd_porta = EX_RESET;
366: while ((addr->xd_portb & EX_TESTOK) == 0)
367: ;
368: /*
369: * Set up configuration message.
370: */
371: cm->cm_1rsrv = 1;
372: cm->cm_cc = 0xFF;
373: cm->cm_opmode = 0; /* link-level controller mode */
374: cm->cm_dfo = 0x0101; /* enable host data order conversion */
375: cm->cm_dcn1 = 1;
376: cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
377: cm->cm_ham = 3; /* absolute address mode */
378: cm->cm_3rsrv = 0;
379: cm->cm_mapsiz = 0;
380: cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */
381: cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */
382: cm->cm_byteptrn[2] = 0x07;
383: cm->cm_byteptrn[3] = 0x0F;
384: cm->cm_wordptrn[0] = 0x0103;
385: cm->cm_wordptrn[1] = 0x070F;
386: cm->cm_lwordptrn = 0x0103070F;
387: for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
388: cm->cm_mba = 0xFFFFFFFF;
389: cm->cm_nproc = 0xFF;
390: cm->cm_nmbox = 0xFF;
391: cm->cm_nmcast = 0xFF;
392: cm->cm_nhost = 1;
393: cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
394: cm->cm_h2xhdr = H2XHDR_OFFSET(unit);
395: cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */
396: cm->cm_x2hba = cm->cm_h2xba;
397: cm->cm_x2hhdr = X2HHDR_OFFSET(unit);
398: cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */
399: for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
400: #ifdef DEBUG
401: if (i >= NEX)
402: panic("ex: matching csr address not found");
403: #endif
404: ;
405: cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */
406: /*
407: * Set up message queues and headers.
408: * First the request queue.
409: */
410: for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
411: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
412: bp->mb_rsrv = 0;
413: bp->mb_length = MBDATALEN;
414: bp->mb_status = MH_HOST;
415: bp->mb_next = bp+1;
416: }
417: xs->xs_h2xhdr =
418: xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit);
419: xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
420:
421: /* Now the reply queue. */
422: for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
423: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
424: bp->mb_rsrv = 0;
425: bp->mb_length = MBDATALEN;
426: bp->mb_status = MH_EXOS;
427: bp->mb_next = bp+1;
428: }
429: xs->xs_x2hhdr =
430: xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit);
431: xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
432:
433: /*
434: * Write config msg address to EXOS and wait for
435: * configuration to complete (guaranteed response
436: * within 2 seconds).
437: */
438: shiftreg = (u_long)0x0000FFFF;
439: for (i = 0; i < 8; i++) {
440: if (i == 4)
441: shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit);
442: while (addr->xd_portb & EX_UNREADY)
443: ;
444: addr->xd_portb = (u_char)(shiftreg & 0xFF);
445: shiftreg >>= 8;
446: }
447: for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
448: if (cm->cm_cc)
449: printf("ex%d: configuration failed; cc = %x\n",
450: unit, cm->cm_cc);
451: }
452:
453: /*
454: * Start or re-start output on interface.
455: * Get another datagram to send off of the interface queue,
456: * and map it to the interface before starting the output.
457: * This routine is called by exinit(), ether_output(), and excdint().
458: * In all cases, interrupts by EXOS are disabled.
459: */
460: exstart(ifp)
461: struct ifnet *ifp;
462: {
463: int unit = ifp->if_unit;
464: struct uba_device *ui = exinfo[unit];
465: register struct ex_softc *xs = &ex_softc[unit];
466: register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
467: register struct ex_msg *bp;
468: struct mbuf *m;
469: int len;
470:
471: #ifdef DEBUG
472: if (xs->xs_if.if_flags & IFF_OACTIVE)
473: panic("exstart(): xmit still pending");
474: #endif
475: IF_DEQUEUE(&xs->xs_if.if_snd, m);
476: if (m == 0)
477: return (0);
478: len = if_wubaput(&xs->xs_ifuba, m);
479: if (len - sizeof(struct ether_header) < ETHERMIN)
480: len = ETHERMIN + sizeof(struct ether_header);
481: /*
482: * Place a transmit request.
483: */
484: bp = exgetcbuf(xs);
485: bp->mb_rqst = LLRTRANSMIT;
486: bp->mb_et.et_nblock = 1;
487: bp->mb_et.et_blks[0].bb_len = (u_short)len;
488: *(u_long *)bp->mb_et.et_blks[0].bb_addr =
489: UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
490: xs->xs_if.if_flags |= IFF_OACTIVE;
491: bp->mb_status |= MH_EXOS;
492: addr->xd_portb = EX_NTRUPT;
493: return (0);
494: }
495:
496: /*
497: * Command done interrupt.
498: */
499: excdint(unit)
500: int unit;
501: {
502: register struct ex_softc *xs = &ex_softc[unit];
503: register struct ex_msg *bp = xs->xs_x2hnext;
504: struct uba_device *ui = exinfo[unit];
505: struct exdevice *addr = (struct exdevice *)ui->ui_addr;
506:
507: while ((bp->mb_status & MH_OWNER) == MH_HOST) {
508: switch (bp->mb_rqst) {
509: case LLRECEIVE:
510: exrecv(unit, bp);
511: exhangrcv(unit);
512: break;
513: case LLRTRANSMIT:
514: #ifdef DEBUG
515: if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0)
516: panic("exxmit: no xmit pending");
517: #endif
518: xs->xs_if.if_flags &= ~IFF_OACTIVE;
519: xs->xs_if.if_opackets++;
520: if (bp->mb_rply == LL_OK) {
521: ;
522: } else if (bp->mb_rply & LLXM_1RTRY) {
523: xs->xs_if.if_collisions++;
524: } else if (bp->mb_rply & LLXM_RTRYS) {
525: xs->xs_if.if_collisions += 2; /* guess */
526: } else if (bp->mb_rply & LLXM_ERROR) {
527: xs->xs_if.if_oerrors++;
528: log(LOG_ERR, "ex%d: transmit error=%b\n",
529: unit, bp->mb_rply, XMIT_BITS);
530: }
531: if (xs->xs_ifuba.ifu_xtofree) {
532: m_freem(xs->xs_ifuba.ifu_xtofree);
533: xs->xs_ifuba.ifu_xtofree = 0;
534: }
535: (void) exstart(&xs->xs_if);
536: break;
537: case LLNET_STSTCS:
538: xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
539: xs->xs_flags &= ~EX_STATPENDING;
540: break;
541: case LLNET_ADDRS:
542: case LLNET_RECV:
543: break;
544: #ifdef DEBUG
545: default:
546: panic("ex%d: unknown reply");
547: #endif
548: } /* end of switch */
549: bp->mb_length = MBDATALEN;
550: bp->mb_status |= MH_EXOS; /* free up buffer */
551: addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
552: bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
553: }
554: }
555:
556: /*
557: * Get a request buffer, fill in standard values, advance pointer.
558: */
559: struct ex_msg *
560: exgetcbuf(xs)
561: struct ex_softc *xs;
562: {
563: register struct ex_msg *bp = xs->xs_h2xnext;
564:
565: #ifdef DEBUG
566: if ((bp->mb_status & MH_OWNER) == MH_EXOS)
567: panic("exgetcbuf(): EXOS owns message buffer");
568: #endif
569: bp->mb_1rsrv = 0;
570: bp->mb_length = MBDATALEN;
571: xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
572: return bp;
573: }
574:
575: /*
576: * Process Ethernet receive completion:
577: * If input error just drop packet.
578: * Otherwise purge input buffered data path and examine
579: * packet to determine type. If can't determine length
580: * from type, then have to drop packet. Otherwise decapsulate
581: * packet based on type and pass to type-specific higher-level
582: * input routine.
583: */
584: exrecv(unit, bp)
585: int unit;
586: register struct ex_msg *bp;
587: {
588: register struct ex_softc *xs = &ex_softc[unit];
589: register struct ether_header *eh;
590: struct mbuf *m;
591: register int len, off, resid;
592: register struct ifqueue *inq;
593: int s;
594:
595: xs->xs_if.if_ipackets++;
596: len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
597: if (bp->mb_rply != LL_OK) {
598: xs->xs_if.if_ierrors++;
599: log(LOG_ERR, "ex%d: receive error=%b\n",
600: unit, bp->mb_rply, RECV_BITS);
601: return;
602: }
603: eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
604:
605: /*
606: * Deal with trailer protocol: if type is trailer
607: * get true type from first 16-bit word past data.
608: * Remember that type was trailer by setting off.
609: */
610: eh->ether_type = ntohs((u_short)eh->ether_type);
611: #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
612: if (eh->ether_type >= ETHERTYPE_TRAIL &&
613: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
614: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
615: if (off >= ETHERMTU)
616: return; /* sanity */
617: eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
618: resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
619: if (off + resid > len)
620: return; /* sanity */
621: len = off + resid;
622: } else
623: off = 0;
624: if (len == 0)
625: return;
626:
627: /*
628: * Pull packet off interface. Off is nonzero if packet
629: * has trailing header; if_rubaget will then force this header
630: * information to be at the front, but we still have to drop
631: * the type and length which are at the front of any trailer data.
632: */
633: m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if);
634: if (m == 0)
635: return;
636: ether_input(&xs->xs_if, eh, m);
637: }
638:
639: /*
640: * Send receive request to EXOS.
641: * This routine is called by exinit and excdint,
642: * with interrupts disabled in both cases.
643: */
644: exhangrcv(unit)
645: int unit;
646: {
647: register struct ex_softc *xs = &ex_softc[unit];
648: register struct ex_msg *bp = exgetcbuf(xs);
649: struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
650:
651: bp->mb_rqst = LLRECEIVE;
652: bp->mb_er.er_nblock = 1;
653: bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
654: *(u_long *)bp->mb_er.er_blks[0].bb_addr =
655: UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
656: bp->mb_status |= MH_EXOS;
657: addr->xd_portb = EX_NTRUPT;
658: }
659:
660: /*
661: * Watchdog routine - place stats request to EXOS
662: * (This could be dispensed with, if you don't care
663: * about the if_ierrors count, or are willing to receive
664: * bad packets in order to derive it.)
665: */
666: exwatch(unit)
667: int unit;
668: {
669: struct uba_device *ui = exinfo[unit];
670: struct exdevice *addr = (struct exdevice *)ui->ui_addr;
671: register struct ex_softc *xs = &ex_softc[unit];
672: register struct ex_msg *bp;
673: int s = splimp();
674:
675: if (xs->xs_flags & EX_STATPENDING) goto exspnd;
676: bp = exgetcbuf(xs);
677: xs->xs_flags |= EX_STATPENDING;
678: bp->mb_rqst = LLNET_STSTCS;
679: bp->mb_ns.ns_mask = READ_OBJ;
680: bp->mb_ns.ns_rsrv = 0;
681: bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */
682: bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */
683: bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit);
684: bp->mb_status |= MH_EXOS;
685: addr->xd_portb = EX_NTRUPT;
686: exspnd:
687: splx(s);
688: xs->xs_if.if_timer = EXWATCHINTVL;
689: }
690:
691: /*
692: * Process an ioctl request.
693: */
694: exioctl(ifp, cmd, data)
695: register struct ifnet *ifp;
696: int cmd;
697: caddr_t data;
698: {
699: register struct ifaddr *ifa = (struct ifaddr *)data;
700: register struct ex_softc *xs = &ex_softc[ifp->if_unit];
701: int s = splimp(), error = 0;
702:
703: switch (cmd) {
704:
705: case SIOCSIFADDR:
706: ifp->if_flags |= IFF_UP;
707: exinit(ifp->if_unit);
708:
709: switch (ifa->ifa_addr->sa_family) {
710: #ifdef INET
711: case AF_INET:
712: ((struct arpcom *)ifp)->ac_ipaddr =
713: IA_SIN(ifa)->sin_addr;
714: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
715: break;
716: #endif
717: #ifdef NS
718: case AF_NS:
719: {
720: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
721:
722: if (ns_nullhost(*ina))
723: ina->x_host = *(union ns_host *)(xs->xs_addr);
724: else
725: ex_setaddr(ina->x_host.c_host,ifp->if_unit);
726: break;
727: }
728: #endif
729: }
730: break;
731:
732: case SIOCSIFFLAGS:
733: if ((ifp->if_flags & IFF_UP) == 0 &&
734: xs->xs_flags & EX_RUNNING) {
735: ((struct exdevice *)
736: (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET;
737: xs->xs_flags &= ~EX_RUNNING;
738: } else if (ifp->if_flags & IFF_UP &&
739: (xs->xs_flags & EX_RUNNING) == 0)
740: exinit(ifp->if_unit);
741: break;
742:
743: default:
744: error = EINVAL;
745: }
746: splx(s);
747: return (error);
748: }
749:
750: /*
751: * set ethernet address for unit
752: */
753: ex_setaddr(physaddr, unit)
754: u_char *physaddr;
755: int unit;
756: {
757: register struct ex_softc *xs = &ex_softc[unit];
758:
759: if (physaddr) {
760: xs->xs_flags |= EX_SETADDR;
761: bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
762: }
763: ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
764: }
765: /*
766: * enable multicast reception on a particular address.
767: */
768: ex_setmulti(linkaddr, unit, slot)
769: u_char *linkaddr;
770: int unit;
771: {
772: register struct ex_softc *xs = &ex_softc[unit];
773: struct uba_device *ui = exinfo[unit];
774: register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
775: register struct ex_msg *bp;
776:
777: if (! (xs->xs_flags & EX_RUNNING))
778: return;
779: bp = exgetcbuf(xs);
780: bp->mb_rqst = LLNET_ADDRS;
781: bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
782: bp->mb_na.na_slot = slot;
783: bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
784: bp->mb_status |= MH_EXOS;
785: addr->xd_portb = EX_NTRUPT;
786: bp = xs->xs_x2hnext;
787: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
788: ;
789: #ifdef DEBUG
790: log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
791: (slot == PHYSSLOT ? "reset addr" : "add multicast"
792: ether_sprintf(bp->mb_na.na_addrs), slot);
793: #endif
794: /*
795: * Now, re-enable reception on slot.
796: */
797: bp = exgetcbuf(xs);
798: bp->mb_rqst = LLNET_RECV;
799: bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
800: bp->mb_nr.nr_slot = slot;
801: bp->mb_status |= MH_EXOS;
802: addr->xd_portb = EX_NTRUPT;
803: bp = xs->xs_x2hnext;
804: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
805: ;
806: }
807: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.