|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Tim L. Tucker.
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_we.c 7.3 (Berkeley) 5/21/91
1.1.1.3 ! root 37: *
! 38: * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
! 39: * -------------------- ----- ----------------------
! 40: * CURRENT PATCH LEVEL: 3 00047
! 41: * -------------------- ----- ----------------------
! 42: *
! 43: * 20 Sep 92 Barry Lustig WD8013 16 bit mode -- enable
! 44: * with "option WD8013".
! 45: * 19 Sep 92 Michael Galassi Fixed multiboard routing
! 46: * 09 Sep 92 Mike Durkin Fix Danpex EW-2016 & other 8013 clones
1.1 root 47: */
48:
49: /*
50: * Modification history
51: *
52: * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
1.1.1.3 ! root 53: *
! 54: * 92.09.19 - Changes to allow multiple we interfaces in one box.
! 55: * Allowed interupt handler to look at unit other than 0
! 56: * Bdry was static, made it into an array w/ one entry per
! 57: * interface. [email protected] (Michael Galassi)
! 58: *
! 59: * BPF Packet Filter Support added by Marc Frajola, 12/30/92
! 60: * Input & other routines re-written by David Greenman, 1/2/93
! 61: * BPF trailer support added by David Greenman, 1/7/93
! 62: *
! 63: * $Log: if_we.c,v $
! 64: * Revision 1.5 1993/04/10 15:58:56 glass
! 65: * Fixed so they are useable when compiled with options NS. Not that I know
! 66: * anyone who will.....
! 67: *
! 68: * Revision 1.4 1993/04/08 08:26:54 deraadt
! 69: * dmesg output at boottime now tries to print out information as
! 70: * soon as it is available. The output looks much more like Sunos.
! 71: *
! 72: * Revision 1.3 1993/03/24 23:54:19 cgd
! 73: * brought in drivers from David Greenman's ([email protected])
! 74: * BPF package
! 75: *
! 76: * Revision 1.2 93/02/18 17:21:57 davidg
! 77: * Bugs in mbuf cluster allocation fixed
! 78: * Problem with nfs wanting mbufs aligned on longword boundries fixed
! 79: *
1.1 root 80: */
81:
82: #include "we.h"
83: #if NWE > 0
84: /*
85: * Western Digital 8003 ethernet/starlan adapter
86: *
87: * Supports the following interface cards:
88: * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT
89: *
90: * The Western Digital card is one of many AT/MCA ethernet interfaces
91: * based on the National DS8390 Network Interface chip set.
92: */
93: #include "param.h"
94: #include "mbuf.h"
95: #include "socket.h"
96: #include "ioctl.h"
97: #include "errno.h"
98: #include "syslog.h"
99:
100: #include "net/if.h"
1.1.1.3 ! root 101: #include "net/if_types.h"
! 102: #include "net/if_dl.h"
1.1 root 103: #include "net/netisr.h"
104:
105: #ifdef INET
106: #include "netinet/in.h"
107: #include "netinet/in_systm.h"
108: #include "netinet/in_var.h"
109: #include "netinet/ip.h"
110: #include "netinet/if_ether.h"
111: #endif
112:
113: #ifdef NS
114: #include "netns/ns.h"
115: #include "netns/ns_if.h"
116: #endif
117:
1.1.1.3 ! root 118: #include "bpfilter.h"
! 119: #if NBPFILTER > 0
! 120: #include "net/bpf.h"
! 121: #include "net/bpfdesc.h"
! 122: #endif
! 123:
1.1.1.2 root 124: #include "i386/isa/isa.h"
1.1 root 125: #include "i386/isa/if_wereg.h"
126: #include "i386/isa/isa_device.h"
1.1.1.2 root 127: #include "i386/isa/icu.h"
1.1.1.3 ! root 128: #if 0
! 129: #include "i386/include/pio.h"
! 130: #endif
! 131:
! 132: static inline char *we_ring_copy();
1.1 root 133:
134: /*
135: * This constant should really be 60 because the we adds 4 bytes of crc.
1.1.1.2 root 136: * However when set to 60 our packets are ignored by deunas , 3coms are
1.1 root 137: * okay ??????????????????????????????????????????
138: */
139: #define ETHER_MIN_LEN 64
140: #define ETHER_ADDR_LEN 6
141: #define ETHER_HDR_SIZE 14
142:
143: /*
144: * Ethernet software status per interface.
145: *
146: * Each interface is referenced by a network interface structure,
147: * qe_if, which the routing code uses to locate the interface.
148: * This structure contains the output queue for the interface, its address, ...
149: */
150: struct we_softc {
151: struct arpcom we_ac; /* Ethernet common part */
152: #define we_if we_ac.ac_if /* network-visible interface */
153: #define we_addr we_ac.ac_enaddr /* hardware Ethernet address */
1.1.1.3 ! root 154: #define ns_addrp we_ac.ac_enaddr /* hardware Ethernet address */
1.1 root 155: u_char we_flags; /* software state */
156: #define WDF_RUNNING 0x01
157: #define WDF_TXBUSY 0x02
1.1.1.3 ! root 158: #if NBPFILTER > 0
! 159: #define WDF_ATTACHED 0x80
! 160: #endif
1.1 root 161:
162: u_char we_type; /* interface type code */
163: u_short we_vector; /* interrupt vector */
164: short we_io_ctl_addr; /* i/o bus address, control */
165: short we_io_nic_addr; /* i/o bus address, DS8390 */
166:
167: caddr_t we_vmem_addr; /* card RAM virtual memory base */
168: u_long we_vmem_size; /* card RAM bytes */
169: caddr_t we_vmem_ring; /* receive ring RAM vaddress */
170: caddr_t we_vmem_end; /* receive ring RAM end */
1.1.1.3 ! root 171: caddr_t we_bpf; /* Magic Cookie for BPF */
1.1 root 172: } we_softc[NWE];
173:
174: int weprobe(), weattach(), weintr(), westart();
175: int weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
176:
177: struct isa_driver wedriver = {
178: weprobe, weattach, "we",
179: };
180:
1.1.1.2 root 181: static unsigned short wemask[] =
182: { IRQ9, IRQ3, IRQ5, IRQ7, IRQ10, IRQ11, IRQ15, IRQ4 };
183:
1.1 root 184: /*
1.1.1.2 root 185: * Probe the WD8003 to see if its there
1.1 root 186: */
187: weprobe(is)
188: struct isa_device *is;
189: {
190: register int i;
191: register struct we_softc *sc = &we_softc[is->id_unit];
192: union we_mem_sel wem;
193: u_char sum;
1.1.1.3 ! root 194: #ifdef WD8013 /* 20 Sep 92*/
! 195: union we_laar laar;
! 196:
! 197: laar.laar_byte = 0;
! 198: #endif /* WD8013*/
! 199:
! 200: wem.ms_byte = 0; /* 20 Sep 92*/
1.1 root 201:
1.1.1.2 root 202: /* reset card to force it into a known state. */
203: outb(is->id_iobase, 0x80);
204: DELAY(100);
205: outb(is->id_iobase, 0x00);
206: /* wait in the case this card is reading it's EEROM */
207: DELAY(5000);
208:
1.1.1.3 ! root 209: #ifdef WD8013 /* 20 Sep 92*/
! 210: /* allow the NIC to access the shared RAM 16 bits at a time */
! 211:
! 212: laar.addr_l19 = 1;
! 213: laar.lan_16_en = 1;
! 214: laar.mem_16_en = 1;
! 215: outb(is->id_iobase+5, laar.laar_byte); /* Write a 0xc1 */
! 216: #endif /* WD8013*/
! 217:
1.1 root 218: /*
219: * Here we check the card ROM, if the checksum passes, and the
220: * type code and ethernet address check out, then we know we have
221: * a wd8003 card.
222: *
223: * Autoconfiguration: No warning message is printed on error.
224: */
225: for (sum = 0, i = 0; i < 8; ++i)
226: sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
1.1.1.3 ! root 227: if (sum != WD_CHECKSUM) { /* 09 Sep 92*/
! 228: #ifdef WECOMPAT
! 229: printf( "we: probe: checksum failed... installing anyway\n");
! 230: printf( "we: Danpex EW-2016 or other 8013 clone card?\n");
! 231: #else /* !WECOMPAT*/
1.1 root 232: return (0);
1.1.1.3 ! root 233: #endif /* !WECOMPAT*/
! 234: }
1.1 root 235: sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
1.1.1.2 root 236: #ifdef nope
237: if ((sc->we_type & WD_REVMASK) != 2 /* WD8003E or WD8003S */
238: && (sc->we_type & WD_REVMASK) != 4 /* WD8003EBT */
239: && (sc->we_type & WD_REVMASK) != 6) /* WD8003ELB? */
1.1 root 240: return (0);
1.1.1.2 root 241: #endif
242: /*printf("type %x ", sc->we_type);*/
243: if (sc->we_type & WD_SOFTCONFIG) {
244: int iv = inb(is->id_iobase + 1) & 4 |
245: ((inb(is->id_iobase+4) & 0x60) >> 5);
246: /*printf("iv %d ", iv);*/
247: if (wemask[iv] != is->id_irq)
248: return(0);
249: outb(is->id_iobase+4, inb(is->id_iobase+4) | 0x80);
250: }
1.1 root 251:
252: /*
253: * Setup card RAM area and i/o addresses
254: * Kernel Virtual to segment C0000-DFFFF?????
255: */
256: sc->we_io_ctl_addr = is->id_iobase;
257: sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
258: sc->we_vector = is->id_irq;
259: sc->we_vmem_addr = (caddr_t)is->id_maddr;
260: sc->we_vmem_size = is->id_msize;
261: sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
262: sc->we_vmem_end = sc->we_vmem_addr + is->id_msize;
263:
264: /*
265: * Save board ROM station address
266: */
267: for (i = 0; i < ETHER_ADDR_LEN; ++i)
268: sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
269:
270: /*
271: * Mapin interface memory, setup memory select register
272: */
1.1.1.2 root 273: wem.ms_addr = kvtop(sc->we_vmem_addr) >> 13;
1.1 root 274: wem.ms_enable = 1;
275: wem.ms_reset = 0;
276: outb(sc->we_io_ctl_addr, wem.ms_byte);
277:
278: /*
279: * clear interface memory, then sum to make sure its valid
280: */
281: for (i = 0; i < sc->we_vmem_size; ++i)
282: sc->we_vmem_addr[i] = 0x0;
283: for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
284: sum += sc->we_vmem_addr[i];
285: if (sum != 0x0) {
286: printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
287: return (0);
288: }
289:
290: return (WD_IO_PORTS);
291: }
292:
293: /*
294: * Interface exists: make available by filling in network interface
295: * record. System will initialize the interface when it is ready
296: * to accept packets.
297: */
298: weattach(is)
299: struct isa_device *is;
300: {
301: register struct we_softc *sc = &we_softc[is->id_unit];
302: register struct ifnet *ifp = &sc->we_if;
303: union we_command wecmd;
1.1.1.3 ! root 304: struct ifaddr *ifa;
! 305: struct sockaddr_dl *sdl;
1.1 root 306:
307: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
308: wecmd.cs_stp = 1;
309: wecmd.cs_sta = 0;
310: wecmd.cs_ps = 0;
311: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
312: /*
313: * Initialize ifnet structure
314: */
315: ifp->if_unit = is->id_unit;
316: ifp->if_name = "we" ;
317: ifp->if_mtu = ETHERMTU;
318: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ;
319: ifp->if_init = weinit;
320: ifp->if_output = ether_output;
321: ifp->if_start = westart;
322: ifp->if_ioctl = weioctl;
323: ifp->if_reset = wereset;
324: ifp->if_watchdog = wewatchdog;
325: if_attach(ifp);
1.1.1.3 ! root 326: /* Search down the ifa address list looking for the AF_LINK type entry */
! 327: ifa = ifp->if_addrlist;
! 328: while ((ifa != 0) &&
! 329: (ifa->ifa_addr != 0) &&
! 330: (ifa->ifa_addr->sa_family != AF_LINK))
! 331: {
! 332: ifa = ifa->ifa_next;
! 333: }
! 334: /* If we find an AF_LINK type entry, we well fill in the hardware addr */
! 335: if ((ifa != 0) &&
! 336: (ifa->ifa_addr != 0))
! 337: {
! 338: /* Fill in the link level address for this interface */
! 339: sdl = (struct sockaddr_dl *)ifa->ifa_addr;
! 340: sdl->sdl_type = IFT_ETHER;
! 341: sdl->sdl_alen = ETHER_ADDR_LEN;
! 342: sdl->sdl_slen = 0;
! 343: bcopy(sc->we_addr, LLADDR(sdl), ETHER_ADDR_LEN);
! 344: }
! 345:
! 346: #if NBPFILTER > 0
! 347: sc->we_flags &= ~WDF_ATTACHED; /* Make sure BPF attach flag clear */
! 348: #endif
1.1 root 349:
350: /*
351: * Banner...
352: */
1.1.1.3 ! root 353: printf("we%d: %saddr %s\n", is->id_unit,
! 354: (sc->we_type & WD_ETHERNET) ? "enet" : "slan",
1.1 root 355: ether_sprintf(sc->we_addr));
356: }
357:
358: /*
359: * Reset of interface.
360: */
361: wereset(unit, uban)
362: int unit, uban;
363: {
364: if (unit >= NWE)
365: return;
366: printf("we%d: reset\n", unit);
367: /* we_softc[unit].we_flags &= ~WDF_RUNNING; */
368: weinit(unit);
369: }
370:
371: /*
372: * Take interface offline.
373: */
374: westop(unit)
375: int unit;
376: {
377: register struct we_softc *sc = &we_softc[unit];
378: union we_command wecmd;
379: int s;
380:
381: /*
382: * Shutdown DS8390
383: */
384: s = splimp();
385: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
386: wecmd.cs_stp = 1;
387: wecmd.cs_sta = 0;
388: wecmd.cs_ps = 0;
389: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
390: (void) splx(s);
391: }
392:
393: wewatchdog(unit) {
394:
1.1.1.3 ! root 395: weintr(unit);
! 396: /*log(LOG_WARNING,"we%d: soft reset\n", unit);
1.1 root 397: westop(unit);
1.1.1.3 ! root 398: weinit(unit);*/
1.1 root 399: }
400:
1.1.1.3 ! root 401: static Bdry[NWE]; /* 19 Sep 92*/
1.1 root 402: /*
403: * Initialization of interface (really just DS8390).
404: */
405: weinit(unit)
406: int unit;
407: {
408: register struct we_softc *sc = &we_softc[unit];
409: register struct ifnet *ifp = &sc->we_if;
410: union we_command wecmd;
411: int i, s;
1.1.1.3 ! root 412:
! 413: #if NBPFILTER > 0
! 414: if ((sc->we_flags & WDF_ATTACHED) == 0) {
! 415: bpfattach(&sc->we_bpf, ifp, DLT_EN10MB,
! 416: sizeof(struct ether_header));
! 417: sc->we_flags |= WDF_ATTACHED;
! 418: }
! 419: #endif
! 420:
1.1 root 421: /* address not known */
422: if (ifp->if_addrlist == (struct ifaddr *)0)
423: return;
424:
425: /* already running */
426: /*if (ifp->if_flags & IFF_RUNNING) return; */
427:
428: /*
429: * Initialize DS8390 in order given in NSC NIC manual.
430: * this is stock code...please see the National manual for details.
431: */
432: s = splhigh();
1.1.1.3 ! root 433: Bdry[unit] = 0; /* 19 Sep 92*/
1.1 root 434: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
435: wecmd.cs_stp = 1;
436: wecmd.cs_sta = 0;
437: wecmd.cs_ps = 0;
438: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root 439: #ifdef WD8013 /* 20 Sep 92*/
! 440: /* enable 16 bit access if 8013 card */
! 441: outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG16);
! 442: #else /* !WD8013*/
1.1 root 443: outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
1.1.1.3 ! root 444: #endif /* !WD8013*/
1.1 root 445: outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
446: outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
447: outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
448: outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
449: outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
450: outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
451: outb(sc->we_io_nic_addr + WD_P0_PSTOP,
452: sc->we_vmem_size / WD_PAGE_SIZE);
453: outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
454: outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
455: outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
456: wecmd.cs_ps = 1;
457: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
458: for (i = 0; i < ETHER_ADDR_LEN; ++i)
459: outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
460: for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
461: outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
462: outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
463: wecmd.cs_ps = 0;
464: wecmd.cs_stp = 0;
465: wecmd.cs_sta = 1;
466: wecmd.cs_rd = 0x4;
467: outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root 468: #if NBPFILTER > 0
! 469: if (sc->we_if.if_flags & IFF_PROMISC) {
! 470: outb(sc->we_io_nic_addr + WD_P0_RCR,
! 471: WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
! 472: } else
! 473: #endif
! 474: outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
1.1 root 475:
476: /*
477: * Take the interface out of reset, program the vector,
478: * enable interrupts, and tell the world we are up.
479: */
480: ifp->if_flags |= IFF_RUNNING;
481: sc->we_flags &= ~WDF_TXBUSY;
482: (void) splx(s);
483: westart(ifp);
484: }
485:
486: /*
487: * Start output on interface.
488: */
489: westart(ifp)
490: struct ifnet *ifp;
491: {
492: register struct we_softc *sc = &we_softc[ifp->if_unit];
493: struct mbuf *m0, *m;
494: register caddr_t buffer;
495: int len, s;
496: union we_command wecmd;
1.1.1.3 ! root 497:
1.1 root 498: /*
499: * The DS8390 has only one transmit buffer, if it is busy we
500: * must wait until the transmit interrupt completes.
501: */
502: s = splhigh();
1.1.1.3 ! root 503:
1.1 root 504: if (sc->we_flags & WDF_TXBUSY) {
505: (void) splx(s);
506: return;
507: }
508: IF_DEQUEUE(&sc->we_if.if_snd, m);
509: if (m == 0) {
510: (void) splx(s);
511: return;
512: }
513: sc->we_flags |= WDF_TXBUSY;
1.1.1.3 ! root 514:
1.1 root 515: (void) splx(s);
516:
1.1.1.3 ! root 517: #if NBPFILTER > 0
! 518: if (sc->we_bpf) {
! 519: u_short etype;
! 520: int off, datasize, resid;
! 521: struct ether_header *eh;
! 522: struct trailer_header {
! 523: u_short ether_type;
! 524: u_short ether_residual;
! 525: } trailer_header;
! 526: char ether_packet[ETHERMTU+100];
! 527: char *ep;
! 528:
! 529: ep = ether_packet;
! 530:
! 531: /*
! 532: * We handle trailers below:
! 533: * Copy ether header first, then residual data,
! 534: * then data. Put all this in a temporary buffer
! 535: * 'ether_packet' and send off to bpf. Since the
! 536: * system has generated this packet, we assume
! 537: * that all of the offsets in the packet are
! 538: * correct; if they're not, the system will almost
! 539: * certainly crash in m_copydata.
! 540: * We make no assumptions about how the data is
! 541: * arranged in the mbuf chain (i.e. how much
! 542: * data is in each mbuf, if mbuf clusters are
! 543: * used, etc.), which is why we use m_copydata
! 544: * to get the ether header rather than assume
! 545: * that this is located in the first mbuf.
! 546: */
! 547: /* copy ether header */
! 548: m_copydata(m, 0, sizeof(struct ether_header), ep);
! 549: eh = (struct ether_header *) ep;
! 550: ep += sizeof(struct ether_header);
! 551: etype = ntohs(eh->ether_type);
! 552: if (etype >= ETHERTYPE_TRAIL &&
! 553: etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
! 554: datasize = ((etype - ETHERTYPE_TRAIL) << 9);
! 555: off = datasize + sizeof(struct ether_header);
! 556:
! 557: /* copy trailer_header into a data structure */
! 558: m_copydata(m, off, sizeof(struct trailer_header),
! 559: &trailer_header.ether_type);
! 560:
! 561: /* copy residual data */
! 562: m_copydata(m, off+sizeof(struct trailer_header),
! 563: resid = ntohs(trailer_header.ether_residual) -
! 564: sizeof(struct trailer_header), ep);
! 565: ep += resid;
! 566:
! 567: /* copy data */
! 568: m_copydata(m, sizeof(struct ether_header), datasize, ep);
! 569: ep += datasize;
! 570:
! 571: /* restore original ether packet type */
! 572: eh->ether_type = trailer_header.ether_type;
! 573:
! 574: bpf_tap(sc->we_bpf, ether_packet, ep - ether_packet);
! 575: } else
! 576: bpf_mtap(sc->we_bpf, m);
! 577: }
! 578: #endif
! 579:
1.1 root 580: /*
581: * Copy the mbuf chain into the transmit buffer
582: */
583: buffer = sc->we_vmem_addr;
584: len = 0;
585: for (m0 = m; m != 0; m = m->m_next) {
586: bcopy(mtod(m, caddr_t), buffer, m->m_len);
587: buffer += m->m_len;
588: len += m->m_len;
589: }
590:
591: m_freem(m0);
592:
593: /*
594: * Init transmit length registers, and set transmit start flag.
595: */
596: s = splhigh();
597: len = MAX(len, ETHER_MIN_LEN);
598: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
599: wecmd.cs_ps = 0;
600: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
601: outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
602: outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
603: wecmd.cs_txp = 1;
604: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root 605: sc->we_if.if_timer = 3;
1.1 root 606: (void) splx(s);
607: }
608:
609: /*
610: * Ethernet interface interrupt processor
611: */
612: weintr(unit)
613: int unit;
614: {
615: register struct we_softc *sc = &we_softc[unit];
616: union we_command wecmd;
617: union we_interrupt weisr;
618:
619:
620: /* disable onboard interrupts, then get interrupt status */
621: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
622: wecmd.cs_ps = 0;
623: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
624: weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
625: loop:
626: outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
627:
628: /* transmit error */
629: if (weisr.is_txe) {
630: /* need to read these registers to clear status */
631: sc->we_if.if_collisions +=
632: inb(sc->we_io_nic_addr + WD_P0_TBCR0);
633: ++sc->we_if.if_oerrors;
634: }
635:
636: /* receiver error */
637: if (weisr.is_rxe) {
638: /* need to read these registers to clear status */
639: (void) inb(sc->we_io_nic_addr + 0xD);
640: (void) inb(sc->we_io_nic_addr + 0xE);
641: (void) inb(sc->we_io_nic_addr + 0xF);
642: ++sc->we_if.if_ierrors;
643: }
644:
645: /* normal transmit complete */
646: if (weisr.is_ptx || weisr.is_txe)
647: wetint (unit);
648:
649: /* normal receive notification */
650: if (weisr.is_prx || weisr.is_rxe)
651: werint (unit);
652:
653: /* try to start transmit */
654: westart(&sc->we_if);
655:
656: /* re-enable onboard interrupts */
657: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
658: wecmd.cs_ps = 0;
659: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
660: outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
661: weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
662: if (weisr.is_byte) goto loop;
663: }
664:
665: /*
666: * Ethernet interface transmit interrupt.
667: */
668: wetint(unit)
669: int unit;
670: {
671: register struct we_softc *sc = &we_softc[unit];
672:
673: /*
674: * Do some statistics (assume page zero of NIC mapped in)
675: */
676: sc->we_flags &= ~WDF_TXBUSY;
677: sc->we_if.if_timer = 0;
678: ++sc->we_if.if_opackets;
679: sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
680: }
681:
682: /*
683: * Ethernet interface receiver interrupt.
684: */
685: werint(unit)
686: int unit;
687: {
688: register struct we_softc *sc = &we_softc[unit];
689: u_char bnry, curr;
690: long len;
691: union we_command wecmd;
692: struct we_ring *wer;
693:
694: /*
695: * Traverse the receive ring looking for packets to pass back.
696: * The search is complete when we find a descriptor not in use.
697: */
698: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
699: wecmd.cs_ps = 0;
700: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
701: bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
702: wecmd.cs_ps = 1;
703: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
704: curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
1.1.1.3 ! root 705: if(Bdry[unit]) /* 19 Sep 92*/
! 706: bnry = Bdry[unit];
1.1 root 707:
708: while (bnry != curr)
709: {
710: /* get pointer to this buffer header structure */
711: wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
712:
713: /* count includes CRC */
714: len = wer->we_count - 4;
1.1.1.3 ! root 715: if (len > 30 && len <= ETHERMTU+100)
1.1 root 716: weread(sc, (caddr_t)(wer + 1), len);
1.1.1.3 ! root 717: else printf("we%d: reject - bad length %d", unit, len);
1.1 root 718:
719: outofbufs:
720: wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
721: wecmd.cs_ps = 0;
722: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
723:
724: /* advance on chip Boundry register */
725: if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
726: bnry = WD_TXBUF_SIZE;
727: outb(sc->we_io_nic_addr + WD_P0_BNRY,
728: sc->we_vmem_size / WD_PAGE_SIZE-1);
729:
730: } else {
731: if (len > 30 && len <= ETHERMTU+100)
732: bnry = wer->we_next_packet;
733: else bnry = curr;
734:
735: /* watch out for NIC overflow, reset Boundry if invalid */
736: if ((bnry - 1) < WD_TXBUF_SIZE) {
737: outb(sc->we_io_nic_addr + WD_P0_BNRY,
738: (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
739: bnry = WD_TXBUF_SIZE;
740: } else
741: outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
742: }
743:
744: /* refresh our copy of CURR */
745: wecmd.cs_ps = 1;
746: outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
747: curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
748: }
1.1.1.3 ! root 749: Bdry[unit] = bnry; /* 19 Sep 92*/
1.1 root 750: }
751:
752: /*
753: * Process an ioctl request.
754: */
755: weioctl(ifp, cmd, data)
756: register struct ifnet *ifp;
757: int cmd;
758: caddr_t data;
759: {
760: register struct ifaddr *ifa = (struct ifaddr *)data;
761: struct we_softc *sc = &we_softc[ifp->if_unit];
762: struct ifreq *ifr = (struct ifreq *)data;
763: int s = splimp(), error = 0;
764:
765:
766: switch (cmd) {
767:
768: case SIOCSIFADDR:
769: ifp->if_flags |= IFF_UP;
770:
771: switch (ifa->ifa_addr->sa_family) {
772: #ifdef INET
773: case AF_INET:
774: weinit(ifp->if_unit); /* before arpwhohas */
775: ((struct arpcom *)ifp)->ac_ipaddr =
776: IA_SIN(ifa)->sin_addr;
777: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
778: break;
779: #endif
780: #ifdef NS
781: case AF_NS:
782: {
783: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
784:
785: if (ns_nullhost(*ina))
1.1.1.3 ! root 786: ina->x_host = *(union ns_host *)(sc->ns_addrp);
1.1 root 787: else {
788: /*
1.1.1.2 root 789: * The manual says we cant change the address
1.1 root 790: * while the receiver is armed,
791: * so reset everything
792: */
793: ifp->if_flags &= ~IFF_RUNNING;
794: bcopy((caddr_t)ina->x_host.c_host,
1.1.1.3 ! root 795: (caddr_t)sc->ns_addrp, sizeof(sc->ns_addrp));
1.1 root 796: }
797: weinit(ifp->if_unit); /* does ne_setaddr() */
798: break;
799: }
800: #endif
801: default:
802: weinit(ifp->if_unit);
803: break;
804: }
805: break;
806:
807: case SIOCSIFFLAGS:
808: if ((ifp->if_flags & IFF_UP) == 0 &&
809: ifp->if_flags & IFF_RUNNING) {
810: ifp->if_flags &= ~IFF_RUNNING;
811: westop(ifp->if_unit);
812: } else if (ifp->if_flags & IFF_UP &&
813: (ifp->if_flags & IFF_RUNNING) == 0)
814: weinit(ifp->if_unit);
1.1.1.3 ! root 815: #if NBPFILTER > 0
! 816: if (sc->we_if.if_flags & IFF_PROMISC) {
! 817: outb(sc->we_io_nic_addr + WD_P0_RCR,
! 818: WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
! 819: } else
! 820: #endif
! 821: outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
1.1 root 822: break;
823:
824: #ifdef notdef
825: case SIOCGHWADDR:
826: bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
827: sizeof(sc->sc_addr));
828: break;
829: #endif
830:
831: default:
832: error = EINVAL;
833: }
834: splx(s);
835: return (error);
836: }
837: /*
838: * set ethernet address for unit
839: */
840: wesetaddr(physaddr, unit)
841: u_char *physaddr;
842: int unit;
843: {
844: register struct we_softc *sc = &we_softc[unit];
845: register int i;
846:
847: /*
848: * Rewrite ethernet address, and then force restart of NIC
849: */
850: for (i = 0; i < ETHER_ADDR_LEN; i++)
851: sc->we_addr[i] = physaddr[i];
852: sc->we_flags &= ~WDF_RUNNING;
853: weinit(unit);
854: }
855:
1.1.1.3 ! root 856: #define ringoffset(sc, eh, off, type) \
! 857: ((type)( ((caddr_t)(eh)+(off) >= (sc)->we_vmem_end) ? \
! 858: (((caddr_t)(eh)+(off))) - (sc)->we_vmem_end \
1.1 root 859: + (sc)->we_vmem_ring: \
1.1.1.3 ! root 860: ((caddr_t)(eh)+(off)) ))
1.1 root 861: /*
862: * Pass a packet to the higher levels.
863: * We deal with the trailer protocol here.
864: */
865: weread(sc, buf, len)
866: register struct we_softc *sc;
867: char *buf;
868: int len;
869: {
1.1.1.3 ! root 870: caddr_t we_ring_copy();
! 871: struct ether_header *eh;
! 872: struct mbuf *m, *head, *we_ring_to_mbuf();
1.1 root 873: int off, resid;
1.1.1.3 ! root 874: u_short etype;
! 875: struct trailer_header {
! 876: u_short trail_type;
! 877: u_short trail_residual;
! 878: } trailer_header;
! 879:
! 880: ++sc->we_if.if_ipackets;
! 881:
! 882: /* Allocate a header mbuf */
! 883: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 884: if (m == 0)
! 885: goto bad;
! 886: m->m_pkthdr.rcvif = &sc->we_if;
! 887: m->m_pkthdr.len = len;
! 888: m->m_len = 0;
! 889: head = m;
1.1 root 890:
891: eh = (struct ether_header *)buf;
892:
1.1.1.3 ! root 893: #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
! 894: #define EOFF (EROUND - sizeof(struct ether_header))
! 895:
! 896: /*
! 897: * The following assumes there is room for
! 898: * the ether header in the header mbuf
! 899: */
! 900: head->m_data += EOFF;
! 901: bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
! 902: buf += sizeof(struct ether_header);
! 903: head->m_len += sizeof(struct ether_header);
1.1 root 904: len -= sizeof(struct ether_header);
1.1.1.3 ! root 905:
! 906: etype = ntohs((u_short)eh->ether_type);
1.1 root 907:
908: /*
1.1.1.3 ! root 909: * Deal with trailer protocol:
! 910: * If trailer protocol, calculate the datasize as 'off',
! 911: * which is also the offset to the trailer header.
! 912: * Set resid to the amount of packet data following the
! 913: * trailer header.
! 914: * Finally, copy residual data into mbuf chain.
1.1 root 915: */
1.1.1.3 ! root 916: if (etype >= ETHERTYPE_TRAIL &&
! 917: etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
! 918:
! 919: off = (etype - ETHERTYPE_TRAIL) << 9;
! 920: if ((off + sizeof(struct trailer_header)) > len)
! 921: goto bad; /* insanity */
! 922:
! 923: eh->ether_type = *ringoffset(sc, buf, off, u_short *);
! 924: resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
! 925:
! 926: if ((off + resid) > len) goto bad; /* insanity */
! 927:
! 928: resid -= sizeof(struct trailer_header);
! 929: if (resid < 0) goto bad; /* insanity */
! 930:
! 931: m = we_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
! 932: if (m == 0) goto bad;
! 933:
! 934: len = off;
! 935: head->m_pkthdr.len -= 4; /* subtract trailer header */
! 936: }
! 937:
! 938: /*
! 939: * Pull packet off interface. Or if this was a trailer packet,
! 940: * the data portion is appended.
! 941: */
! 942: m = we_ring_to_mbuf(sc, buf, m, len);
! 943: if (m == 0) goto bad;
! 944:
! 945: #if NBPFILTER > 0
! 946: /*
! 947: * Check if there's a bpf filter listening on this interface.
! 948: * If so, hand off the raw packet to bpf.
! 949: */
! 950: if (sc->we_bpf) {
! 951: bpf_mtap(sc->we_bpf, head);
! 952: }
! 953:
! 954: /*
! 955: * Note that the interface cannot be in promiscuous mode if
! 956: * there are no bpf listeners. And if we are in promiscuous
! 957: * mode, we have to check if this packet is really ours.
! 958: *
! 959: * XXX This test does not support multicasts.
! 960: */
! 961: if ((sc->we_if.if_flags & IFF_PROMISC) &&
! 962: bcmp(eh->ether_dhost, sc->we_addr,
! 963: sizeof(eh->ether_dhost)) != 0 &&
! 964: bcmp(eh->ether_dhost, etherbroadcastaddr,
! 965: sizeof(eh->ether_dhost)) != 0) {
! 966:
! 967: m_freem(head);
! 968: return;
! 969: }
! 970: #endif
! 971:
! 972: /*
! 973: * Fix up data start offset in mbuf to point past ether header
! 974: */
! 975: m_adj(head, sizeof(struct ether_header));
! 976:
! 977: /*
! 978: * silly ether_input routine needs 'type' in host byte order
! 979: */
! 980: eh->ether_type = ntohs(eh->ether_type);
! 981:
! 982: ether_input(&sc->we_if, eh, head);
! 983: return;
! 984:
! 985: bad: if (head)
! 986: m_freem(head);
! 987: return;
1.1 root 988: }
989:
990: /*
991: * Supporting routines
992: */
993:
994: /*
1.1.1.3 ! root 995: * Copy data from receive buffer to end of mbuf chain
! 996: * allocate additional mbufs as needed. return pointer
! 997: * to last mbuf in chain.
! 998: * sc = we info
! 999: * src = pointer in we ring buffer
! 1000: * dst = pointer to last mbuf in mbuf chain to copy to
! 1001: * amount = amount of data to copy
1.1 root 1002: */
1003: struct mbuf *
1.1.1.3 ! root 1004: we_ring_to_mbuf(sc,src,dst,total_len)
1.1 root 1005: struct we_softc *sc;
1.1.1.3 ! root 1006: char *src;
! 1007: struct mbuf *dst;
! 1008: int total_len;
1.1 root 1009: {
1.1.1.3 ! root 1010: register struct mbuf *m = dst;
1.1 root 1011:
1.1.1.3 ! root 1012: while (total_len > 0) {
! 1013: register int amount = min(total_len, M_TRAILINGSPACE(m));
1.1 root 1014:
1.1.1.3 ! root 1015: if (amount == 0) { /* no more data in this mbuf, alloc another */
! 1016: /*
! 1017: * if there is enough data for an mbuf cluster, attempt
! 1018: * to allocate one of those, otherwise, a regular mbuf
! 1019: * will do.
! 1020: */
! 1021: dst = m;
1.1 root 1022: MGET(m, M_DONTWAIT, MT_DATA);
1.1.1.3 ! root 1023: if (m == 0)
1.1 root 1024: return (0);
1025:
1.1.1.3 ! root 1026: if (total_len >= MINCLSIZE)
! 1027: MCLGET(m, M_DONTWAIT);
! 1028:
! 1029: m->m_len = 0;
! 1030: dst->m_next = m;
! 1031: amount = min(total_len, M_TRAILINGSPACE(m));
1.1 root 1032: }
1.1.1.3 ! root 1033:
! 1034: src = we_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
! 1035:
! 1036: m->m_len += amount;
! 1037: total_len -= amount;
! 1038:
1.1 root 1039: }
1.1.1.3 ! root 1040: return (m);
! 1041: }
! 1042:
! 1043: static inline char *
! 1044: we_ring_copy(sc,src,dst,amount)
! 1045: struct we_softc *sc;
! 1046: char *src;
! 1047: char *dst;
! 1048: int amount;
! 1049: {
! 1050: int tmp_amount;
! 1051:
! 1052: /* does copy wrap to lower addr in ring buffer? */
! 1053: if (src + amount > sc->we_vmem_end) {
! 1054: tmp_amount = sc->we_vmem_end - src;
! 1055: bcopy(src,dst,tmp_amount); /* copy amount up to end */
! 1056: amount -= tmp_amount;
! 1057: src = sc->we_vmem_ring;
! 1058: dst += tmp_amount;
! 1059: }
! 1060:
! 1061: bcopy(src, dst, amount);
! 1062:
! 1063: return(src + amount);
1.1 root 1064: }
1065: #endif
1.1.1.3 ! root 1066:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.