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