152130Smckusick /* 252130Smckusick * Copyright (c) 1992 Regents of the University of California. 352130Smckusick * All rights reserved. 452130Smckusick * 552130Smckusick * This code is derived from software contributed to Berkeley by 652130Smckusick * Ralph Campbell. 752130Smckusick * 852130Smckusick * %sccs.include.redist.c% 952130Smckusick * 10*54144Sralph * @(#)if_le.c 7.4 (Berkeley) 06/20/92 1152130Smckusick */ 1252130Smckusick 1352130Smckusick #include "le.h" 1452130Smckusick #if NLE > 0 1552130Smckusick 1652130Smckusick #include "bpfilter.h" 1752130Smckusick 1852130Smckusick /* 1952130Smckusick * AMD 7990 LANCE 2052130Smckusick * 2152130Smckusick * This driver will generate and accept trailer encapsulated packets even 2252130Smckusick * though it buys us nothing. The motivation was to avoid incompatibilities 2352130Smckusick * with VAXen, SUNs, and others that handle and benefit from them. 2452130Smckusick * This reasoning is dubious. 2552130Smckusick */ 2652130Smckusick #include "param.h" 2752130Smckusick #include "systm.h" 2852130Smckusick #include "mbuf.h" 2952130Smckusick #include "buf.h" 3052130Smckusick #include "protosw.h" 3152130Smckusick #include "socket.h" 3252130Smckusick #include "syslog.h" 3352130Smckusick #include "ioctl.h" 3452130Smckusick #include "errno.h" 3552130Smckusick 3652130Smckusick #include "net/if.h" 3752130Smckusick #include "net/netisr.h" 3852130Smckusick #include "net/route.h" 3952130Smckusick 4052130Smckusick #ifdef INET 4152130Smckusick #include "netinet/in.h" 4252130Smckusick #include "netinet/in_systm.h" 4352130Smckusick #include "netinet/in_var.h" 4452130Smckusick #include "netinet/ip.h" 4552130Smckusick #include "netinet/if_ether.h" 4652130Smckusick #endif 4752130Smckusick 4852130Smckusick #ifdef NS 4952130Smckusick #include "netns/ns.h" 5052130Smckusick #include "netns/ns_if.h" 5152130Smckusick #endif 5252130Smckusick 5352130Smckusick #ifdef RMP 5452130Smckusick #include "netrmp/rmp.h" 5552130Smckusick #include "netrmp/rmp_var.h" 5652130Smckusick #endif 5752130Smckusick 5852130Smckusick #include "machine/machConst.h" 5952130Smckusick #include "device.h" 6052130Smckusick #include "if_lereg.h" 6152130Smckusick 6252130Smckusick #if NBPFILTER > 0 6352130Smckusick #include "../net/bpf.h" 6452130Smckusick #include "../net/bpfdesc.h" 6552130Smckusick #endif 6652130Smckusick 6752130Smckusick int leprobe(); 6852695Sralph void leintr(); 6952130Smckusick struct driver ledriver = { 7052695Sralph "le", leprobe, 0, 0, leintr, 7152130Smckusick }; 7252130Smckusick 7352130Smckusick int ledebug = 1; /* console error messages */ 7452130Smckusick 7552130Smckusick /* 7652130Smckusick * Ethernet software status per interface. 7752130Smckusick * 7852130Smckusick * Each interface is referenced by a network interface structure, 7952130Smckusick * le_if, which the routing code uses to locate the interface. 8052130Smckusick * This structure contains the output queue for the interface, its address, ... 8152130Smckusick */ 8252130Smckusick struct le_softc { 8352130Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 8452130Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 8552130Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 8652130Smckusick volatile struct lereg1 *sc_r1; /* LANCE registers */ 8752130Smckusick volatile struct lereg2 *sc_r2; /* dual-port RAM */ 8852130Smckusick int sc_rmd; /* predicted next rmd to process */ 8952130Smckusick int sc_tmd; /* last tmd processed */ 9052130Smckusick int sc_tmdnext; /* next tmd to transmit with */ 9152130Smckusick int sc_runt; 9252130Smckusick int sc_jab; 9352130Smckusick int sc_merr; 9452130Smckusick int sc_babl; 9552130Smckusick int sc_cerr; 9652130Smckusick int sc_miss; 9752130Smckusick int sc_xint; 9852130Smckusick int sc_xown; 9952130Smckusick int sc_uflo; 10052130Smckusick int sc_rxlen; 10152130Smckusick int sc_rxoff; 10252130Smckusick int sc_txoff; 10352130Smckusick int sc_busy; 10452130Smckusick short sc_iflags; 10552130Smckusick #if NBPFILTER > 0 10652130Smckusick caddr_t sc_bpf; 10752130Smckusick #endif 10852130Smckusick } le_softc[NLE]; 10952130Smckusick 11052695Sralph #ifdef DS3100 11152130Smckusick /* access LANCE registers */ 11252130Smckusick #define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); } 11352130Smckusick 11452130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \ 11552130Smckusick (((unsigned)(&(((struct lereg2 *)0)->cpu))) >> 1) 11652695Sralph #endif 11752130Smckusick 11852695Sralph #ifdef DS5000 11952695Sralph /* access LANCE registers */ 12052695Sralph #define LERDWR(cntl, src, dst) (dst) = (src); 12152695Sralph 12252695Sralph #define CPU_TO_CHIP_ADDR(cpu) \ 12352695Sralph ((unsigned)(&(((struct lereg2 *)0)->cpu))) 12452695Sralph 12552695Sralph #define LE_OFFSET_RAM 0x0 12652695Sralph #define LE_OFFSET_LANCE 0x100000 12752695Sralph #define LE_OFFSET_ROM 0x1c0000 12852695Sralph #endif 12952695Sralph 13052130Smckusick /* 13152130Smckusick * Test to see if device is present. 13252130Smckusick * Return true if found and initialized ok. 13352130Smckusick * If interface exists, make available by filling in network interface 13452130Smckusick * record. System will initialize the interface when it is ready 13552130Smckusick * to accept packets. 13652130Smckusick */ 13752130Smckusick leprobe(dp) 13852130Smckusick struct pmax_ctlr *dp; 13952130Smckusick { 14052130Smckusick volatile struct lereg1 *ler1; 14152130Smckusick struct le_softc *le = &le_softc[dp->pmax_unit]; 14252130Smckusick struct ifnet *ifp = &le->sc_if; 14352130Smckusick u_char *cp; 14452130Smckusick int i; 14552695Sralph extern int leinit(), leioctl(), lestart(), ether_output(); 14652130Smckusick 14752695Sralph #ifdef DS3100 14852130Smckusick le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; 14952130Smckusick le->sc_r2 = (volatile struct lereg2 *)MACH_NETWORK_BUFFER_ADDR; 15052130Smckusick 15152130Smckusick /* 15252130Smckusick * Read the ethernet address. 15352130Smckusick * See "DECstation 3100 Desktop Workstation Functional Specification". 15452130Smckusick */ 15552130Smckusick cp = (u_char *)(MACH_CLOCK_ADDR + 1); 15652130Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 15752130Smckusick le->sc_addr[i] = *cp; 15852130Smckusick cp += 4; 15952130Smckusick } 16052695Sralph #endif 16152695Sralph #ifdef DS5000 16252695Sralph le->sc_r1 = ler1 = (volatile struct lereg1 *) 16352695Sralph (dp->pmax_addr + LE_OFFSET_LANCE); 16452695Sralph le->sc_r2 = (volatile struct lereg2 *)(dp->pmax_addr + LE_OFFSET_RAM); 16552130Smckusick 16652695Sralph /* 16752695Sralph * Read the ethernet address. 16852695Sralph */ 16952695Sralph cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2); 17052695Sralph for (i = 0; i < sizeof(le->sc_addr); i++) { 17152695Sralph le->sc_addr[i] = *cp; 17252695Sralph cp += 4; 17352695Sralph } 17452695Sralph #endif 17552695Sralph 17652130Smckusick /* make sure the chip is stopped */ 17752130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 17852130Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 17952130Smckusick 18052130Smckusick ifp->if_unit = dp->pmax_unit; 18152130Smckusick ifp->if_name = "le"; 18252130Smckusick ifp->if_mtu = ETHERMTU; 18352130Smckusick ifp->if_init = leinit; 18452130Smckusick ifp->if_ioctl = leioctl; 18552130Smckusick ifp->if_output = ether_output; 18652130Smckusick ifp->if_start = lestart; 18752130Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 18852130Smckusick #if NBPFILTER > 0 18952130Smckusick bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 19052130Smckusick #endif 19152130Smckusick if_attach(ifp); 19252130Smckusick 19352695Sralph printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n", 19452695Sralph dp->pmax_unit, dp->pmax_addr, dp->pmax_pri, 19552695Sralph ether_sprintf(le->sc_addr)); 19652130Smckusick return (1); 19752130Smckusick } 19852130Smckusick 19952130Smckusick ledrinit(ler2) 20052130Smckusick register volatile struct lereg2 *ler2; 20152130Smckusick { 20252130Smckusick register int i; 20352130Smckusick 20452130Smckusick for (i = 0; i < LERBUF; i++) { 20552130Smckusick ler2->ler2_rmd[i].rmd0 = CPU_TO_CHIP_ADDR(ler2_rbuf[i][0]); 20652130Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 20752130Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 20852130Smckusick ler2->ler2_rmd[i].rmd3 = 0; 20952130Smckusick } 21052130Smckusick for (i = 0; i < LETBUF; i++) { 21152130Smckusick ler2->ler2_tmd[i].tmd0 = CPU_TO_CHIP_ADDR(ler2_tbuf[i][0]); 21252130Smckusick ler2->ler2_tmd[i].tmd1 = 0; 21352130Smckusick ler2->ler2_tmd[i].tmd2 = 0; 21452130Smckusick ler2->ler2_tmd[i].tmd3 = 0; 21552130Smckusick } 21652130Smckusick } 21752130Smckusick 21852130Smckusick lereset(unit) 21952130Smckusick register int unit; 22052130Smckusick { 22152130Smckusick register struct le_softc *le = &le_softc[unit]; 22252130Smckusick register volatile struct lereg1 *ler1 = le->sc_r1; 22352130Smckusick register volatile struct lereg2 *ler2 = le->sc_r2; 22452130Smckusick register int timo = 100000; 22552130Smckusick register int stat; 22652130Smckusick 22752130Smckusick #ifdef lint 22852130Smckusick stat = unit; 22952130Smckusick #endif 23052130Smckusick #if NBPFILTER > 0 23152130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 23252130Smckusick /* set the promiscuous bit */ 23352130Smckusick le->sc_r2->ler2_mode = LE_MODE|0x8000; 23452130Smckusick else 23552130Smckusick le->sc_r2->ler2_mode = LE_MODE; 23652130Smckusick #endif 23752130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 23852130Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 23952130Smckusick 24052130Smckusick /* 24152130Smckusick * Setup for transmit/receive 24252130Smckusick */ 24352130Smckusick ler2->ler2_mode = LE_MODE; 24452130Smckusick ler2->ler2_padr0 = (le->sc_addr[1] << 8) | le->sc_addr[0]; 24552130Smckusick ler2->ler2_padr1 = (le->sc_addr[3] << 8) | le->sc_addr[2]; 24652130Smckusick ler2->ler2_padr2 = (le->sc_addr[5] << 8) | le->sc_addr[4]; 24752130Smckusick #ifdef RMP 24852130Smckusick /* 24952130Smckusick * Set up logical addr filter to accept multicast 9:0:9:0:0:4 25052130Smckusick * This should be an ioctl() to the driver. (XXX) 25152130Smckusick */ 25252130Smckusick ler2->ler2_ladrf0 = 0x0010; 25352130Smckusick ler2->ler2_ladrf1 = 0x0; 25452130Smckusick ler2->ler2_ladrf2 = 0x0; 25552130Smckusick ler2->ler2_ladrf3 = 0x0; 25652130Smckusick #else 25752130Smckusick ler2->ler2_ladrf0 = 0; 25852130Smckusick ler2->ler2_ladrf1 = 0; 25952130Smckusick ler2->ler2_ladrf2 = 0; 26052130Smckusick ler2->ler2_ladrf3 = 0; 26152130Smckusick #endif 26252130Smckusick ler2->ler2_rlen = LE_RLEN; 26352130Smckusick ler2->ler2_rdra = CPU_TO_CHIP_ADDR(ler2_rmd[0]); 26452130Smckusick ler2->ler2_tlen = LE_TLEN; 26552130Smckusick ler2->ler2_tdra = CPU_TO_CHIP_ADDR(ler2_tmd[0]); 26652130Smckusick ledrinit(ler2); 26752130Smckusick le->sc_rmd = 0; 26852130Smckusick le->sc_tmd = LETBUF - 1; 26952130Smckusick le->sc_tmdnext = 0; 27052130Smckusick 27152130Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 27252130Smckusick LERDWR(ler0, CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 27352130Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 27452130Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 27552130Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 27652130Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 27752130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 27852130Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 27952130Smckusick MachEmptyWriteBuffer(); 28052130Smckusick do { 28152130Smckusick if (--timo == 0) { 28252130Smckusick printf("le%d: init timeout, stat = 0x%x\n", 28352130Smckusick unit, stat); 28452130Smckusick break; 28552130Smckusick } 28652130Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 28752130Smckusick } while ((stat & LE_IDON) == 0); 28852130Smckusick LERDWR(ler0, LE_IDON, ler1->ler1_rdp); 28952130Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 29052130Smckusick MachEmptyWriteBuffer(); 29152130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 29252130Smckusick } 29352130Smckusick 29452130Smckusick /* 29552130Smckusick * Initialization of interface 29652130Smckusick */ 29752130Smckusick leinit(unit) 29852130Smckusick int unit; 29952130Smckusick { 30052130Smckusick struct le_softc *le = &le_softc[unit]; 30152130Smckusick register struct ifnet *ifp = &le->sc_if; 30252130Smckusick int s; 30352130Smckusick 30452130Smckusick /* not yet, if address still unknown */ 30552130Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 30652130Smckusick return; 30752130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 30852130Smckusick s = splnet(); 30952130Smckusick ifp->if_flags |= IFF_RUNNING; 31052130Smckusick lereset(unit); 31152130Smckusick (void) lestart(ifp); 31252130Smckusick splx(s); 31352130Smckusick } 31452130Smckusick } 31552130Smckusick 31652130Smckusick #define LENEXTTMP \ 31752130Smckusick if (++bix == LETBUF) bix = 0, tmd = le->sc_r2->ler2_tmd; else ++tmd 31852130Smckusick 31952130Smckusick /* 32052130Smckusick * Start output on interface. Get another datagram to send 32152130Smckusick * off of the interface queue, and copy it to the interface 32252130Smckusick * before starting the output. 32352130Smckusick */ 32452130Smckusick lestart(ifp) 32552130Smckusick struct ifnet *ifp; 32652130Smckusick { 32752130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 32852130Smckusick register int bix = le->sc_tmdnext; 32952130Smckusick register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix]; 33052130Smckusick register struct mbuf *m; 33152130Smckusick int len = 0; 33252130Smckusick 33352130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 33452130Smckusick return (0); 33552130Smckusick while (bix != le->sc_tmd) { 33652130Smckusick if (tmd->tmd1 & LE_OWN) 33752130Smckusick panic("lestart"); 33852130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 33952130Smckusick if (m == 0) 34052130Smckusick break; 34152130Smckusick len = leput(le->sc_r2->ler2_tbuf[bix], m); 34252130Smckusick #if NBPFILTER > 0 34352130Smckusick /* 34452130Smckusick * If bpf is listening on this interface, let it 34552130Smckusick * see the packet before we commit it to the wire. 34652130Smckusick */ 34752130Smckusick if (le->sc_bpf) 34852130Smckusick bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[bix], len); 34952130Smckusick #endif 35052130Smckusick tmd->tmd3 = 0; 35152130Smckusick tmd->tmd2 = -len; 35252130Smckusick tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 35352130Smckusick LENEXTTMP; 35452130Smckusick } 35552130Smckusick if (len != 0) { 35652130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 35752130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 35852130Smckusick MachEmptyWriteBuffer(); 35952130Smckusick } 36052130Smckusick le->sc_tmdnext = bix; 36152130Smckusick return (0); 36252130Smckusick } 36352130Smckusick 36452130Smckusick /* 36552130Smckusick * Process interrupts from the 7990 chip. 36652130Smckusick */ 36752695Sralph void 36852695Sralph leintr(unit) 36952695Sralph int unit; 37052130Smckusick { 37152130Smckusick register struct le_softc *le; 37252130Smckusick register volatile struct lereg1 *ler1; 37352695Sralph register int stat; 37452130Smckusick 37552130Smckusick le = &le_softc[unit]; 37652130Smckusick ler1 = le->sc_r1; 37752130Smckusick stat = ler1->ler1_rdp; 37852130Smckusick if (!(stat & LE_INTR)) { 37953081Sralph printf("le%d: spurrious interrupt\n", unit); 38052130Smckusick return; 38152130Smckusick } 38252130Smckusick if (stat & LE_SERR) { 38352130Smckusick leerror(unit, stat); 38452130Smckusick if (stat & LE_MERR) { 38552130Smckusick le->sc_merr++; 38652130Smckusick lereset(unit); 38752130Smckusick return; 38852130Smckusick } 38952130Smckusick if (stat & LE_BABL) 39052130Smckusick le->sc_babl++; 39152130Smckusick if (stat & LE_CERR) 39252130Smckusick le->sc_cerr++; 39352130Smckusick if (stat & LE_MISS) 39452130Smckusick le->sc_miss++; 39552130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 39652130Smckusick MachEmptyWriteBuffer(); 39752130Smckusick } 39852130Smckusick if ((stat & LE_RXON) == 0) { 39952130Smckusick le->sc_rxoff++; 40052130Smckusick lereset(unit); 40152130Smckusick return; 40252130Smckusick } 40352130Smckusick if ((stat & LE_TXON) == 0) { 40452130Smckusick le->sc_txoff++; 40552130Smckusick lereset(unit); 40652130Smckusick return; 40752130Smckusick } 40852130Smckusick if (stat & LE_RINT) { 40952130Smckusick /* interrupt is cleared in lerint */ 41052130Smckusick lerint(unit); 41152130Smckusick } 41252130Smckusick if (stat & LE_TINT) { 41352130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 41452130Smckusick MachEmptyWriteBuffer(); 41552130Smckusick lexint(unit); 41652130Smckusick } 41752130Smckusick } 41852130Smckusick 41952130Smckusick /* 42052130Smckusick * Ethernet interface transmitter interrupt. 42152130Smckusick * Start another output if more data to send. 42252130Smckusick */ 42352130Smckusick lexint(unit) 42452130Smckusick register int unit; 42552130Smckusick { 42652130Smckusick register struct le_softc *le = &le_softc[unit]; 42752130Smckusick register int bix = le->sc_tmd; 42852130Smckusick register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix]; 42952130Smckusick 43052130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 43152130Smckusick le->sc_xint++; 43252130Smckusick return; 43352130Smckusick } 43452130Smckusick LENEXTTMP; 43552130Smckusick while (bix != le->sc_tmdnext && (tmd->tmd1 & LE_OWN) == 0) { 43652130Smckusick le->sc_tmd = bix; 43752130Smckusick if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { 43852130Smckusick lexerror(unit); 43952130Smckusick le->sc_if.if_oerrors++; 44052130Smckusick if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 44152130Smckusick le->sc_uflo++; 44252130Smckusick lereset(unit); 44352130Smckusick break; 44452130Smckusick } 44552130Smckusick else if (tmd->tmd3 & LE_LCOL) 44652130Smckusick le->sc_if.if_collisions++; 44752130Smckusick else if (tmd->tmd3 & LE_RTRY) 44852130Smckusick le->sc_if.if_collisions += 16; 44952130Smckusick } 45052130Smckusick else if (tmd->tmd1 & LE_ONE) 45152130Smckusick le->sc_if.if_collisions++; 45252130Smckusick else if (tmd->tmd1 & LE_MORE) 45352130Smckusick /* what is the real number? */ 45452130Smckusick le->sc_if.if_collisions += 2; 45552130Smckusick else 45652130Smckusick le->sc_if.if_opackets++; 45752130Smckusick LENEXTTMP; 45852130Smckusick } 45952130Smckusick if (bix == le->sc_tmdnext) 46052130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 46152130Smckusick (void) lestart(&le->sc_if); 46252130Smckusick } 46352130Smckusick 46452130Smckusick #define LENEXTRMP \ 46552130Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 46652130Smckusick 46752130Smckusick /* 46852130Smckusick * Ethernet interface receiver interrupt. 46952130Smckusick * If input error just drop packet. 47052130Smckusick * Decapsulate packet based on type and pass to type specific 47152130Smckusick * higher-level input routine. 47252130Smckusick */ 47352130Smckusick lerint(unit) 47452130Smckusick int unit; 47552130Smckusick { 47652130Smckusick register struct le_softc *le = &le_softc[unit]; 47752130Smckusick register int bix = le->sc_rmd; 47852130Smckusick register volatile struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 47952130Smckusick 48052130Smckusick /* 48152130Smckusick * Out of sync with hardware, should never happen? 48252130Smckusick */ 48352130Smckusick if (rmd->rmd1 & LE_OWN) { 48452130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 48552130Smckusick MachEmptyWriteBuffer(); 48652130Smckusick return; 48752130Smckusick } 48852130Smckusick 48952130Smckusick /* 49052130Smckusick * Process all buffers with valid data 49152130Smckusick */ 49252130Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 49352130Smckusick int len = rmd->rmd3; 49452130Smckusick 49552130Smckusick /* Clear interrupt to avoid race condition */ 49652130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 49752130Smckusick MachEmptyWriteBuffer(); 49852130Smckusick 49952130Smckusick if (rmd->rmd1 & LE_ERR) { 50052130Smckusick le->sc_rmd = bix; 50152130Smckusick lererror(unit, "bad packet"); 50252130Smckusick le->sc_if.if_ierrors++; 50352130Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 50452130Smckusick /* 50552130Smckusick * Find the end of the packet so we can see how long 50652130Smckusick * it was. We still throw it away. 50752130Smckusick */ 50852130Smckusick do { 50952130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 51052130Smckusick le->sc_r1->ler1_rdp); 51152130Smckusick MachEmptyWriteBuffer(); 51252130Smckusick rmd->rmd3 = 0; 51352130Smckusick rmd->rmd1 = LE_OWN; 51452130Smckusick LENEXTRMP; 51552130Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 51652130Smckusick le->sc_rmd = bix; 51752130Smckusick lererror(unit, "chained buffer"); 51852130Smckusick le->sc_rxlen++; 51952130Smckusick /* 52052130Smckusick * If search terminated without successful completion 52152130Smckusick * we reset the hardware (conservative). 52252130Smckusick */ 52352130Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 52452130Smckusick LE_ENP) { 52552130Smckusick lereset(unit); 52652130Smckusick return; 52752130Smckusick } 52852130Smckusick } else 52952130Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 53052130Smckusick rmd->rmd3 = 0; 53152130Smckusick rmd->rmd1 = LE_OWN; 53252130Smckusick LENEXTRMP; 53352130Smckusick } 53452130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 53552130Smckusick le->sc_rmd = bix; 53652130Smckusick } 53752130Smckusick 53852130Smckusick /* 53952130Smckusick * Look at the packet in network buffer memory so we can be smart about how 54052130Smckusick * we copy the data into mbufs. 54152130Smckusick * This needs work since we can't just read network buffer memory like 54252130Smckusick * regular memory. 54352130Smckusick */ 54452130Smckusick leread(unit, buf, len) 54552130Smckusick int unit; 54652695Sralph le_buf_t *buf; 54752130Smckusick int len; 54852130Smckusick { 54952130Smckusick register struct le_softc *le = &le_softc[unit]; 55052130Smckusick struct ether_header et; 55152130Smckusick struct mbuf *m; 55252130Smckusick int off, resid; 55352695Sralph #ifdef DS3100 55452130Smckusick u_short sbuf[2]; 55552695Sralph #endif 55652695Sralph extern struct mbuf *leget(); 55752130Smckusick 55852130Smckusick le->sc_if.if_ipackets++; 55952695Sralph #ifdef DS3100 56052130Smckusick CopyFromBuffer(buf, (char *)&et, sizeof(et)); 56152695Sralph #endif 56252695Sralph #ifdef DS5000 56352695Sralph bcopy(buf, (char *)&et, sizeof(et)); 56452695Sralph #endif 56552130Smckusick et.ether_type = ntohs(et.ether_type); 56652130Smckusick /* adjust input length to account for header and CRC */ 56752130Smckusick len = len - sizeof(struct ether_header) - 4; 56852130Smckusick 56952130Smckusick #ifdef RMP 57052130Smckusick /* (XXX) 57152130Smckusick * 57252130Smckusick * If Ethernet Type field is < MaxPacketSize, we probably have 57352130Smckusick * a IEEE802 packet here. Make sure that the size is at least 57452130Smckusick * that of the HP LLC. Also do sanity checks on length of LLC 57552130Smckusick * (old Ethernet Type field) and packet length. 57652130Smckusick * 57752130Smckusick * Provided the above checks succeed, change `len' to reflect 57852130Smckusick * the length of the LLC (i.e. et.ether_type) and change the 57952130Smckusick * type field to ETHERTYPE_IEEE so we can switch() on it later. 58052130Smckusick * Yes, this is a hack and will eventually be done "right". 58152130Smckusick */ 58252130Smckusick if (et.ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 58352130Smckusick len >= et.ether_type && len >= IEEE802LEN_MIN) { 58452130Smckusick len = et.ether_type; 58552130Smckusick et.ether_type = ETHERTYPE_IEEE; /* hack! */ 58652130Smckusick } 58752130Smckusick #endif 58852130Smckusick 58952130Smckusick if (et.ether_type >= ETHERTYPE_TRAIL && 59052130Smckusick et.ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 59152130Smckusick off = (et.ether_type - ETHERTYPE_TRAIL) * 512; 59252130Smckusick if (off >= ETHERMTU) 59352130Smckusick return; /* sanity */ 59452695Sralph #ifdef DS3100 59552130Smckusick CopyFromBuffer(buf + (sizeof(et) + off), 59652130Smckusick (char *)sbuf, sizeof(sbuf)); 59752130Smckusick et.ether_type = ntohs(sbuf[0]); 59852130Smckusick resid = ntohs(sbuf[1]); 59952695Sralph #endif 60052695Sralph #ifdef DS5000 601*54144Sralph et.ether_type = ntohs(((u_short *)(buf + (sizeof(et) + off)))[0]); 602*54144Sralph resid = ntohs(((u_short *)(buf + (sizeof(et) + off)))[1]); 60352695Sralph #endif 60452130Smckusick if (off + resid > len) 60552130Smckusick return; /* sanity */ 60652130Smckusick len = off + resid; 60752130Smckusick } else 60852130Smckusick off = 0; 60952130Smckusick 61052130Smckusick if (len <= 0) { 61152130Smckusick if (ledebug) 61252130Smckusick log(LOG_WARNING, 61352130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 61452130Smckusick unit, ether_sprintf(et.ether_shost), len); 61552130Smckusick le->sc_runt++; 61652130Smckusick le->sc_if.if_ierrors++; 61752130Smckusick return; 61852130Smckusick } 61952130Smckusick #if NBPFILTER > 0 62052130Smckusick /* 62152130Smckusick * Check if there's a bpf filter listening on this interface. 62252130Smckusick * If so, hand off the raw packet to bpf, which must deal with 62352130Smckusick * trailers in its own way. 62452130Smckusick */ 62552130Smckusick if (le->sc_bpf) { 62652130Smckusick bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header)); 62752130Smckusick 62852130Smckusick /* 62952130Smckusick * Note that the interface cannot be in promiscuous mode if 63052130Smckusick * there are no bpf listeners. And if we are in promiscuous 63152130Smckusick * mode, we have to check if this packet is really ours. 63252130Smckusick * 63352130Smckusick * XXX This test does not support multicasts. 63452130Smckusick */ 63552130Smckusick if ((le->sc_if.if_flags & IFF_PROMISC) 63652130Smckusick && bcmp(et.ether_dhost, le->sc_addr, 63752130Smckusick sizeof(et.ether_dhost)) != 0 63852130Smckusick && bcmp(et.ether_dhost, etherbroadcastaddr, 63952130Smckusick sizeof(et.ether_dhost)) != 0) 64052130Smckusick return; 64152130Smckusick } 64252130Smckusick #endif 64352130Smckusick /* 64452130Smckusick * Pull packet off interface. Off is nonzero if packet 64552130Smckusick * has trailing header; leget will then force this header 64652130Smckusick * information to be at the front, but we still have to drop 64752130Smckusick * the type and length which are at the front of any trailer data. 64852130Smckusick */ 64952130Smckusick m = leget(buf, len, off, &le->sc_if); 65052130Smckusick if (m == 0) 65152130Smckusick return; 65252130Smckusick #ifdef RMP 65352130Smckusick /* 65452130Smckusick * (XXX) 65552130Smckusick * This needs to be integrated with the ISO stuff in ether_input() 65652130Smckusick */ 65752130Smckusick if (et.ether_type == ETHERTYPE_IEEE) { 65852130Smckusick /* 65952130Smckusick * Snag the Logical Link Control header (IEEE 802.2). 66052130Smckusick */ 66152130Smckusick struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc); 66252130Smckusick 66352130Smckusick /* 66452130Smckusick * If the DSAP (and HP's extended DXSAP) indicate this 66552130Smckusick * is an RMP packet, hand it to the raw input routine. 66652130Smckusick */ 66752130Smckusick if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 66852130Smckusick static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 66952130Smckusick static struct sockaddr rmp_src = {AF_RMP}; 67052130Smckusick static struct sockaddr rmp_dst = {AF_RMP}; 67152130Smckusick 67252130Smckusick bcopy(et.ether_shost, rmp_src.sa_data, 67352130Smckusick sizeof(et.ether_shost)); 67452130Smckusick bcopy(et.ether_dhost, rmp_dst.sa_data, 67552130Smckusick sizeof(et.ether_dhost)); 67652130Smckusick 67752130Smckusick raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 67852130Smckusick return; 67952130Smckusick } 68052130Smckusick } 68152130Smckusick #endif 68252130Smckusick ether_input(&le->sc_if, &et, m); 68352130Smckusick } 68452130Smckusick 68552130Smckusick /* 68652130Smckusick * Routine to copy from mbuf chain to transmit buffer in 68752130Smckusick * network buffer memory. 68852695Sralph * NOTE: On the DS3100, network memory can only be written one short at 68952695Sralph * every other address. 69052130Smckusick */ 69152130Smckusick leput(lebuf, m) 69252695Sralph register le_buf_t *lebuf; 69352130Smckusick register struct mbuf *m; 69452130Smckusick { 69552130Smckusick register struct mbuf *mp; 69652695Sralph register int len, tlen = 0; 69752695Sralph #ifdef DS3100 69852130Smckusick register char *cp; 69952695Sralph int tmp, xfer; 70052695Sralph #endif 70152130Smckusick 70252130Smckusick for (mp = m; mp; mp = mp->m_next) { 70352130Smckusick len = mp->m_len; 70452130Smckusick if (len == 0) 70552130Smckusick continue; 70652695Sralph #ifdef DS3100 70752130Smckusick /* copy data for this mbuf */ 70852130Smckusick cp = mtod(mp, char *); 70952130Smckusick if (tlen & 1) { 71052130Smckusick /* handle odd length from previous mbuf */ 71152130Smckusick *lebuf = (cp[0] << 8) | tmp; 71252130Smckusick lebuf += 2; 71352130Smckusick cp++; 71452130Smckusick len--; 71552130Smckusick tlen++; 71652130Smckusick } 71752130Smckusick tlen += len; 71852130Smckusick if ((unsigned)cp & 1) { 71952130Smckusick while (len > 1) { 72052130Smckusick *lebuf = (cp[1] << 8) | cp[0]; 72152130Smckusick lebuf += 2; 72252130Smckusick cp += 2; 72352130Smckusick len -= 2; 72452130Smckusick } 72552130Smckusick } else { 72652130Smckusick /* optimize for aligned transfers */ 72752130Smckusick xfer = (int)((unsigned)len & ~0x1); 72852130Smckusick CopyToBuffer((u_short *)cp, lebuf, xfer); 72952130Smckusick lebuf += xfer; 73052130Smckusick cp += xfer; 73152130Smckusick len -= xfer; 73252130Smckusick } 73352130Smckusick if (len == 1) 73452130Smckusick tmp = *cp; 73552695Sralph #endif 73652695Sralph #ifdef DS5000 73752695Sralph tlen += len; 73852695Sralph bcopy(mtod(mp, char *), lebuf, len); 73952695Sralph lebuf += len; 74052695Sralph #endif 74152130Smckusick } 74252130Smckusick m_freem(m); 74352695Sralph #ifdef DS3100 74452130Smckusick /* handle odd length from previous mbuf */ 74552130Smckusick if (tlen & 1) 74652130Smckusick *lebuf = tmp; 74752695Sralph #endif 74852695Sralph if (tlen < LEMINSIZE) { 74952695Sralph #ifdef DS3100 75052695Sralph tlen = (tlen + 1) & ~1; 75152695Sralph while (tlen < LEMINSIZE) { 75252695Sralph *lebuf++ = 0; 75352695Sralph tlen += 2; 75452695Sralph } 75552695Sralph #endif 75652695Sralph #ifdef DS5000 75752695Sralph bzero(lebuf, LEMINSIZE - tlen); 75852695Sralph #endif 75952130Smckusick tlen = LEMINSIZE; 76052695Sralph } 76152130Smckusick return(tlen); 76252130Smckusick } 76352130Smckusick 76452130Smckusick /* 76552130Smckusick * Routine to copy from network buffer memory into mbufs. 76652695Sralph * NOTE: On the DS3100, network memory can only be written one short at 76752695Sralph * every other address. 76852130Smckusick */ 76952130Smckusick struct mbuf * 77052130Smckusick leget(lebuf, totlen, off, ifp) 77152695Sralph le_buf_t *lebuf; 77252130Smckusick int totlen, off; 77352130Smckusick struct ifnet *ifp; 77452130Smckusick { 77552130Smckusick register struct mbuf *m; 77652130Smckusick struct mbuf *top = 0, **mp = ⊤ 77752130Smckusick register int len, resid; 77852695Sralph register le_buf_t *sp; 77952130Smckusick 78052130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 78152130Smckusick lebuf += sizeof(struct ether_header); 78252130Smckusick sp = lebuf; 78352130Smckusick if (off) { 78452130Smckusick /* NOTE: off should be even */ 78552130Smckusick sp += off + 2 * sizeof(u_short); 78652130Smckusick totlen -= 2 * sizeof(u_short); 78752130Smckusick resid = totlen - off; 78852130Smckusick } else 78952130Smckusick resid = totlen; 79052130Smckusick 79152130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 79252130Smckusick if (m == 0) 79352130Smckusick return (0); 79452130Smckusick m->m_pkthdr.rcvif = ifp; 79552130Smckusick m->m_pkthdr.len = totlen; 79652130Smckusick m->m_len = MHLEN; 79752130Smckusick 79852130Smckusick while (totlen > 0) { 79952130Smckusick if (top) { 80052130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 80152130Smckusick if (m == 0) { 80252130Smckusick m_freem(top); 80352130Smckusick return (0); 80452130Smckusick } 80552130Smckusick m->m_len = MLEN; 80652130Smckusick } 80752130Smckusick 80852130Smckusick if (resid >= MINCLSIZE) 80952130Smckusick MCLGET(m, M_DONTWAIT); 81052130Smckusick if (m->m_flags & M_EXT) 81152130Smckusick m->m_len = MIN(resid, MCLBYTES); 81252130Smckusick else if (resid < m->m_len) { 81352130Smckusick /* 81452130Smckusick * Place initial small packet/header at end of mbuf. 81552130Smckusick */ 81652130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 81752130Smckusick m->m_data += max_linkhdr; 81852130Smckusick m->m_len = resid; 81952130Smckusick } 82052130Smckusick len = m->m_len; 82152695Sralph #ifdef DS3100 82252130Smckusick if ((unsigned)sp & 2) { 82352130Smckusick /* 82452130Smckusick * Previous len was odd. Copy the single byte specially. 82552130Smckusick * XXX Can this ever happen?? 82652130Smckusick */ 82752130Smckusick panic("le odd rcv"); 82852130Smckusick *mtod(m, char *) = ((volatile char *)sp)[-1]; 82952130Smckusick CopyFromBuffer(sp + 1, mtod(m, char *) + 1, len - 1); 83052130Smckusick } else 83152130Smckusick CopyFromBuffer(sp, mtod(m, char *), len); 83252695Sralph #endif 83352695Sralph #ifdef DS5000 83452695Sralph bcopy(sp, mtod(m, char *), len); 83552695Sralph #endif 83652130Smckusick sp += len; 83752130Smckusick *mp = m; 83852130Smckusick mp = &m->m_next; 83952130Smckusick totlen -= len; 84052130Smckusick resid -= len; 84152130Smckusick if (resid == 0) { 84252130Smckusick sp = lebuf; 84352130Smckusick resid = totlen; 84452130Smckusick } 84552130Smckusick } 84652130Smckusick return (top); 84752130Smckusick } 84852130Smckusick 84952130Smckusick /* 85052130Smckusick * Process an ioctl request. 85152130Smckusick */ 85252130Smckusick leioctl(ifp, cmd, data) 85352130Smckusick register struct ifnet *ifp; 85452130Smckusick int cmd; 85552130Smckusick caddr_t data; 85652130Smckusick { 85752130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 85852130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 85952130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 86052130Smckusick int s, error = 0; 86152130Smckusick 86252130Smckusick s = splnet(); 86352130Smckusick switch (cmd) { 86452130Smckusick 86552130Smckusick case SIOCSIFADDR: 86652130Smckusick ifp->if_flags |= IFF_UP; 86752130Smckusick switch (ifa->ifa_addr->sa_family) { 86852130Smckusick #ifdef INET 86952130Smckusick case AF_INET: 87052130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 87152130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 87252130Smckusick IA_SIN(ifa)->sin_addr; 87352130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 87452130Smckusick break; 87552130Smckusick #endif 87652130Smckusick #ifdef NS 87752130Smckusick case AF_NS: 87852130Smckusick { 87952130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 88052130Smckusick 88152130Smckusick if (ns_nullhost(*ina)) 88252130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 88352130Smckusick else { 88452130Smckusick /* 88552130Smckusick * The manual says we can't change the address 88652130Smckusick * while the receiver is armed, 88752130Smckusick * so reset everything 88852130Smckusick */ 88952130Smckusick ifp->if_flags &= ~IFF_RUNNING; 89052130Smckusick bcopy((caddr_t)ina->x_host.c_host, 89152130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 89252130Smckusick } 89352130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 89452130Smckusick break; 89552130Smckusick } 89652130Smckusick #endif 89752130Smckusick default: 89852130Smckusick leinit(ifp->if_unit); 89952130Smckusick break; 90052130Smckusick } 90152130Smckusick break; 90252130Smckusick 90352130Smckusick case SIOCSIFFLAGS: 90452130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 90552130Smckusick ifp->if_flags & IFF_RUNNING) { 90652130Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 90752130Smckusick MachEmptyWriteBuffer(); 90852130Smckusick ifp->if_flags &= ~IFF_RUNNING; 90952130Smckusick } else if (ifp->if_flags & IFF_UP && 91052130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 91152130Smckusick leinit(ifp->if_unit); 91252130Smckusick /* 91352130Smckusick * If the state of the promiscuous bit changes, the interface 91452130Smckusick * must be reset to effect the change. 91552130Smckusick */ 91652130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 91752130Smckusick (ifp->if_flags & IFF_RUNNING)) { 91852130Smckusick le->sc_iflags = ifp->if_flags; 91952130Smckusick lereset(ifp->if_unit); 92052130Smckusick lestart(ifp); 92152130Smckusick } 92252130Smckusick break; 92352130Smckusick 92452130Smckusick default: 92552130Smckusick error = EINVAL; 92652130Smckusick } 92752130Smckusick splx(s); 92852130Smckusick return (error); 92952130Smckusick } 93052130Smckusick 93152130Smckusick leerror(unit, stat) 93252130Smckusick int unit; 93352130Smckusick int stat; 93452130Smckusick { 93552130Smckusick if (!ledebug) 93652130Smckusick return; 93752130Smckusick 93852130Smckusick /* 93952130Smckusick * Not all transceivers implement heartbeat 94052130Smckusick * so we only log CERR once. 94152130Smckusick */ 94252130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 94352130Smckusick return; 94452130Smckusick log(LOG_WARNING, 94552130Smckusick "le%d: error: stat=%b\n", unit, 94652130Smckusick stat, 94752130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 94852130Smckusick } 94952130Smckusick 95052130Smckusick lererror(unit, msg) 95152130Smckusick int unit; 95252130Smckusick char *msg; 95352130Smckusick { 95452130Smckusick register struct le_softc *le = &le_softc[unit]; 95552130Smckusick register volatile struct lermd *rmd; 956*54144Sralph u_char eaddr[6]; 957*54144Sralph char *cp; 95852130Smckusick int len; 95952130Smckusick 96052130Smckusick if (!ledebug) 96152130Smckusick return; 96252130Smckusick 96352130Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 96452130Smckusick len = rmd->rmd3; 965*54144Sralph if (len > 11) { 966*54144Sralph #ifdef DS3100 967*54144Sralph CopyFromBuffer((char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6], 968*54144Sralph eaddr, sizeof(eaddr)); 969*54144Sralph #endif 970*54144Sralph #ifdef DS5000 971*54144Sralph bcopy((char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6], 972*54144Sralph eaddr, sizeof(eaddr)); 973*54144Sralph #endif 974*54144Sralph cp = ether_sprintf(eaddr); 975*54144Sralph } else 976*54144Sralph cp = "unknown"; 97752130Smckusick log(LOG_WARNING, 97852130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 979*54144Sralph unit, msg, cp, le->sc_rmd, len, 98052130Smckusick rmd->rmd1, 98152130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 98252130Smckusick } 98352130Smckusick 98452130Smckusick lexerror(unit) 98552130Smckusick int unit; 98652130Smckusick { 98752130Smckusick register struct le_softc *le = &le_softc[unit]; 98852130Smckusick register volatile struct letmd *tmd; 989*54144Sralph u_char eaddr[6]; 990*54144Sralph char *cp; 99152130Smckusick int len; 99252130Smckusick 99352130Smckusick if (!ledebug) 99452130Smckusick return; 99552130Smckusick 99652130Smckusick tmd = le->sc_r2->ler2_tmd; 99752130Smckusick len = -tmd->tmd2; 998*54144Sralph if (len > 5) { 999*54144Sralph #ifdef DS3100 1000*54144Sralph CopyFromBuffer((char *)&le->sc_r2->ler2_tbuf[le->sc_tmd][0], 1001*54144Sralph eaddr, sizeof(eaddr)); 1002*54144Sralph #endif 1003*54144Sralph #ifdef DS5000 1004*54144Sralph bcopy((char *)&le->sc_r2->ler2_tbuf[le->sc_tmd][0], 1005*54144Sralph eaddr, sizeof(eaddr)); 1006*54144Sralph #endif 1007*54144Sralph cp = ether_sprintf(eaddr); 1008*54144Sralph } else 1009*54144Sralph cp = "unknown"; 101052130Smckusick log(LOG_WARNING, 101152130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 1012*54144Sralph unit, cp, le->sc_tmd, len, 101352130Smckusick tmd->tmd1, 101452130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 101552130Smckusick tmd->tmd3, 101652130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 101752130Smckusick } 101852130Smckusick #endif 1019