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