123557Ssklower /* 229367Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335323Sbostic * All rights reserved. 423557Ssklower * 535323Sbostic * Redistribution and use in source and binary forms are permitted 635323Sbostic * provided that the above copyright notice and this paragraph are 735323Sbostic * duplicated in all such forms and that any documentation, 835323Sbostic * advertising materials, and other materials related to such 935323Sbostic * distribution and use acknowledge that the software was developed 1035323Sbostic * by the University of California, Berkeley. The name of the 1135323Sbostic * University may not be used to endorse or promote products derived 1235323Sbostic * from this software without specific prior written permission. 1335323Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435323Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535323Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635323Sbostic * 17*37476Ssklower * @(#)if_il.c 7.4 (Berkeley) 04/22/89 1823557Ssklower */ 196893Sfeldman 206893Sfeldman #include "il.h" 2125274Sbloom #if NIL > 0 226893Sfeldman 236893Sfeldman /* 246893Sfeldman * Interlan Ethernet Communications Controller interface 256893Sfeldman */ 269797Ssam #include "../machine/pte.h" 279797Ssam 2817115Sbloom #include "param.h" 2917115Sbloom #include "systm.h" 3017115Sbloom #include "mbuf.h" 3117115Sbloom #include "buf.h" 3217115Sbloom #include "protosw.h" 3317115Sbloom #include "socket.h" 3417115Sbloom #include "vmmac.h" 3517115Sbloom #include "ioctl.h" 3617115Sbloom #include "errno.h" 3729730Ssklower #include "syslog.h" 388463Sroot 398463Sroot #include "../net/if.h" 408463Sroot #include "../net/netisr.h" 418463Sroot #include "../net/route.h" 4223557Ssklower 4323557Ssklower #ifdef INET 448419Swnj #include "../netinet/in.h" 458419Swnj #include "../netinet/in_systm.h" 4619865Skarels #include "../netinet/in_var.h" 478419Swnj #include "../netinet/ip.h" 4811575Ssam #include "../netinet/if_ether.h" 4923557Ssklower #endif 5023557Ssklower 5123557Ssklower #ifdef NS 5223557Ssklower #include "../netns/ns.h" 5323557Ssklower #include "../netns/ns_if.h" 5423557Ssklower #endif 5523557Ssklower 568463Sroot #include "../vax/cpu.h" 578463Sroot #include "../vax/mtpr.h" 5817115Sbloom #include "if_il.h" 5917115Sbloom #include "if_ilreg.h" 6017115Sbloom #include "if_uba.h" 618463Sroot #include "../vaxuba/ubareg.h" 628463Sroot #include "../vaxuba/ubavar.h" 638463Sroot 646893Sfeldman int ilprobe(), ilattach(), ilrint(), ilcint(); 656893Sfeldman struct uba_device *ilinfo[NIL]; 666893Sfeldman u_short ilstd[] = { 0 }; 676893Sfeldman struct uba_driver ildriver = 686893Sfeldman { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo }; 696893Sfeldman #define ILUNIT(x) minor(x) 70*37476Ssklower int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(),ilstart(); 7126167Skarels int ildebug = 0; 726893Sfeldman 736893Sfeldman /* 746893Sfeldman * Ethernet software status per interface. 756893Sfeldman * 766893Sfeldman * Each interface is referenced by a network interface structure, 776893Sfeldman * is_if, which the routing code uses to locate the interface. 786893Sfeldman * This structure contains the output queue for the interface, its address, ... 796893Sfeldman * We also have, for each interface, a UBA interface structure, which 806893Sfeldman * contains information about the UNIBUS resources held by the interface: 816893Sfeldman * map registers, buffered data paths, etc. Information is cached in this 826893Sfeldman * structure for use by the if_uba.c routines in running the interface 836893Sfeldman * efficiently. 846893Sfeldman */ 85*37476Ssklower 86*37476Ssklower struct ether_addr { 87*37476Ssklower u_char addr[6]; 88*37476Ssklower }; 896893Sfeldman struct il_softc { 9011575Ssam struct arpcom is_ac; /* Ethernet common part */ 9111575Ssam #define is_if is_ac.ac_if /* network-visible interface */ 9211575Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 936893Sfeldman struct ifuba is_ifuba; /* UNIBUS resources */ 947261Ssam int is_flags; 957261Ssam #define ILF_RCVPENDING 0x2 /* start rcv in ilcint */ 967261Ssam #define ILF_STATPENDING 0x4 /* stat cmd pending */ 9725444Skarels #define ILF_RUNNING 0x8 /* board is running */ 9825976Skarels #define ILF_SETADDR 0x10 /* physical address is changed */ 997261Ssam short is_lastcmd; /* can't read csr, so must save it */ 1007261Ssam short is_scaninterval; /* interval of stat collection */ 1017261Ssam #define ILWATCHINTERVAL 60 /* once every 60 seconds */ 102*37476Ssklower union { 103*37476Ssklower struct il_stats isu_stats; /* holds on-board statistics */ 104*37476Ssklower struct ether_addr isu_maddrs[63]; /* multicast addrs */ 105*37476Ssklower } is_isu; 106*37476Ssklower #define is_stats is_isu.isu_stats 107*37476Ssklower #define is_maddrs is_isu.isu_maddrs 1087261Ssam struct il_stats is_sum; /* summation over time */ 1097261Ssam int is_ubaddr; /* mapping registers of is_stats */ 1106893Sfeldman } il_softc[NIL]; 1116893Sfeldman 1126893Sfeldman ilprobe(reg) 1136893Sfeldman caddr_t reg; 1146893Sfeldman { 1156893Sfeldman register int br, cvec; /* r11, r10 value-result */ 1166893Sfeldman register struct ildevice *addr = (struct ildevice *)reg; 1176893Sfeldman register i; 1186893Sfeldman 1196893Sfeldman #ifdef lint 1206893Sfeldman br = 0; cvec = br; br = cvec; 1219179Ssam i = 0; ilrint(i); ilcint(i); ilwatch(i); 1226893Sfeldman #endif 1236893Sfeldman 1246893Sfeldman addr->il_csr = ILC_OFFLINE|IL_CIE; 1256893Sfeldman DELAY(100000); 1267261Ssam i = addr->il_csr; /* clear CDONE */ 1276893Sfeldman if (cvec > 0 && cvec != 0x200) 1286893Sfeldman cvec -= 4; 1296893Sfeldman return (1); 1306893Sfeldman } 1316893Sfeldman 1326893Sfeldman /* 1336893Sfeldman * Interface exists: make available by filling in network interface 1346893Sfeldman * record. System will initialize the interface when it is ready 1356893Sfeldman * to accept packets. A STATUS command is done to get the ethernet 1366893Sfeldman * address and other interesting data. 1376893Sfeldman */ 1386893Sfeldman ilattach(ui) 1396893Sfeldman struct uba_device *ui; 1406893Sfeldman { 1416893Sfeldman register struct il_softc *is = &il_softc[ui->ui_unit]; 1427220Ssam register struct ifnet *ifp = &is->is_if; 1436893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 1446893Sfeldman 1457220Ssam ifp->if_unit = ui->ui_unit; 1467220Ssam ifp->if_name = "il"; 1479746Ssam ifp->if_mtu = ETHERMTU; 14819865Skarels ifp->if_flags = IFF_BROADCAST; 1496893Sfeldman 1506893Sfeldman /* 1517261Ssam * Reset the board and map the statistics 1527261Ssam * buffer onto the Unibus. 1536893Sfeldman */ 1547261Ssam addr->il_csr = ILC_RESET; 15525976Skarels (void)ilwait(ui, "reset"); 1566893Sfeldman 1579179Ssam is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 15813056Ssam sizeof (struct il_stats), 0); 1597261Ssam addr->il_bar = is->is_ubaddr & 0xffff; 1607261Ssam addr->il_bcr = sizeof (struct il_stats); 1617261Ssam addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 16225976Skarels (void)ilwait(ui, "status"); 1637261Ssam ubarelse(ui->ui_ubanum, &is->is_ubaddr); 16426167Skarels if (ildebug) 16526167Skarels printf("il%d: module=%s firmware=%s\n", ui->ui_unit, 16626167Skarels is->is_stats.ils_module, is->is_stats.ils_firmware); 16719865Skarels bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 16819865Skarels sizeof (is->is_addr)); 16925976Skarels printf("il%d: hardware address %s\n", ui->ui_unit, 17025976Skarels ether_sprintf(is->is_addr)); 1717220Ssam ifp->if_init = ilinit; 172*37476Ssklower ifp->if_output = ether_output; 17313056Ssam ifp->if_ioctl = ilioctl; 1748979Sroot ifp->if_reset = ilreset; 175*37476Ssklower ifp->if_start = ilstart; 1766893Sfeldman is->is_ifuba.ifu_flags = UBA_CANTWAIT; 1777220Ssam if_attach(ifp); 1786893Sfeldman } 1796893Sfeldman 18025976Skarels ilwait(ui, op) 18125976Skarels struct uba_device *ui; 18225976Skarels char *op; 18325976Skarels { 18425976Skarels register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 18525976Skarels 18625976Skarels while ((addr->il_csr&IL_CDONE) == 0) 18725976Skarels ; 18825976Skarels if (addr->il_csr&IL_STATUS) { 18925976Skarels printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op, 19025976Skarels addr->il_csr, IL_BITS); 19125976Skarels return (-1); 19225976Skarels } 19325976Skarels return (0); 19425976Skarels } 19525976Skarels 1966893Sfeldman /* 1976893Sfeldman * Reset of interface after UNIBUS reset. 1986893Sfeldman * If interface is on specified uba, reset its state. 1996893Sfeldman */ 2006893Sfeldman ilreset(unit, uban) 2016893Sfeldman int unit, uban; 2026893Sfeldman { 2036893Sfeldman register struct uba_device *ui; 2046893Sfeldman 2056893Sfeldman if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 2066893Sfeldman ui->ui_ubanum != uban) 2076893Sfeldman return; 2086893Sfeldman printf(" il%d", unit); 20925444Skarels il_softc[unit].is_if.if_flags &= ~IFF_RUNNING; 21025444Skarels il_softc[unit].is_flags &= ~ILF_RUNNING; 2116893Sfeldman ilinit(unit); 2126893Sfeldman } 2136893Sfeldman 2146893Sfeldman /* 2156893Sfeldman * Initialization of interface; clear recorded pending 2166893Sfeldman * operations, and reinitialize UNIBUS usage. 2176893Sfeldman */ 2186893Sfeldman ilinit(unit) 2196893Sfeldman int unit; 2206893Sfeldman { 2216893Sfeldman register struct il_softc *is = &il_softc[unit]; 2226893Sfeldman register struct uba_device *ui = ilinfo[unit]; 2236893Sfeldman register struct ildevice *addr; 22413056Ssam register struct ifnet *ifp = &is->is_if; 2257261Ssam int s; 2266893Sfeldman 22719865Skarels /* not yet, if address still unknown */ 22819865Skarels if (ifp->if_addrlist == (struct ifaddr *)0) 22911575Ssam return; 23025444Skarels if (is->is_flags & ILF_RUNNING) 23125444Skarels return; 23211575Ssam 23325444Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 23425444Skarels if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 23525444Skarels sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 23625444Skarels printf("il%d: can't initialize\n", unit); 23725444Skarels is->is_if.if_flags &= ~IFF_UP; 23825444Skarels return; 23925444Skarels } 240*37476Ssklower is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_isu, 241*37476Ssklower sizeof (is->is_isu), 0); 2426893Sfeldman } 24315071Skarels ifp->if_watchdog = ilwatch; 24415071Skarels is->is_scaninterval = ILWATCHINTERVAL; 24515071Skarels ifp->if_timer = is->is_scaninterval; 2466893Sfeldman addr = (struct ildevice *)ui->ui_addr; 2476893Sfeldman 2486893Sfeldman /* 2499179Ssam * Turn off source address insertion (it's faster this way), 25012488Ssam * and set board online. Former doesn't work if board is 25112488Ssam * already online (happens on ubareset), so we put it offline 25212488Ssam * first. 2539179Ssam */ 2549179Ssam s = splimp(); 25525444Skarels addr->il_csr = ILC_RESET; 25625976Skarels if (ilwait(ui, "hardware diag")) { 25725444Skarels is->is_if.if_flags &= ~IFF_UP; 25825444Skarels splx(s); 25925444Skarels return; 26025444Skarels } 26112488Ssam addr->il_csr = ILC_CISA; 2629179Ssam while ((addr->il_csr & IL_CDONE) == 0) 2639179Ssam ; 2649179Ssam /* 26526145Ssklower * If we must reprogram this board's physical ethernet 26626145Ssklower * address (as for secondary XNS interfaces), we do so 26726145Ssklower * before putting it on line, and starting receive requests. 26826145Ssklower * If you try this on an older 1010 board, it will total 26926145Ssklower * wedge the board. 27026145Ssklower */ 27126145Ssklower if (is->is_flags & ILF_SETADDR) { 272*37476Ssklower bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_isu, 27326145Ssklower sizeof is->is_addr); 27426145Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 27526145Ssklower addr->il_bcr = sizeof is->is_addr; 27626145Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA; 27726145Ssklower if (ilwait(ui, "setaddr")) 27826145Ssklower return; 27926145Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 28026145Ssklower addr->il_bcr = sizeof (struct il_stats); 28126145Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 28226145Ssklower if (ilwait(ui, "verifying setaddr")) 28326145Ssklower return; 28426145Ssklower if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 28526145Ssklower sizeof (is->is_addr)) != 0) { 28626145Ssklower printf("il%d: setaddr didn't work\n", ui->ui_unit); 28726145Ssklower return; 28826145Ssklower } 28926145Ssklower } 290*37476Ssklower #ifdef MULTICAST 291*37476Ssklower if (is->is_if.if_flags & IFF_PROMISC) { 292*37476Ssklower addr->il_csr = ILC_PRMSC; 293*37476Ssklower if (ilwait(ui, "all multi")) 294*37476Ssklower return; 295*37476Ssklower } else if (is->is_if.if_flags & IFF_ALLMULTI) { 296*37476Ssklower too_many_multis: 297*37476Ssklower addr->il_csr = ILC_ALLMC; 298*37476Ssklower if (ilwait(ui, "all multi")) 299*37476Ssklower return; 300*37476Ssklower else { 301*37476Ssklower int i; 302*37476Ssklower register struct ether_addr *ep = is->is_maddrs; 303*37476Ssklower struct ether_multi *enm; 304*37476Ssklower struct ether_multistep step; 305*37476Ssklower /* 306*37476Ssklower * Step through our list of multicast addresses. If we have 307*37476Ssklower * too many multicast addresses, or if we have to listen to 308*37476Ssklower * a range of multicast addresses, turn on reception of all 309*37476Ssklower * multicasts. 310*37476Ssklower */ 311*37476Ssklower i = 0; 312*37476Ssklower ETHER_FIRST_MULTI(step, &is->is_ac, enm); 313*37476Ssklower while (enm != NULL) { 314*37476Ssklower if (++i > 63 && k != 0) { 315*37476Ssklower break; 316*37476Ssklower } 317*37476Ssklower *ep++ = *(struct ether_addr *)enm->enm_addrlo; 318*37476Ssklower ETHER_NEXT_MULTI(step, enm); 319*37476Ssklower } 320*37476Ssklower if (i = 0) { 321*37476Ssklower /* no multicasts! */ 322*37476Ssklower } else if (i <= 63) { 323*37476Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 324*37476Ssklower addr->il_bcr = i * sizeof (struct ether_addr); 325*37476Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)| 326*37476Ssklower LC_LDGRPS; 327*37476Ssklower if (ilwait(ui, "load multi")) 328*37476Ssklower return; 329*37476Ssklower } else { 330*37476Ssklower is->is_if.if_flags |= IFF_ALLMULTI; 331*37476Ssklower goto too_many_multis; 332*37476Ssklower } 333*37476Ssklower } 334*37476Ssklower #endif MULTI 33526145Ssklower /* 3366893Sfeldman * Set board online. 3376893Sfeldman * Hang receive buffer and start any pending 3386893Sfeldman * writes by faking a transmit complete. 33925444Skarels * Receive bcr is not a multiple of 8 so buffer 3406893Sfeldman * chaining can't happen. 3416893Sfeldman */ 3426893Sfeldman addr->il_csr = ILC_ONLINE; 3437220Ssam while ((addr->il_csr & IL_CDONE) == 0) 3447220Ssam ; 3456893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 3469746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 3477261Ssam addr->il_csr = 34813056Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 3497220Ssam while ((addr->il_csr & IL_CDONE) == 0) 3507220Ssam ; 351*37476Ssklower is->is_if.if_flags = IFF_OACTIVE; 35219865Skarels is->is_if.if_flags |= IFF_RUNNING; 35325444Skarels is->is_flags |= ILF_RUNNING; 3547261Ssam is->is_lastcmd = 0; 3556893Sfeldman ilcint(unit); 3566893Sfeldman splx(s); 3576893Sfeldman } 3586893Sfeldman 3596893Sfeldman /* 3606893Sfeldman * Start output on interface. 3616893Sfeldman * Get another datagram to send off of the interface queue, 3626893Sfeldman * and map it to the interface before starting the output. 3636893Sfeldman */ 364*37476Ssklower ilstart(ifp) 365*37476Ssklower register struct ifnet *ifp; 3666893Sfeldman { 367*37476Ssklower int unit = ifp->if_unit, len; 3686893Sfeldman struct uba_device *ui = ilinfo[unit]; 3696893Sfeldman register struct il_softc *is = &il_softc[unit]; 3706893Sfeldman register struct ildevice *addr; 3716893Sfeldman struct mbuf *m; 3727220Ssam short csr; 3736893Sfeldman 3746893Sfeldman IF_DEQUEUE(&is->is_if.if_snd, m); 3757261Ssam addr = (struct ildevice *)ui->ui_addr; 3767261Ssam if (m == 0) { 3777261Ssam if ((is->is_flags & ILF_STATPENDING) == 0) 378*37476Ssklower return (0); 3799179Ssam addr->il_bar = is->is_ubaddr & 0xffff; 3807261Ssam addr->il_bcr = sizeof (struct il_stats); 3817261Ssam csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; 3827261Ssam is->is_flags &= ~ILF_STATPENDING; 3837261Ssam goto startcmd; 3847261Ssam } 3856893Sfeldman len = if_wubaput(&is->is_ifuba, m); 3869179Ssam /* 3879179Ssam * Ensure minimum packet length. 3889179Ssam * This makes the safe assumtion that there are no virtual holes 3899179Ssam * after the data. 3909179Ssam * For security, it might be wise to zero out the added bytes, 3919179Ssam * but we're mainly interested in speed at the moment. 3929179Ssam */ 3939746Ssam if (len - sizeof(struct ether_header) < ETHERMIN) 3949746Ssam len = ETHERMIN + sizeof(struct ether_header); 3956893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 3966893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 3976893Sfeldman addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 3986893Sfeldman addr->il_bcr = len; 3997261Ssam csr = 4007261Ssam ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE; 4017261Ssam 4027261Ssam startcmd: 4037261Ssam is->is_lastcmd = csr & IL_CMD; 4047220Ssam addr->il_csr = csr; 405*37476Ssklower is->is_if.if_flags |= IFF_OACTIVE; 406*37476Ssklower return (0); 4076893Sfeldman } 4086893Sfeldman 4096893Sfeldman /* 4106893Sfeldman * Command done interrupt. 4116893Sfeldman */ 4126893Sfeldman ilcint(unit) 4136893Sfeldman int unit; 4146893Sfeldman { 4156893Sfeldman register struct il_softc *is = &il_softc[unit]; 4167220Ssam struct uba_device *ui = ilinfo[unit]; 4176893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 4187266Ssam short csr; 4196893Sfeldman 420*37476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) { 4217220Ssam printf("il%d: stray xmit interrupt, csr=%b\n", unit, 4227261Ssam addr->il_csr, IL_BITS); 4236893Sfeldman return; 4246893Sfeldman } 4257220Ssam 4267266Ssam csr = addr->il_csr; 4276893Sfeldman /* 4287261Ssam * Hang receive buffer if it couldn't 4297261Ssam * be done earlier (in ilrint). 4306893Sfeldman */ 4317261Ssam if (is->is_flags & ILF_RCVPENDING) { 43225444Skarels int s; 43325444Skarels 4346893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 4359746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 4367261Ssam addr->il_csr = 4377261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 43825444Skarels s = splhigh(); 4397220Ssam while ((addr->il_csr & IL_CDONE) == 0) 4407220Ssam ; 44125444Skarels splx(s); 4427261Ssam is->is_flags &= ~ILF_RCVPENDING; 4436893Sfeldman } 444*37476Ssklower is->is_if.if_flags &= ~IFF_OACTIVE; 4457266Ssam csr &= IL_STATUS; 4467261Ssam switch (is->is_lastcmd) { 4477261Ssam 4487261Ssam case ILC_XMIT: 4497261Ssam is->is_if.if_opackets++; 4507266Ssam if (csr > ILERR_RETRIES) 4517261Ssam is->is_if.if_oerrors++; 4527261Ssam break; 4537261Ssam 4547261Ssam case ILC_STAT: 4557266Ssam if (csr == ILERR_SUCCESS) 4567261Ssam iltotal(is); 4577261Ssam break; 4587261Ssam } 4596893Sfeldman if (is->is_ifuba.ifu_xtofree) { 4606893Sfeldman m_freem(is->is_ifuba.ifu_xtofree); 4616893Sfeldman is->is_ifuba.ifu_xtofree = 0; 4626893Sfeldman } 463*37476Ssklower (void) ilstart(&is->is_if); 4646893Sfeldman } 4656893Sfeldman 4666893Sfeldman /* 4676893Sfeldman * Ethernet interface receiver interrupt. 4686893Sfeldman * If input error just drop packet. 4696893Sfeldman * Otherwise purge input buffered data path and examine 4706893Sfeldman * packet to determine type. If can't determine length 4716893Sfeldman * from type, then have to drop packet. Othewise decapsulate 4726893Sfeldman * packet based on type and pass to type specific higher-level 4736893Sfeldman * input routine. 4746893Sfeldman */ 4756893Sfeldman ilrint(unit) 4766893Sfeldman int unit; 4776893Sfeldman { 4786893Sfeldman register struct il_softc *is = &il_softc[unit]; 4796893Sfeldman struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 4806893Sfeldman register struct il_rheader *il; 4816893Sfeldman struct mbuf *m; 48215787Sleres int len, off, resid, s; 4836893Sfeldman register struct ifqueue *inq; 4846893Sfeldman 4856893Sfeldman is->is_if.if_ipackets++; 4866893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 4876893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 4886893Sfeldman il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 4896893Sfeldman len = il->ilr_length - sizeof(struct il_rheader); 4909746Ssam if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || 4919746Ssam len > ETHERMTU) { 4926893Sfeldman is->is_if.if_ierrors++; 4936893Sfeldman #ifdef notdef 4946893Sfeldman if (is->is_if.if_ierrors % 100 == 0) 4956893Sfeldman printf("il%d: += 100 input errors\n", unit); 4966893Sfeldman #endif 4976893Sfeldman goto setup; 4986893Sfeldman } 4996893Sfeldman 5006893Sfeldman /* 50119865Skarels * Deal with trailer protocol: if type is trailer type 5026893Sfeldman * get true type from first 16-bit word past data. 5036893Sfeldman * Remember that type was trailer by setting off. 5046893Sfeldman */ 5059746Ssam il->ilr_type = ntohs((u_short)il->ilr_type); 5066893Sfeldman #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 50719865Skarels if (il->ilr_type >= ETHERTYPE_TRAIL && 50819865Skarels il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 50919865Skarels off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; 5109746Ssam if (off >= ETHERMTU) 5116893Sfeldman goto setup; /* sanity */ 5129746Ssam il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); 5139746Ssam resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 5146893Sfeldman if (off + resid > len) 5156893Sfeldman goto setup; /* sanity */ 5166893Sfeldman len = off + resid; 5176893Sfeldman } else 5186893Sfeldman off = 0; 5196893Sfeldman if (len == 0) 5206893Sfeldman goto setup; 5216893Sfeldman 5226893Sfeldman /* 5236893Sfeldman * Pull packet off interface. Off is nonzero if packet 5246893Sfeldman * has trailing header; ilget will then force this header 5256893Sfeldman * information to be at the front, but we still have to drop 5266893Sfeldman * the type and length which are at the front of any trailer data. 5276893Sfeldman */ 52824791Skarels m = if_rubaget(&is->is_ifuba, len, off, &is->is_if); 529*37476Ssklower if (m) 530*37476Ssklower ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m); 5316893Sfeldman setup: 5326893Sfeldman /* 5336893Sfeldman * Reset for next packet if possible. 5346893Sfeldman * If waiting for transmit command completion, set flag 5356893Sfeldman * and wait until command completes. 5366893Sfeldman */ 537*37476Ssklower if (is->is_if.if_flags & IFF_OACTIVE) { 5387261Ssam is->is_flags |= ILF_RCVPENDING; 5397220Ssam return; 5407220Ssam } 5417220Ssam addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 5429746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 5437261Ssam addr->il_csr = 5447261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 54525444Skarels s = splhigh(); 5467220Ssam while ((addr->il_csr & IL_CDONE) == 0) 5477220Ssam ; 54825444Skarels splx(s); 5496893Sfeldman } 5506893Sfeldman /* 5517261Ssam * Watchdog routine, request statistics from board. 5527261Ssam */ 5537261Ssam ilwatch(unit) 5547261Ssam int unit; 5557261Ssam { 5567261Ssam register struct il_softc *is = &il_softc[unit]; 5577261Ssam register struct ifnet *ifp = &is->is_if; 5587261Ssam int s; 5597261Ssam 5607261Ssam if (is->is_flags & ILF_STATPENDING) { 5617261Ssam ifp->if_timer = is->is_scaninterval; 5627261Ssam return; 5637261Ssam } 5647261Ssam s = splimp(); 5657261Ssam is->is_flags |= ILF_STATPENDING; 566*37476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) 567*37476Ssklower (void) ilstart(ifp); 5687261Ssam splx(s); 5697261Ssam ifp->if_timer = is->is_scaninterval; 5707261Ssam } 5717261Ssam 5727261Ssam /* 5737261Ssam * Total up the on-board statistics. 5747261Ssam */ 5757261Ssam iltotal(is) 5767261Ssam register struct il_softc *is; 5777261Ssam { 5787261Ssam register u_short *interval, *sum, *end; 5797261Ssam 5807261Ssam interval = &is->is_stats.ils_frames; 5817261Ssam sum = &is->is_sum.ils_frames; 5827261Ssam end = is->is_sum.ils_fill2; 5837261Ssam while (sum < end) 5847261Ssam *sum++ += *interval++; 5857261Ssam is->is_if.if_collisions = is->is_sum.ils_collis; 58629730Ssklower if ((is->is_flags & ILF_SETADDR) && 58729730Ssklower (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 58829730Ssklower sizeof (is->is_addr)) != 0)) { 58929730Ssklower log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit); 59029730Ssklower is->is_flags &= ~ILF_RUNNING; 59129730Ssklower ilinit(is->is_if.if_unit); 59229730Ssklower } 5937261Ssam } 59413056Ssam 59513056Ssam /* 59613056Ssam * Process an ioctl request. 59713056Ssam */ 59813056Ssam ilioctl(ifp, cmd, data) 59913056Ssam register struct ifnet *ifp; 60013056Ssam int cmd; 60113056Ssam caddr_t data; 60213056Ssam { 60319865Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 60425444Skarels register struct il_softc *is = &il_softc[ifp->if_unit]; 60513056Ssam int s = splimp(), error = 0; 60613056Ssam 60713056Ssam switch (cmd) { 60813056Ssam 60913056Ssam case SIOCSIFADDR: 61019865Skarels ifp->if_flags |= IFF_UP; 61113056Ssam ilinit(ifp->if_unit); 61219865Skarels 613*37476Ssklower switch (ifa->ifa_addr->sa_family) { 61423557Ssklower #ifdef INET 61519865Skarels case AF_INET: 61619865Skarels ((struct arpcom *)ifp)->ac_ipaddr = 61719865Skarels IA_SIN(ifa)->sin_addr; 61819865Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 61919865Skarels break; 62023557Ssklower #endif 62123557Ssklower #ifdef NS 62223557Ssklower case AF_NS: 62325976Skarels { 62425976Skarels register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 62525976Skarels 62625976Skarels if (ns_nullhost(*ina)) { 62725976Skarels ina->x_host = * (union ns_host *) 62825976Skarels (il_softc[ifp->if_unit].is_addr); 62925976Skarels } else { 63025976Skarels il_setaddr(ina->x_host.c_host, ifp->if_unit); 63126145Ssklower return (0); 63225976Skarels } 63323557Ssklower break; 63425976Skarels } 63523557Ssklower #endif 63619865Skarels } 63713056Ssam break; 63813056Ssam 63925444Skarels case SIOCSIFFLAGS: 64025444Skarels if ((ifp->if_flags & IFF_UP) == 0 && 64125444Skarels is->is_flags & ILF_RUNNING) { 64225444Skarels ((struct ildevice *) 64325444Skarels (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; 64425444Skarels is->is_flags &= ~ILF_RUNNING; 64525444Skarels } else if (ifp->if_flags & IFF_UP && 64625444Skarels (is->is_flags & ILF_RUNNING) == 0) 64725444Skarels ilinit(ifp->if_unit); 64825444Skarels break; 64925444Skarels 65013056Ssam default: 65113056Ssam error = EINVAL; 65213056Ssam } 65313056Ssam splx(s); 65413056Ssam return (error); 65513056Ssam } 65625976Skarels 65725976Skarels /* 65825976Skarels * set ethernet address for unit 65925976Skarels */ 66025976Skarels il_setaddr(physaddr, unit) 66125976Skarels u_char *physaddr; 66225976Skarels int unit; 66325976Skarels { 66425976Skarels register struct il_softc *is = &il_softc[unit]; 66525976Skarels 66625976Skarels if (! (is->is_flags & ILF_RUNNING)) 66725976Skarels return; 66825976Skarels 66926145Ssklower bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); 67026145Ssklower is->is_flags &= ~ILF_RUNNING; 67126145Ssklower is->is_flags |= ILF_SETADDR; 67226145Ssklower ilinit(unit); 67325976Skarels } 67425274Sbloom #endif 675