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*45788Sbostic * @(#)if_le.c 7.2 (Berkeley) 12/16/90 841480Smckusick */ 941480Smckusick 1041480Smckusick #include "le.h" 1141480Smckusick #if NLE > 0 1241480Smckusick 1341480Smckusick /* 1441480Smckusick * AMD 7990 LANCE 1541480Smckusick * 1641480Smckusick * This driver will generate and accept tailer encapsulated packets even 1741480Smckusick * though it buys us nothing. The motivation was to avoid incompatibilities 1841480Smckusick * with VAXen, SUNs, and others that handle and benefit from them. 1941480Smckusick * This reasoning is dubious. 2041480Smckusick */ 21*45788Sbostic #include "sys/param.h" 22*45788Sbostic #include "sys/systm.h" 23*45788Sbostic #include "sys/mbuf.h" 24*45788Sbostic #include "sys/buf.h" 25*45788Sbostic #include "sys/protosw.h" 26*45788Sbostic #include "sys/socket.h" 27*45788Sbostic #include "sys/syslog.h" 28*45788Sbostic #include "sys/ioctl.h" 29*45788Sbostic #include "sys/errno.h" 3041480Smckusick 31*45788Sbostic #include "net/if.h" 32*45788Sbostic #include "net/netisr.h" 33*45788Sbostic #include "net/route.h" 3441480Smckusick 3541480Smckusick #ifdef INET 36*45788Sbostic #include "netinet/in.h" 37*45788Sbostic #include "netinet/in_systm.h" 38*45788Sbostic #include "netinet/in_var.h" 39*45788Sbostic #include "netinet/ip.h" 40*45788Sbostic #include "netinet/if_ether.h" 4141480Smckusick #endif 4241480Smckusick 4341480Smckusick #ifdef NS 44*45788Sbostic #include "netns/ns.h" 45*45788Sbostic #include "netns/ns_if.h" 4641480Smckusick #endif 4741480Smckusick 4841480Smckusick #ifdef RMP 49*45788Sbostic #include "netrmp/rmp.h" 50*45788Sbostic #include "netrmp/rmp_var.h" 5141480Smckusick #endif 5241480Smckusick 53*45788Sbostic #include "../include/cpu.h" 54*45788Sbostic #include "../hp300/isr.h" 55*45788Sbostic #include "../include/mtpr.h" 5641480Smckusick #include "device.h" 5741480Smckusick #include "if_lereg.h" 5841480Smckusick 5941480Smckusick /* offsets for: ID, REGS, MEM, NVRAM */ 6041480Smckusick int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; 6141480Smckusick 6241480Smckusick int leattach(); 6341480Smckusick struct driver ledriver = { 6441480Smckusick leattach, "le", 6541480Smckusick }; 6641480Smckusick 6741480Smckusick struct isr le_isr[NLE]; 6841480Smckusick int ledebug = 0; /* console error messages */ 6941480Smckusick 7041480Smckusick int leintr(), leinit(), leioctl(), lestart(), ether_output(); 7141480Smckusick struct mbuf *leget(); 7241480Smckusick extern struct ifnet loif; 7341480Smckusick 7441480Smckusick /* 7541480Smckusick * Ethernet software status per interface. 7641480Smckusick * 7741480Smckusick * Each interface is referenced by a network interface structure, 7841480Smckusick * le_if, which the routing code uses to locate the interface. 7941480Smckusick * This structure contains the output queue for the interface, its address, ... 8041480Smckusick */ 8141480Smckusick struct le_softc { 8241480Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 8341480Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 8441480Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 8541480Smckusick struct lereg0 *sc_r0; /* DIO registers */ 8641480Smckusick struct lereg1 *sc_r1; /* LANCE registers */ 8741480Smckusick struct lereg2 *sc_r2; /* dual-port RAM */ 8841480Smckusick int sc_rmd; /* predicted next rmd to process */ 8941480Smckusick int sc_runt; 9041480Smckusick int sc_jab; 9141480Smckusick int sc_merr; 9241480Smckusick int sc_babl; 9341480Smckusick int sc_cerr; 9441480Smckusick int sc_miss; 9541480Smckusick int sc_xint; 9641480Smckusick int sc_xown; 9741480Smckusick int sc_uflo; 9841480Smckusick int sc_rxlen; 9941480Smckusick int sc_rxoff; 10041480Smckusick int sc_txoff; 10141480Smckusick int sc_busy; 10241480Smckusick } le_softc[NLE]; 10341480Smckusick 10441480Smckusick /* access LANCE registers */ 10541480Smckusick #define LERDWR(cntl, src, dst) \ 10641480Smckusick do { \ 10741480Smckusick (dst) = (src); \ 10841480Smckusick } while (((cntl)->ler0_status & LE_ACK) == 0); 10941480Smckusick 11041480Smckusick /* 11141480Smckusick * Interface exists: make available by filling in network interface 11241480Smckusick * record. System will initialize the interface when it is ready 11341480Smckusick * to accept packets. 11441480Smckusick */ 11541480Smckusick leattach(hd) 11641480Smckusick struct hp_device *hd; 11741480Smckusick { 11841480Smckusick register struct lereg0 *ler0; 11941480Smckusick register struct lereg2 *ler2; 12041480Smckusick struct lereg2 *lemem = 0; 12141480Smckusick struct le_softc *le = &le_softc[hd->hp_unit]; 12241480Smckusick struct ifnet *ifp = &le->sc_if; 12341480Smckusick char *cp; 12441480Smckusick int i; 12541480Smckusick 12641480Smckusick ler0 = le->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr); 12741480Smckusick le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr); 12841480Smckusick ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)hd->hp_addr); 12941480Smckusick if (ler0->ler0_id != LEID) 13041480Smckusick return(0); 13141480Smckusick le_isr[hd->hp_unit].isr_intr = leintr; 13241480Smckusick hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status); 13341480Smckusick le_isr[hd->hp_unit].isr_arg = hd->hp_unit; 13441480Smckusick ler0->ler0_id = 0xFF; 13541480Smckusick DELAY(100); 13641480Smckusick 13741480Smckusick /* 13841480Smckusick * Read the ethernet address off the board, one nibble at a time. 13941480Smckusick */ 14041480Smckusick cp = (char *)(lestd[3] + (int)hd->hp_addr); 14141480Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 14241480Smckusick le->sc_addr[i] = (*++cp & 0xF) << 4; 14341480Smckusick cp++; 14441480Smckusick le->sc_addr[i] |= *++cp & 0xF; 14541480Smckusick cp++; 14641480Smckusick } 14741480Smckusick printf("le%d: hardware address %s\n", hd->hp_unit, 14841480Smckusick ether_sprintf(le->sc_addr)); 14941480Smckusick 15041480Smckusick /* 15141480Smckusick * Setup for transmit/receive 15241480Smckusick */ 15341480Smckusick ler2->ler2_mode = LE_MODE; 15441480Smckusick ler2->ler2_padr[0] = le->sc_addr[1]; 15541480Smckusick ler2->ler2_padr[1] = le->sc_addr[0]; 15641480Smckusick ler2->ler2_padr[2] = le->sc_addr[3]; 15741480Smckusick ler2->ler2_padr[3] = le->sc_addr[2]; 15841480Smckusick ler2->ler2_padr[4] = le->sc_addr[5]; 15941480Smckusick ler2->ler2_padr[5] = le->sc_addr[4]; 16041480Smckusick #ifdef RMP 16141480Smckusick /* 16241480Smckusick * Set up logical addr filter to accept multicast 9:0:9:0:0:4 16341480Smckusick * This should be an ioctl() to the driver. (XXX) 16441480Smckusick */ 16541480Smckusick ler2->ler2_ladrf0 = 0x00100000; 16641480Smckusick ler2->ler2_ladrf1 = 0x0; 16741480Smckusick #else 16841480Smckusick ler2->ler2_ladrf0 = 0; 16941480Smckusick ler2->ler2_ladrf1 = 0; 17041480Smckusick #endif 17141480Smckusick ler2->ler2_rlen = LE_RLEN; 17241480Smckusick ler2->ler2_rdra = (int)lemem->ler2_rmd; 17341480Smckusick ler2->ler2_tlen = LE_TLEN; 17441480Smckusick ler2->ler2_tdra = (int)lemem->ler2_tmd; 17541480Smckusick isrlink(&le_isr[hd->hp_unit]); 17641480Smckusick ler0->ler0_status = LE_IE; 17741480Smckusick 17841480Smckusick ifp->if_unit = hd->hp_unit; 17941480Smckusick ifp->if_name = "le"; 18041480Smckusick ifp->if_mtu = ETHERMTU; 18141480Smckusick ifp->if_init = leinit; 18241480Smckusick ifp->if_ioctl = leioctl; 18341480Smckusick ifp->if_output = ether_output; 18441480Smckusick ifp->if_start = lestart; 18541480Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 18641480Smckusick if_attach(ifp); 18741480Smckusick return (1); 18841480Smckusick } 18941480Smckusick 19041480Smckusick ledrinit(ler2) 19141480Smckusick register struct lereg2 *ler2; 19241480Smckusick { 19341480Smckusick register struct lereg2 *lemem = 0; 19441480Smckusick register int i; 19541480Smckusick 19641480Smckusick for (i = 0; i < LERBUF; i++) { 19741480Smckusick ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; 19841480Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 19941480Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 20041480Smckusick ler2->ler2_rmd[i].rmd3 = 0; 20141480Smckusick } 20241480Smckusick for (i = 0; i < LETBUF; i++) { 20341480Smckusick ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; 20441480Smckusick ler2->ler2_tmd[i].tmd1 = 0; 20541480Smckusick ler2->ler2_tmd[i].tmd2 = 0; 20641480Smckusick ler2->ler2_tmd[i].tmd3 = 0; 20741480Smckusick } 20841480Smckusick } 20941480Smckusick 21041480Smckusick lereset(unit) 21141480Smckusick register int unit; 21241480Smckusick { 21341480Smckusick register struct le_softc *le = &le_softc[unit]; 21441480Smckusick register struct lereg0 *ler0 = le->sc_r0; 21541480Smckusick register struct lereg1 *ler1 = le->sc_r1; 21641480Smckusick register struct lereg2 *lemem = 0; 21741480Smckusick register int timo = 100000; 21841480Smckusick register int stat; 21941480Smckusick 22041480Smckusick #ifdef lint 22141480Smckusick stat = unit; 22241480Smckusick #endif 22341480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 22441480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 22541480Smckusick ledrinit(le->sc_r2); 22641480Smckusick le->sc_rmd = 0; 22741480Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 22841480Smckusick LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp); 22941480Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 23041480Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 23141480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 23241480Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 23341480Smckusick do { 23441480Smckusick if (--timo == 0) { 23541480Smckusick printf("le%d: init timeout, stat = 0x%x\n", 23641480Smckusick unit, stat); 23741480Smckusick break; 23841480Smckusick } 23941480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 24041480Smckusick } while ((stat & LE_IDON) == 0); 24141480Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 24241480Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 24341480Smckusick LERDWR(ler0, LE_BSWP, ler1->ler1_rdp); 24441480Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 24541480Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 24641480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 24741480Smckusick } 24841480Smckusick 24941480Smckusick /* 25041480Smckusick * Initialization of interface 25141480Smckusick */ 25241480Smckusick leinit(unit) 25341480Smckusick int unit; 25441480Smckusick { 25541480Smckusick struct le_softc *le = &le_softc[unit]; 25641480Smckusick register struct ifnet *ifp = &le->sc_if; 25741480Smckusick int s; 25841480Smckusick 25941480Smckusick /* not yet, if address still unknown */ 26041480Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 26141480Smckusick return; 26241480Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 26341480Smckusick s = splimp(); 26441480Smckusick ifp->if_flags |= IFF_RUNNING; 26541480Smckusick lereset(unit); 26641480Smckusick (void) lestart(ifp); 26741480Smckusick splx(s); 26841480Smckusick } 26941480Smckusick } 27041480Smckusick 27141480Smckusick /* 27241480Smckusick * Start output on interface. Get another datagram to send 27341480Smckusick * off of the interface queue, and copy it to the interface 27441480Smckusick * before starting the output. 27541480Smckusick */ 27641480Smckusick lestart(ifp) 27741480Smckusick struct ifnet *ifp; 27841480Smckusick { 27941480Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 28041480Smckusick register struct letmd *tmd; 28141480Smckusick register struct mbuf *m; 28241480Smckusick int len; 28341480Smckusick 28441480Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 28541480Smckusick return (0); 28641480Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 28741480Smckusick if (m == 0) 28841480Smckusick return (0); 28941480Smckusick len = leput(le->sc_r2->ler2_tbuf[0], m); 29041480Smckusick tmd = le->sc_r2->ler2_tmd; 29141480Smckusick tmd->tmd3 = 0; 29241480Smckusick tmd->tmd2 = -len; 29341480Smckusick tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 29441480Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 29541480Smckusick return (0); 29641480Smckusick } 29741480Smckusick 29841480Smckusick leintr(unit) 29941480Smckusick register int unit; 30041480Smckusick { 30141480Smckusick register struct le_softc *le = &le_softc[unit]; 30241480Smckusick register struct lereg0 *ler0 = le->sc_r0; 30341480Smckusick register struct lereg1 *ler1; 30441480Smckusick register int stat; 30541480Smckusick 30641480Smckusick if ((ler0->ler0_status & LE_IR) == 0) 30741480Smckusick return(0); 30841480Smckusick if (ler0->ler0_status & LE_JAB) { 30941480Smckusick le->sc_jab++; 31041480Smckusick lereset(unit); 31141480Smckusick return(1); 31241480Smckusick } 31341480Smckusick ler1 = le->sc_r1; 31441480Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 31541480Smckusick if (stat & LE_SERR) { 31641480Smckusick leerror(unit, stat); 31741480Smckusick if (stat & LE_MERR) { 31841480Smckusick le->sc_merr++; 31941480Smckusick lereset(unit); 32041480Smckusick return(1); 32141480Smckusick } 32241480Smckusick if (stat & LE_BABL) 32341480Smckusick le->sc_babl++; 32441480Smckusick if (stat & LE_CERR) 32541480Smckusick le->sc_cerr++; 32641480Smckusick if (stat & LE_MISS) 32741480Smckusick le->sc_miss++; 32841480Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 32941480Smckusick } 33041480Smckusick if ((stat & LE_RXON) == 0) { 33141480Smckusick le->sc_rxoff++; 33241480Smckusick lereset(unit); 33341480Smckusick return(1); 33441480Smckusick } 33541480Smckusick if ((stat & LE_TXON) == 0) { 33641480Smckusick le->sc_txoff++; 33741480Smckusick lereset(unit); 33841480Smckusick return(1); 33941480Smckusick } 34041480Smckusick if (stat & LE_RINT) { 34141480Smckusick /* interrupt is cleared in lerint */ 34241480Smckusick lerint(unit); 34341480Smckusick } 34441480Smckusick if (stat & LE_TINT) { 34541480Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 34641480Smckusick lexint(unit); 34741480Smckusick } 34841480Smckusick return(1); 34941480Smckusick } 35041480Smckusick 35141480Smckusick /* 35241480Smckusick * Ethernet interface transmitter interrupt. 35341480Smckusick * Start another output if more data to send. 35441480Smckusick */ 35541480Smckusick lexint(unit) 35641480Smckusick register int unit; 35741480Smckusick { 35841480Smckusick register struct le_softc *le = &le_softc[unit]; 35941480Smckusick register struct letmd *tmd = le->sc_r2->ler2_tmd; 36041480Smckusick 36141480Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 36241480Smckusick le->sc_xint++; 36341480Smckusick return; 36441480Smckusick } 36541480Smckusick if (tmd->tmd1 & LE_OWN) { 36641480Smckusick le->sc_xown++; 36741480Smckusick return; 36841480Smckusick } 36941480Smckusick if (tmd->tmd1 & LE_ERR) { 37041480Smckusick err: 37141480Smckusick lexerror(unit); 37241480Smckusick le->sc_if.if_oerrors++; 37341480Smckusick if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 37441480Smckusick le->sc_uflo++; 37541480Smckusick lereset(unit); 37641480Smckusick } 37741480Smckusick else if (tmd->tmd3 & LE_LCOL) 37841480Smckusick le->sc_if.if_collisions++; 37941480Smckusick else if (tmd->tmd3 & LE_RTRY) 38041480Smckusick le->sc_if.if_collisions += 16; 38141480Smckusick } 38241480Smckusick else if (tmd->tmd3 & LE_TBUFF) 38341480Smckusick /* XXX documentation says BUFF not included in ERR */ 38441480Smckusick goto err; 38541480Smckusick else if (tmd->tmd1 & LE_ONE) 38641480Smckusick le->sc_if.if_collisions++; 38741480Smckusick else if (tmd->tmd1 & LE_MORE) 38841480Smckusick /* what is the real number? */ 38941480Smckusick le->sc_if.if_collisions += 2; 39041480Smckusick else 39141480Smckusick le->sc_if.if_opackets++; 39241480Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 39341480Smckusick (void) lestart(&le->sc_if); 39441480Smckusick } 39541480Smckusick 39641480Smckusick #define LENEXTRMP \ 39741480Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 39841480Smckusick 39941480Smckusick /* 40041480Smckusick * Ethernet interface receiver interrupt. 40141480Smckusick * If input error just drop packet. 40241480Smckusick * Decapsulate packet based on type and pass to type specific 40341480Smckusick * higher-level input routine. 40441480Smckusick */ 40541480Smckusick lerint(unit) 40641480Smckusick int unit; 40741480Smckusick { 40841480Smckusick register struct le_softc *le = &le_softc[unit]; 40941480Smckusick register int bix = le->sc_rmd; 41041480Smckusick register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 41141480Smckusick 41241480Smckusick /* 41341480Smckusick * Out of sync with hardware, should never happen? 41441480Smckusick */ 41541480Smckusick if (rmd->rmd1 & LE_OWN) { 41641480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 41741480Smckusick return; 41841480Smckusick } 41941480Smckusick 42041480Smckusick /* 42141480Smckusick * Process all buffers with valid data 42241480Smckusick */ 42341480Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 42441480Smckusick int len = rmd->rmd3; 42541480Smckusick 42641480Smckusick /* Clear interrupt to avoid race condition */ 42741480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 42841480Smckusick 42941480Smckusick if (rmd->rmd1 & LE_ERR) { 43041480Smckusick le->sc_rmd = bix; 43141480Smckusick lererror(unit, "bad packet"); 43241480Smckusick le->sc_if.if_ierrors++; 43341480Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 43441480Smckusick /* 43541480Smckusick * Find the end of the packet so we can see how long 43641480Smckusick * it was. We still throw it away. 43741480Smckusick */ 43841480Smckusick do { 43941480Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 44041480Smckusick le->sc_r1->ler1_rdp); 44141480Smckusick rmd->rmd3 = 0; 44241480Smckusick rmd->rmd1 = LE_OWN; 44341480Smckusick LENEXTRMP; 44441480Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 44541480Smckusick le->sc_rmd = bix; 44641480Smckusick lererror(unit, "chained buffer"); 44741480Smckusick le->sc_rxlen++; 44841480Smckusick /* 44941480Smckusick * If search terminated without successful completion 45041480Smckusick * we reset the hardware (conservative). 45141480Smckusick */ 45241480Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 45341480Smckusick LE_ENP) { 45441480Smckusick lereset(unit); 45541480Smckusick return; 45641480Smckusick } 45741480Smckusick } else 45841480Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 45941480Smckusick rmd->rmd3 = 0; 46041480Smckusick rmd->rmd1 = LE_OWN; 46141480Smckusick LENEXTRMP; 46241480Smckusick } 46341480Smckusick le->sc_rmd = bix; 46441480Smckusick } 46541480Smckusick 46641480Smckusick leread(unit, buf, len) 46741480Smckusick int unit; 46841480Smckusick char *buf; 46941480Smckusick int len; 47041480Smckusick { 47141480Smckusick register struct le_softc *le = &le_softc[unit]; 47241480Smckusick register struct ether_header *et; 47341480Smckusick struct mbuf *m; 47441480Smckusick int off, resid; 47541480Smckusick 47641480Smckusick le->sc_if.if_ipackets++; 47741480Smckusick et = (struct ether_header *)buf; 47841480Smckusick et->ether_type = ntohs((u_short)et->ether_type); 47941480Smckusick /* adjust input length to account for header and CRC */ 48041480Smckusick len = len - sizeof(struct ether_header) - 4; 48141480Smckusick 48241480Smckusick #ifdef RMP 48341480Smckusick /* (XXX) 48441480Smckusick * 48541480Smckusick * If Ethernet Type field is < MaxPacketSize, we probably have 48641480Smckusick * a IEEE802 packet here. Make sure that the size is at least 48741480Smckusick * that of the HP LLC. Also do sanity checks on length of LLC 48841480Smckusick * (old Ethernet Type field) and packet length. 48941480Smckusick * 49041480Smckusick * Provided the above checks succeed, change `len' to reflect 49141480Smckusick * the length of the LLC (i.e. et->ether_type) and change the 49241480Smckusick * type field to ETHERTYPE_IEEE so we can switch() on it later. 49341480Smckusick * Yes, this is a hack and will eventually be done "right". 49441480Smckusick */ 49541480Smckusick if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 49641480Smckusick len >= et->ether_type && len >= IEEE802LEN_MIN) { 49741480Smckusick len = et->ether_type; 49841480Smckusick et->ether_type = ETHERTYPE_IEEE; /* hack! */ 49941480Smckusick } 50041480Smckusick #endif 50141480Smckusick 50241480Smckusick #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) 50341480Smckusick if (et->ether_type >= ETHERTYPE_TRAIL && 50441480Smckusick et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 50541480Smckusick off = (et->ether_type - ETHERTYPE_TRAIL) * 512; 50641480Smckusick if (off >= ETHERMTU) 50741480Smckusick return; /* sanity */ 50841480Smckusick et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); 50941480Smckusick resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 51041480Smckusick if (off + resid > len) 51141480Smckusick return; /* sanity */ 51241480Smckusick len = off + resid; 51341480Smckusick } else 51441480Smckusick off = 0; 51541480Smckusick 51641480Smckusick if (len <= 0) { 51741480Smckusick if (ledebug) 51841480Smckusick log(LOG_WARNING, 51941480Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 52041480Smckusick unit, ether_sprintf(et->ether_shost), len); 52141480Smckusick le->sc_runt++; 52241480Smckusick le->sc_if.if_ierrors++; 52341480Smckusick return; 52441480Smckusick } 52541480Smckusick 52641480Smckusick /* 52741480Smckusick * Pull packet off interface. Off is nonzero if packet 52841480Smckusick * has trailing header; leget will then force this header 52941480Smckusick * information to be at the front, but we still have to drop 53041480Smckusick * the type and length which are at the front of any trailer data. 53141480Smckusick */ 53241480Smckusick m = leget(buf, len, off, &le->sc_if); 53341480Smckusick if (m == 0) 53441480Smckusick return; 53541480Smckusick #ifdef RMP 53641480Smckusick /* 53741480Smckusick * (XXX) 53841480Smckusick * This needs to be integrated with the ISO stuff in ether_input() 53941480Smckusick */ 54041480Smckusick if (et->ether_type == ETHERTYPE_IEEE) { 54141480Smckusick /* 54241480Smckusick * Snag the Logical Link Control header (IEEE 802.2). 54341480Smckusick */ 54441480Smckusick struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc); 54541480Smckusick 54641480Smckusick /* 54741480Smckusick * If the DSAP (and HP's extended DXSAP) indicate this 54841480Smckusick * is an RMP packet, hand it to the raw input routine. 54941480Smckusick */ 55041480Smckusick if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 55141480Smckusick static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 55241480Smckusick static struct sockaddr rmp_src = {AF_RMP}; 55341480Smckusick static struct sockaddr rmp_dst = {AF_RMP}; 55441480Smckusick 55541480Smckusick bcopy(et->ether_shost, rmp_src.sa_data, 55641480Smckusick sizeof(et->ether_shost)); 55741480Smckusick bcopy(et->ether_dhost, rmp_dst.sa_data, 55841480Smckusick sizeof(et->ether_dhost)); 55941480Smckusick 56041480Smckusick raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 56141480Smckusick return; 56241480Smckusick } 56341480Smckusick } 56441480Smckusick #endif 56541480Smckusick ether_input(&le->sc_if, et, m); 56641480Smckusick } 56741480Smckusick 56841480Smckusick /* 56941480Smckusick * Routine to copy from mbuf chain to transmit 57041480Smckusick * buffer in board local memory. 57141480Smckusick */ 57241480Smckusick leput(lebuf, m) 57341480Smckusick register char *lebuf; 57441480Smckusick register struct mbuf *m; 57541480Smckusick { 57641480Smckusick register struct mbuf *mp; 57741480Smckusick register int len, tlen = 0; 57841480Smckusick 57941480Smckusick for (mp = m; mp; mp = mp->m_next) { 58041480Smckusick len = mp->m_len; 58141480Smckusick if (len == 0) 58241480Smckusick continue; 58341480Smckusick tlen += len; 58441480Smckusick bcopy(mtod(mp, char *), lebuf, len); 58541480Smckusick lebuf += len; 58641480Smckusick } 58741480Smckusick m_freem(m); 58841480Smckusick if (tlen < LEMINSIZE) { 58941480Smckusick bzero(lebuf, LEMINSIZE - tlen); 59041480Smckusick tlen = LEMINSIZE; 59141480Smckusick } 59241480Smckusick return(tlen); 59341480Smckusick } 59441480Smckusick 59541480Smckusick /* 59641480Smckusick * Routine to copy from board local memory into mbufs. 59741480Smckusick */ 59841480Smckusick struct mbuf * 59941480Smckusick leget(lebuf, totlen, off0, ifp) 60041480Smckusick char *lebuf; 60141480Smckusick int totlen, off0; 60241480Smckusick struct ifnet *ifp; 60341480Smckusick { 60441480Smckusick register struct mbuf *m; 60541480Smckusick struct mbuf *top = 0, **mp = ⊤ 60641480Smckusick register int off = off0, len; 60741480Smckusick register char *cp; 60841480Smckusick char *epkt; 60941480Smckusick 61041480Smckusick lebuf += sizeof (struct ether_header); 61141480Smckusick cp = lebuf; 61241480Smckusick epkt = cp + totlen; 61341480Smckusick if (off) { 61441480Smckusick cp += off + 2 * sizeof(u_short); 61541480Smckusick totlen -= 2 * sizeof(u_short); 61641480Smckusick } 61741480Smckusick 61841480Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 61941480Smckusick if (m == 0) 62041480Smckusick return (0); 62141480Smckusick m->m_pkthdr.rcvif = ifp; 62241480Smckusick m->m_pkthdr.len = totlen; 62341480Smckusick m->m_len = MHLEN; 62441480Smckusick 62541480Smckusick while (totlen > 0) { 62641480Smckusick if (top) { 62741480Smckusick MGET(m, M_DONTWAIT, MT_DATA); 62841480Smckusick if (m == 0) { 62941480Smckusick m_freem(top); 63041480Smckusick return (0); 63141480Smckusick } 63241480Smckusick m->m_len = MLEN; 63341480Smckusick } 63441480Smckusick len = min(totlen, epkt - cp); 63541480Smckusick if (len >= MINCLSIZE) { 63641480Smckusick MCLGET(m, M_DONTWAIT); 63741480Smckusick if (m->m_flags & M_EXT) 63841480Smckusick m->m_len = len = min(len, MCLBYTES); 63941480Smckusick else 64041480Smckusick len = m->m_len; 64141480Smckusick } else { 64241480Smckusick /* 64341480Smckusick * Place initial small packet/header at end of mbuf. 64441480Smckusick */ 64541480Smckusick if (len < m->m_len) { 64641480Smckusick if (top == 0 && len + max_linkhdr <= m->m_len) 64741480Smckusick m->m_data += max_linkhdr; 64841480Smckusick m->m_len = len; 64941480Smckusick } else 65041480Smckusick len = m->m_len; 65141480Smckusick } 65241480Smckusick bcopy(cp, mtod(m, caddr_t), (unsigned)len); 65341480Smckusick cp += len; 65441480Smckusick *mp = m; 65541480Smckusick mp = &m->m_next; 65641480Smckusick totlen -= len; 65741480Smckusick if (cp == epkt) 65841480Smckusick cp = lebuf; 65941480Smckusick } 66041480Smckusick return (top); 66141480Smckusick } 66241480Smckusick 66341480Smckusick /* 66441480Smckusick * Process an ioctl request. 66541480Smckusick */ 66641480Smckusick leioctl(ifp, cmd, data) 66741480Smckusick register struct ifnet *ifp; 66841480Smckusick int cmd; 66941480Smckusick caddr_t data; 67041480Smckusick { 67141480Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 67241480Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 67341480Smckusick struct lereg1 *ler1 = le->sc_r1; 67441480Smckusick int s = splimp(), error = 0; 67541480Smckusick 67641480Smckusick switch (cmd) { 67741480Smckusick 67841480Smckusick case SIOCSIFADDR: 67941480Smckusick ifp->if_flags |= IFF_UP; 68041480Smckusick switch (ifa->ifa_addr->sa_family) { 68141480Smckusick #ifdef INET 68241480Smckusick case AF_INET: 68341480Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 68441480Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 68541480Smckusick IA_SIN(ifa)->sin_addr; 68641480Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 68741480Smckusick break; 68841480Smckusick #endif 68941480Smckusick #ifdef NS 69041480Smckusick case AF_NS: 69141480Smckusick { 69241480Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 69341480Smckusick 69441480Smckusick if (ns_nullhost(*ina)) 69541480Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 69641480Smckusick else { 69741480Smckusick /* 69841480Smckusick * The manual says we can't change the address 69941480Smckusick * while the receiver is armed, 70041480Smckusick * so reset everything 70141480Smckusick */ 70241480Smckusick ifp->if_flags &= ~IFF_RUNNING; 70341480Smckusick bcopy((caddr_t)ina->x_host.c_host, 70441480Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 70541480Smckusick } 70641480Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 70741480Smckusick break; 70841480Smckusick } 70941480Smckusick #endif 71041480Smckusick default: 71141480Smckusick leinit(ifp->if_unit); 71241480Smckusick break; 71341480Smckusick } 71441480Smckusick break; 71541480Smckusick 71641480Smckusick case SIOCSIFFLAGS: 71741480Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 71841480Smckusick ifp->if_flags & IFF_RUNNING) { 71941480Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 72041480Smckusick ifp->if_flags &= ~IFF_RUNNING; 72141480Smckusick } else if (ifp->if_flags & IFF_UP && 72241480Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 72341480Smckusick leinit(ifp->if_unit); 72441480Smckusick break; 72541480Smckusick 72641480Smckusick default: 72741480Smckusick error = EINVAL; 72841480Smckusick } 72941480Smckusick splx(s); 73041480Smckusick return (error); 73141480Smckusick } 73241480Smckusick 73341480Smckusick leerror(unit, stat) 73441480Smckusick int unit; 73541480Smckusick int stat; 73641480Smckusick { 73741480Smckusick if (!ledebug) 73841480Smckusick return; 73941480Smckusick 74041480Smckusick /* 74141480Smckusick * Not all transceivers implement heartbeat 74241480Smckusick * so we only log CERR once. 74341480Smckusick */ 74441480Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 74541480Smckusick return; 74641480Smckusick log(LOG_WARNING, 74741480Smckusick "le%d: error: stat=%b\n", unit, 74841480Smckusick stat, 74941480Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 75041480Smckusick } 75141480Smckusick 75241480Smckusick lererror(unit, msg) 75341480Smckusick int unit; 75441480Smckusick char *msg; 75541480Smckusick { 75641480Smckusick register struct le_softc *le = &le_softc[unit]; 75741480Smckusick register struct lermd *rmd; 75841480Smckusick int len; 75941480Smckusick 76041480Smckusick if (!ledebug) 76141480Smckusick return; 76241480Smckusick 76341480Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 76441480Smckusick len = rmd->rmd3; 76541480Smckusick log(LOG_WARNING, 76641480Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 76741480Smckusick unit, msg, 76841480Smckusick len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown", 76941480Smckusick le->sc_rmd, len, 77041480Smckusick rmd->rmd1, 77141480Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 77241480Smckusick } 77341480Smckusick 77441480Smckusick lexerror(unit) 77541480Smckusick int unit; 77641480Smckusick { 77741480Smckusick register struct le_softc *le = &le_softc[unit]; 77841480Smckusick register struct letmd *tmd; 77941480Smckusick int len; 78041480Smckusick 78141480Smckusick if (!ledebug) 78241480Smckusick return; 78341480Smckusick 78441480Smckusick tmd = le->sc_r2->ler2_tmd; 78541480Smckusick len = -tmd->tmd2; 78641480Smckusick log(LOG_WARNING, 78741480Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 78841480Smckusick unit, 78941480Smckusick len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown", 79041480Smckusick 0, len, 79141480Smckusick tmd->tmd1, 79241480Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 79341480Smckusick tmd->tmd3, 79441480Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 79541480Smckusick } 79641480Smckusick #endif 797