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