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