1*52130Smckusick /* 2*52130Smckusick * Copyright (c) 1992 Regents of the University of California. 3*52130Smckusick * All rights reserved. 4*52130Smckusick * 5*52130Smckusick * This code is derived from software contributed to Berkeley by 6*52130Smckusick * Ralph Campbell. 7*52130Smckusick * 8*52130Smckusick * %sccs.include.redist.c% 9*52130Smckusick * 10*52130Smckusick * @(#)if_le.c 7.1 (Berkeley) 01/07/92 11*52130Smckusick */ 12*52130Smckusick 13*52130Smckusick #include "le.h" 14*52130Smckusick #if NLE > 0 15*52130Smckusick 16*52130Smckusick #include "bpfilter.h" 17*52130Smckusick 18*52130Smckusick /* 19*52130Smckusick * AMD 7990 LANCE 20*52130Smckusick * 21*52130Smckusick * This driver will generate and accept trailer encapsulated packets even 22*52130Smckusick * though it buys us nothing. The motivation was to avoid incompatibilities 23*52130Smckusick * with VAXen, SUNs, and others that handle and benefit from them. 24*52130Smckusick * This reasoning is dubious. 25*52130Smckusick */ 26*52130Smckusick #include "param.h" 27*52130Smckusick #include "systm.h" 28*52130Smckusick #include "mbuf.h" 29*52130Smckusick #include "buf.h" 30*52130Smckusick #include "protosw.h" 31*52130Smckusick #include "socket.h" 32*52130Smckusick #include "syslog.h" 33*52130Smckusick #include "ioctl.h" 34*52130Smckusick #include "errno.h" 35*52130Smckusick 36*52130Smckusick #include "net/if.h" 37*52130Smckusick #include "net/netisr.h" 38*52130Smckusick #include "net/route.h" 39*52130Smckusick 40*52130Smckusick #ifdef INET 41*52130Smckusick #include "netinet/in.h" 42*52130Smckusick #include "netinet/in_systm.h" 43*52130Smckusick #include "netinet/in_var.h" 44*52130Smckusick #include "netinet/ip.h" 45*52130Smckusick #include "netinet/if_ether.h" 46*52130Smckusick #endif 47*52130Smckusick 48*52130Smckusick #ifdef NS 49*52130Smckusick #include "netns/ns.h" 50*52130Smckusick #include "netns/ns_if.h" 51*52130Smckusick #endif 52*52130Smckusick 53*52130Smckusick #ifdef RMP 54*52130Smckusick #include "netrmp/rmp.h" 55*52130Smckusick #include "netrmp/rmp_var.h" 56*52130Smckusick #endif 57*52130Smckusick 58*52130Smckusick #include "machine/machConst.h" 59*52130Smckusick #include "device.h" 60*52130Smckusick #include "if_lereg.h" 61*52130Smckusick 62*52130Smckusick #if NBPFILTER > 0 63*52130Smckusick #include "../net/bpf.h" 64*52130Smckusick #include "../net/bpfdesc.h" 65*52130Smckusick #endif 66*52130Smckusick 67*52130Smckusick int leprobe(); 68*52130Smckusick struct driver ledriver = { 69*52130Smckusick "le", leprobe, 70*52130Smckusick }; 71*52130Smckusick 72*52130Smckusick int ledebug = 1; /* console error messages */ 73*52130Smckusick 74*52130Smckusick int leintr(), leinit(), leioctl(), lestart(), ether_output(); 75*52130Smckusick struct mbuf *leget(); 76*52130Smckusick 77*52130Smckusick /* 78*52130Smckusick * Ethernet software status per interface. 79*52130Smckusick * 80*52130Smckusick * Each interface is referenced by a network interface structure, 81*52130Smckusick * le_if, which the routing code uses to locate the interface. 82*52130Smckusick * This structure contains the output queue for the interface, its address, ... 83*52130Smckusick */ 84*52130Smckusick struct le_softc { 85*52130Smckusick struct arpcom sc_ac; /* common Ethernet structures */ 86*52130Smckusick #define sc_if sc_ac.ac_if /* network-visible interface */ 87*52130Smckusick #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 88*52130Smckusick volatile struct lereg1 *sc_r1; /* LANCE registers */ 89*52130Smckusick volatile struct lereg2 *sc_r2; /* dual-port RAM */ 90*52130Smckusick int sc_rmd; /* predicted next rmd to process */ 91*52130Smckusick int sc_tmd; /* last tmd processed */ 92*52130Smckusick int sc_tmdnext; /* next tmd to transmit with */ 93*52130Smckusick int sc_runt; 94*52130Smckusick int sc_jab; 95*52130Smckusick int sc_merr; 96*52130Smckusick int sc_babl; 97*52130Smckusick int sc_cerr; 98*52130Smckusick int sc_miss; 99*52130Smckusick int sc_xint; 100*52130Smckusick int sc_xown; 101*52130Smckusick int sc_uflo; 102*52130Smckusick int sc_rxlen; 103*52130Smckusick int sc_rxoff; 104*52130Smckusick int sc_txoff; 105*52130Smckusick int sc_busy; 106*52130Smckusick short sc_iflags; 107*52130Smckusick #if NBPFILTER > 0 108*52130Smckusick caddr_t sc_bpf; 109*52130Smckusick #endif 110*52130Smckusick } le_softc[NLE]; 111*52130Smckusick 112*52130Smckusick /* access LANCE registers */ 113*52130Smckusick #define LERDWR(cntl, src, dst) { (dst) = (src); DELAY(10); } 114*52130Smckusick 115*52130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \ 116*52130Smckusick (((unsigned)(&(((struct lereg2 *)0)->cpu))) >> 1) 117*52130Smckusick 118*52130Smckusick /* 119*52130Smckusick * Test to see if device is present. 120*52130Smckusick * Return true if found and initialized ok. 121*52130Smckusick * If interface exists, make available by filling in network interface 122*52130Smckusick * record. System will initialize the interface when it is ready 123*52130Smckusick * to accept packets. 124*52130Smckusick */ 125*52130Smckusick leprobe(dp) 126*52130Smckusick struct pmax_ctlr *dp; 127*52130Smckusick { 128*52130Smckusick volatile struct lereg1 *ler1; 129*52130Smckusick struct le_softc *le = &le_softc[dp->pmax_unit]; 130*52130Smckusick struct ifnet *ifp = &le->sc_if; 131*52130Smckusick u_char *cp; 132*52130Smckusick int i; 133*52130Smckusick 134*52130Smckusick le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr; 135*52130Smckusick le->sc_r2 = (volatile struct lereg2 *)MACH_NETWORK_BUFFER_ADDR; 136*52130Smckusick 137*52130Smckusick /* 138*52130Smckusick * Read the ethernet address. 139*52130Smckusick * See "DECstation 3100 Desktop Workstation Functional Specification". 140*52130Smckusick */ 141*52130Smckusick cp = (u_char *)(MACH_CLOCK_ADDR + 1); 142*52130Smckusick for (i = 0; i < sizeof(le->sc_addr); i++) { 143*52130Smckusick le->sc_addr[i] = *cp; 144*52130Smckusick cp += 4; 145*52130Smckusick } 146*52130Smckusick 147*52130Smckusick /* make sure the chip is stopped */ 148*52130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 149*52130Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 150*52130Smckusick 151*52130Smckusick ifp->if_unit = dp->pmax_unit; 152*52130Smckusick ifp->if_name = "le"; 153*52130Smckusick ifp->if_mtu = ETHERMTU; 154*52130Smckusick ifp->if_init = leinit; 155*52130Smckusick ifp->if_ioctl = leioctl; 156*52130Smckusick ifp->if_output = ether_output; 157*52130Smckusick ifp->if_start = lestart; 158*52130Smckusick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 159*52130Smckusick #if NBPFILTER > 0 160*52130Smckusick bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 161*52130Smckusick #endif 162*52130Smckusick if_attach(ifp); 163*52130Smckusick 164*52130Smckusick printf("le%d at nexus0 csr 0x%x ethernet address %s\n", dp->pmax_unit, 165*52130Smckusick dp->pmax_addr, ether_sprintf(le->sc_addr)); 166*52130Smckusick return (1); 167*52130Smckusick } 168*52130Smckusick 169*52130Smckusick ledrinit(ler2) 170*52130Smckusick register volatile struct lereg2 *ler2; 171*52130Smckusick { 172*52130Smckusick register int i; 173*52130Smckusick 174*52130Smckusick for (i = 0; i < LERBUF; i++) { 175*52130Smckusick ler2->ler2_rmd[i].rmd0 = CPU_TO_CHIP_ADDR(ler2_rbuf[i][0]); 176*52130Smckusick ler2->ler2_rmd[i].rmd1 = LE_OWN; 177*52130Smckusick ler2->ler2_rmd[i].rmd2 = -LEMTU; 178*52130Smckusick ler2->ler2_rmd[i].rmd3 = 0; 179*52130Smckusick } 180*52130Smckusick for (i = 0; i < LETBUF; i++) { 181*52130Smckusick ler2->ler2_tmd[i].tmd0 = CPU_TO_CHIP_ADDR(ler2_tbuf[i][0]); 182*52130Smckusick ler2->ler2_tmd[i].tmd1 = 0; 183*52130Smckusick ler2->ler2_tmd[i].tmd2 = 0; 184*52130Smckusick ler2->ler2_tmd[i].tmd3 = 0; 185*52130Smckusick } 186*52130Smckusick } 187*52130Smckusick 188*52130Smckusick lereset(unit) 189*52130Smckusick register int unit; 190*52130Smckusick { 191*52130Smckusick register struct le_softc *le = &le_softc[unit]; 192*52130Smckusick register volatile struct lereg1 *ler1 = le->sc_r1; 193*52130Smckusick register volatile struct lereg2 *ler2 = le->sc_r2; 194*52130Smckusick register int timo = 100000; 195*52130Smckusick register int stat; 196*52130Smckusick 197*52130Smckusick #ifdef lint 198*52130Smckusick stat = unit; 199*52130Smckusick #endif 200*52130Smckusick #if NBPFILTER > 0 201*52130Smckusick if (le->sc_if.if_flags & IFF_PROMISC) 202*52130Smckusick /* set the promiscuous bit */ 203*52130Smckusick le->sc_r2->ler2_mode = LE_MODE|0x8000; 204*52130Smckusick else 205*52130Smckusick le->sc_r2->ler2_mode = LE_MODE; 206*52130Smckusick #endif 207*52130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 208*52130Smckusick LERDWR(ler0, LE_STOP, ler1->ler1_rdp); 209*52130Smckusick 210*52130Smckusick /* 211*52130Smckusick * Setup for transmit/receive 212*52130Smckusick */ 213*52130Smckusick ler2->ler2_mode = LE_MODE; 214*52130Smckusick ler2->ler2_padr0 = (le->sc_addr[1] << 8) | le->sc_addr[0]; 215*52130Smckusick ler2->ler2_padr1 = (le->sc_addr[3] << 8) | le->sc_addr[2]; 216*52130Smckusick ler2->ler2_padr2 = (le->sc_addr[5] << 8) | le->sc_addr[4]; 217*52130Smckusick #ifdef RMP 218*52130Smckusick /* 219*52130Smckusick * Set up logical addr filter to accept multicast 9:0:9:0:0:4 220*52130Smckusick * This should be an ioctl() to the driver. (XXX) 221*52130Smckusick */ 222*52130Smckusick ler2->ler2_ladrf0 = 0x0010; 223*52130Smckusick ler2->ler2_ladrf1 = 0x0; 224*52130Smckusick ler2->ler2_ladrf2 = 0x0; 225*52130Smckusick ler2->ler2_ladrf3 = 0x0; 226*52130Smckusick #else 227*52130Smckusick ler2->ler2_ladrf0 = 0; 228*52130Smckusick ler2->ler2_ladrf1 = 0; 229*52130Smckusick ler2->ler2_ladrf2 = 0; 230*52130Smckusick ler2->ler2_ladrf3 = 0; 231*52130Smckusick #endif 232*52130Smckusick ler2->ler2_rlen = LE_RLEN; 233*52130Smckusick ler2->ler2_rdra = CPU_TO_CHIP_ADDR(ler2_rmd[0]); 234*52130Smckusick ler2->ler2_tlen = LE_TLEN; 235*52130Smckusick ler2->ler2_tdra = CPU_TO_CHIP_ADDR(ler2_tmd[0]); 236*52130Smckusick ledrinit(ler2); 237*52130Smckusick le->sc_rmd = 0; 238*52130Smckusick le->sc_tmd = LETBUF - 1; 239*52130Smckusick le->sc_tmdnext = 0; 240*52130Smckusick 241*52130Smckusick LERDWR(ler0, LE_CSR1, ler1->ler1_rap); 242*52130Smckusick LERDWR(ler0, CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp); 243*52130Smckusick LERDWR(ler0, LE_CSR2, ler1->ler1_rap); 244*52130Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 245*52130Smckusick LERDWR(ler0, LE_CSR3, ler1->ler1_rap); 246*52130Smckusick LERDWR(ler0, 0, ler1->ler1_rdp); 247*52130Smckusick LERDWR(ler0, LE_CSR0, ler1->ler1_rap); 248*52130Smckusick LERDWR(ler0, LE_INIT, ler1->ler1_rdp); 249*52130Smckusick MachEmptyWriteBuffer(); 250*52130Smckusick do { 251*52130Smckusick if (--timo == 0) { 252*52130Smckusick printf("le%d: init timeout, stat = 0x%x\n", 253*52130Smckusick unit, stat); 254*52130Smckusick break; 255*52130Smckusick } 256*52130Smckusick LERDWR(ler0, ler1->ler1_rdp, stat); 257*52130Smckusick } while ((stat & LE_IDON) == 0); 258*52130Smckusick LERDWR(ler0, LE_IDON, ler1->ler1_rdp); 259*52130Smckusick LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp); 260*52130Smckusick MachEmptyWriteBuffer(); 261*52130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 262*52130Smckusick } 263*52130Smckusick 264*52130Smckusick /* 265*52130Smckusick * Initialization of interface 266*52130Smckusick */ 267*52130Smckusick leinit(unit) 268*52130Smckusick int unit; 269*52130Smckusick { 270*52130Smckusick struct le_softc *le = &le_softc[unit]; 271*52130Smckusick register struct ifnet *ifp = &le->sc_if; 272*52130Smckusick int s; 273*52130Smckusick 274*52130Smckusick /* not yet, if address still unknown */ 275*52130Smckusick if (ifp->if_addrlist == (struct ifaddr *)0) 276*52130Smckusick return; 277*52130Smckusick if ((ifp->if_flags & IFF_RUNNING) == 0) { 278*52130Smckusick s = splnet(); 279*52130Smckusick ifp->if_flags |= IFF_RUNNING; 280*52130Smckusick lereset(unit); 281*52130Smckusick (void) lestart(ifp); 282*52130Smckusick splx(s); 283*52130Smckusick } 284*52130Smckusick } 285*52130Smckusick 286*52130Smckusick #define LENEXTTMP \ 287*52130Smckusick if (++bix == LETBUF) bix = 0, tmd = le->sc_r2->ler2_tmd; else ++tmd 288*52130Smckusick 289*52130Smckusick /* 290*52130Smckusick * Start output on interface. Get another datagram to send 291*52130Smckusick * off of the interface queue, and copy it to the interface 292*52130Smckusick * before starting the output. 293*52130Smckusick */ 294*52130Smckusick lestart(ifp) 295*52130Smckusick struct ifnet *ifp; 296*52130Smckusick { 297*52130Smckusick register struct le_softc *le = &le_softc[ifp->if_unit]; 298*52130Smckusick register int bix = le->sc_tmdnext; 299*52130Smckusick register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix]; 300*52130Smckusick register struct mbuf *m; 301*52130Smckusick int len = 0; 302*52130Smckusick 303*52130Smckusick if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 304*52130Smckusick return (0); 305*52130Smckusick while (bix != le->sc_tmd) { 306*52130Smckusick if (tmd->tmd1 & LE_OWN) 307*52130Smckusick panic("lestart"); 308*52130Smckusick IF_DEQUEUE(&le->sc_if.if_snd, m); 309*52130Smckusick if (m == 0) 310*52130Smckusick break; 311*52130Smckusick len = leput(le->sc_r2->ler2_tbuf[bix], m); 312*52130Smckusick #if NBPFILTER > 0 313*52130Smckusick /* 314*52130Smckusick * If bpf is listening on this interface, let it 315*52130Smckusick * see the packet before we commit it to the wire. 316*52130Smckusick */ 317*52130Smckusick if (le->sc_bpf) 318*52130Smckusick bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[bix], len); 319*52130Smckusick #endif 320*52130Smckusick tmd->tmd3 = 0; 321*52130Smckusick tmd->tmd2 = -len; 322*52130Smckusick tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 323*52130Smckusick LENEXTTMP; 324*52130Smckusick } 325*52130Smckusick if (len != 0) { 326*52130Smckusick le->sc_if.if_flags |= IFF_OACTIVE; 327*52130Smckusick LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp); 328*52130Smckusick MachEmptyWriteBuffer(); 329*52130Smckusick } 330*52130Smckusick le->sc_tmdnext = bix; 331*52130Smckusick return (0); 332*52130Smckusick } 333*52130Smckusick 334*52130Smckusick /* 335*52130Smckusick * Process interrupts from the 7990 chip. 336*52130Smckusick */ 337*52130Smckusick leintr() 338*52130Smckusick { 339*52130Smckusick register struct le_softc *le; 340*52130Smckusick register volatile struct lereg1 *ler1; 341*52130Smckusick register int unit, stat; 342*52130Smckusick 343*52130Smckusick /* only one unit right now; should be a loop. */ 344*52130Smckusick unit = 0; 345*52130Smckusick le = &le_softc[unit]; 346*52130Smckusick ler1 = le->sc_r1; 347*52130Smckusick stat = ler1->ler1_rdp; 348*52130Smckusick if (!(stat & LE_INTR)) { 349*52130Smckusick printf("le?: spurrious interrupt\n"); 350*52130Smckusick return; 351*52130Smckusick } 352*52130Smckusick if (stat & LE_SERR) { 353*52130Smckusick leerror(unit, stat); 354*52130Smckusick if (stat & LE_MERR) { 355*52130Smckusick le->sc_merr++; 356*52130Smckusick lereset(unit); 357*52130Smckusick return; 358*52130Smckusick } 359*52130Smckusick if (stat & LE_BABL) 360*52130Smckusick le->sc_babl++; 361*52130Smckusick if (stat & LE_CERR) 362*52130Smckusick le->sc_cerr++; 363*52130Smckusick if (stat & LE_MISS) 364*52130Smckusick le->sc_miss++; 365*52130Smckusick LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp); 366*52130Smckusick MachEmptyWriteBuffer(); 367*52130Smckusick } 368*52130Smckusick if ((stat & LE_RXON) == 0) { 369*52130Smckusick le->sc_rxoff++; 370*52130Smckusick lereset(unit); 371*52130Smckusick return; 372*52130Smckusick } 373*52130Smckusick if ((stat & LE_TXON) == 0) { 374*52130Smckusick le->sc_txoff++; 375*52130Smckusick lereset(unit); 376*52130Smckusick return; 377*52130Smckusick } 378*52130Smckusick if (stat & LE_RINT) { 379*52130Smckusick /* interrupt is cleared in lerint */ 380*52130Smckusick lerint(unit); 381*52130Smckusick } 382*52130Smckusick if (stat & LE_TINT) { 383*52130Smckusick LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp); 384*52130Smckusick MachEmptyWriteBuffer(); 385*52130Smckusick lexint(unit); 386*52130Smckusick } 387*52130Smckusick } 388*52130Smckusick 389*52130Smckusick /* 390*52130Smckusick * Ethernet interface transmitter interrupt. 391*52130Smckusick * Start another output if more data to send. 392*52130Smckusick */ 393*52130Smckusick lexint(unit) 394*52130Smckusick register int unit; 395*52130Smckusick { 396*52130Smckusick register struct le_softc *le = &le_softc[unit]; 397*52130Smckusick register int bix = le->sc_tmd; 398*52130Smckusick register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix]; 399*52130Smckusick 400*52130Smckusick if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 401*52130Smckusick le->sc_xint++; 402*52130Smckusick return; 403*52130Smckusick } 404*52130Smckusick LENEXTTMP; 405*52130Smckusick while (bix != le->sc_tmdnext && (tmd->tmd1 & LE_OWN) == 0) { 406*52130Smckusick le->sc_tmd = bix; 407*52130Smckusick if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) { 408*52130Smckusick lexerror(unit); 409*52130Smckusick le->sc_if.if_oerrors++; 410*52130Smckusick if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 411*52130Smckusick le->sc_uflo++; 412*52130Smckusick lereset(unit); 413*52130Smckusick break; 414*52130Smckusick } 415*52130Smckusick else if (tmd->tmd3 & LE_LCOL) 416*52130Smckusick le->sc_if.if_collisions++; 417*52130Smckusick else if (tmd->tmd3 & LE_RTRY) 418*52130Smckusick le->sc_if.if_collisions += 16; 419*52130Smckusick } 420*52130Smckusick else if (tmd->tmd1 & LE_ONE) 421*52130Smckusick le->sc_if.if_collisions++; 422*52130Smckusick else if (tmd->tmd1 & LE_MORE) 423*52130Smckusick /* what is the real number? */ 424*52130Smckusick le->sc_if.if_collisions += 2; 425*52130Smckusick else 426*52130Smckusick le->sc_if.if_opackets++; 427*52130Smckusick LENEXTTMP; 428*52130Smckusick } 429*52130Smckusick if (bix == le->sc_tmdnext) 430*52130Smckusick le->sc_if.if_flags &= ~IFF_OACTIVE; 431*52130Smckusick (void) lestart(&le->sc_if); 432*52130Smckusick } 433*52130Smckusick 434*52130Smckusick #define LENEXTRMP \ 435*52130Smckusick if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 436*52130Smckusick 437*52130Smckusick /* 438*52130Smckusick * Ethernet interface receiver interrupt. 439*52130Smckusick * If input error just drop packet. 440*52130Smckusick * Decapsulate packet based on type and pass to type specific 441*52130Smckusick * higher-level input routine. 442*52130Smckusick */ 443*52130Smckusick lerint(unit) 444*52130Smckusick int unit; 445*52130Smckusick { 446*52130Smckusick register struct le_softc *le = &le_softc[unit]; 447*52130Smckusick register int bix = le->sc_rmd; 448*52130Smckusick register volatile struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 449*52130Smckusick 450*52130Smckusick /* 451*52130Smckusick * Out of sync with hardware, should never happen? 452*52130Smckusick */ 453*52130Smckusick if (rmd->rmd1 & LE_OWN) { 454*52130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 455*52130Smckusick MachEmptyWriteBuffer(); 456*52130Smckusick return; 457*52130Smckusick } 458*52130Smckusick 459*52130Smckusick /* 460*52130Smckusick * Process all buffers with valid data 461*52130Smckusick */ 462*52130Smckusick while ((rmd->rmd1 & LE_OWN) == 0) { 463*52130Smckusick int len = rmd->rmd3; 464*52130Smckusick 465*52130Smckusick /* Clear interrupt to avoid race condition */ 466*52130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp); 467*52130Smckusick MachEmptyWriteBuffer(); 468*52130Smckusick 469*52130Smckusick if (rmd->rmd1 & LE_ERR) { 470*52130Smckusick le->sc_rmd = bix; 471*52130Smckusick lererror(unit, "bad packet"); 472*52130Smckusick le->sc_if.if_ierrors++; 473*52130Smckusick } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 474*52130Smckusick /* 475*52130Smckusick * Find the end of the packet so we can see how long 476*52130Smckusick * it was. We still throw it away. 477*52130Smckusick */ 478*52130Smckusick do { 479*52130Smckusick LERDWR(le->sc_r0, LE_RINT|LE_INEA, 480*52130Smckusick le->sc_r1->ler1_rdp); 481*52130Smckusick MachEmptyWriteBuffer(); 482*52130Smckusick rmd->rmd3 = 0; 483*52130Smckusick rmd->rmd1 = LE_OWN; 484*52130Smckusick LENEXTRMP; 485*52130Smckusick } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 486*52130Smckusick le->sc_rmd = bix; 487*52130Smckusick lererror(unit, "chained buffer"); 488*52130Smckusick le->sc_rxlen++; 489*52130Smckusick /* 490*52130Smckusick * If search terminated without successful completion 491*52130Smckusick * we reset the hardware (conservative). 492*52130Smckusick */ 493*52130Smckusick if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 494*52130Smckusick LE_ENP) { 495*52130Smckusick lereset(unit); 496*52130Smckusick return; 497*52130Smckusick } 498*52130Smckusick } else 499*52130Smckusick leread(unit, le->sc_r2->ler2_rbuf[bix], len); 500*52130Smckusick rmd->rmd3 = 0; 501*52130Smckusick rmd->rmd1 = LE_OWN; 502*52130Smckusick LENEXTRMP; 503*52130Smckusick } 504*52130Smckusick MachEmptyWriteBuffer(); /* Paranoia */ 505*52130Smckusick le->sc_rmd = bix; 506*52130Smckusick } 507*52130Smckusick 508*52130Smckusick /* 509*52130Smckusick * Look at the packet in network buffer memory so we can be smart about how 510*52130Smckusick * we copy the data into mbufs. 511*52130Smckusick * This needs work since we can't just read network buffer memory like 512*52130Smckusick * regular memory. 513*52130Smckusick */ 514*52130Smckusick leread(unit, buf, len) 515*52130Smckusick int unit; 516*52130Smckusick volatile u_short *buf; 517*52130Smckusick int len; 518*52130Smckusick { 519*52130Smckusick register struct le_softc *le = &le_softc[unit]; 520*52130Smckusick struct ether_header et; 521*52130Smckusick struct mbuf *m; 522*52130Smckusick int off, resid; 523*52130Smckusick u_short sbuf[2]; 524*52130Smckusick 525*52130Smckusick le->sc_if.if_ipackets++; 526*52130Smckusick CopyFromBuffer(buf, (char *)&et, sizeof(et)); 527*52130Smckusick et.ether_type = ntohs(et.ether_type); 528*52130Smckusick /* adjust input length to account for header and CRC */ 529*52130Smckusick len = len - sizeof(struct ether_header) - 4; 530*52130Smckusick 531*52130Smckusick #ifdef RMP 532*52130Smckusick /* (XXX) 533*52130Smckusick * 534*52130Smckusick * If Ethernet Type field is < MaxPacketSize, we probably have 535*52130Smckusick * a IEEE802 packet here. Make sure that the size is at least 536*52130Smckusick * that of the HP LLC. Also do sanity checks on length of LLC 537*52130Smckusick * (old Ethernet Type field) and packet length. 538*52130Smckusick * 539*52130Smckusick * Provided the above checks succeed, change `len' to reflect 540*52130Smckusick * the length of the LLC (i.e. et.ether_type) and change the 541*52130Smckusick * type field to ETHERTYPE_IEEE so we can switch() on it later. 542*52130Smckusick * Yes, this is a hack and will eventually be done "right". 543*52130Smckusick */ 544*52130Smckusick if (et.ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) && 545*52130Smckusick len >= et.ether_type && len >= IEEE802LEN_MIN) { 546*52130Smckusick len = et.ether_type; 547*52130Smckusick et.ether_type = ETHERTYPE_IEEE; /* hack! */ 548*52130Smckusick } 549*52130Smckusick #endif 550*52130Smckusick 551*52130Smckusick if (et.ether_type >= ETHERTYPE_TRAIL && 552*52130Smckusick et.ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 553*52130Smckusick off = (et.ether_type - ETHERTYPE_TRAIL) * 512; 554*52130Smckusick if (off >= ETHERMTU) 555*52130Smckusick return; /* sanity */ 556*52130Smckusick CopyFromBuffer(buf + (sizeof(et) + off), 557*52130Smckusick (char *)sbuf, sizeof(sbuf)); 558*52130Smckusick et.ether_type = ntohs(sbuf[0]); 559*52130Smckusick resid = ntohs(sbuf[1]); 560*52130Smckusick if (off + resid > len) 561*52130Smckusick return; /* sanity */ 562*52130Smckusick len = off + resid; 563*52130Smckusick } else 564*52130Smckusick off = 0; 565*52130Smckusick 566*52130Smckusick if (len <= 0) { 567*52130Smckusick if (ledebug) 568*52130Smckusick log(LOG_WARNING, 569*52130Smckusick "le%d: ierror(runt packet): from %s: len=%d\n", 570*52130Smckusick unit, ether_sprintf(et.ether_shost), len); 571*52130Smckusick le->sc_runt++; 572*52130Smckusick le->sc_if.if_ierrors++; 573*52130Smckusick return; 574*52130Smckusick } 575*52130Smckusick #if NBPFILTER > 0 576*52130Smckusick /* 577*52130Smckusick * Check if there's a bpf filter listening on this interface. 578*52130Smckusick * If so, hand off the raw packet to bpf, which must deal with 579*52130Smckusick * trailers in its own way. 580*52130Smckusick */ 581*52130Smckusick if (le->sc_bpf) { 582*52130Smckusick bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header)); 583*52130Smckusick 584*52130Smckusick /* 585*52130Smckusick * Note that the interface cannot be in promiscuous mode if 586*52130Smckusick * there are no bpf listeners. And if we are in promiscuous 587*52130Smckusick * mode, we have to check if this packet is really ours. 588*52130Smckusick * 589*52130Smckusick * XXX This test does not support multicasts. 590*52130Smckusick */ 591*52130Smckusick if ((le->sc_if.if_flags & IFF_PROMISC) 592*52130Smckusick && bcmp(et.ether_dhost, le->sc_addr, 593*52130Smckusick sizeof(et.ether_dhost)) != 0 594*52130Smckusick && bcmp(et.ether_dhost, etherbroadcastaddr, 595*52130Smckusick sizeof(et.ether_dhost)) != 0) 596*52130Smckusick return; 597*52130Smckusick } 598*52130Smckusick #endif 599*52130Smckusick /* 600*52130Smckusick * Pull packet off interface. Off is nonzero if packet 601*52130Smckusick * has trailing header; leget will then force this header 602*52130Smckusick * information to be at the front, but we still have to drop 603*52130Smckusick * the type and length which are at the front of any trailer data. 604*52130Smckusick */ 605*52130Smckusick m = leget(buf, len, off, &le->sc_if); 606*52130Smckusick if (m == 0) 607*52130Smckusick return; 608*52130Smckusick #ifdef RMP 609*52130Smckusick /* 610*52130Smckusick * (XXX) 611*52130Smckusick * This needs to be integrated with the ISO stuff in ether_input() 612*52130Smckusick */ 613*52130Smckusick if (et.ether_type == ETHERTYPE_IEEE) { 614*52130Smckusick /* 615*52130Smckusick * Snag the Logical Link Control header (IEEE 802.2). 616*52130Smckusick */ 617*52130Smckusick struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc); 618*52130Smckusick 619*52130Smckusick /* 620*52130Smckusick * If the DSAP (and HP's extended DXSAP) indicate this 621*52130Smckusick * is an RMP packet, hand it to the raw input routine. 622*52130Smckusick */ 623*52130Smckusick if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 624*52130Smckusick static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 625*52130Smckusick static struct sockaddr rmp_src = {AF_RMP}; 626*52130Smckusick static struct sockaddr rmp_dst = {AF_RMP}; 627*52130Smckusick 628*52130Smckusick bcopy(et.ether_shost, rmp_src.sa_data, 629*52130Smckusick sizeof(et.ether_shost)); 630*52130Smckusick bcopy(et.ether_dhost, rmp_dst.sa_data, 631*52130Smckusick sizeof(et.ether_dhost)); 632*52130Smckusick 633*52130Smckusick raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 634*52130Smckusick return; 635*52130Smckusick } 636*52130Smckusick } 637*52130Smckusick #endif 638*52130Smckusick ether_input(&le->sc_if, &et, m); 639*52130Smckusick } 640*52130Smckusick 641*52130Smckusick /* 642*52130Smckusick * Routine to copy from mbuf chain to transmit buffer in 643*52130Smckusick * network buffer memory. 644*52130Smckusick * NOTE: network memory can only be written one short at every other address. 645*52130Smckusick */ 646*52130Smckusick leput(lebuf, m) 647*52130Smckusick volatile register u_short *lebuf; 648*52130Smckusick register struct mbuf *m; 649*52130Smckusick { 650*52130Smckusick register struct mbuf *mp; 651*52130Smckusick register int len, tlen = 0, xfer; 652*52130Smckusick register char *cp; 653*52130Smckusick int tmp; 654*52130Smckusick 655*52130Smckusick for (mp = m; mp; mp = mp->m_next) { 656*52130Smckusick len = mp->m_len; 657*52130Smckusick if (len == 0) 658*52130Smckusick continue; 659*52130Smckusick /* copy data for this mbuf */ 660*52130Smckusick cp = mtod(mp, char *); 661*52130Smckusick if (tlen & 1) { 662*52130Smckusick /* handle odd length from previous mbuf */ 663*52130Smckusick *lebuf = (cp[0] << 8) | tmp; 664*52130Smckusick lebuf += 2; 665*52130Smckusick cp++; 666*52130Smckusick len--; 667*52130Smckusick tlen++; 668*52130Smckusick } 669*52130Smckusick tlen += len; 670*52130Smckusick if ((unsigned)cp & 1) { 671*52130Smckusick while (len > 1) { 672*52130Smckusick *lebuf = (cp[1] << 8) | cp[0]; 673*52130Smckusick lebuf += 2; 674*52130Smckusick cp += 2; 675*52130Smckusick len -= 2; 676*52130Smckusick } 677*52130Smckusick } else { 678*52130Smckusick /* optimize for aligned transfers */ 679*52130Smckusick xfer = (int)((unsigned)len & ~0x1); 680*52130Smckusick CopyToBuffer((u_short *)cp, lebuf, xfer); 681*52130Smckusick lebuf += xfer; 682*52130Smckusick cp += xfer; 683*52130Smckusick len -= xfer; 684*52130Smckusick } 685*52130Smckusick if (len == 1) 686*52130Smckusick tmp = *cp; 687*52130Smckusick } 688*52130Smckusick m_freem(m); 689*52130Smckusick /* handle odd length from previous mbuf */ 690*52130Smckusick if (tlen & 1) 691*52130Smckusick *lebuf = tmp; 692*52130Smckusick if (tlen < LEMINSIZE) 693*52130Smckusick tlen = LEMINSIZE; 694*52130Smckusick return(tlen); 695*52130Smckusick } 696*52130Smckusick 697*52130Smckusick /* 698*52130Smckusick * Routine to copy from network buffer memory into mbufs. 699*52130Smckusick * NOTE: network memory can only be read one short at every other address. 700*52130Smckusick */ 701*52130Smckusick struct mbuf * 702*52130Smckusick leget(lebuf, totlen, off, ifp) 703*52130Smckusick volatile u_short *lebuf; 704*52130Smckusick int totlen, off; 705*52130Smckusick struct ifnet *ifp; 706*52130Smckusick { 707*52130Smckusick register struct mbuf *m; 708*52130Smckusick struct mbuf *top = 0, **mp = ⊤ 709*52130Smckusick register int len, resid; 710*52130Smckusick register volatile u_short *sp; 711*52130Smckusick 712*52130Smckusick /* NOTE: sizeof(struct ether_header) should be even */ 713*52130Smckusick lebuf += sizeof(struct ether_header); 714*52130Smckusick sp = lebuf; 715*52130Smckusick if (off) { 716*52130Smckusick /* NOTE: off should be even */ 717*52130Smckusick sp += off + 2 * sizeof(u_short); 718*52130Smckusick totlen -= 2 * sizeof(u_short); 719*52130Smckusick resid = totlen - off; 720*52130Smckusick } else 721*52130Smckusick resid = totlen; 722*52130Smckusick 723*52130Smckusick MGETHDR(m, M_DONTWAIT, MT_DATA); 724*52130Smckusick if (m == 0) 725*52130Smckusick return (0); 726*52130Smckusick m->m_pkthdr.rcvif = ifp; 727*52130Smckusick m->m_pkthdr.len = totlen; 728*52130Smckusick m->m_len = MHLEN; 729*52130Smckusick 730*52130Smckusick while (totlen > 0) { 731*52130Smckusick if (top) { 732*52130Smckusick MGET(m, M_DONTWAIT, MT_DATA); 733*52130Smckusick if (m == 0) { 734*52130Smckusick m_freem(top); 735*52130Smckusick return (0); 736*52130Smckusick } 737*52130Smckusick m->m_len = MLEN; 738*52130Smckusick } 739*52130Smckusick 740*52130Smckusick if (resid >= MINCLSIZE) 741*52130Smckusick MCLGET(m, M_DONTWAIT); 742*52130Smckusick if (m->m_flags & M_EXT) 743*52130Smckusick m->m_len = MIN(resid, MCLBYTES); 744*52130Smckusick else if (resid < m->m_len) { 745*52130Smckusick /* 746*52130Smckusick * Place initial small packet/header at end of mbuf. 747*52130Smckusick */ 748*52130Smckusick if (top == 0 && resid + max_linkhdr <= m->m_len) 749*52130Smckusick m->m_data += max_linkhdr; 750*52130Smckusick m->m_len = resid; 751*52130Smckusick } 752*52130Smckusick len = m->m_len; 753*52130Smckusick if ((unsigned)sp & 2) { 754*52130Smckusick /* 755*52130Smckusick * Previous len was odd. Copy the single byte specially. 756*52130Smckusick * XXX Can this ever happen?? 757*52130Smckusick */ 758*52130Smckusick panic("le odd rcv"); 759*52130Smckusick *mtod(m, char *) = ((volatile char *)sp)[-1]; 760*52130Smckusick CopyFromBuffer(sp + 1, mtod(m, char *) + 1, len - 1); 761*52130Smckusick } else 762*52130Smckusick CopyFromBuffer(sp, mtod(m, char *), len); 763*52130Smckusick sp += len; 764*52130Smckusick *mp = m; 765*52130Smckusick mp = &m->m_next; 766*52130Smckusick totlen -= len; 767*52130Smckusick resid -= len; 768*52130Smckusick if (resid == 0) { 769*52130Smckusick sp = lebuf; 770*52130Smckusick resid = totlen; 771*52130Smckusick } 772*52130Smckusick } 773*52130Smckusick return (top); 774*52130Smckusick } 775*52130Smckusick 776*52130Smckusick /* 777*52130Smckusick * Process an ioctl request. 778*52130Smckusick */ 779*52130Smckusick leioctl(ifp, cmd, data) 780*52130Smckusick register struct ifnet *ifp; 781*52130Smckusick int cmd; 782*52130Smckusick caddr_t data; 783*52130Smckusick { 784*52130Smckusick register struct ifaddr *ifa = (struct ifaddr *)data; 785*52130Smckusick struct le_softc *le = &le_softc[ifp->if_unit]; 786*52130Smckusick volatile struct lereg1 *ler1 = le->sc_r1; 787*52130Smckusick int s, error = 0; 788*52130Smckusick 789*52130Smckusick s = splnet(); 790*52130Smckusick switch (cmd) { 791*52130Smckusick 792*52130Smckusick case SIOCSIFADDR: 793*52130Smckusick ifp->if_flags |= IFF_UP; 794*52130Smckusick switch (ifa->ifa_addr->sa_family) { 795*52130Smckusick #ifdef INET 796*52130Smckusick case AF_INET: 797*52130Smckusick leinit(ifp->if_unit); /* before arpwhohas */ 798*52130Smckusick ((struct arpcom *)ifp)->ac_ipaddr = 799*52130Smckusick IA_SIN(ifa)->sin_addr; 800*52130Smckusick arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 801*52130Smckusick break; 802*52130Smckusick #endif 803*52130Smckusick #ifdef NS 804*52130Smckusick case AF_NS: 805*52130Smckusick { 806*52130Smckusick register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 807*52130Smckusick 808*52130Smckusick if (ns_nullhost(*ina)) 809*52130Smckusick ina->x_host = *(union ns_host *)(le->sc_addr); 810*52130Smckusick else { 811*52130Smckusick /* 812*52130Smckusick * The manual says we can't change the address 813*52130Smckusick * while the receiver is armed, 814*52130Smckusick * so reset everything 815*52130Smckusick */ 816*52130Smckusick ifp->if_flags &= ~IFF_RUNNING; 817*52130Smckusick bcopy((caddr_t)ina->x_host.c_host, 818*52130Smckusick (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 819*52130Smckusick } 820*52130Smckusick leinit(ifp->if_unit); /* does le_setaddr() */ 821*52130Smckusick break; 822*52130Smckusick } 823*52130Smckusick #endif 824*52130Smckusick default: 825*52130Smckusick leinit(ifp->if_unit); 826*52130Smckusick break; 827*52130Smckusick } 828*52130Smckusick break; 829*52130Smckusick 830*52130Smckusick case SIOCSIFFLAGS: 831*52130Smckusick if ((ifp->if_flags & IFF_UP) == 0 && 832*52130Smckusick ifp->if_flags & IFF_RUNNING) { 833*52130Smckusick LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp); 834*52130Smckusick MachEmptyWriteBuffer(); 835*52130Smckusick ifp->if_flags &= ~IFF_RUNNING; 836*52130Smckusick } else if (ifp->if_flags & IFF_UP && 837*52130Smckusick (ifp->if_flags & IFF_RUNNING) == 0) 838*52130Smckusick leinit(ifp->if_unit); 839*52130Smckusick /* 840*52130Smckusick * If the state of the promiscuous bit changes, the interface 841*52130Smckusick * must be reset to effect the change. 842*52130Smckusick */ 843*52130Smckusick if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 844*52130Smckusick (ifp->if_flags & IFF_RUNNING)) { 845*52130Smckusick le->sc_iflags = ifp->if_flags; 846*52130Smckusick lereset(ifp->if_unit); 847*52130Smckusick lestart(ifp); 848*52130Smckusick } 849*52130Smckusick break; 850*52130Smckusick 851*52130Smckusick default: 852*52130Smckusick error = EINVAL; 853*52130Smckusick } 854*52130Smckusick splx(s); 855*52130Smckusick return (error); 856*52130Smckusick } 857*52130Smckusick 858*52130Smckusick leerror(unit, stat) 859*52130Smckusick int unit; 860*52130Smckusick int stat; 861*52130Smckusick { 862*52130Smckusick if (!ledebug) 863*52130Smckusick return; 864*52130Smckusick 865*52130Smckusick /* 866*52130Smckusick * Not all transceivers implement heartbeat 867*52130Smckusick * so we only log CERR once. 868*52130Smckusick */ 869*52130Smckusick if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 870*52130Smckusick return; 871*52130Smckusick log(LOG_WARNING, 872*52130Smckusick "le%d: error: stat=%b\n", unit, 873*52130Smckusick stat, 874*52130Smckusick "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 875*52130Smckusick } 876*52130Smckusick 877*52130Smckusick lererror(unit, msg) 878*52130Smckusick int unit; 879*52130Smckusick char *msg; 880*52130Smckusick { 881*52130Smckusick register struct le_softc *le = &le_softc[unit]; 882*52130Smckusick register volatile struct lermd *rmd; 883*52130Smckusick int len; 884*52130Smckusick 885*52130Smckusick if (!ledebug) 886*52130Smckusick return; 887*52130Smckusick 888*52130Smckusick rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 889*52130Smckusick len = rmd->rmd3; 890*52130Smckusick log(LOG_WARNING, 891*52130Smckusick "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 892*52130Smckusick unit, msg, 893*52130Smckusick len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown", 894*52130Smckusick le->sc_rmd, len, 895*52130Smckusick rmd->rmd1, 896*52130Smckusick "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 897*52130Smckusick } 898*52130Smckusick 899*52130Smckusick lexerror(unit) 900*52130Smckusick int unit; 901*52130Smckusick { 902*52130Smckusick register struct le_softc *le = &le_softc[unit]; 903*52130Smckusick register volatile struct letmd *tmd; 904*52130Smckusick int len; 905*52130Smckusick 906*52130Smckusick if (!ledebug) 907*52130Smckusick return; 908*52130Smckusick 909*52130Smckusick tmd = le->sc_r2->ler2_tmd; 910*52130Smckusick len = -tmd->tmd2; 911*52130Smckusick log(LOG_WARNING, 912*52130Smckusick "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 913*52130Smckusick unit, 914*52130Smckusick len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown", 915*52130Smckusick 0, len, 916*52130Smckusick tmd->tmd1, 917*52130Smckusick "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 918*52130Smckusick tmd->tmd3, 919*52130Smckusick "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 920*52130Smckusick } 921*52130Smckusick #endif 922