141480Smckusick /* 2*63151Sbostic * Copyright (c) 1982, 1990, 1993 3*63151Sbostic * The Regents of the University of California. All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*63151Sbostic * @(#)if_le.c 8.1 (Berkeley) 06/10/93 841480Smckusick */ 941480Smckusick 1041480Smckusick #include "le.h" 1141480Smckusick #if NLE > 0 1241480Smckusick 1347567Smccanne #include "bpfilter.h" 1447567Smccanne 1541480Smckusick /* 1641480Smckusick * AMD 7990 LANCE 1741480Smckusick * 1854719Ssklower * This driver will accept tailer encapsulated packets even 1941480Smckusick * though it buys us nothing. The motivation was to avoid incompatibilities 2041480Smckusick * with VAXen, SUNs, and others that handle and benefit from them. 2141480Smckusick * This reasoning is dubious. 2241480Smckusick */ 2356507Sbostic #include <sys/param.h> 2456507Sbostic #include <sys/proc.h> 2556507Sbostic #include <sys/systm.h> 2656507Sbostic #include <sys/mbuf.h> 2756507Sbostic #include <sys/buf.h> 2856507Sbostic #include <sys/protosw.h> 2956507Sbostic #include <sys/socket.h> 3056507Sbostic #include <sys/syslog.h> 3156507Sbostic #include <sys/ioctl.h> 3256507Sbostic #include <sys/errno.h> 3341480Smckusick 3456507Sbostic #include <net/if.h> 3556507Sbostic #include <net/netisr.h> 3656507Sbostic #include <net/route.h> 3741480Smckusick 3841480Smckusick #ifdef INET 3956507Sbostic #include <netinet/in.h> 4056507Sbostic #include <netinet/in_systm.h> 4156507Sbostic #include <netinet/in_var.h> 4256507Sbostic #include <netinet/ip.h> 4356507Sbostic #include <netinet/if_ether.h> 4441480Smckusick #endif 4541480Smckusick 4641480Smckusick #ifdef NS 4756507Sbostic #include <netns/ns.h> 4856507Sbostic #include <netns/ns_if.h> 4941480Smckusick #endif 5041480Smckusick 5157348Shibler #if defined (CCITT) && defined (LLC) 5257348Shibler #include <sys/socketvar.h> 5357348Shibler #include <netccitt/x25.h> 5457348Shibler extern llc_ctlinput(), cons_rtrequest(); 5557348Shibler #endif 5657348Shibler 5756507Sbostic #include <machine/cpu.h> 5856507Sbostic #include <hp300/hp300/isr.h> 5956507Sbostic #include <machine/mtpr.h> 6056507Sbostic #include <hp/dev/device.h> 6156507Sbostic #include <hp300/dev/if_lereg.h> 6257349Shibler #ifdef USELEDS 6357349Shibler #include <hp300/hp300/led.h> 6457349Shibler #endif 6541480Smckusick 6647567Smccanne #if NBPFILTER > 0 6756507Sbostic #include <net/bpf.h> 6856507Sbostic #include <net/bpfdesc.h> 6947567Smccanne #endif 7047567Smccanne 7141480Smckusick /* offsets for: ID, REGS, MEM, NVRAM */ 7241480Smckusick int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; 7341480Smckusick 7441480Smckusick int leattach(); 7541480Smckusick struct driver ledriver = { 7641480Smckusick leattach, "le", 7741480Smckusick }; 7841480Smckusick 7941480Smckusick struct isr le_isr[NLE]; 8041480Smckusick int ledebug = 0; /* console error messages */ 8141480Smckusick 8257348Shibler int leintr(), leinit(), leioctl(), lestart(), ether_output(), lereset(); 8353034Ssklower struct mbuf *m_devget(); 8441480Smckusick extern struct ifnet loif; 8541480Smckusick 8641480Smckusick /* 8741480Smckusick * Ethernet software status per interface. 8841480Smckusick * 8941480Smckusick * Each interface is referenced by a network interface structure, 9041480Smckusick * le_if, which the routing code uses to locate the interface. 9141480Smckusick * This structure contains the output queue for the interface, its address, ... 9241480Smckusick */ 9341480Smckusick struct le_softc { 9441480Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 9541480Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 9641480Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 9741480Smckusick struct lereg0 *sc_r0; /* DIO registers */ 9841480Smckusick struct lereg1 *sc_r1; /* LANCE registers */ 9941480Smckusick struct lereg2 *sc_r2; /* dual-port RAM */ 10041480Smckusick int sc_rmd; /* predicted next rmd to process */ 10153930Shibler int sc_tmd; /* next available tmd */ 10253930Shibler int sc_txcnt; /* # of transmit buffers in use */ 10353930Shibler /* stats */ 10441480Smckusick int sc_runt; 10541480Smckusick int sc_jab; 10641480Smckusick int sc_merr; 10741480Smckusick int sc_babl; 10841480Smckusick int sc_cerr; 10941480Smckusick int sc_miss; 11053930Shibler int sc_rown; 11141480Smckusick int sc_xown; 11253930Shibler int sc_xown2; 11341480Smckusick int sc_uflo; 11441480Smckusick int sc_rxlen; 11541480Smckusick int sc_rxoff; 11641480Smckusick int sc_txoff; 11741480Smckusick int sc_busy; 11848771Smccanne short sc_iflags; 11941480Smckusick } le_softc[NLE]; 12041480Smckusick 12141480Smckusick /* access LANCE registers */ 12241480Smckusick #define LERDWR(cntl, src, dst) \ 12341480Smckusick do { \ 12441480Smckusick (dst) = (src); \ 12541480Smckusick } while (((cntl)->ler0_status & LE_ACK) == 0); 12641480Smckusick 12741480Smckusick /* 12841480Smckusick * Interface exists: make available by filling in network interface 12941480Smckusick * record. System will initialize the interface when it is ready 13041480Smckusick * to accept packets. 13141480Smckusick */ 13241480Smckusick leattach(hd) 13341480Smckusick struct hp_device *hd; 13441480Smckusick { 13541480Smckusick register struct lereg0 *ler0; 13641480Smckusick register struct lereg2 *ler2; 13741480Smckusick struct lereg2 *lemem = 0; 13841480Smckusick struct le_softc *le = &le_softc[hd->hp_unit]; 13941480Smckusick struct ifnet *ifp = &le->sc_if; 14041480Smckusick char *cp; 14141480Smckusick int i; 14241480Smckusick 14341480Smckusick ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); 14441480Smckusick le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); 14541480Smckusick ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); 14641480Smckusick if (ler0->ler0_id != LEID) 14741480Smckusick return(0); 14841480Smckusick le_isr[hd->hp_unit].isr_intr = leintr; 14941480Smckusick hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); 15041480Smckusick le_isr[hd->hp_unit].isr_arg = hd->hp_unit; 15141480Smckusick ler0->ler0_id = 0xFF; 15241480Smckusick DELAY(100); 15341480Smckusick 15441480Smckusick /* 15541480Smckusick * Read the ethernet address off the board, one nibble at a time. 15641480Smckusick */ 15741480Smckusick cp = (char *)(lestd[3] + (int)hd->hp_addr); 15841480Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 15941480Smckusick le->sc_addr[i] = (*++cp & 0xF) << 4; 16041480Smckusick cp++; 16141480Smckusick le->sc_addr[i] |= *++cp & 0xF; 16241480Smckusick cp++; 16341480Smckusick } 16441480Smckusick printf("le%d: hardware address %s\n", hd->hp_unit, 16541480Smckusick ether_sprintf(le->sc_addr)); 16641480Smckusick 16741480Smckusick /* 16841480Smckusick * Setup for transmit/receive 16941480Smckusick */ 17041480Smckusick ler2->ler2_mode = LE_MODE; 17154719Ssklower ler2->ler2_ladrf[0] = 0; 17254719Ssklower ler2->ler2_ladrf[1] = 0; 17341480Smckusick ler2->ler2_rlen = LE_RLEN; 17441480Smckusick ler2->ler2_rdra = (int)lemem->ler2_rmd; 17541480Smckusick ler2->ler2_tlen = LE_TLEN; 17641480Smckusick ler2->ler2_tdra = (int)lemem->ler2_tmd; 17741480Smckusick isrlink(&le_isr[hd->hp_unit]); 17841480Smckusick ler0->ler0_status = LE_IE; 17941480Smckusick 18041480Smckusick ifp->if_unit = hd->hp_unit; 18141480Smckusick ifp->if_name = "le"; 18241480Smckusick ifp->if_mtu = ETHERMTU; 18341480Smckusick ifp->if_init = leinit; 18457348Shibler ifp->if_reset = lereset; 18541480Smckusick ifp->if_ioctl = leioctl; 18641480Smckusick ifp->if_output = ether_output; 18741480Smckusick ifp->if_start = lestart; 18854719Ssklower #ifdef MULTICAST 18954719Ssklower ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 19054719Ssklower #else 19141480Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 19254719Ssklower #endif 19347567Smccanne #if NBPFILTER > 0 19454719Ssklower bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 19547567Smccanne #endif 19641480Smckusick if_attach(ifp); 19741480Smckusick return (1); 19841480Smckusick } 19941480Smckusick 20054719Ssklower #ifdef MULTICAST 20154719Ssklower /* 20254719Ssklower * Setup the logical address filter 20354719Ssklower */ 20454719Ssklower void 20554719Ssklower lesetladrf(sc) 20654719Ssklower register struct le_softc *sc; 20754719Ssklower { 20854719Ssklower register volatile struct lereg2 *ler2 = sc->sc_r2; 20954719Ssklower register struct ifnet *ifp = &sc->sc_if; 21054719Ssklower register struct ether_multi *enm; 21154719Ssklower register u_char *cp; 21254719Ssklower register u_long crc; 21354719Ssklower register u_long c; 21454719Ssklower register int i, len; 21554719Ssklower struct ether_multistep step; 21654719Ssklower 21754719Ssklower /* 21854719Ssklower * Set up multicast address filter by passing all multicast 21954719Ssklower * addresses through a crc generator, and then using the high 22054719Ssklower * order 6 bits as a index into the 64 bit logical address 22154719Ssklower * filter. The high order two bits select the word, while the 22254719Ssklower * rest of the bits select the bit within the word. 22354719Ssklower */ 22454719Ssklower 22554719Ssklower ler2->ler2_ladrf[0] = 0; 22654719Ssklower ler2->ler2_ladrf[1] = 0; 22754719Ssklower ifp->if_flags &= ~IFF_ALLMULTI; 22854719Ssklower ETHER_FIRST_MULTI(step, &sc->sc_ac, enm); 22954719Ssklower while (enm != NULL) { 23054719Ssklower if (bcmp((caddr_t)&enm->enm_addrlo, 23154719Ssklower (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) { 23254719Ssklower /* 23354719Ssklower * We must listen to a range of multicast 23454719Ssklower * addresses. For now, just accept all 23554719Ssklower * multicasts, rather than trying to set only 23654719Ssklower * those filter bits needed to match the range. 23754719Ssklower * (At this time, the only use of address 23854719Ssklower * ranges is for IP multicast routing, for 23954719Ssklower * which the range is big enough to require all 24054719Ssklower * bits set.) 24154719Ssklower */ 24254719Ssklower ler2->ler2_ladrf[0] = 0xffffffff; 24354719Ssklower ler2->ler2_ladrf[1] = 0xffffffff; 24454719Ssklower ifp->if_flags |= IFF_ALLMULTI; 24554719Ssklower return; 24654719Ssklower } 24754719Ssklower 24854719Ssklower cp = (unsigned char *)&enm->enm_addrlo; 24954719Ssklower c = *cp; 25054719Ssklower crc = 0xffffffff; 25154719Ssklower len = 6; 25254719Ssklower while (len-- > 0) { 25354719Ssklower c = *cp; 25454719Ssklower for (i = 0; i < 8; i++) { 25554719Ssklower if ((c & 0x01) ^ (crc & 0x01)) { 25654719Ssklower crc >>= 1; 25754719Ssklower crc = crc ^ 0xedb88320; 25854719Ssklower } 25954719Ssklower else 26054719Ssklower crc >>= 1; 26154719Ssklower c >>= 1; 26254719Ssklower } 26354719Ssklower cp++; 26454719Ssklower } 26554719Ssklower /* Just want the 6 most significant bits. */ 26654719Ssklower crc = crc >> 26; 26754719Ssklower 26854719Ssklower /* Turn on the corresponding bit in the filter. */ 26954719Ssklower ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f); 27054719Ssklower 27154719Ssklower ETHER_NEXT_MULTI(step, enm); 27254719Ssklower } 27354719Ssklower } 27454719Ssklower #endif 27554719Ssklower 27650816Ssklower ledrinit(ler2, le) 27741480Smckusick register struct lereg2 *ler2; 27850816Ssklower register struct le_softc *le; 27941480Smckusick { 28041480Smckusick register struct lereg2 *lemem = 0; 28141480Smckusick register int i; 28241480Smckusick 28350816Ssklower ler2->ler2_padr[0] = le->sc_addr[1]; 28450816Ssklower ler2->ler2_padr[1] = le->sc_addr[0]; 28550816Ssklower ler2->ler2_padr[2] = le->sc_addr[3]; 28650816Ssklower ler2->ler2_padr[3] = le->sc_addr[2]; 28750816Ssklower ler2->ler2_padr[4] = le->sc_addr[5]; 28850816Ssklower ler2->ler2_padr[5] = le->sc_addr[4]; 28941480Smckusick for (i = 0; i < LERBUF; i++) { 29041480Smckusick ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; 29141480Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 29241480Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 29341480Smckusick ler2->ler2_rmd[i].rmd3 = 0; 29441480Smckusick } 29541480Smckusick for (i = 0; i < LETBUF; i++) { 29641480Smckusick ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; 29741480Smckusick ler2->ler2_tmd[i].tmd1 = 0; 29841480Smckusick ler2->ler2_tmd[i].tmd2 = 0; 29941480Smckusick ler2->ler2_tmd[i].tmd3 = 0; 30041480Smckusick } 30154719Ssklower /* Setup the logical address filter */ 30254719Ssklower #ifdef MULTICAST 30354719Ssklower lesetladrf(le); 30454719Ssklower #else 30554719Ssklower ler2->ler2_ladrf[0] = 0; 30654719Ssklower ler2->ler2_ladrf[1] = 0; 30754719Ssklower #endif 30841480Smckusick } 30941480Smckusick 31041480Smckusick lereset(unit) 31141480Smckusick register int unit; 31241480Smckusick { 31341480Smckusick register struct le_softc *le = &le_softc[unit]; 31441480Smckusick register struct lereg0 *ler0 = le->sc_r0; 31541480Smckusick register struct lereg1 *ler1 = le->sc_r1; 31641480Smckusick register struct lereg2 *lemem = 0; 31741480Smckusick register int timo = 100000; 31841480Smckusick register int stat; 31941480Smckusick 32041480Smckusick #ifdef lint 32141480Smckusick stat = unit; 32241480Smckusick #endif 32347567Smccanne #if NBPFILTER > 0 32447567Smccanne if (le->sc_if.if_flags & IFF_PROMISC) 32547567Smccanne /* set the promiscuous bit */ 32647567Smccanne le->sc_r2->ler2_mode = LE_MODE|0x8000; 32747567Smccanne else 32847567Smccanne le->sc_r2->ler2_mode = LE_MODE; 32947567Smccanne #endif 33041480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 33141480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 33250816Ssklower ledrinit(le->sc_r2, le); 33353930Shibler le->sc_rmd = le->sc_tmd = 0; 33441480Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 33541480Smckusick LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); 33641480Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 33741480Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 33841480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 33941480Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 34041480Smckusick do { 34141480Smckusick if (--timo == 0) { 34241480Smckusick printf("le%d: init timeout, stat = 0x%x\n", 34341480Smckusick unit, stat); 34441480Smckusick break; 34541480Smckusick } 34641480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 34741480Smckusick } while ((stat & LE_IDON) == 0); 34841480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 34941480Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 35041480Smckusick LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); 35141480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 35241480Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 35341480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 35453930Shibler le->sc_txcnt = 0; 35541480Smckusick } 35641480Smckusick 35741480Smckusick /* 35841480Smckusick * Initialization of interface 35941480Smckusick */ 36041480Smckusick leinit(unit) 36141480Smckusick int unit; 36241480Smckusick { 36353034Ssklower register struct ifnet *ifp = &le_softc[unit].sc_if; 36453034Ssklower register struct ifaddr *ifa; 36541480Smckusick int s; 36641480Smckusick 36741480Smckusick /* not yet, if address still unknown */ 36853034Ssklower for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) 36953034Ssklower if (ifa == 0) 37053034Ssklower return; 37153034Ssklower else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) 37253034Ssklower break; 37341480Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 37441480Smckusick s = splimp(); 37541480Smckusick ifp->if_flags |= IFF_RUNNING; 37641480Smckusick lereset(unit); 37741480Smckusick (void) lestart(ifp); 37841480Smckusick splx(s); 37941480Smckusick } 38041480Smckusick } 38141480Smckusick 38241480Smckusick /* 38341480Smckusick * Start output on interface. Get another datagram to send 38441480Smckusick * off of the interface queue, and copy it to the interface 38541480Smckusick * before starting the output. 38641480Smckusick */ 38741480Smckusick lestart(ifp) 38841480Smckusick struct ifnet *ifp; 38941480Smckusick { 39041480Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 39141480Smckusick register struct letmd *tmd; 39241480Smckusick register struct mbuf *m; 39341480Smckusick int len; 39441480Smckusick 39541480Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 39641480Smckusick return (0); 39753930Shibler tmd = &le->sc_r2->ler2_tmd[le->sc_tmd]; 39853930Shibler do { 39953930Shibler if (tmd->tmd1 & LE_OWN) { 40053930Shibler le->sc_xown2++; 40153930Shibler return (0); 40253930Shibler } 40353930Shibler IF_DEQUEUE(&le->sc_if.if_snd, m); 40453930Shibler if (m == 0) 40553930Shibler return (0); 40653930Shibler len = leput(le->sc_r2->ler2_tbuf[le->sc_tmd], m); 40747567Smccanne #if NBPFILTER > 0 40853930Shibler /* 40953930Shibler * If bpf is listening on this interface, let it 41053930Shibler * see the packet before we commit it to the wire. 41153930Shibler */ 41254719Ssklower if (ifp->if_bpf) 41354719Ssklower bpf_tap(ifp->if_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd], 41453930Shibler len); 41547567Smccanne #endif 41653930Shibler 41753930Shibler tmd->tmd3 = 0; 41853930Shibler tmd->tmd2 = -len; 41953034Ssklower tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 42053930Shibler if (++le->sc_tmd == LETBUF) { 42153930Shibler le->sc_tmd = 0; 42253930Shibler tmd = le->sc_r2->ler2_tmd; 42353930Shibler } else 42453930Shibler tmd++; 42553930Shibler } while (++le->sc_txcnt < LETBUF); 42653930Shibler le->sc_if.if_flags |= IFF_OACTIVE; 42741480Smckusick return (0); 42841480Smckusick } 42941480Smckusick 43041480Smckusick leintr(unit) 43141480Smckusick register int unit; 43241480Smckusick { 43341480Smckusick register struct le_softc *le = &le_softc[unit]; 43441480Smckusick register struct lereg0 *ler0 = le->sc_r0; 43541480Smckusick register struct lereg1 *ler1; 43641480Smckusick register int stat; 43741480Smckusick 43841480Smckusick if ((ler0->ler0_status & LE_IR) == 0) 43941480Smckusick return(0); 44041480Smckusick if (ler0->ler0_status & LE_JAB) { 44141480Smckusick le->sc_jab++; 44241480Smckusick lereset(unit); 44341480Smckusick return(1); 44441480Smckusick } 44541480Smckusick ler1 = le->sc_r1; 44641480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 44741480Smckusick if (stat & LE_SERR) { 44841480Smckusick leerror(unit, stat); 44941480Smckusick if (stat & LE_MERR) { 45041480Smckusick le->sc_merr++; 45141480Smckusick lereset(unit); 45241480Smckusick return(1); 45341480Smckusick } 45441480Smckusick if (stat & LE_BABL) 45541480Smckusick le->sc_babl++; 45641480Smckusick if (stat & LE_CERR) 45741480Smckusick le->sc_cerr++; 45841480Smckusick if (stat & LE_MISS) 45941480Smckusick le->sc_miss++; 46041480Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 46141480Smckusick } 46241480Smckusick if ((stat & LE_RXON) == 0) { 46341480Smckusick le->sc_rxoff++; 46441480Smckusick lereset(unit); 46541480Smckusick return(1); 46641480Smckusick } 46741480Smckusick if ((stat & LE_TXON) == 0) { 46841480Smckusick le->sc_txoff++; 46941480Smckusick lereset(unit); 47041480Smckusick return(1); 47141480Smckusick } 47253930Shibler if (stat & LE_RINT) 47341480Smckusick lerint(unit); 47453930Shibler if (stat & LE_TINT) 47541480Smckusick lexint(unit); 47641480Smckusick return(1); 47741480Smckusick } 47841480Smckusick 47941480Smckusick /* 48041480Smckusick * Ethernet interface transmitter interrupt. 48141480Smckusick * Start another output if more data to send. 48241480Smckusick */ 48341480Smckusick lexint(unit) 48441480Smckusick register int unit; 48541480Smckusick { 48641480Smckusick register struct le_softc *le = &le_softc[unit]; 48750823Ssklower register struct letmd *tmd; 48853930Shibler int i, gotone = 0; 48941480Smckusick 49057349Shibler #ifdef USELEDS 49157349Shibler if (inledcontrol == 0) 49257349Shibler ledcontrol(0, 0, LED_LANXMT); 49357349Shibler #endif 49453930Shibler do { 49553930Shibler if ((i = le->sc_tmd - le->sc_txcnt) < 0) 49653930Shibler i += LETBUF; 49753930Shibler tmd = &le->sc_r2->ler2_tmd[i]; 49853930Shibler if (tmd->tmd1 & LE_OWN) { 49953930Shibler if (gotone) 50053930Shibler break; 50153930Shibler le->sc_xown++; 50253930Shibler return; 50341480Smckusick } 50453930Shibler 50553930Shibler /* clear interrupt */ 50653930Shibler LERDWR(le->sc_r0, LE_TINT|LE_INEA, le->sc_r1->ler1_rdp); 50753930Shibler 50853930Shibler /* XXX documentation says BUFF not included in ERR */ 50953930Shibler if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { 51053930Shibler lexerror(unit); 51153930Shibler le->sc_if.if_oerrors++; 51253930Shibler if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 51353930Shibler le->sc_uflo++; 51453930Shibler lereset(unit); 51553930Shibler } else if (tmd->tmd3 & LE_LCOL) 51653930Shibler le->sc_if.if_collisions++; 51753930Shibler else if (tmd->tmd3 & LE_RTRY) 51853930Shibler le->sc_if.if_collisions += 16; 51953930Shibler } else if (tmd->tmd1 & LE_ONE) 52041480Smckusick le->sc_if.if_collisions++; 52153930Shibler else if (tmd->tmd1 & LE_MORE) 52253930Shibler /* what is the real number? */ 52353930Shibler le->sc_if.if_collisions += 2; 52453930Shibler else 52553930Shibler le->sc_if.if_opackets++; 52653930Shibler gotone++; 52753930Shibler } while (--le->sc_txcnt > 0); 52841480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 52941480Smckusick (void) lestart(&le->sc_if); 53041480Smckusick } 53141480Smckusick 53241480Smckusick #define LENEXTRMP \ 53341480Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 53441480Smckusick 53541480Smckusick /* 53641480Smckusick * Ethernet interface receiver interrupt. 53741480Smckusick * If input error just drop packet. 53841480Smckusick * Decapsulate packet based on type and pass to type specific 53941480Smckusick * higher-level input routine. 54041480Smckusick */ 54141480Smckusick lerint(unit) 54241480Smckusick int unit; 54341480Smckusick { 54441480Smckusick register struct le_softc *le = &le_softc[unit]; 54541480Smckusick register int bix = le->sc_rmd; 54641480Smckusick register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 54741480Smckusick 54857349Shibler #ifdef USELEDS 54957349Shibler if (inledcontrol == 0) 55057349Shibler ledcontrol(0, 0, LED_LANRCV); 55157349Shibler #endif 55241480Smckusick /* 55341480Smckusick * Out of sync with hardware, should never happen? 55441480Smckusick */ 55541480Smckusick if (rmd->rmd1 & LE_OWN) { 55653930Shibler le->sc_rown++; 55741480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 55841480Smckusick return; 55941480Smckusick } 56041480Smckusick 56141480Smckusick /* 56241480Smckusick * Process all buffers with valid data 56341480Smckusick */ 56441480Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 56541480Smckusick int len = rmd->rmd3; 56641480Smckusick 56741480Smckusick /* Clear interrupt to avoid race condition */ 56841480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 56941480Smckusick 57041480Smckusick if (rmd->rmd1 & LE_ERR) { 57141480Smckusick le->sc_rmd = bix; 57241480Smckusick lererror(unit, "bad packet"); 57341480Smckusick le->sc_if.if_ierrors++; 57441480Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 57541480Smckusick /* 57641480Smckusick * Find the end of the packet so we can see how long 57741480Smckusick * it was. We still throw it away. 57841480Smckusick */ 57941480Smckusick do { 58041480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 58141480Smckusick le->sc_r1->ler1_rdp); 58241480Smckusick rmd->rmd3 = 0; 58341480Smckusick rmd->rmd1 = LE_OWN; 58441480Smckusick LENEXTRMP; 58541480Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 58641480Smckusick le->sc_rmd = bix; 58741480Smckusick lererror(unit, "chained buffer"); 58841480Smckusick le->sc_rxlen++; 58941480Smckusick /* 59041480Smckusick * If search terminated without successful completion 59141480Smckusick * we reset the hardware (conservative). 59241480Smckusick */ 59341480Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 59441480Smckusick LE_ENP) { 59541480Smckusick lereset(unit); 59641480Smckusick return; 59741480Smckusick } 59841480Smckusick } else 59941480Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 60041480Smckusick rmd->rmd3 = 0; 60141480Smckusick rmd->rmd1 = LE_OWN; 60241480Smckusick LENEXTRMP; 60341480Smckusick } 60441480Smckusick le->sc_rmd = bix; 60541480Smckusick } 60641480Smckusick 60741480Smckusick leread(unit, buf, len) 60841480Smckusick int unit; 60941480Smckusick char *buf; 61041480Smckusick int len; 61141480Smckusick { 61241480Smckusick register struct le_softc *le = &le_softc[unit]; 61341480Smckusick register struct ether_header *et; 61441480Smckusick struct mbuf *m; 61554719Ssklower int off, resid, flags; 61641480Smckusick 61741480Smckusick le->sc_if.if_ipackets++; 61841480Smckusick et = (struct ether_header *)buf; 61941480Smckusick et->ether_type = ntohs((u_short)et->ether_type); 62041480Smckusick /* adjust input length to account for header and CRC */ 62141480Smckusick len = len - sizeof(struct ether_header) - 4; 62241480Smckusick 62341480Smckusick #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) 62441480Smckusick if (et->ether_type >= ETHERTYPE_TRAIL && 62541480Smckusick et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 62641480Smckusick off = (et->ether_type - ETHERTYPE_TRAIL) * 512; 62741480Smckusick if (off >= ETHERMTU) 62841480Smckusick return; /* sanity */ 62941480Smckusick et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); 63041480Smckusick resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 63141480Smckusick if (off + resid > len) 63241480Smckusick return; /* sanity */ 63341480Smckusick len = off + resid; 63441480Smckusick } else 63541480Smckusick off = 0; 63641480Smckusick 63741480Smckusick if (len <= 0) { 63841480Smckusick if (ledebug) 63941480Smckusick log(LOG_WARNING, 64041480Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 64141480Smckusick unit, ether_sprintf(et->ether_shost), len); 64241480Smckusick le->sc_runt++; 64341480Smckusick le->sc_if.if_ierrors++; 64441480Smckusick return; 64541480Smckusick } 64654719Ssklower flags = 0; 64754719Ssklower if (bcmp((caddr_t)etherbroadcastaddr, 64854719Ssklower (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0) 64954719Ssklower flags |= M_BCAST; 65054719Ssklower if (et->ether_dhost[0] & 1) 65154719Ssklower flags |= M_MCAST; 65254719Ssklower 65347567Smccanne #if NBPFILTER > 0 65447567Smccanne /* 65547567Smccanne * Check if there's a bpf filter listening on this interface. 65654719Ssklower * If so, hand off the raw packet to enet. 65747567Smccanne */ 65854719Ssklower if (le->sc_if.if_bpf) { 65954719Ssklower bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header)); 66054719Ssklower 66154719Ssklower /* 66254719Ssklower * Keep the packet if it's a broadcast or has our 66354719Ssklower * physical ethernet address (or if we support 66454719Ssklower * multicast and it's one). 66554719Ssklower */ 66654719Ssklower if ( 66754719Ssklower #ifdef MULTICAST 66854719Ssklower (flags & (M_BCAST | M_MCAST)) == 0 && 66954719Ssklower #else 67054719Ssklower (flags & M_BCAST) == 0 && 67147567Smccanne #endif 67254719Ssklower bcmp(et->ether_dhost, le->sc_addr, 67354719Ssklower sizeof(et->ether_dhost)) != 0) 67454719Ssklower return; 67554719Ssklower } 67650816Ssklower #endif 67750816Ssklower /* 67841480Smckusick * Pull packet off interface. Off is nonzero if packet 67953034Ssklower * has trailing header; m_devget will then force this header 68041480Smckusick * information to be at the front, but we still have to drop 68141480Smckusick * the type and length which are at the front of any trailer data. 68241480Smckusick */ 68353034Ssklower m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0); 68441480Smckusick if (m == 0) 68541480Smckusick return; 68658649Ssklower m->m_flags |= flags; 68741480Smckusick ether_input(&le->sc_if, et, m); 68841480Smckusick } 68941480Smckusick 69041480Smckusick /* 69141480Smckusick * Routine to copy from mbuf chain to transmit 69241480Smckusick * buffer in board local memory. 69341480Smckusick */ 69441480Smckusick leput(lebuf, m) 69541480Smckusick register char *lebuf; 69641480Smckusick register struct mbuf *m; 69741480Smckusick { 69841480Smckusick register struct mbuf *mp; 69941480Smckusick register int len, tlen = 0; 70041480Smckusick 70141480Smckusick for (mp = m; mp; mp = mp->m_next) { 70241480Smckusick len = mp->m_len; 70341480Smckusick if (len == 0) 70441480Smckusick continue; 70541480Smckusick tlen += len; 70641480Smckusick bcopy(mtod(mp, char *), lebuf, len); 70741480Smckusick lebuf += len; 70841480Smckusick } 70941480Smckusick m_freem(m); 71041480Smckusick if (tlen < LEMINSIZE) { 71141480Smckusick bzero(lebuf, LEMINSIZE - tlen); 71241480Smckusick tlen = LEMINSIZE; 71341480Smckusick } 71441480Smckusick return(tlen); 71541480Smckusick } 71641480Smckusick 71741480Smckusick /* 71841480Smckusick * Process an ioctl request. 71941480Smckusick */ 72041480Smckusick leioctl(ifp, cmd, data) 72141480Smckusick register struct ifnet *ifp; 72241480Smckusick int cmd; 72341480Smckusick caddr_t data; 72441480Smckusick { 72541480Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 72641480Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 72741480Smckusick struct lereg1 *ler1 = le->sc_r1; 72841480Smckusick int s = splimp(), error = 0; 72941480Smckusick 73041480Smckusick switch (cmd) { 73141480Smckusick 73241480Smckusick case SIOCSIFADDR: 73341480Smckusick ifp->if_flags |= IFF_UP; 73441480Smckusick switch (ifa->ifa_addr->sa_family) { 73541480Smckusick #ifdef INET 73641480Smckusick case AF_INET: 73741480Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 73841480Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 73941480Smckusick IA_SIN(ifa)->sin_addr; 74041480Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 74141480Smckusick break; 74241480Smckusick #endif 74341480Smckusick #ifdef NS 74441480Smckusick case AF_NS: 74541480Smckusick { 74641480Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 74741480Smckusick 74841480Smckusick if (ns_nullhost(*ina)) 74941480Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 75041480Smckusick else { 75141480Smckusick /* 75241480Smckusick * The manual says we can't change the address 75341480Smckusick * while the receiver is armed, 75441480Smckusick * so reset everything 75541480Smckusick */ 75641480Smckusick ifp->if_flags &= ~IFF_RUNNING; 75750816Ssklower LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 75841480Smckusick bcopy((caddr_t)ina->x_host.c_host, 75941480Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 76041480Smckusick } 76141480Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 76241480Smckusick break; 76341480Smckusick } 76441480Smckusick #endif 76541480Smckusick default: 76641480Smckusick leinit(ifp->if_unit); 76741480Smckusick break; 76841480Smckusick } 76941480Smckusick break; 77041480Smckusick 77157348Shibler #if defined (CCITT) && defined (LLC) 77257348Shibler case SIOCSIFCONF_X25: 77357348Shibler ifp -> if_flags |= IFF_UP; 77457348Shibler ifa -> ifa_rtrequest = cons_rtrequest; 77557348Shibler error = x25_llcglue(PRC_IFUP, ifa -> ifa_addr); 77657348Shibler if (error == 0) 77757348Shibler leinit(ifp -> if_unit); 77857348Shibler break; 77957348Shibler #endif /* CCITT && LLC */ 78057348Shibler 78157348Shibler 78241480Smckusick case SIOCSIFFLAGS: 78341480Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 78441480Smckusick ifp->if_flags & IFF_RUNNING) { 78541480Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 78641480Smckusick ifp->if_flags &= ~IFF_RUNNING; 78741480Smckusick } else if (ifp->if_flags & IFF_UP && 78841480Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 78941480Smckusick leinit(ifp->if_unit); 79048771Smccanne /* 79148771Smccanne * If the state of the promiscuous bit changes, the interface 79248771Smccanne * must be reset to effect the change. 79348771Smccanne */ 79448771Smccanne if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 79548771Smccanne (ifp->if_flags & IFF_RUNNING)) { 79648771Smccanne le->sc_iflags = ifp->if_flags; 79748771Smccanne lereset(ifp->if_unit); 79848771Smccanne lestart(ifp); 79948771Smccanne } 80041480Smckusick break; 80141480Smckusick 80254719Ssklower #ifdef MULTICAST 80354719Ssklower case SIOCADDMULTI: 80454719Ssklower case SIOCDELMULTI: 80554719Ssklower /* Update our multicast list */ 80654719Ssklower error = (cmd == SIOCADDMULTI) ? 80754719Ssklower ether_addmulti((struct ifreq *)data, &le->sc_ac) : 80854719Ssklower ether_delmulti((struct ifreq *)data, &le->sc_ac); 80954719Ssklower 81054719Ssklower if (error == ENETRESET) { 81154719Ssklower /* 81254719Ssklower * Multicast list has changed; set the hardware 81354719Ssklower * filter accordingly. 81454719Ssklower */ 81554719Ssklower lereset(ifp->if_unit); 81654719Ssklower error = 0; 81754719Ssklower } 81854719Ssklower break; 81954719Ssklower #endif 82041480Smckusick default: 82141480Smckusick error = EINVAL; 82241480Smckusick } 82341480Smckusick splx(s); 82441480Smckusick return (error); 82541480Smckusick } 82641480Smckusick 82741480Smckusick leerror(unit, stat) 82841480Smckusick int unit; 82941480Smckusick int stat; 83041480Smckusick { 83141480Smckusick if (!ledebug) 83241480Smckusick return; 83341480Smckusick 83441480Smckusick /* 83541480Smckusick * Not all transceivers implement heartbeat 83641480Smckusick * so we only log CERR once. 83741480Smckusick */ 83841480Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 83941480Smckusick return; 84041480Smckusick log(LOG_WARNING, 84141480Smckusick "le%d: error: stat=%b\n", unit, 84241480Smckusick stat, 84341480Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 84441480Smckusick } 84541480Smckusick 84641480Smckusick lererror(unit, msg) 84741480Smckusick int unit; 84841480Smckusick char *msg; 84941480Smckusick { 85041480Smckusick register struct le_softc *le = &le_softc[unit]; 85141480Smckusick register struct lermd *rmd; 85241480Smckusick int len; 85341480Smckusick 85441480Smckusick if (!ledebug) 85541480Smckusick return; 85641480Smckusick 85741480Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 85841480Smckusick len = rmd->rmd3; 85941480Smckusick log(LOG_WARNING, 86041480Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 86141480Smckusick unit, msg, 86252420Smckusick len > 11 ? 86352420Smckusick ether_sprintf((u_char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : 86452420Smckusick "unknown", 86541480Smckusick le->sc_rmd, len, 86641480Smckusick rmd->rmd1, 86741480Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 86841480Smckusick } 86941480Smckusick 87041480Smckusick lexerror(unit) 87141480Smckusick int unit; 87241480Smckusick { 87341480Smckusick register struct le_softc *le = &le_softc[unit]; 87441480Smckusick register struct letmd *tmd; 87541480Smckusick int len; 87641480Smckusick 87741480Smckusick if (!ledebug) 87841480Smckusick return; 87941480Smckusick 88041480Smckusick tmd = le->sc_r2->ler2_tmd; 88141480Smckusick len = -tmd->tmd2; 88241480Smckusick log(LOG_WARNING, 88341480Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 88441480Smckusick unit, 88552420Smckusick len > 5 ? 88652420Smckusick ether_sprintf((u_char *)&le->sc_r2->ler2_tbuf[0][0]) : 88752420Smckusick "unknown", 88841480Smckusick 0, len, 88941480Smckusick tmd->tmd1, 89041480Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 89141480Smckusick tmd->tmd3, 89241480Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 89341480Smckusick } 89441480Smckusick #endif 895