|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The 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.5 (Berkeley) 12/16/90
37: */
38:
39: #include "ex.h"
40:
41: #if NEX > 0
42:
43: /*
44: * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers
45: */
46: #include "sys/param.h"
47: #include "sys/systm.h"
48: #include "sys/mbuf.h"
49: #include "sys/buf.h"
50: #include "sys/protosw.h"
51: #include "sys/socket.h"
52: #include "sys/vmmac.h"
53: #include "sys/ioctl.h"
54: #include "sys/errno.h"
55: #include "sys/vmparam.h"
56: #include "sys/syslog.h"
57: #include "sys/uio.h"
58:
59: #include "net/if.h"
60: #include "net/netisr.h"
61: #include "net/route.h"
62:
63: #ifdef INET
64: #include "netinet/in.h"
65: #include "netinet/in_systm.h"
66: #include "netinet/in_var.h"
67: #include "netinet/ip.h"
68: #include "netinet/if_ether.h"
69: #endif
70:
71: #ifdef NS
72: #include "netns/ns.h"
73: #include "netns/ns_if.h"
74: #endif
75:
76: #ifdef ISO
77: #include "netiso/iso.h"
78: #include "netiso/iso_var.h"
79: extern char all_es_snpa[], all_is_snpa[];
80: #endif
81:
82: #include "../include/cpu.h"
83: #include "../include/pte.h"
84: #include "../include/mtpr.h"
85:
86: #include "../vba/vbavar.h"
87: #include "if_exreg.h"
88: #include "if_vba.h"
89:
90:
91: #define NH2X 32 /* Host to eXcelan request buffers */
92:
93: #define NX2H 16 /* eXcelan to Host reply buffers */
94: #define NREC 16 /* Number of RECeive buffers */
95: #define NTRB 4 /* Number of TRansmit Buffers */
96: #define NVBI (NREC + NTRB)
97:
98: #define EXWATCHINTVL 10 /* call exwatch every x secs */
99:
100: int exprobe(), exslave(), exattach(), exintr(), exstart();
101: struct vba_device *exinfo[NEX];
102:
103: long exstd[] = { 0 };
104:
105:
106: struct vba_driver exdriver =
107: { exprobe, 0, exattach, exstart, exstd, "ex", exinfo };
108: int exinit(),ether_output(),exioctl(),exreset(),exwatch();
109: struct ex_msg *exgetcbuf();
110: int ex_ncall = 0; /* counts calls to exprobe */
111: u_long busoff;
112:
113: /*
114: * Ethernet software status per interface.
115: *
116: * Each interface is referenced by a network interface structure, xs_if, which
117: * the routing code uses to locate the interface. This structure contains the
118: * output queue for the interface, its address, ... NOTE: To configure multiple
119: * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr).
120: */
121: struct ex_softc {
122: struct arpcom xs_ac; /* Ethernet common part */
123: #define xs_if xs_ac.ac_if /* network-visible interface */
124: #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
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: int xs_cvec; /* probe stores cvec here */
131: short xs_enetunit; /* unit number for enet filtering */
132: short xs_enetinit; /* enet inetrface is initialized */
133: struct ex_msg *xs_h2xnext; /* host pointer to request queue */
134: struct ex_msg *xs_x2hnext; /* host pointer to reply queue */
135: u_long xs_qbaddr; /* map info for structs below */
136: struct ex_shm {
137: /* the following structures are always mapped in */
138: u_short sm_h2xhdr; /* EXOS's request queue header */
139: u_short sm_x2hhdr; /* EXOS's reply queue header */
140: struct ex_msg sm_h2xent[NH2X];/* request msg buffers */
141: struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */
142: struct ex_conf sm_cm; /* configuration message */
143: struct ex_stat sm_xsa; /* EXOS writes stats here */
144: /* end mapped area */
145: } *xs_shm; /* host pointer to shared area */
146: #define xs_h2xhdr xs_shm->sm_h2xhdr
147: #define xs_x2hhdr xs_shm->sm_x2hhdr
148: #define xs_h2xent xs_shm->sm_h2xent
149: #define xs_x2hent xs_shm->sm_x2hent
150: #define xs_cm xs_shm->sm_cm
151: #define xs_xsa xs_shm->sm_xsa
152: #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF))
153: #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0))
154: #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0)
155: /* we will arrange that the shared memory begins on a 16 byte boundary */
156: #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0)
157: #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0)
158: #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr)
159: #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr)
160: #define H2XENT_OFFSET LVAL_OFF(sm_h2xent)
161: #define X2HENT_OFFSET LVAL_OFF(sm_x2hent)
162: #define CM_OFFSET RVAL_OFF(sm_cm)
163: #define SA_OFFSET RVAL_OFF(sm_xsa)
164: struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */
165: struct ifvba *xs_pkblist; /* free list of above */
166: #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\
167: (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf))
168: #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\
169: (xs->xs_pkblist = v))
170: char xs_nrec; /* number of pending receive buffers */
171: char xs_ntrb; /* number of pending transmit buffers */
172: } ex_softc[NEX];
173:
174: int ex_padcheck = sizeof (struct ex_softc);
175:
176: exprobe(reg, vi)
177: caddr_t reg;
178: struct vba_device *vi;
179: {
180: register br, cvec; /* r12, r11 value-result */
181: register struct exdevice *exaddr = (struct exdevice *)reg;
182: int i;
183:
184: if (badaddr((caddr_t)exaddr, 2))
185: return 0;
186: /*
187: * Reset EXOS and run self-test (should complete within 2 seconds).
188: */
189: movow(&exaddr->ex_porta, EX_RESET);
190: for (i = 1000000; i; i--) {
191: uncache(&(exaddr->ex_portb));
192: if (exaddr->ex_portb & EX_TESTOK)
193: break;
194: }
195: if ((exaddr->ex_portb & EX_TESTOK) == 0)
196: return 0;
197: br = 0x15;
198: cvec = --vi->ui_hd->vh_lastiv;
199: ex_softc[vi->ui_unit].xs_cvec = cvec;
200: ex_ncall++;
201: return (sizeof(struct exdevice));
202: }
203:
204: /*
205: * Interface exists: make available by filling in network interface record.
206: * System will initialize the interface when it is ready to accept packets.
207: * A NET_ADDRS command is done to get the ethernet address.
208: */
209: exattach(ui)
210: register struct vba_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 *exaddr = (struct exdevice *)ui->ui_addr;
215: register struct ex_msg *bp;
216:
217: ifp->if_unit = ui->ui_unit;
218: ifp->if_name = "ex";
219: ifp->if_mtu = ETHERMTU;
220: ifp->if_init = exinit;
221: ifp->if_ioctl = exioctl;
222: ifp->if_output = ether_output;
223: ifp->if_reset = exreset;
224: ifp->if_start = exstart;
225: ifp->if_flags = IFF_BROADCAST;
226:
227: /*
228: * Note: extra memory gets returned by if_vbareserve()
229: * first, so, being page alligned, it is also 16-byte alligned.
230: */
231: if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF,
232: (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0)
233: return;
234: /*
235: * Temporarily map queues in order to configure EXOS
236: */
237: xs->xs_qbaddr = INCORE_BASE(xs);
238: exconfig(ui, 0); /* without interrupts */
239: if (xs->xs_cm.cm_cc)
240: return; /* bad conf */
241: /*
242: * Get Ethernet address.
243: */
244: if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)
245: panic("exattach");
246: bp->mb_na.na_mask = READ_OBJ;
247: bp->mb_na.na_slot = PHYSSLOT;
248: bp->mb_status |= MH_EXOS;
249: movow(&exaddr->ex_portb, EX_NTRUPT);
250: bp = xs->xs_x2hnext;
251: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
252: printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",
253: ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
254: xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
255: ether_sprintf(bp->mb_na.na_addrs));
256: bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
257: sizeof(xs->xs_addr));
258: if_attach(ifp);
259: }
260:
261: /*
262: * Reset of interface after BUS reset.
263: * If interface is on specified vba, reset its state.
264: */
265: exreset(unit)
266: int unit;
267: {
268: register struct vba_device *ui;
269:
270: if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)
271: return;
272: printf(" ex%d", unit);
273: ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
274: ex_softc[unit].xs_flags &= ~EX_RUNNING;
275:
276: exinit(unit);
277: }
278:
279: /*
280: * Initialization of interface; clear recorded pending operations, and
281: * reinitialize BUS usage. Called at boot time, and at ifconfig time via
282: * exioctl, with interrupts disabled.
283: */
284: exinit(unit)
285: int unit;
286: {
287: register struct ex_softc *xs = &ex_softc[unit];
288: register struct vba_device *ui = exinfo[unit];
289: register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
290: register struct ifnet *ifp = &xs->xs_if;
291: register struct sockaddr_in *sin;
292: register struct ex_msg *bp;
293: int s;
294:
295: /* not yet, if address still unknown */
296: if (ifp->if_addrlist == (struct ifaddr *)0)
297: return;
298: if (xs->xs_flags & EX_RUNNING)
299: return;
300:
301: xs->xs_qbaddr = INCORE_BASE(xs);
302: exconfig(ui, 4); /* with vectored interrupts*/
303:
304: /*
305: * Put EXOS on the Ethernet, using NET_MODE command
306: */
307: if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)
308: panic("exinit");
309: bp->mb_nm.nm_mask = WRITE_OBJ;
310: bp->mb_nm.nm_optn = 0;
311: bp->mb_nm.nm_mode = MODE_PERF;
312: bp->mb_status |= MH_EXOS;
313: movow(&exaddr->ex_portb, EX_NTRUPT);
314: bp = xs->xs_x2hnext;
315: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
316: ;
317: bp->mb_length = MBDATALEN;
318: bp->mb_status |= MH_EXOS; /* free up buffer */
319: movow(&exaddr->ex_portb, EX_NTRUPT);
320: xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
321:
322: ifp->if_watchdog = exwatch;
323: ifp->if_timer = EXWATCHINTVL;
324: s = splimp(); /* are interrupts disabled here, anyway? */
325: exhangrcv(unit);
326: xs->xs_if.if_flags |= IFF_RUNNING;
327: xs->xs_flags |= EX_RUNNING;
328: if (xs->xs_flags & EX_SETADDR)
329: ex_setaddr((u_char *)0, unit);
330: #ifdef ISO
331: ex_setmulti(all_es_snpa, unit, 1);
332: ex_setmulti(all_is_snpa, unit, 2);
333: #endif
334: exstart(&ex_softc[unit].xs_if); /* start transmits */
335: splx(s); /* are interrupts disabled here, anyway? */
336: }
337:
338: /*
339: * Reset, test, and configure EXOS. It is called by exinit, and exattach.
340: * Returns 0 if successful, 1 if self-test failed.
341: */
342: exconfig(ui, itype)
343: struct vba_device *ui;
344: int itype;
345: {
346: register int unit = ui->ui_unit;
347: register struct ex_softc *xs = &ex_softc[unit];
348: register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;
349: register struct ex_conf *cm = &xs->xs_cm;
350: register struct ex_msg *bp;
351: register struct ifvba *pkb;
352: int i;
353: u_long shiftreg;
354: static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0};
355:
356: xs->xs_flags = 0;
357: /*
358: * Reset EXOS, wait for self-test to complete
359: */
360: movow(&exaddr->ex_porta, EX_RESET);
361: do {
362: uncache(&exaddr->ex_portb);
363: } while ((exaddr->ex_portb & EX_TESTOK) == 0) ;
364: /*
365: * Set up configuration message.
366: */
367: cm->cm_1rsrv = 1;
368: cm->cm_cc = 0xFF;
369: cm->cm_opmode = 0; /* link-level controller mode */
370: cm->cm_dfo = 0x0101; /* enable host data order conversion */
371: cm->cm_dcn1 = 1;
372: cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
373: cm->cm_ham = 3; /* absolute address mode */
374: cm->cm_3rsrv = 0;
375: cm->cm_mapsiz = 0;
376: cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */
377: cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */
378: cm->cm_byteptrn[2] = 0x07;
379: cm->cm_byteptrn[3] = 0x0F;
380: cm->cm_wordptrn[0] = 0x0103;
381: cm->cm_wordptrn[1] = 0x070F;
382: cm->cm_lwordptrn = 0x0103070F;
383: for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
384: cm->cm_mba = 0xFFFFFFFF;
385: cm->cm_nproc = 0xFF;
386: cm->cm_nmbox = 0xFF;
387: cm->cm_nmcast = 0xFF;
388: cm->cm_nhost = 1;
389: cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);
390: cm->cm_h2xhdr = H2XHDR_OFFSET;
391: cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */
392: cm->cm_x2hba = cm->cm_h2xba;
393: cm->cm_x2hhdr = X2HHDR_OFFSET;
394: cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */
395: cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */
396: /*
397: * Set up message queues and headers.
398: * First the request queue
399: */
400: for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
401: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
402: bp->mb_rsrv = 0;
403: bp->mb_length = MBDATALEN;
404: bp->mb_status = MH_HOST;
405: bp->mb_next = bp+1;
406: }
407: xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;
408: xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
409:
410: /* Now the reply queue. */
411: for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
412: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
413: bp->mb_rsrv = 0;
414: bp->mb_length = MBDATALEN;
415: bp->mb_status = MH_EXOS;
416: bp->mb_next = bp+1;
417: }
418: xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;
419: xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
420: xs->xs_nrec = 0;
421: xs->xs_ntrb = 0;
422: xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1;
423: for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--)
424: pkb->iff_mbuf = (struct mbuf *)(pkb - 1);
425: xs->xs_vbinfo[0].iff_mbuf = 0;
426:
427: /*
428: * Write config msg address to EXOS and wait for configuration to
429: * complete (guaranteed response within 2 seconds).
430: */
431: shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;
432: for (i = 4; i < 8; i++) {
433: cmaddr[i] = (u_char)(shiftreg & 0xFF);
434: shiftreg >>= 8;
435: }
436: for (i = 0; i < 8; i++) {
437: do {
438: uncache(&exaddr->ex_portb);
439: } while (exaddr->ex_portb & EX_UNREADY) ;
440: DELAY(500);
441: movow(&exaddr->ex_portb, cmaddr[i]);
442: }
443: for (i = 500000; i; --i) {
444: DELAY(10);
445: uncache(&cm->cm_cc);
446: if (cm->cm_cc != 0xFF)
447: break;
448: }
449: if (cm->cm_cc)
450: printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);
451: }
452:
453: /*
454: * Start or re-start output on interface. Get another datagram to send off of
455: * the interface queue, and map it to the interface before starting the output.
456: * This routine is called by exinit(), exoutput(), and excdint(). In all cases,
457: * interrupts by EXOS are disabled.
458: */
459: exstart(ifp)
460: struct ifnet *ifp;
461: {
462: int unit = ifp->if_unit;
463: struct vba_device *ui = exinfo[unit];
464: register struct ex_softc *xs = &ex_softc[unit];
465: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
466: register struct ex_msg *bp;
467: register struct mbuf *m;
468: int len;
469: register struct ifvba *pkb;
470: struct mbuf *m0 = 0;
471: register int nb = 0, tlen = 0;
472: union l_util {
473: u_long l;
474: struct i86_long i;
475: } l_util;
476:
477: if (xs->xs_ntrb >= NTRB)
478: return;
479: if (xs->xs_pkblist == 0) {
480: printf("ex%d: vbinfo exhausted, would panic", unit);
481: return;
482: }
483: IF_DEQUEUE(&xs->xs_if.if_snd, m);
484: if (m == 0)
485: return;
486: /*
487: * Get a transmit request.
488: */
489: if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) {
490: m_freem(m);
491: printf("exstart: no command buffers\n");
492: return;
493: }
494: xs->xs_ntrb++;
495: GetPkBuf(bp, pkb);
496: pkb->iff_mbuf = m; /* save mbuf pointer to free when done */
497: /*
498: * point directly to the first group of mbufs to be transmitted. The
499: * hardware can only support NFRAGMENTS descriptors.
500: */
501: while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) {
502: l_util.l = BUSADDR(mtod(m, caddr_t));
503: bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len;
504: bp->mb_et.et_blks[nb].bb_addr = l_util.i;
505: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
506: /* Here, the phys memory for the mbuf is out
507: of range for the vmebus to talk to it */
508: if (m == pkb->iff_mbuf)
509: pkb->iff_mbuf = 0;
510: break;
511: }
512: tlen += m->m_len;
513: m0 = m;
514: m = m->m_next;
515: nb++;
516: }
517:
518: /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */
519: if (m0)
520: m0->m_next = 0;
521:
522: /*
523: * if not all of the descriptors would fit then merge remaining data
524: * into the transmit buffer, and point to it. Note: the mbufs are freed
525: * during the merge, they do not have to be freed when we get the
526: * transmit interrupt.
527: */
528: if (m) {
529: if (m == pkb->iff_mbuf) {
530: printf("ex%d: exstart insanity\n", unit);
531: pkb->iff_mbuf = 0;
532: }
533: len = if_vbaput(pkb->iff_buffer, m, 0);
534: l_util.l = BUSADDR(pkb->iff_buffer);
535: bp->mb_et.et_blks[nb].bb_len = (u_short)len;
536: bp->mb_et.et_blks[nb].bb_addr = l_util.i;
537: tlen += len;
538: nb++;
539: }
540:
541: /*
542: * If the total length of the packet is too small,
543: * pad the last fragment. (May run into very obscure problems)
544: */
545: if (tlen < sizeof(struct ether_header) + ETHERMIN) {
546: len = (ETHERMIN + sizeof(struct ether_header)) - tlen;
547: bp->mb_et.et_blks[nb-1].bb_len += (u_short)len;
548: tlen += len;
549: #ifdef notdef
550: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
551: must copy last frag into private buffer
552: }
553: #endif
554: }
555:
556: /* set number of fragments in descriptor */
557: bp->mb_et.et_nblock = nb;
558: bp->mb_status |= MH_EXOS;
559: movow(&exaddr->ex_portb, EX_NTRUPT);
560: }
561:
562: /*
563: * interrupt service routine.
564: */
565: exintr(unit)
566: int unit;
567: {
568: register struct ex_softc *xs = &ex_softc[unit];
569: register struct ex_msg *bp = xs->xs_x2hnext;
570: struct vba_device *ui = exinfo[unit];
571: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
572: struct ex_msg *next_bp;
573:
574: while ((bp->mb_status & MH_OWNER) == MH_HOST) {
575: switch (bp->mb_rqst) {
576: case LLRECEIVE:
577: if (--xs->xs_nrec < 0) {
578: printf("ex%d: internal receive check\n", unit);
579: xs->xs_nrec = 0;
580: }
581: exrecv(unit, bp);
582: FreePkBuf(bp->mb_pkb);
583: bp->mb_pkb = (struct ifvba *)0;
584: exhangrcv(unit);
585: break;
586:
587: case LLTRANSMIT:
588: case LLRTRANSMIT:
589: if (--xs->xs_ntrb < 0) {
590: printf("ex%d: internal transmit check\n", unit);
591: xs->xs_ntrb = 0;
592: }
593: xs->xs_if.if_opackets++;
594: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
595: ;
596: else if (bp->mb_rply & LLXM_1RTRY)
597: xs->xs_if.if_collisions++;
598: else if (bp->mb_rply & LLXM_RTRYS)
599: xs->xs_if.if_collisions += 2; /* guess */
600: else if (bp->mb_rply & LLXM_ERROR)
601: if (xs->xs_if.if_oerrors++ % 100 == 0)
602: printf("ex%d: 100 transmit errors=%b\n",
603: unit, bp->mb_rply, XMIT_BITS);
604: if (bp->mb_pkb->iff_mbuf) {
605: m_freem(bp->mb_pkb->iff_mbuf);
606: bp->mb_pkb->iff_mbuf = (struct mbuf *)0;
607: }
608: FreePkBuf(bp->mb_pkb);
609: bp->mb_pkb = (struct ifvba *)0;
610: exstart(&xs->xs_if);
611: exhangrcv(unit);
612: break;
613:
614: case LLNET_STSTCS:
615: xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc;
616: xs->xs_flags &= ~EX_STATPENDING;
617: case LLNET_ADDRS:
618: case LLNET_RECV:
619: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
620: ;
621: else
622: printf("ex%d: %s, request 0x%x, reply 0x%x\n",
623: unit, "unsucessful stat or address change",
624: bp->mb_rqst, bp->mb_rply);
625: break;
626:
627: default:
628: printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst);
629: }
630: bp->mb_length = MBDATALEN;
631: next_bp = bp->mb_next;
632: bp->mb_status |= MH_EXOS; /* free up buffer */
633: bp = next_bp; /* paranoia about race */
634: movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */
635: }
636: xs->xs_x2hnext = bp;
637: }
638:
639: /*
640: * Get a request buffer, fill in standard values, advance pointer.
641: */
642: struct ex_msg *
643: exgetcbuf(xs, req)
644: struct ex_softc *xs;
645: int req;
646: {
647: register struct ex_msg *bp;
648: struct ifvba *pkb;
649: int s = splimp();
650:
651: bp = xs->xs_h2xnext;
652: if ((bp->mb_status & MH_OWNER) == MH_EXOS) {
653: splx(s);
654: return (struct ex_msg *)0;
655: }
656: xs->xs_h2xnext = bp->mb_next;
657: bp->mb_1rsrv = 0;
658: bp->mb_rqst = req;
659: bp->mb_length = MBDATALEN;
660: bp->mb_pkb = (struct ifvba *)0;
661: splx(s);
662: return bp;
663: }
664:
665: /*
666: * Process Ethernet receive completion: If input error just drop packet,
667: * otherwise examine packet to determine type. If can't determine length from
668: * type, then have to drop packet, otherwise decapsulate packet based on type
669: * and pass to type-specific higher-level input routine.
670: */
671: exrecv(unit, bp)
672: int unit;
673: register struct ex_msg *bp;
674: {
675: register struct ex_softc *xs = &ex_softc[unit];
676: register struct ether_header *eh;
677: register struct mbuf *m;
678: int len, off, resid;
679: register struct ifqueue *inq;
680: int s;
681:
682: xs->xs_if.if_ipackets++;
683: /* total length - header - crc */
684: len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
685: if (bp->mb_rply != LL_OK) {
686: if (xs->xs_if.if_ierrors++ % 100 == 0)
687: printf("ex%d: 100 receive errors=%b\n",
688: unit, bp->mb_rply, RECV_BITS);
689: return;
690: }
691: eh = (struct ether_header *)(bp->mb_pkb->iff_buffer);
692:
693: /*
694: * Deal with trailer protocol: if type is PUP trailer get true type from
695: * first 16-bit word past data. Remember that type was trailer by
696: * setting off.
697: */
698: eh->ether_type = ntohs((u_short)eh->ether_type);
699: #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
700: if (eh->ether_type >= ETHERTYPE_TRAIL &&
701: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
702: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
703: if (off >= ETHERMTU)
704: return; /* sanity */
705: eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
706: resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
707: if (off + resid > len)
708: return; /* sanity */
709: len = off + resid;
710: } else
711: off = 0;
712: if (len == 0)
713: return;
714: /*
715: * Pull packet off interface. Off is nonzero if packet
716: * has trailing header; if_vbaget will then force this header
717: * information to be at the front, but we still have to drop
718: * the type and length which are at the front of any trailer data.
719: */
720: m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0);
721: if (m == 0)
722: return;
723: ether_input(&xs->xs_if, eh, m);
724: return;
725: }
726:
727: /*
728: * Hang a receive request. This routine is called by exinit and excdint,
729: * with interrupts disabled in both cases.
730: */
731: exhangrcv(unit)
732: int unit;
733: {
734: register struct ex_softc *xs = &ex_softc[unit];
735: register struct ex_msg *bp;
736: register struct ifvba *pkb;
737: short mustint = 0;
738: union l_util {
739: u_long l;
740: struct i86_long i;
741: } l_util;
742:
743: while (xs->xs_nrec < NREC) {
744: if (xs->xs_pkblist == (struct ifvba *)0)
745: break;
746: if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) {
747: break;
748: }
749: GetPkBuf(bp, pkb);
750: pkb->iff_mbuf = 0;
751: xs->xs_nrec += 1;
752: bp->mb_er.er_nblock = 1;
753: bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
754: l_util.l = BUSADDR(pkb->iff_buffer);
755: bp->mb_er.er_blks[0].bb_addr = l_util.i;
756: bp->mb_status |= MH_EXOS;
757: mustint = 1;
758: }
759: if (mustint == 0)
760: return;
761: movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);
762: }
763:
764: /*
765: * Ethernet output routine is ether_output().
766: */
767:
768: /*
769: * Watchdog routine (currently not used). Might use this to get stats from EXOS.
770: */
771: exwatch(unit)
772: int unit;
773: {
774: struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr;
775: register struct ex_softc *xs = &ex_softc[unit];
776: register struct ex_msg *bp;
777: int s = splimp();
778:
779: if (xs->xs_flags & EX_STATPENDING)
780: goto exspnd;
781: if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) {
782: splx(s);
783: return;
784: }
785: xs->xs_flags |= EX_STATPENDING;
786: bp->mb_ns.ns_mask = READ_OBJ;
787: bp->mb_ns.ns_rsrv = 0;
788: bp->mb_ns.ns_nobj = 8;
789: bp->mb_ns.ns_xobj = 0;
790: bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET;
791: bp->mb_status |= MH_EXOS;
792: movow(&exaddr->ex_portb, EX_NTRUPT);
793: exspnd: splx(s);
794: xs->xs_if.if_timer = EXWATCHINTVL;
795: }
796:
797: /*
798: * Process an ioctl request.
799: */
800: exioctl(ifp, cmd, data)
801: register struct ifnet *ifp;
802: int cmd;
803: caddr_t data;
804: {
805: register struct ifaddr *ifa = (struct ifaddr *)data;
806: register struct ex_softc *xs = &ex_softc[ifp->if_unit];
807: int s = splimp(), error = 0;
808:
809: switch (cmd) {
810:
811: case SIOCSIFADDR:
812: ifp->if_flags |= IFF_UP;
813: exinit(ifp->if_unit);
814:
815: switch (ifa->ifa_addr->sa_family) {
816: #ifdef INET
817: case AF_INET:
818: ((struct arpcom *)ifp)->ac_ipaddr =
819: IA_SIN(ifa)->sin_addr;
820: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
821: break;
822: #endif
823: #ifdef NS
824: case AF_NS:
825: {
826: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
827:
828: if (ns_nullhost(*ina))
829: ina->x_host = *(union ns_host *)(xs->xs_addr);
830: else
831: ex_setaddr(ina->x_host.c_host,ifp->if_unit);
832: break;
833: }
834: #endif
835: }
836: break;
837:
838: case SIOCSIFFLAGS:
839: if ((ifp->if_flags & IFF_UP) == 0 &&
840: xs->xs_flags & EX_RUNNING) {
841: movow(&((struct exdevice *)
842: (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET);
843: xs->xs_flags &= ~EX_RUNNING;
844: } else if (ifp->if_flags & IFF_UP &&
845: (xs->xs_flags & EX_RUNNING) == 0)
846: exinit(ifp->if_unit);
847: break;
848:
849: default:
850: error = EINVAL;
851: }
852: splx(s);
853: return (error);
854: }
855:
856: /*
857: * set ethernet address for unit
858: */
859: ex_setaddr(physaddr, unit)
860: u_char *physaddr;
861: int unit;
862: {
863: register struct ex_softc *xs = &ex_softc[unit];
864:
865: if (physaddr) {
866: xs->xs_flags |= EX_SETADDR;
867: bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
868: }
869: ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
870: }
871:
872: /*
873: * Enable multicast reception for unit.
874: */
875: ex_setmulti(linkaddr, unit, slot)
876: u_char *linkaddr;
877: int unit, slot;
878: {
879: register struct ex_softc *xs = &ex_softc[unit];
880: struct vba_device *ui = exinfo[unit];
881: register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
882: register struct ex_msg *bp;
883:
884: if (!(xs->xs_flags & EX_RUNNING))
885: return;
886: bp = exgetcbuf(xs, LLNET_ADDRS);
887: bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
888: bp->mb_na.na_slot = slot;
889: bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
890: bp->mb_status |= MH_EXOS;
891: movow(&addr->ex_portb, EX_NTRUPT);
892: bp = xs->xs_x2hnext;
893: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
894: #ifdef DEBUG
895: log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
896: (slot == PHYSSLOT ? "reset addr" : "add multicast"
897: ether_sprintf(bp->mb_na.na_addrs), slot);
898: #endif
899: /*
900: * Now, re-enable reception on slot.
901: */
902: bp = exgetcbuf(xs, LLNET_RECV);
903: bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
904: bp->mb_nr.nr_slot = slot;
905: bp->mb_status |= MH_EXOS;
906: movow(&addr->ex_portb, EX_NTRUPT);
907: bp = xs->xs_x2hnext;
908: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
909: ;
910: }
911: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.