141480Smckusick /* 241480Smckusick * Copyright (c) 1982, 1990 The Regents of the University of California. 341480Smckusick * All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*53930Shibler * @(#)if_le.c 7.11 (Berkeley) 06/05/92 841480Smckusick */ 941480Smckusick 1041480Smckusick #include "le.h" 1141480Smckusick #if NLE > 0 1241480Smckusick 1347567Smccanne #include "bpfilter.h" 1447567Smccanne 1541480Smckusick /* 1641480Smckusick * AMD 7990 LANCE 1741480Smckusick * 1841480Smckusick * This driver will generate and 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 */ 2345788Sbostic #include "sys/param.h" 2453034Ssklower #include "sys/proc.h" 2545788Sbostic #include "sys/systm.h" 2645788Sbostic #include "sys/mbuf.h" 2745788Sbostic #include "sys/buf.h" 2845788Sbostic #include "sys/protosw.h" 2945788Sbostic #include "sys/socket.h" 3045788Sbostic #include "sys/syslog.h" 3145788Sbostic #include "sys/ioctl.h" 3245788Sbostic #include "sys/errno.h" 3341480Smckusick 3445788Sbostic #include "net/if.h" 3545788Sbostic #include "net/netisr.h" 3645788Sbostic #include "net/route.h" 3741480Smckusick 3841480Smckusick #ifdef INET 3945788Sbostic #include "netinet/in.h" 4045788Sbostic #include "netinet/in_systm.h" 4145788Sbostic #include "netinet/in_var.h" 4245788Sbostic #include "netinet/ip.h" 4345788Sbostic #include "netinet/if_ether.h" 4441480Smckusick #endif 4541480Smckusick 4641480Smckusick #ifdef NS 4745788Sbostic #include "netns/ns.h" 4845788Sbostic #include "netns/ns_if.h" 4941480Smckusick #endif 5041480Smckusick 5150816Ssklower #ifdef ISO 5250816Ssklower extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[]; 5341480Smckusick #endif 5441480Smckusick 5545788Sbostic #include "../include/cpu.h" 5645788Sbostic #include "../hp300/isr.h" 5745788Sbostic #include "../include/mtpr.h" 58*53930Shibler #include "hp/dev/device.h" 5941480Smckusick #include "if_lereg.h" 6041480Smckusick 6147567Smccanne #if NBPFILTER > 0 6247567Smccanne #include "../net/bpf.h" 6347567Smccanne #include "../net/bpfdesc.h" 6450816Ssklower char hprmp_multi[] = { 9, 0, 9, 0, 0, 4}; 6547567Smccanne #endif 6647567Smccanne 6741480Smckusick /* offsets for: ID, REGS, MEM, NVRAM */ 6841480Smckusick int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; 6941480Smckusick 7041480Smckusick int leattach(); 7141480Smckusick struct driver ledriver = { 7241480Smckusick leattach, "le", 7341480Smckusick }; 7441480Smckusick 7541480Smckusick struct isr le_isr[NLE]; 7641480Smckusick int ledebug = 0; /* console error messages */ 7741480Smckusick 7841480Smckusick int leintr(), leinit(), leioctl(), lestart(), ether_output(); 7953034Ssklower struct mbuf *m_devget(); 8041480Smckusick extern struct ifnet loif; 8141480Smckusick 8241480Smckusick /* 8341480Smckusick * Ethernet software status per interface. 8441480Smckusick * 8541480Smckusick * Each interface is referenced by a network interface structure, 8641480Smckusick * le_if, which the routing code uses to locate the interface. 8741480Smckusick * This structure contains the output queue for the interface, its address, ... 8841480Smckusick */ 8941480Smckusick struct le_softc { 9041480Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 9141480Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 9241480Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 9341480Smckusick struct lereg0 *sc_r0; /* DIO registers */ 9441480Smckusick struct lereg1 *sc_r1; /* LANCE registers */ 9541480Smckusick struct lereg2 *sc_r2; /* dual-port RAM */ 9641480Smckusick int sc_rmd; /* predicted next rmd to process */ 97*53930Shibler int sc_tmd; /* next available tmd */ 98*53930Shibler int sc_txcnt; /* # of transmit buffers in use */ 99*53930Shibler /* stats */ 10041480Smckusick int sc_runt; 10141480Smckusick int sc_jab; 10241480Smckusick int sc_merr; 10341480Smckusick int sc_babl; 10441480Smckusick int sc_cerr; 10541480Smckusick int sc_miss; 106*53930Shibler int sc_rown; 10741480Smckusick int sc_xown; 108*53930Shibler int sc_xown2; 10941480Smckusick int sc_uflo; 11041480Smckusick int sc_rxlen; 11141480Smckusick int sc_rxoff; 11241480Smckusick int sc_txoff; 11341480Smckusick int sc_busy; 11448771Smccanne short sc_iflags; 11547567Smccanne caddr_t sc_bpf; 11641480Smckusick } le_softc[NLE]; 11741480Smckusick 11841480Smckusick /* access LANCE registers */ 11941480Smckusick #define LERDWR(cntl, src, dst) \ 12041480Smckusick do { \ 12141480Smckusick (dst) = (src); \ 12241480Smckusick } while (((cntl)->ler0_status & LE_ACK) == 0); 12341480Smckusick 12441480Smckusick /* 12541480Smckusick * Interface exists: make available by filling in network interface 12641480Smckusick * record. System will initialize the interface when it is ready 12741480Smckusick * to accept packets. 12841480Smckusick */ 12941480Smckusick leattach(hd) 13041480Smckusick struct hp_device *hd; 13141480Smckusick { 13241480Smckusick register struct lereg0 *ler0; 13341480Smckusick register struct lereg2 *ler2; 13441480Smckusick struct lereg2 *lemem = 0; 13541480Smckusick struct le_softc *le = &le_softc[hd->hp_unit]; 13641480Smckusick struct ifnet *ifp = &le->sc_if; 13741480Smckusick char *cp; 13841480Smckusick int i; 13941480Smckusick 14041480Smckusick ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); 14141480Smckusick le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); 14241480Smckusick ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); 14341480Smckusick if (ler0->ler0_id != LEID) 14441480Smckusick return(0); 14541480Smckusick le_isr[hd->hp_unit].isr_intr = leintr; 14641480Smckusick hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); 14741480Smckusick le_isr[hd->hp_unit].isr_arg = hd->hp_unit; 14841480Smckusick ler0->ler0_id = 0xFF; 14941480Smckusick DELAY(100); 15041480Smckusick 15141480Smckusick /* 15241480Smckusick * Read the ethernet address off the board, one nibble at a time. 15341480Smckusick */ 15441480Smckusick cp = (char *)(lestd[3] + (int)hd->hp_addr); 15541480Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 15641480Smckusick le->sc_addr[i] = (*++cp & 0xF) << 4; 15741480Smckusick cp++; 15841480Smckusick le->sc_addr[i] |= *++cp & 0xF; 15941480Smckusick cp++; 16041480Smckusick } 16141480Smckusick printf("le%d: hardware address %s\n", hd->hp_unit, 16241480Smckusick ether_sprintf(le->sc_addr)); 16341480Smckusick 16441480Smckusick /* 16541480Smckusick * Setup for transmit/receive 16641480Smckusick */ 16741480Smckusick ler2->ler2_mode = LE_MODE; 16850816Ssklower #if defined(ISO) || NBPFILTER > 0 16950816Ssklower ler2->ler2_ladrf0 = 0xffffffff; 17050816Ssklower ler2->ler2_ladrf1 = 0xffffffff; 17141480Smckusick #else 17241480Smckusick ler2->ler2_ladrf0 = 0; 17341480Smckusick ler2->ler2_ladrf1 = 0; 17441480Smckusick #endif 17541480Smckusick ler2->ler2_rlen = LE_RLEN; 17641480Smckusick ler2->ler2_rdra = (int)lemem->ler2_rmd; 17741480Smckusick ler2->ler2_tlen = LE_TLEN; 17841480Smckusick ler2->ler2_tdra = (int)lemem->ler2_tmd; 17941480Smckusick isrlink(&le_isr[hd->hp_unit]); 18041480Smckusick ler0->ler0_status = LE_IE; 18141480Smckusick 18241480Smckusick ifp->if_unit = hd->hp_unit; 18341480Smckusick ifp->if_name = "le"; 18441480Smckusick ifp->if_mtu = ETHERMTU; 18541480Smckusick ifp->if_init = leinit; 18641480Smckusick ifp->if_ioctl = leioctl; 18741480Smckusick ifp->if_output = ether_output; 18841480Smckusick ifp->if_start = lestart; 18941480Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 19047567Smccanne #if NBPFILTER > 0 19149407Smccanne bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 19247567Smccanne #endif 19341480Smckusick if_attach(ifp); 19441480Smckusick return (1); 19541480Smckusick } 19641480Smckusick 19750816Ssklower ledrinit(ler2, le) 19841480Smckusick register struct lereg2 *ler2; 19950816Ssklower register struct le_softc *le; 20041480Smckusick { 20141480Smckusick register struct lereg2 *lemem = 0; 20241480Smckusick register int i; 20341480Smckusick 20450816Ssklower ler2->ler2_padr[0] = le->sc_addr[1]; 20550816Ssklower ler2->ler2_padr[1] = le->sc_addr[0]; 20650816Ssklower ler2->ler2_padr[2] = le->sc_addr[3]; 20750816Ssklower ler2->ler2_padr[3] = le->sc_addr[2]; 20850816Ssklower ler2->ler2_padr[4] = le->sc_addr[5]; 20950816Ssklower ler2->ler2_padr[5] = le->sc_addr[4]; 21041480Smckusick for (i = 0; i < LERBUF; i++) { 21141480Smckusick ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; 21241480Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 21341480Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 21441480Smckusick ler2->ler2_rmd[i].rmd3 = 0; 21541480Smckusick } 21641480Smckusick for (i = 0; i < LETBUF; i++) { 21741480Smckusick ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; 21841480Smckusick ler2->ler2_tmd[i].tmd1 = 0; 21941480Smckusick ler2->ler2_tmd[i].tmd2 = 0; 22041480Smckusick ler2->ler2_tmd[i].tmd3 = 0; 22141480Smckusick } 22241480Smckusick } 22341480Smckusick 22441480Smckusick lereset(unit) 22541480Smckusick register int unit; 22641480Smckusick { 22741480Smckusick register struct le_softc *le = &le_softc[unit]; 22841480Smckusick register struct lereg0 *ler0 = le->sc_r0; 22941480Smckusick register struct lereg1 *ler1 = le->sc_r1; 23041480Smckusick register struct lereg2 *lemem = 0; 23141480Smckusick register int timo = 100000; 23241480Smckusick register int stat; 23341480Smckusick 23441480Smckusick #ifdef lint 23541480Smckusick stat = unit; 23641480Smckusick #endif 23747567Smccanne #if NBPFILTER > 0 23847567Smccanne if (le->sc_if.if_flags & IFF_PROMISC) 23947567Smccanne /* set the promiscuous bit */ 24047567Smccanne le->sc_r2->ler2_mode = LE_MODE|0x8000; 24147567Smccanne else 24247567Smccanne le->sc_r2->ler2_mode = LE_MODE; 24347567Smccanne #endif 24441480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 24541480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 24650816Ssklower ledrinit(le->sc_r2, le); 247*53930Shibler le->sc_rmd = le->sc_tmd = 0; 24841480Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 24941480Smckusick LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); 25041480Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 25141480Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 25241480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 25341480Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 25441480Smckusick do { 25541480Smckusick if (--timo == 0) { 25641480Smckusick printf("le%d: init timeout, stat = 0x%x\n", 25741480Smckusick unit, stat); 25841480Smckusick break; 25941480Smckusick } 26041480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 26141480Smckusick } while ((stat & LE_IDON) == 0); 26241480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 26341480Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 26441480Smckusick LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); 26541480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 26641480Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 26741480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 268*53930Shibler le->sc_txcnt = 0; 26941480Smckusick } 27041480Smckusick 27141480Smckusick /* 27241480Smckusick * Initialization of interface 27341480Smckusick */ 27441480Smckusick leinit(unit) 27541480Smckusick int unit; 27641480Smckusick { 27753034Ssklower register struct ifnet *ifp = &le_softc[unit].sc_if; 27853034Ssklower register struct ifaddr *ifa; 27941480Smckusick int s; 28041480Smckusick 28141480Smckusick /* not yet, if address still unknown */ 28253034Ssklower for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next) 28353034Ssklower if (ifa == 0) 28453034Ssklower return; 28553034Ssklower else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK) 28653034Ssklower break; 28741480Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 28841480Smckusick s = splimp(); 28941480Smckusick ifp->if_flags |= IFF_RUNNING; 29041480Smckusick lereset(unit); 29141480Smckusick (void) lestart(ifp); 29241480Smckusick splx(s); 29341480Smckusick } 29441480Smckusick } 29541480Smckusick 29641480Smckusick /* 29741480Smckusick * Start output on interface. Get another datagram to send 29841480Smckusick * off of the interface queue, and copy it to the interface 29941480Smckusick * before starting the output. 30041480Smckusick */ 30141480Smckusick lestart(ifp) 30241480Smckusick struct ifnet *ifp; 30341480Smckusick { 30441480Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 30541480Smckusick register struct letmd *tmd; 30641480Smckusick register struct mbuf *m; 30741480Smckusick int len; 30841480Smckusick 30941480Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 31041480Smckusick return (0); 311*53930Shibler tmd = &le->sc_r2->ler2_tmd[le->sc_tmd]; 312*53930Shibler do { 313*53930Shibler if (tmd->tmd1 & LE_OWN) { 314*53930Shibler le->sc_xown2++; 315*53930Shibler return (0); 316*53930Shibler } 317*53930Shibler IF_DEQUEUE(&le->sc_if.if_snd, m); 318*53930Shibler if (m == 0) 319*53930Shibler return (0); 320*53930Shibler len = leput(le->sc_r2->ler2_tbuf[le->sc_tmd], m); 32147567Smccanne #if NBPFILTER > 0 322*53930Shibler /* 323*53930Shibler * If bpf is listening on this interface, let it 324*53930Shibler * see the packet before we commit it to the wire. 325*53930Shibler */ 326*53930Shibler if (le->sc_bpf) 327*53930Shibler bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd], 328*53930Shibler len); 32947567Smccanne #endif 330*53930Shibler 331*53930Shibler tmd->tmd3 = 0; 332*53930Shibler tmd->tmd2 = -len; 33353034Ssklower tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 334*53930Shibler if (++le->sc_tmd == LETBUF) { 335*53930Shibler le->sc_tmd = 0; 336*53930Shibler tmd = le->sc_r2->ler2_tmd; 337*53930Shibler } else 338*53930Shibler tmd++; 339*53930Shibler } while (++le->sc_txcnt < LETBUF); 340*53930Shibler le->sc_if.if_flags |= IFF_OACTIVE; 34141480Smckusick return (0); 34241480Smckusick } 34341480Smckusick 34441480Smckusick leintr(unit) 34541480Smckusick register int unit; 34641480Smckusick { 34741480Smckusick register struct le_softc *le = &le_softc[unit]; 34841480Smckusick register struct lereg0 *ler0 = le->sc_r0; 34941480Smckusick register struct lereg1 *ler1; 35041480Smckusick register int stat; 35141480Smckusick 35241480Smckusick if ((ler0->ler0_status & LE_IR) == 0) 35341480Smckusick return(0); 35441480Smckusick if (ler0->ler0_status & LE_JAB) { 35541480Smckusick le->sc_jab++; 35641480Smckusick lereset(unit); 35741480Smckusick return(1); 35841480Smckusick } 35941480Smckusick ler1 = le->sc_r1; 36041480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 36141480Smckusick if (stat & LE_SERR) { 36241480Smckusick leerror(unit, stat); 36341480Smckusick if (stat & LE_MERR) { 36441480Smckusick le->sc_merr++; 36541480Smckusick lereset(unit); 36641480Smckusick return(1); 36741480Smckusick } 36841480Smckusick if (stat & LE_BABL) 36941480Smckusick le->sc_babl++; 37041480Smckusick if (stat & LE_CERR) 37141480Smckusick le->sc_cerr++; 37241480Smckusick if (stat & LE_MISS) 37341480Smckusick le->sc_miss++; 37441480Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 37541480Smckusick } 37641480Smckusick if ((stat & LE_RXON) == 0) { 37741480Smckusick le->sc_rxoff++; 37841480Smckusick lereset(unit); 37941480Smckusick return(1); 38041480Smckusick } 38141480Smckusick if ((stat & LE_TXON) == 0) { 38241480Smckusick le->sc_txoff++; 38341480Smckusick lereset(unit); 38441480Smckusick return(1); 38541480Smckusick } 386*53930Shibler if (stat & LE_RINT) 38741480Smckusick lerint(unit); 388*53930Shibler if (stat & LE_TINT) 38941480Smckusick lexint(unit); 39041480Smckusick return(1); 39141480Smckusick } 39241480Smckusick 39341480Smckusick /* 39441480Smckusick * Ethernet interface transmitter interrupt. 39541480Smckusick * Start another output if more data to send. 39641480Smckusick */ 39741480Smckusick lexint(unit) 39841480Smckusick register int unit; 39941480Smckusick { 40041480Smckusick register struct le_softc *le = &le_softc[unit]; 40150823Ssklower register struct letmd *tmd; 402*53930Shibler int i, gotone = 0; 40341480Smckusick 404*53930Shibler do { 405*53930Shibler if ((i = le->sc_tmd - le->sc_txcnt) < 0) 406*53930Shibler i += LETBUF; 407*53930Shibler tmd = &le->sc_r2->ler2_tmd[i]; 408*53930Shibler if (tmd->tmd1 & LE_OWN) { 409*53930Shibler if (gotone) 410*53930Shibler break; 411*53930Shibler le->sc_xown++; 412*53930Shibler return; 41341480Smckusick } 414*53930Shibler 415*53930Shibler /* clear interrupt */ 416*53930Shibler LERDWR(le->sc_r0, LE_TINT|LE_INEA, le->sc_r1->ler1_rdp); 417*53930Shibler 418*53930Shibler /* XXX documentation says BUFF not included in ERR */ 419*53930Shibler if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { 420*53930Shibler lexerror(unit); 421*53930Shibler le->sc_if.if_oerrors++; 422*53930Shibler if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 423*53930Shibler le->sc_uflo++; 424*53930Shibler lereset(unit); 425*53930Shibler } else if (tmd->tmd3 & LE_LCOL) 426*53930Shibler le->sc_if.if_collisions++; 427*53930Shibler else if (tmd->tmd3 & LE_RTRY) 428*53930Shibler le->sc_if.if_collisions += 16; 429*53930Shibler } else if (tmd->tmd1 & LE_ONE) 43041480Smckusick le->sc_if.if_collisions++; 431*53930Shibler else if (tmd->tmd1 & LE_MORE) 432*53930Shibler /* what is the real number? */ 433*53930Shibler le->sc_if.if_collisions += 2; 434*53930Shibler else 435*53930Shibler le->sc_if.if_opackets++; 436*53930Shibler gotone++; 437*53930Shibler } while (--le->sc_txcnt > 0); 43841480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 43941480Smckusick (void) lestart(&le->sc_if); 44041480Smckusick } 44141480Smckusick 44241480Smckusick #define LENEXTRMP \ 44341480Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 44441480Smckusick 44541480Smckusick /* 44641480Smckusick * Ethernet interface receiver interrupt. 44741480Smckusick * If input error just drop packet. 44841480Smckusick * Decapsulate packet based on type and pass to type specific 44941480Smckusick * higher-level input routine. 45041480Smckusick */ 45141480Smckusick lerint(unit) 45241480Smckusick int unit; 45341480Smckusick { 45441480Smckusick register struct le_softc *le = &le_softc[unit]; 45541480Smckusick register int bix = le->sc_rmd; 45641480Smckusick register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 45741480Smckusick 45841480Smckusick /* 45941480Smckusick * Out of sync with hardware, should never happen? 46041480Smckusick */ 46141480Smckusick if (rmd->rmd1 & LE_OWN) { 462*53930Shibler le->sc_rown++; 46341480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 46441480Smckusick return; 46541480Smckusick } 46641480Smckusick 46741480Smckusick /* 46841480Smckusick * Process all buffers with valid data 46941480Smckusick */ 47041480Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 47141480Smckusick int len = rmd->rmd3; 47241480Smckusick 47341480Smckusick /* Clear interrupt to avoid race condition */ 47441480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 47541480Smckusick 47641480Smckusick if (rmd->rmd1 & LE_ERR) { 47741480Smckusick le->sc_rmd = bix; 47841480Smckusick lererror(unit, "bad packet"); 47941480Smckusick le->sc_if.if_ierrors++; 48041480Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 48141480Smckusick /* 48241480Smckusick * Find the end of the packet so we can see how long 48341480Smckusick * it was. We still throw it away. 48441480Smckusick */ 48541480Smckusick do { 48641480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 48741480Smckusick le->sc_r1->ler1_rdp); 48841480Smckusick rmd->rmd3 = 0; 48941480Smckusick rmd->rmd1 = LE_OWN; 49041480Smckusick LENEXTRMP; 49141480Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 49241480Smckusick le->sc_rmd = bix; 49341480Smckusick lererror(unit, "chained buffer"); 49441480Smckusick le->sc_rxlen++; 49541480Smckusick /* 49641480Smckusick * If search terminated without successful completion 49741480Smckusick * we reset the hardware (conservative). 49841480Smckusick */ 49941480Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 50041480Smckusick LE_ENP) { 50141480Smckusick lereset(unit); 50241480Smckusick return; 50341480Smckusick } 50441480Smckusick } else 50541480Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 50641480Smckusick rmd->rmd3 = 0; 50741480Smckusick rmd->rmd1 = LE_OWN; 50841480Smckusick LENEXTRMP; 50941480Smckusick } 51041480Smckusick le->sc_rmd = bix; 51141480Smckusick } 51241480Smckusick 51341480Smckusick leread(unit, buf, len) 51441480Smckusick int unit; 51541480Smckusick char *buf; 51641480Smckusick int len; 51741480Smckusick { 51841480Smckusick register struct le_softc *le = &le_softc[unit]; 51941480Smckusick register struct ether_header *et; 52041480Smckusick struct mbuf *m; 52141480Smckusick int off, resid; 52241480Smckusick 52341480Smckusick le->sc_if.if_ipackets++; 52441480Smckusick et = (struct ether_header *)buf; 52541480Smckusick et->ether_type = ntohs((u_short)et->ether_type); 52641480Smckusick /* adjust input length to account for header and CRC */ 52741480Smckusick len = len - sizeof(struct ether_header) - 4; 52841480Smckusick 52941480Smckusick #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) 53041480Smckusick if (et->ether_type >= ETHERTYPE_TRAIL && 53141480Smckusick et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 53241480Smckusick off = (et->ether_type - ETHERTYPE_TRAIL) * 512; 53341480Smckusick if (off >= ETHERMTU) 53441480Smckusick return; /* sanity */ 53541480Smckusick et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); 53641480Smckusick resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 53741480Smckusick if (off + resid > len) 53841480Smckusick return; /* sanity */ 53941480Smckusick len = off + resid; 54041480Smckusick } else 54141480Smckusick off = 0; 54241480Smckusick 54341480Smckusick if (len <= 0) { 54441480Smckusick if (ledebug) 54541480Smckusick log(LOG_WARNING, 54641480Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 54741480Smckusick unit, ether_sprintf(et->ether_shost), len); 54841480Smckusick le->sc_runt++; 54941480Smckusick le->sc_if.if_ierrors++; 55041480Smckusick return; 55141480Smckusick } 55247567Smccanne #if NBPFILTER > 0 55347567Smccanne /* 55447567Smccanne * Check if there's a bpf filter listening on this interface. 55547567Smccanne * If so, hand off the raw packet to bpf, which must deal with 55647567Smccanne * trailers in its own way. 55747567Smccanne */ 55850816Ssklower if (le->sc_bpf) 55947567Smccanne bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header)); 56047567Smccanne #endif 56150816Ssklower #if defined(ISO) || NBPFILTER > 0 56241480Smckusick /* 56350816Ssklower * Note that the interface cannot be in promiscuous mode if 56450816Ssklower * there are no bpf listeners. If we are in promiscuous 56550816Ssklower * mode, we have to check if this packet is really ours. 56650816Ssklower * However, there may be appropriate multicate addresses involved 56750816Ssklower */ 56850816Ssklower #define NOT_TO(p) (bcmp(et->ether_dhost, p, sizeof(et->ether_dhost)) != 0) 56950816Ssklower if (et->ether_dhost[0] & 1) { 57050816Ssklower if (NOT_TO(etherbroadcastaddr) && NOT_TO(hprmp_multi) 57150816Ssklower #ifdef ISO 57250816Ssklower && NOT_TO(all_es_snpa) && NOT_TO(all_is_snpa) 57350816Ssklower && NOT_TO(all_l1is_snpa) && NOT_TO(all_l2is_snpa) 57450816Ssklower #endif 57550816Ssklower ) return; 57650816Ssklower } else if ((le->sc_if.if_flags & IFF_PROMISC) && NOT_TO(le->sc_addr)) 57750816Ssklower return; 57850816Ssklower #endif 57950816Ssklower /* 58041480Smckusick * Pull packet off interface. Off is nonzero if packet 58153034Ssklower * has trailing header; m_devget will then force this header 58241480Smckusick * information to be at the front, but we still have to drop 58341480Smckusick * the type and length which are at the front of any trailer data. 58441480Smckusick */ 58553034Ssklower m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0); 58641480Smckusick if (m == 0) 58741480Smckusick return; 58841480Smckusick ether_input(&le->sc_if, et, m); 58941480Smckusick } 59041480Smckusick 59141480Smckusick /* 59241480Smckusick * Routine to copy from mbuf chain to transmit 59341480Smckusick * buffer in board local memory. 59441480Smckusick */ 59541480Smckusick leput(lebuf, m) 59641480Smckusick register char *lebuf; 59741480Smckusick register struct mbuf *m; 59841480Smckusick { 59941480Smckusick register struct mbuf *mp; 60041480Smckusick register int len, tlen = 0; 60141480Smckusick 60241480Smckusick for (mp = m; mp; mp = mp->m_next) { 60341480Smckusick len = mp->m_len; 60441480Smckusick if (len == 0) 60541480Smckusick continue; 60641480Smckusick tlen += len; 60741480Smckusick bcopy(mtod(mp, char *), lebuf, len); 60841480Smckusick lebuf += len; 60941480Smckusick } 61041480Smckusick m_freem(m); 61141480Smckusick if (tlen < LEMINSIZE) { 61241480Smckusick bzero(lebuf, LEMINSIZE - tlen); 61341480Smckusick tlen = LEMINSIZE; 61441480Smckusick } 61541480Smckusick return(tlen); 61641480Smckusick } 61741480Smckusick 61841480Smckusick /* 61941480Smckusick * Process an ioctl request. 62041480Smckusick */ 62141480Smckusick leioctl(ifp, cmd, data) 62241480Smckusick register struct ifnet *ifp; 62341480Smckusick int cmd; 62441480Smckusick caddr_t data; 62541480Smckusick { 62641480Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 62741480Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 62841480Smckusick struct lereg1 *ler1 = le->sc_r1; 62941480Smckusick int s = splimp(), error = 0; 63041480Smckusick 63141480Smckusick switch (cmd) { 63241480Smckusick 63341480Smckusick case SIOCSIFADDR: 63441480Smckusick ifp->if_flags |= IFF_UP; 63541480Smckusick switch (ifa->ifa_addr->sa_family) { 63641480Smckusick #ifdef INET 63741480Smckusick case AF_INET: 63841480Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 63941480Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 64041480Smckusick IA_SIN(ifa)->sin_addr; 64141480Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 64241480Smckusick break; 64341480Smckusick #endif 64441480Smckusick #ifdef NS 64541480Smckusick case AF_NS: 64641480Smckusick { 64741480Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 64841480Smckusick 64941480Smckusick if (ns_nullhost(*ina)) 65041480Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 65141480Smckusick else { 65241480Smckusick /* 65341480Smckusick * The manual says we can't change the address 65441480Smckusick * while the receiver is armed, 65541480Smckusick * so reset everything 65641480Smckusick */ 65741480Smckusick ifp->if_flags &= ~IFF_RUNNING; 65850816Ssklower LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 65941480Smckusick bcopy((caddr_t)ina->x_host.c_host, 66041480Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 66141480Smckusick } 66241480Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 66341480Smckusick break; 66441480Smckusick } 66541480Smckusick #endif 66641480Smckusick default: 66741480Smckusick leinit(ifp->if_unit); 66841480Smckusick break; 66941480Smckusick } 67041480Smckusick break; 67141480Smckusick 67241480Smckusick case SIOCSIFFLAGS: 67341480Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 67441480Smckusick ifp->if_flags & IFF_RUNNING) { 67541480Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 67641480Smckusick ifp->if_flags &= ~IFF_RUNNING; 67741480Smckusick } else if (ifp->if_flags & IFF_UP && 67841480Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 67941480Smckusick leinit(ifp->if_unit); 68048771Smccanne /* 68148771Smccanne * If the state of the promiscuous bit changes, the interface 68248771Smccanne * must be reset to effect the change. 68348771Smccanne */ 68448771Smccanne if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 68548771Smccanne (ifp->if_flags & IFF_RUNNING)) { 68648771Smccanne le->sc_iflags = ifp->if_flags; 68748771Smccanne lereset(ifp->if_unit); 68848771Smccanne lestart(ifp); 68948771Smccanne } 69041480Smckusick break; 69141480Smckusick 69241480Smckusick default: 69341480Smckusick error = EINVAL; 69441480Smckusick } 69541480Smckusick splx(s); 69641480Smckusick return (error); 69741480Smckusick } 69841480Smckusick 69941480Smckusick leerror(unit, stat) 70041480Smckusick int unit; 70141480Smckusick int stat; 70241480Smckusick { 70341480Smckusick if (!ledebug) 70441480Smckusick return; 70541480Smckusick 70641480Smckusick /* 70741480Smckusick * Not all transceivers implement heartbeat 70841480Smckusick * so we only log CERR once. 70941480Smckusick */ 71041480Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 71141480Smckusick return; 71241480Smckusick log(LOG_WARNING, 71341480Smckusick "le%d: error: stat=%b\n", unit, 71441480Smckusick stat, 71541480Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 71641480Smckusick } 71741480Smckusick 71841480Smckusick lererror(unit, msg) 71941480Smckusick int unit; 72041480Smckusick char *msg; 72141480Smckusick { 72241480Smckusick register struct le_softc *le = &le_softc[unit]; 72341480Smckusick register struct lermd *rmd; 72441480Smckusick int len; 72541480Smckusick 72641480Smckusick if (!ledebug) 72741480Smckusick return; 72841480Smckusick 72941480Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 73041480Smckusick len = rmd->rmd3; 73141480Smckusick log(LOG_WARNING, 73241480Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 73341480Smckusick unit, msg, 73452420Smckusick len > 11 ? 73552420Smckusick ether_sprintf((u_char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : 73652420Smckusick "unknown", 73741480Smckusick le->sc_rmd, len, 73841480Smckusick rmd->rmd1, 73941480Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 74041480Smckusick } 74141480Smckusick 74241480Smckusick lexerror(unit) 74341480Smckusick int unit; 74441480Smckusick { 74541480Smckusick register struct le_softc *le = &le_softc[unit]; 74641480Smckusick register struct letmd *tmd; 74741480Smckusick int len; 74841480Smckusick 74941480Smckusick if (!ledebug) 75041480Smckusick return; 75141480Smckusick 75241480Smckusick tmd = le->sc_r2->ler2_tmd; 75341480Smckusick len = -tmd->tmd2; 75441480Smckusick log(LOG_WARNING, 75541480Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 75641480Smckusick unit, 75752420Smckusick len > 5 ? 75852420Smckusick ether_sprintf((u_char *)&le->sc_r2->ler2_tbuf[0][0]) : 75952420Smckusick "unknown", 76041480Smckusick 0, len, 76141480Smckusick tmd->tmd1, 76241480Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 76341480Smckusick tmd->tmd3, 76441480Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 76541480Smckusick } 76641480Smckusick #endif 767