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