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*48771Smccanne * @(#)if_le.c 7.4 (Berkeley) 04/27/91 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" 2445788Sbostic #include "sys/systm.h" 2545788Sbostic #include "sys/mbuf.h" 2645788Sbostic #include "sys/buf.h" 2745788Sbostic #include "sys/protosw.h" 2845788Sbostic #include "sys/socket.h" 2945788Sbostic #include "sys/syslog.h" 3045788Sbostic #include "sys/ioctl.h" 3145788Sbostic #include "sys/errno.h" 3241480Smckusick 3345788Sbostic #include "net/if.h" 3445788Sbostic #include "net/netisr.h" 3545788Sbostic #include "net/route.h" 3641480Smckusick 3741480Smckusick #ifdef INET 3845788Sbostic #include "netinet/in.h" 3945788Sbostic #include "netinet/in_systm.h" 4045788Sbostic #include "netinet/in_var.h" 4145788Sbostic #include "netinet/ip.h" 4245788Sbostic #include "netinet/if_ether.h" 4341480Smckusick #endif 4441480Smckusick 4541480Smckusick #ifdef NS 4645788Sbostic #include "netns/ns.h" 4745788Sbostic #include "netns/ns_if.h" 4841480Smckusick #endif 4941480Smckusick 5041480Smckusick #ifdef RMP 5145788Sbostic #include "netrmp/rmp.h" 5245788Sbostic #include "netrmp/rmp_var.h" 5341480Smckusick #endif 5441480Smckusick 5545788Sbostic #include "../include/cpu.h" 5645788Sbostic #include "../hp300/isr.h" 5745788Sbostic #include "../include/mtpr.h" 5841480Smckusick #include "device.h" 5941480Smckusick #include "if_lereg.h" 6041480Smckusick 6147567Smccanne #if NBPFILTER > 0 6247567Smccanne #include "../net/bpf.h" 6347567Smccanne #include "../net/bpfdesc.h" 6447567Smccanne #endif 6547567Smccanne 6641480Smckusick /* offsets for: ID, REGS, MEM, NVRAM */ 6741480Smckusick int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; 6841480Smckusick 6941480Smckusick int leattach(); 7041480Smckusick struct driver ledriver = { 7141480Smckusick leattach, "le", 7241480Smckusick }; 7341480Smckusick 7441480Smckusick struct isr le_isr[NLE]; 7541480Smckusick int ledebug = 0; /* console error messages */ 7641480Smckusick 7741480Smckusick int leintr(), leinit(), leioctl(), lestart(), ether_output(); 7841480Smckusick struct mbuf *leget(); 7941480Smckusick extern struct ifnet loif; 8041480Smckusick 8141480Smckusick /* 8241480Smckusick * Ethernet software status per interface. 8341480Smckusick * 8441480Smckusick * Each interface is referenced by a network interface structure, 8541480Smckusick * le_if, which the routing code uses to locate the interface. 8641480Smckusick * This structure contains the output queue for the interface, its address, ... 8741480Smckusick */ 8841480Smckusick struct le_softc { 8941480Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 9041480Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 9141480Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 9241480Smckusick struct lereg0 *sc_r0; /* DIO registers */ 9341480Smckusick struct lereg1 *sc_r1; /* LANCE registers */ 9441480Smckusick struct lereg2 *sc_r2; /* dual-port RAM */ 9541480Smckusick int sc_rmd; /* predicted next rmd to process */ 9641480Smckusick int sc_runt; 9741480Smckusick int sc_jab; 9841480Smckusick int sc_merr; 9941480Smckusick int sc_babl; 10041480Smckusick int sc_cerr; 10141480Smckusick int sc_miss; 10241480Smckusick int sc_xint; 10341480Smckusick int sc_xown; 10441480Smckusick int sc_uflo; 10541480Smckusick int sc_rxlen; 10641480Smckusick int sc_rxoff; 10741480Smckusick int sc_txoff; 10841480Smckusick int sc_busy; 109*48771Smccanne short sc_iflags; 11047567Smccanne #if NBPFILTER > 0 11147567Smccanne caddr_t sc_bpf; 11247567Smccanne #endif 11341480Smckusick } le_softc[NLE]; 11441480Smckusick 11541480Smckusick /* access LANCE registers */ 11641480Smckusick #define LERDWR(cntl, src, dst) \ 11741480Smckusick do { \ 11841480Smckusick (dst) = (src); \ 11941480Smckusick } while (((cntl)->ler0_status & LE_ACK) == 0); 12041480Smckusick 12141480Smckusick /* 12241480Smckusick * Interface exists: make available by filling in network interface 12341480Smckusick * record. System will initialize the interface when it is ready 12441480Smckusick * to accept packets. 12541480Smckusick */ 12641480Smckusick leattach(hd) 12741480Smckusick struct hp_device *hd; 12841480Smckusick { 12941480Smckusick register struct lereg0 *ler0; 13041480Smckusick register struct lereg2 *ler2; 13141480Smckusick struct lereg2 *lemem = 0; 13241480Smckusick struct le_softc *le = &le_softc[hd->hp_unit]; 13341480Smckusick struct ifnet *ifp = &le->sc_if; 13441480Smckusick char *cp; 13541480Smckusick int i; 13641480Smckusick 13741480Smckusick ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); 13841480Smckusick le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); 13941480Smckusick ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); 14041480Smckusick if (ler0->ler0_id != LEID) 14141480Smckusick return(0); 14241480Smckusick le_isr[hd->hp_unit].isr_intr = leintr; 14341480Smckusick hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); 14441480Smckusick le_isr[hd->hp_unit].isr_arg = hd->hp_unit; 14541480Smckusick ler0->ler0_id = 0xFF; 14641480Smckusick DELAY(100); 14741480Smckusick 14841480Smckusick /* 14941480Smckusick * Read the ethernet address off the board, one nibble at a time. 15041480Smckusick */ 15141480Smckusick cp = (char *)(lestd[3] + (int)hd->hp_addr); 15241480Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 15341480Smckusick le->sc_addr[i] = (*++cp & 0xF) << 4; 15441480Smckusick cp++; 15541480Smckusick le->sc_addr[i] |= *++cp & 0xF; 15641480Smckusick cp++; 15741480Smckusick } 15841480Smckusick printf("le%d: hardware address %s\n", hd->hp_unit, 15941480Smckusick ether_sprintf(le->sc_addr)); 16041480Smckusick 16141480Smckusick /* 16241480Smckusick * Setup for transmit/receive 16341480Smckusick */ 16441480Smckusick ler2->ler2_mode = LE_MODE; 16541480Smckusick ler2->ler2_padr[0] = le->sc_addr[1]; 16641480Smckusick ler2->ler2_padr[1] = le->sc_addr[0]; 16741480Smckusick ler2->ler2_padr[2] = le->sc_addr[3]; 16841480Smckusick ler2->ler2_padr[3] = le->sc_addr[2]; 16941480Smckusick ler2->ler2_padr[4] = le->sc_addr[5]; 17041480Smckusick ler2->ler2_padr[5] = le->sc_addr[4]; 17141480Smckusick #ifdef RMP 17241480Smckusick /* 17341480Smckusick * Set up logical addr filter to accept multicast 9:0:9:0:0:4 17441480Smckusick * This should be an ioctl() to the driver. (XXX) 17541480Smckusick */ 17641480Smckusick ler2->ler2_ladrf0 = 0x00100000; 17741480Smckusick ler2->ler2_ladrf1 = 0x0; 17841480Smckusick #else 17941480Smckusick ler2->ler2_ladrf0 = 0; 18041480Smckusick ler2->ler2_ladrf1 = 0; 18141480Smckusick #endif 18241480Smckusick ler2->ler2_rlen = LE_RLEN; 18341480Smckusick ler2->ler2_rdra = (int)lemem->ler2_rmd; 18441480Smckusick ler2->ler2_tlen = LE_TLEN; 18541480Smckusick ler2->ler2_tdra = (int)lemem->ler2_tmd; 18641480Smckusick isrlink(&le_isr[hd->hp_unit]); 18741480Smckusick ler0->ler0_status = LE_IE; 18841480Smckusick 18941480Smckusick ifp->if_unit = hd->hp_unit; 19041480Smckusick ifp->if_name = "le"; 19141480Smckusick ifp->if_mtu = ETHERMTU; 19241480Smckusick ifp->if_init = leinit; 19341480Smckusick ifp->if_ioctl = leioctl; 19441480Smckusick ifp->if_output = ether_output; 19541480Smckusick ifp->if_start = lestart; 19641480Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 19747567Smccanne #if NBPFILTER > 0 19847567Smccanne { 19947567Smccanne static struct bpf_devp dev = 20047567Smccanne { DLT_EN10MB, sizeof(struct ether_header) }; 20147567Smccanne 20247567Smccanne bpfattach(&le->sc_bpf, ifp, &dev); 20347567Smccanne } 20447567Smccanne #endif 20541480Smckusick if_attach(ifp); 20641480Smckusick return (1); 20741480Smckusick } 20841480Smckusick 20941480Smckusick ledrinit(ler2) 21041480Smckusick register struct lereg2 *ler2; 21141480Smckusick { 21241480Smckusick register struct lereg2 *lemem = 0; 21341480Smckusick register int i; 21441480Smckusick 21541480Smckusick for (i = 0; i < LERBUF; i++) { 21641480Smckusick ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; 21741480Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 21841480Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 21941480Smckusick ler2->ler2_rmd[i].rmd3 = 0; 22041480Smckusick } 22141480Smckusick for (i = 0; i < LETBUF; i++) { 22241480Smckusick ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; 22341480Smckusick ler2->ler2_tmd[i].tmd1 = 0; 22441480Smckusick ler2->ler2_tmd[i].tmd2 = 0; 22541480Smckusick ler2->ler2_tmd[i].tmd3 = 0; 22641480Smckusick } 22741480Smckusick } 22841480Smckusick 22941480Smckusick lereset(unit) 23041480Smckusick register int unit; 23141480Smckusick { 23241480Smckusick register struct le_softc *le = &le_softc[unit]; 23341480Smckusick register struct lereg0 *ler0 = le->sc_r0; 23441480Smckusick register struct lereg1 *ler1 = le->sc_r1; 23541480Smckusick register struct lereg2 *lemem = 0; 23641480Smckusick register int timo = 100000; 23741480Smckusick register int stat; 23841480Smckusick 23941480Smckusick #ifdef lint 24041480Smckusick stat = unit; 24141480Smckusick #endif 24247567Smccanne #if NBPFILTER > 0 24347567Smccanne if (le->sc_if.if_flags & IFF_PROMISC) 24447567Smccanne /* set the promiscuous bit */ 24547567Smccanne le->sc_r2->ler2_mode = LE_MODE|0x8000; 24647567Smccanne else 24747567Smccanne le->sc_r2->ler2_mode = LE_MODE; 24847567Smccanne #endif 24941480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 25041480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 25141480Smckusick ledrinit(le->sc_r2); 25241480Smckusick le->sc_rmd = 0; 25341480Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 25441480Smckusick LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); 25541480Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 25641480Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 25741480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 25841480Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 25941480Smckusick do { 26041480Smckusick if (--timo == 0) { 26141480Smckusick printf("le%d: init timeout, stat = 0x%x\n", 26241480Smckusick unit, stat); 26341480Smckusick break; 26441480Smckusick } 26541480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 26641480Smckusick } while ((stat & LE_IDON) == 0); 26741480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 26841480Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 26941480Smckusick LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); 27041480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 27141480Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 27241480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 27341480Smckusick } 27441480Smckusick 27541480Smckusick /* 27641480Smckusick * Initialization of interface 27741480Smckusick */ 27841480Smckusick leinit(unit) 27941480Smckusick int unit; 28041480Smckusick { 28141480Smckusick struct le_softc *le = &le_softc[unit]; 28241480Smckusick register struct ifnet *ifp = &le->sc_if; 28341480Smckusick int s; 28441480Smckusick 28541480Smckusick /* not yet, if address still unknown */ 28641480Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 28741480Smckusick return; 28841480Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 28941480Smckusick s = splimp(); 29041480Smckusick ifp->if_flags |= IFF_RUNNING; 29141480Smckusick lereset(unit); 29241480Smckusick (void) lestart(ifp); 29341480Smckusick splx(s); 29441480Smckusick } 29541480Smckusick } 29641480Smckusick 29741480Smckusick /* 29841480Smckusick * Start output on interface. Get another datagram to send 29941480Smckusick * off of the interface queue, and copy it to the interface 30041480Smckusick * before starting the output. 30141480Smckusick */ 30241480Smckusick lestart(ifp) 30341480Smckusick struct ifnet *ifp; 30441480Smckusick { 30541480Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 30641480Smckusick register struct letmd *tmd; 30741480Smckusick register struct mbuf *m; 30841480Smckusick int len; 30941480Smckusick 31041480Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 31141480Smckusick return (0); 31241480Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 31341480Smckusick if (m == 0) 31441480Smckusick return (0); 31547567Smccanne #if NBPFILTER > 0 31647567Smccanne /* 31747567Smccanne * If bpf is listening on this interface, let it 31847567Smccanne * see the packet before we commit it to the wire. 31947567Smccanne */ 32047567Smccanne if (le->sc_bpf) 32147567Smccanne bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len); 32247567Smccanne #endif 32341480Smckusick len = leput(le->sc_r2->ler2_tbuf[0], m); 32441480Smckusick tmd = le->sc_r2->ler2_tmd; 32541480Smckusick tmd->tmd3 = 0; 32641480Smckusick tmd->tmd2 = -len; 32741480Smckusick tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 32841480Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 32941480Smckusick return (0); 33041480Smckusick } 33141480Smckusick 33241480Smckusick leintr(unit) 33341480Smckusick register int unit; 33441480Smckusick { 33541480Smckusick register struct le_softc *le = &le_softc[unit]; 33641480Smckusick register struct lereg0 *ler0 = le->sc_r0; 33741480Smckusick register struct lereg1 *ler1; 33841480Smckusick register int stat; 33941480Smckusick 34041480Smckusick if ((ler0->ler0_status & LE_IR) == 0) 34141480Smckusick return(0); 34241480Smckusick if (ler0->ler0_status & LE_JAB) { 34341480Smckusick le->sc_jab++; 34441480Smckusick lereset(unit); 34541480Smckusick return(1); 34641480Smckusick } 34741480Smckusick ler1 = le->sc_r1; 34841480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 34941480Smckusick if (stat & LE_SERR) { 35041480Smckusick leerror(unit, stat); 35141480Smckusick if (stat & LE_MERR) { 35241480Smckusick le->sc_merr++; 35341480Smckusick lereset(unit); 35441480Smckusick return(1); 35541480Smckusick } 35641480Smckusick if (stat & LE_BABL) 35741480Smckusick le->sc_babl++; 35841480Smckusick if (stat & LE_CERR) 35941480Smckusick le->sc_cerr++; 36041480Smckusick if (stat & LE_MISS) 36141480Smckusick le->sc_miss++; 36241480Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 36341480Smckusick } 36441480Smckusick if ((stat & LE_RXON) == 0) { 36541480Smckusick le->sc_rxoff++; 36641480Smckusick lereset(unit); 36741480Smckusick return(1); 36841480Smckusick } 36941480Smckusick if ((stat & LE_TXON) == 0) { 37041480Smckusick le->sc_txoff++; 37141480Smckusick lereset(unit); 37241480Smckusick return(1); 37341480Smckusick } 37441480Smckusick if (stat & LE_RINT) { 37541480Smckusick /* interrupt is cleared in lerint */ 37641480Smckusick lerint(unit); 37741480Smckusick } 37841480Smckusick if (stat & LE_TINT) { 37941480Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 38041480Smckusick lexint(unit); 38141480Smckusick } 38241480Smckusick return(1); 38341480Smckusick } 38441480Smckusick 38541480Smckusick /* 38641480Smckusick * Ethernet interface transmitter interrupt. 38741480Smckusick * Start another output if more data to send. 38841480Smckusick */ 38941480Smckusick lexint(unit) 39041480Smckusick register int unit; 39141480Smckusick { 39241480Smckusick register struct le_softc *le = &le_softc[unit]; 39341480Smckusick register struct letmd *tmd = le->sc_r2->ler2_tmd; 39441480Smckusick 39541480Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 39641480Smckusick le->sc_xint++; 39741480Smckusick return; 39841480Smckusick } 39941480Smckusick if (tmd->tmd1 & LE_OWN) { 40041480Smckusick le->sc_xown++; 40141480Smckusick return; 40241480Smckusick } 40341480Smckusick if (tmd->tmd1 & LE_ERR) { 40441480Smckusick err: 40541480Smckusick lexerror(unit); 40641480Smckusick le->sc_if.if_oerrors++; 40741480Smckusick if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 40841480Smckusick le->sc_uflo++; 40941480Smckusick lereset(unit); 41041480Smckusick } 41141480Smckusick else if (tmd->tmd3 & LE_LCOL) 41241480Smckusick le->sc_if.if_collisions++; 41341480Smckusick else if (tmd->tmd3 & LE_RTRY) 41441480Smckusick le->sc_if.if_collisions += 16; 41541480Smckusick } 41641480Smckusick else if (tmd->tmd3 & LE_TBUFF) 41741480Smckusick /* XXX documentation says BUFF not included in ERR */ 41841480Smckusick goto err; 41941480Smckusick else if (tmd->tmd1 & LE_ONE) 42041480Smckusick le->sc_if.if_collisions++; 42141480Smckusick else if (tmd->tmd1 & LE_MORE) 42241480Smckusick /* what is the real number? */ 42341480Smckusick le->sc_if.if_collisions += 2; 42441480Smckusick else 42541480Smckusick le->sc_if.if_opackets++; 42641480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 42741480Smckusick (void) lestart(&le->sc_if); 42841480Smckusick } 42941480Smckusick 43041480Smckusick #define LENEXTRMP \ 43141480Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 43241480Smckusick 43341480Smckusick /* 43441480Smckusick * Ethernet interface receiver interrupt. 43541480Smckusick * If input error just drop packet. 43641480Smckusick * Decapsulate packet based on type and pass to type specific 43741480Smckusick * higher-level input routine. 43841480Smckusick */ 43941480Smckusick lerint(unit) 44041480Smckusick int unit; 44141480Smckusick { 44241480Smckusick register struct le_softc *le = &le_softc[unit]; 44341480Smckusick register int bix = le->sc_rmd; 44441480Smckusick register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 44541480Smckusick 44641480Smckusick /* 44741480Smckusick * Out of sync with hardware, should never happen? 44841480Smckusick */ 44941480Smckusick if (rmd->rmd1 & LE_OWN) { 45041480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 45141480Smckusick return; 45241480Smckusick } 45341480Smckusick 45441480Smckusick /* 45541480Smckusick * Process all buffers with valid data 45641480Smckusick */ 45741480Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 45841480Smckusick int len = rmd->rmd3; 45941480Smckusick 46041480Smckusick /* Clear interrupt to avoid race condition */ 46141480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 46241480Smckusick 46341480Smckusick if (rmd->rmd1 & LE_ERR) { 46441480Smckusick le->sc_rmd = bix; 46541480Smckusick lererror(unit, "bad packet"); 46641480Smckusick le->sc_if.if_ierrors++; 46741480Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 46841480Smckusick /* 46941480Smckusick * Find the end of the packet so we can see how long 47041480Smckusick * it was. We still throw it away. 47141480Smckusick */ 47241480Smckusick do { 47341480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 47441480Smckusick le->sc_r1->ler1_rdp); 47541480Smckusick rmd->rmd3 = 0; 47641480Smckusick rmd->rmd1 = LE_OWN; 47741480Smckusick LENEXTRMP; 47841480Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 47941480Smckusick le->sc_rmd = bix; 48041480Smckusick lererror(unit, "chained buffer"); 48141480Smckusick le->sc_rxlen++; 48241480Smckusick /* 48341480Smckusick * If search terminated without successful completion 48441480Smckusick * we reset the hardware (conservative). 48541480Smckusick */ 48641480Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 48741480Smckusick LE_ENP) { 48841480Smckusick lereset(unit); 48941480Smckusick return; 49041480Smckusick } 49141480Smckusick } else 49241480Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 49341480Smckusick rmd->rmd3 = 0; 49441480Smckusick rmd->rmd1 = LE_OWN; 49541480Smckusick LENEXTRMP; 49641480Smckusick } 49741480Smckusick le->sc_rmd = bix; 49841480Smckusick } 49941480Smckusick 50041480Smckusick leread(unit, buf, len) 50141480Smckusick int unit; 50241480Smckusick char *buf; 50341480Smckusick int len; 50441480Smckusick { 50541480Smckusick register struct le_softc *le = &le_softc[unit]; 50641480Smckusick register struct ether_header *et; 50741480Smckusick struct mbuf *m; 50841480Smckusick int off, resid; 50941480Smckusick 51041480Smckusick le->sc_if.if_ipackets++; 51141480Smckusick et = (struct ether_header *)buf; 51241480Smckusick et->ether_type = ntohs((u_short)et->ether_type); 51341480Smckusick /* adjust input length to account for header and CRC */ 51441480Smckusick len = len - sizeof(struct ether_header) - 4; 51541480Smckusick 51641480Smckusick #ifdef RMP 51741480Smckusick /* (XXX) 51841480Smckusick * 51941480Smckusick * If Ethernet Type field is < MaxPacketSize, we probably have 52041480Smckusick * a IEEE802 packet here. Make sure that the size is at least 52141480Smckusick * that of the HP LLC. Also do sanity checks on length of LLC 52241480Smckusick * (old Ethernet Type field) and packet length. 52341480Smckusick * 52441480Smckusick * Provided the above checks succeed, change `len' to reflect 52541480Smckusick * the length of the LLC (i.e. et->ether_type) and change the 52641480Smckusick * type field to ETHERTYPE_IEEE so we can switch() on it later. 52741480Smckusick * Yes, this is a hack and will eventually be done "right". 52841480Smckusick */ 52941480Smckusick if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 53041480Smckusick len >= et->ether_type && len >= IEEE802LEN_MIN) { 53141480Smckusick len = et->ether_type; 53241480Smckusick et->ether_type = ETHERTYPE_IEEE; /* hack! */ 53341480Smckusick } 53441480Smckusick #endif 53541480Smckusick 53641480Smckusick #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) 53741480Smckusick if (et->ether_type >= ETHERTYPE_TRAIL && 53841480Smckusick et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 53941480Smckusick off = (et->ether_type - ETHERTYPE_TRAIL) * 512; 54041480Smckusick if (off >= ETHERMTU) 54141480Smckusick return; /* sanity */ 54241480Smckusick et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); 54341480Smckusick resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 54441480Smckusick if (off + resid > len) 54541480Smckusick return; /* sanity */ 54641480Smckusick len = off + resid; 54741480Smckusick } else 54841480Smckusick off = 0; 54941480Smckusick 55041480Smckusick if (len <= 0) { 55141480Smckusick if (ledebug) 55241480Smckusick log(LOG_WARNING, 55341480Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 55441480Smckusick unit, ether_sprintf(et->ether_shost), len); 55541480Smckusick le->sc_runt++; 55641480Smckusick le->sc_if.if_ierrors++; 55741480Smckusick return; 55841480Smckusick } 55947567Smccanne #if NBPFILTER > 0 56047567Smccanne /* 56147567Smccanne * Check if there's a bpf filter listening on this interface. 56247567Smccanne * If so, hand off the raw packet to bpf, which must deal with 56347567Smccanne * trailers in its own way. 56447567Smccanne */ 56547567Smccanne if (le->sc_bpf) { 56647567Smccanne bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header)); 56741480Smckusick 56847567Smccanne /* 56947567Smccanne * Note that the interface cannot be in promiscuous mode if 57047567Smccanne * there are no bpf listeners. And if we are in promiscuous 57147567Smccanne * mode, we have to check if this packet is really ours. 57247567Smccanne * 57347567Smccanne * XXX This test does not support multicasts. 57447567Smccanne */ 57547567Smccanne if ((le->sc_if.if_flags & IFF_PROMISC) 57647567Smccanne && bcmp(et->ether_dhost, le->sc_addr, 57747567Smccanne sizeof(et->ether_dhost)) != 0 57847567Smccanne && bcmp(et->ether_dhost, etherbroadcastaddr, 57947567Smccanne sizeof(et->ether_dhost)) != 0) 58047567Smccanne return; 58147567Smccanne } 58247567Smccanne #endif 58341480Smckusick /* 58441480Smckusick * Pull packet off interface. Off is nonzero if packet 58541480Smckusick * has trailing header; leget will then force this header 58641480Smckusick * information to be at the front, but we still have to drop 58741480Smckusick * the type and length which are at the front of any trailer data. 58841480Smckusick */ 58941480Smckusick m = leget(buf, len, off, &le->sc_if); 59041480Smckusick if (m == 0) 59141480Smckusick return; 59241480Smckusick #ifdef RMP 59341480Smckusick /* 59441480Smckusick * (XXX) 59541480Smckusick * This needs to be integrated with the ISO stuff in ether_input() 59641480Smckusick */ 59741480Smckusick if (et->ether_type == ETHERTYPE_IEEE) { 59841480Smckusick /* 59941480Smckusick * Snag the Logical Link Control header (IEEE 802.2). 60041480Smckusick */ 60141480Smckusick struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc); 60241480Smckusick 60341480Smckusick /* 60441480Smckusick * If the DSAP (and HP's extended DXSAP) indicate this 60541480Smckusick * is an RMP packet, hand it to the raw input routine. 60641480Smckusick */ 60741480Smckusick if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 60841480Smckusick static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 60941480Smckusick static struct sockaddr rmp_src = {AF_RMP}; 61041480Smckusick static struct sockaddr rmp_dst = {AF_RMP}; 61141480Smckusick 61241480Smckusick bcopy(et->ether_shost, rmp_src.sa_data, 61341480Smckusick sizeof(et->ether_shost)); 61441480Smckusick bcopy(et->ether_dhost, rmp_dst.sa_data, 61541480Smckusick sizeof(et->ether_dhost)); 61641480Smckusick 61741480Smckusick raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 61841480Smckusick return; 61941480Smckusick } 62041480Smckusick } 62141480Smckusick #endif 62241480Smckusick ether_input(&le->sc_if, et, m); 62341480Smckusick } 62441480Smckusick 62541480Smckusick /* 62641480Smckusick * Routine to copy from mbuf chain to transmit 62741480Smckusick * buffer in board local memory. 62841480Smckusick */ 62941480Smckusick leput(lebuf, m) 63041480Smckusick register char *lebuf; 63141480Smckusick register struct mbuf *m; 63241480Smckusick { 63341480Smckusick register struct mbuf *mp; 63441480Smckusick register int len, tlen = 0; 63541480Smckusick 63641480Smckusick for (mp = m; mp; mp = mp->m_next) { 63741480Smckusick len = mp->m_len; 63841480Smckusick if (len == 0) 63941480Smckusick continue; 64041480Smckusick tlen += len; 64141480Smckusick bcopy(mtod(mp, char *), lebuf, len); 64241480Smckusick lebuf += len; 64341480Smckusick } 64441480Smckusick m_freem(m); 64541480Smckusick if (tlen < LEMINSIZE) { 64641480Smckusick bzero(lebuf, LEMINSIZE - tlen); 64741480Smckusick tlen = LEMINSIZE; 64841480Smckusick } 64941480Smckusick return(tlen); 65041480Smckusick } 65141480Smckusick 65241480Smckusick /* 65341480Smckusick * Routine to copy from board local memory into mbufs. 65441480Smckusick */ 65541480Smckusick struct mbuf * 65641480Smckusick leget(lebuf, totlen, off0, ifp) 65741480Smckusick char *lebuf; 65841480Smckusick int totlen, off0; 65941480Smckusick struct ifnet *ifp; 66041480Smckusick { 66141480Smckusick register struct mbuf *m; 66241480Smckusick struct mbuf *top = 0, **mp = ⊤ 66341480Smckusick register int off = off0, len; 66441480Smckusick register char *cp; 66541480Smckusick char *epkt; 66641480Smckusick 66741480Smckusick lebuf += sizeof (struct ether_header); 66841480Smckusick cp = lebuf; 66941480Smckusick epkt = cp + totlen; 67041480Smckusick if (off) { 67141480Smckusick cp += off + 2 * sizeof(u_short); 67241480Smckusick totlen -= 2 * sizeof(u_short); 67341480Smckusick } 67441480Smckusick 67541480Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 67641480Smckusick if (m == 0) 67741480Smckusick return (0); 67841480Smckusick m->m_pkthdr.rcvif = ifp; 67941480Smckusick m->m_pkthdr.len = totlen; 68041480Smckusick m->m_len = MHLEN; 68141480Smckusick 68241480Smckusick while (totlen > 0) { 68341480Smckusick if (top) { 68441480Smckusick MGET(m, M_DONTWAIT, MT_DATA); 68541480Smckusick if (m == 0) { 68641480Smckusick m_freem(top); 68741480Smckusick return (0); 68841480Smckusick } 68941480Smckusick m->m_len = MLEN; 69041480Smckusick } 69141480Smckusick len = min(totlen, epkt - cp); 69241480Smckusick if (len >= MINCLSIZE) { 69341480Smckusick MCLGET(m, M_DONTWAIT); 69441480Smckusick if (m->m_flags & M_EXT) 69541480Smckusick m->m_len = len = min(len, MCLBYTES); 69641480Smckusick else 69741480Smckusick len = m->m_len; 69841480Smckusick } else { 69941480Smckusick /* 70041480Smckusick * Place initial small packet/header at end of mbuf. 70141480Smckusick */ 70241480Smckusick if (len < m->m_len) { 70341480Smckusick if (top == 0 && len + max_linkhdr <= m->m_len) 70441480Smckusick m->m_data += max_linkhdr; 70541480Smckusick m->m_len = len; 70641480Smckusick } else 70741480Smckusick len = m->m_len; 70841480Smckusick } 70941480Smckusick bcopy(cp, mtod(m, caddr_t), (unsigned)len); 71041480Smckusick cp += len; 71141480Smckusick *mp = m; 71241480Smckusick mp = &m->m_next; 71341480Smckusick totlen -= len; 71441480Smckusick if (cp == epkt) 71541480Smckusick cp = lebuf; 71641480Smckusick } 71741480Smckusick return (top); 71841480Smckusick } 71941480Smckusick 72041480Smckusick /* 72141480Smckusick * Process an ioctl request. 72241480Smckusick */ 72341480Smckusick leioctl(ifp, cmd, data) 72441480Smckusick register struct ifnet *ifp; 72541480Smckusick int cmd; 72641480Smckusick caddr_t data; 72741480Smckusick { 72841480Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 72941480Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 73041480Smckusick struct lereg1 *ler1 = le->sc_r1; 73141480Smckusick int s = splimp(), error = 0; 73241480Smckusick 73341480Smckusick switch (cmd) { 73441480Smckusick 73541480Smckusick case SIOCSIFADDR: 73641480Smckusick ifp->if_flags |= IFF_UP; 73741480Smckusick switch (ifa->ifa_addr->sa_family) { 73841480Smckusick #ifdef INET 73941480Smckusick case AF_INET: 74041480Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 74141480Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 74241480Smckusick IA_SIN(ifa)->sin_addr; 74341480Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 74441480Smckusick break; 74541480Smckusick #endif 74641480Smckusick #ifdef NS 74741480Smckusick case AF_NS: 74841480Smckusick { 74941480Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 75041480Smckusick 75141480Smckusick if (ns_nullhost(*ina)) 75241480Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 75341480Smckusick else { 75441480Smckusick /* 75541480Smckusick * The manual says we can't change the address 75641480Smckusick * while the receiver is armed, 75741480Smckusick * so reset everything 75841480Smckusick */ 75941480Smckusick ifp->if_flags &= ~IFF_RUNNING; 76041480Smckusick bcopy((caddr_t)ina->x_host.c_host, 76141480Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 76241480Smckusick } 76341480Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 76441480Smckusick break; 76541480Smckusick } 76641480Smckusick #endif 76741480Smckusick default: 76841480Smckusick leinit(ifp->if_unit); 76941480Smckusick break; 77041480Smckusick } 77141480Smckusick break; 77241480Smckusick 77341480Smckusick case SIOCSIFFLAGS: 77441480Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 77541480Smckusick ifp->if_flags & IFF_RUNNING) { 77641480Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 77741480Smckusick ifp->if_flags &= ~IFF_RUNNING; 77841480Smckusick } else if (ifp->if_flags & IFF_UP && 77941480Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 78041480Smckusick leinit(ifp->if_unit); 781*48771Smccanne /* 782*48771Smccanne * If the state of the promiscuous bit changes, the interface 783*48771Smccanne * must be reset to effect the change. 784*48771Smccanne */ 785*48771Smccanne if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 786*48771Smccanne (ifp->if_flags & IFF_RUNNING)) { 787*48771Smccanne le->sc_iflags = ifp->if_flags; 788*48771Smccanne lereset(ifp->if_unit); 789*48771Smccanne lestart(ifp); 790*48771Smccanne } 79141480Smckusick break; 79241480Smckusick 79341480Smckusick default: 79441480Smckusick error = EINVAL; 79541480Smckusick } 79641480Smckusick splx(s); 79741480Smckusick return (error); 79841480Smckusick } 79941480Smckusick 80041480Smckusick leerror(unit, stat) 80141480Smckusick int unit; 80241480Smckusick int stat; 80341480Smckusick { 80441480Smckusick if (!ledebug) 80541480Smckusick return; 80641480Smckusick 80741480Smckusick /* 80841480Smckusick * Not all transceivers implement heartbeat 80941480Smckusick * so we only log CERR once. 81041480Smckusick */ 81141480Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 81241480Smckusick return; 81341480Smckusick log(LOG_WARNING, 81441480Smckusick "le%d: error: stat=%b\n", unit, 81541480Smckusick stat, 81641480Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 81741480Smckusick } 81841480Smckusick 81941480Smckusick lererror(unit, msg) 82041480Smckusick int unit; 82141480Smckusick char *msg; 82241480Smckusick { 82341480Smckusick register struct le_softc *le = &le_softc[unit]; 82441480Smckusick register struct lermd *rmd; 82541480Smckusick int len; 82641480Smckusick 82741480Smckusick if (!ledebug) 82841480Smckusick return; 82941480Smckusick 83041480Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 83141480Smckusick len = rmd->rmd3; 83241480Smckusick log(LOG_WARNING, 83341480Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 83441480Smckusick unit, msg, 83541480Smckusick len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown", 83641480Smckusick le->sc_rmd, len, 83741480Smckusick rmd->rmd1, 83841480Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 83941480Smckusick } 84041480Smckusick 84141480Smckusick lexerror(unit) 84241480Smckusick int unit; 84341480Smckusick { 84441480Smckusick register struct le_softc *le = &le_softc[unit]; 84541480Smckusick register struct letmd *tmd; 84641480Smckusick int len; 84741480Smckusick 84841480Smckusick if (!ledebug) 84941480Smckusick return; 85041480Smckusick 85141480Smckusick tmd = le->sc_r2->ler2_tmd; 85241480Smckusick len = -tmd->tmd2; 85341480Smckusick log(LOG_WARNING, 85441480Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 85541480Smckusick unit, 85641480Smckusick len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown", 85741480Smckusick 0, len, 85841480Smckusick tmd->tmd1, 85941480Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 86041480Smckusick tmd->tmd3, 86141480Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 86241480Smckusick } 86341480Smckusick #endif 864