123557Ssklower /* 229367Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335323Sbostic * All rights reserved. 423557Ssklower * 5*44560Sbostic * %sccs.include.redist.c% 635323Sbostic * 7*44560Sbostic * @(#)if_il.c 7.7 (Berkeley) 06/28/90 823557Ssklower */ 96893Sfeldman 106893Sfeldman #include "il.h" 1125274Sbloom #if NIL > 0 126893Sfeldman 136893Sfeldman /* 146893Sfeldman * Interlan Ethernet Communications Controller interface 156893Sfeldman */ 1637508Smckusick #include "machine/pte.h" 179797Ssam 1817115Sbloom #include "param.h" 1917115Sbloom #include "systm.h" 2017115Sbloom #include "mbuf.h" 2117115Sbloom #include "buf.h" 2217115Sbloom #include "protosw.h" 2317115Sbloom #include "socket.h" 2417115Sbloom #include "vmmac.h" 2517115Sbloom #include "ioctl.h" 2617115Sbloom #include "errno.h" 2729730Ssklower #include "syslog.h" 288463Sroot 298463Sroot #include "../net/if.h" 308463Sroot #include "../net/netisr.h" 318463Sroot #include "../net/route.h" 3223557Ssklower 3323557Ssklower #ifdef INET 348419Swnj #include "../netinet/in.h" 358419Swnj #include "../netinet/in_systm.h" 3619865Skarels #include "../netinet/in_var.h" 378419Swnj #include "../netinet/ip.h" 3811575Ssam #include "../netinet/if_ether.h" 3923557Ssklower #endif 4023557Ssklower 4123557Ssklower #ifdef NS 4223557Ssklower #include "../netns/ns.h" 4323557Ssklower #include "../netns/ns_if.h" 4423557Ssklower #endif 4523557Ssklower 468463Sroot #include "../vax/cpu.h" 478463Sroot #include "../vax/mtpr.h" 4817115Sbloom #include "if_il.h" 4917115Sbloom #include "if_ilreg.h" 5017115Sbloom #include "if_uba.h" 518463Sroot #include "../vaxuba/ubareg.h" 528463Sroot #include "../vaxuba/ubavar.h" 538463Sroot 546893Sfeldman int ilprobe(), ilattach(), ilrint(), ilcint(); 556893Sfeldman struct uba_device *ilinfo[NIL]; 566893Sfeldman u_short ilstd[] = { 0 }; 576893Sfeldman struct uba_driver ildriver = 586893Sfeldman { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo }; 596893Sfeldman #define ILUNIT(x) minor(x) 6037476Ssklower int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(),ilstart(); 6126167Skarels int ildebug = 0; 626893Sfeldman 636893Sfeldman /* 646893Sfeldman * Ethernet software status per interface. 656893Sfeldman * 666893Sfeldman * Each interface is referenced by a network interface structure, 676893Sfeldman * is_if, which the routing code uses to locate the interface. 686893Sfeldman * This structure contains the output queue for the interface, its address, ... 696893Sfeldman * We also have, for each interface, a UBA interface structure, which 706893Sfeldman * contains information about the UNIBUS resources held by the interface: 716893Sfeldman * map registers, buffered data paths, etc. Information is cached in this 726893Sfeldman * structure for use by the if_uba.c routines in running the interface 736893Sfeldman * efficiently. 746893Sfeldman */ 7537476Ssklower 7637476Ssklower struct ether_addr { 7737476Ssklower u_char addr[6]; 7837476Ssklower }; 796893Sfeldman struct il_softc { 8011575Ssam struct arpcom is_ac; /* Ethernet common part */ 8111575Ssam #define is_if is_ac.ac_if /* network-visible interface */ 8211575Ssam #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 836893Sfeldman struct ifuba is_ifuba; /* UNIBUS resources */ 847261Ssam int is_flags; 857261Ssam #define ILF_RCVPENDING 0x2 /* start rcv in ilcint */ 867261Ssam #define ILF_STATPENDING 0x4 /* stat cmd pending */ 8725444Skarels #define ILF_RUNNING 0x8 /* board is running */ 8825976Skarels #define ILF_SETADDR 0x10 /* physical address is changed */ 897261Ssam short is_lastcmd; /* can't read csr, so must save it */ 907261Ssam short is_scaninterval; /* interval of stat collection */ 917261Ssam #define ILWATCHINTERVAL 60 /* once every 60 seconds */ 9237476Ssklower union { 9337476Ssklower struct il_stats isu_stats; /* holds on-board statistics */ 9437476Ssklower struct ether_addr isu_maddrs[63]; /* multicast addrs */ 9537476Ssklower } is_isu; 9637476Ssklower #define is_stats is_isu.isu_stats 9737476Ssklower #define is_maddrs is_isu.isu_maddrs 987261Ssam struct il_stats is_sum; /* summation over time */ 997261Ssam int is_ubaddr; /* mapping registers of is_stats */ 1006893Sfeldman } il_softc[NIL]; 1016893Sfeldman 1026893Sfeldman ilprobe(reg) 1036893Sfeldman caddr_t reg; 1046893Sfeldman { 1056893Sfeldman register int br, cvec; /* r11, r10 value-result */ 1066893Sfeldman register struct ildevice *addr = (struct ildevice *)reg; 1076893Sfeldman register i; 1086893Sfeldman 1096893Sfeldman #ifdef lint 1106893Sfeldman br = 0; cvec = br; br = cvec; 1119179Ssam i = 0; ilrint(i); ilcint(i); ilwatch(i); 1126893Sfeldman #endif 1136893Sfeldman 1146893Sfeldman addr->il_csr = ILC_OFFLINE|IL_CIE; 1156893Sfeldman DELAY(100000); 1167261Ssam i = addr->il_csr; /* clear CDONE */ 1176893Sfeldman if (cvec > 0 && cvec != 0x200) 1186893Sfeldman cvec -= 4; 1196893Sfeldman return (1); 1206893Sfeldman } 1216893Sfeldman 1226893Sfeldman /* 1236893Sfeldman * Interface exists: make available by filling in network interface 1246893Sfeldman * record. System will initialize the interface when it is ready 1256893Sfeldman * to accept packets. A STATUS command is done to get the ethernet 1266893Sfeldman * address and other interesting data. 1276893Sfeldman */ 1286893Sfeldman ilattach(ui) 1296893Sfeldman struct uba_device *ui; 1306893Sfeldman { 1316893Sfeldman register struct il_softc *is = &il_softc[ui->ui_unit]; 1327220Ssam register struct ifnet *ifp = &is->is_if; 1336893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 1346893Sfeldman 1357220Ssam ifp->if_unit = ui->ui_unit; 1367220Ssam ifp->if_name = "il"; 1379746Ssam ifp->if_mtu = ETHERMTU; 13819865Skarels ifp->if_flags = IFF_BROADCAST; 1396893Sfeldman 1406893Sfeldman /* 1417261Ssam * Reset the board and map the statistics 1427261Ssam * buffer onto the Unibus. 1436893Sfeldman */ 1447261Ssam addr->il_csr = ILC_RESET; 14525976Skarels (void)ilwait(ui, "reset"); 1466893Sfeldman 1479179Ssam is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 14813056Ssam sizeof (struct il_stats), 0); 1497261Ssam addr->il_bar = is->is_ubaddr & 0xffff; 1507261Ssam addr->il_bcr = sizeof (struct il_stats); 1517261Ssam addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 15225976Skarels (void)ilwait(ui, "status"); 1537261Ssam ubarelse(ui->ui_ubanum, &is->is_ubaddr); 15426167Skarels if (ildebug) 15526167Skarels printf("il%d: module=%s firmware=%s\n", ui->ui_unit, 15626167Skarels is->is_stats.ils_module, is->is_stats.ils_firmware); 15719865Skarels bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 15819865Skarels sizeof (is->is_addr)); 15925976Skarels printf("il%d: hardware address %s\n", ui->ui_unit, 16025976Skarels ether_sprintf(is->is_addr)); 1617220Ssam ifp->if_init = ilinit; 16237476Ssklower ifp->if_output = ether_output; 16313056Ssam ifp->if_ioctl = ilioctl; 1648979Sroot ifp->if_reset = ilreset; 16537476Ssklower ifp->if_start = ilstart; 1666893Sfeldman is->is_ifuba.ifu_flags = UBA_CANTWAIT; 1677220Ssam if_attach(ifp); 1686893Sfeldman } 1696893Sfeldman 17025976Skarels ilwait(ui, op) 17125976Skarels struct uba_device *ui; 17225976Skarels char *op; 17325976Skarels { 17425976Skarels register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 17525976Skarels 17625976Skarels while ((addr->il_csr&IL_CDONE) == 0) 17725976Skarels ; 17825976Skarels if (addr->il_csr&IL_STATUS) { 17925976Skarels printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op, 18025976Skarels addr->il_csr, IL_BITS); 18125976Skarels return (-1); 18225976Skarels } 18325976Skarels return (0); 18425976Skarels } 18525976Skarels 1866893Sfeldman /* 1876893Sfeldman * Reset of interface after UNIBUS reset. 1886893Sfeldman * If interface is on specified uba, reset its state. 1896893Sfeldman */ 1906893Sfeldman ilreset(unit, uban) 1916893Sfeldman int unit, uban; 1926893Sfeldman { 1936893Sfeldman register struct uba_device *ui; 1946893Sfeldman 1956893Sfeldman if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 1966893Sfeldman ui->ui_ubanum != uban) 1976893Sfeldman return; 1986893Sfeldman printf(" il%d", unit); 19925444Skarels il_softc[unit].is_if.if_flags &= ~IFF_RUNNING; 20025444Skarels il_softc[unit].is_flags &= ~ILF_RUNNING; 2016893Sfeldman ilinit(unit); 2026893Sfeldman } 2036893Sfeldman 2046893Sfeldman /* 2056893Sfeldman * Initialization of interface; clear recorded pending 2066893Sfeldman * operations, and reinitialize UNIBUS usage. 2076893Sfeldman */ 2086893Sfeldman ilinit(unit) 2096893Sfeldman int unit; 2106893Sfeldman { 2116893Sfeldman register struct il_softc *is = &il_softc[unit]; 2126893Sfeldman register struct uba_device *ui = ilinfo[unit]; 2136893Sfeldman register struct ildevice *addr; 21413056Ssam register struct ifnet *ifp = &is->is_if; 2157261Ssam int s; 2166893Sfeldman 21719865Skarels /* not yet, if address still unknown */ 21819865Skarels if (ifp->if_addrlist == (struct ifaddr *)0) 21911575Ssam return; 22025444Skarels if (is->is_flags & ILF_RUNNING) 22125444Skarels return; 22211575Ssam 22325444Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 22425444Skarels if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 22525444Skarels sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 22625444Skarels printf("il%d: can't initialize\n", unit); 22725444Skarels is->is_if.if_flags &= ~IFF_UP; 22825444Skarels return; 22925444Skarels } 23037476Ssklower is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_isu, 23137476Ssklower sizeof (is->is_isu), 0); 2326893Sfeldman } 23315071Skarels ifp->if_watchdog = ilwatch; 23415071Skarels is->is_scaninterval = ILWATCHINTERVAL; 23515071Skarels ifp->if_timer = is->is_scaninterval; 2366893Sfeldman addr = (struct ildevice *)ui->ui_addr; 2376893Sfeldman 2386893Sfeldman /* 2399179Ssam * Turn off source address insertion (it's faster this way), 24012488Ssam * and set board online. Former doesn't work if board is 24112488Ssam * already online (happens on ubareset), so we put it offline 24212488Ssam * first. 2439179Ssam */ 2449179Ssam s = splimp(); 24525444Skarels addr->il_csr = ILC_RESET; 24625976Skarels if (ilwait(ui, "hardware diag")) { 24725444Skarels is->is_if.if_flags &= ~IFF_UP; 24825444Skarels splx(s); 24925444Skarels return; 25025444Skarels } 25112488Ssam addr->il_csr = ILC_CISA; 2529179Ssam while ((addr->il_csr & IL_CDONE) == 0) 2539179Ssam ; 2549179Ssam /* 25526145Ssklower * If we must reprogram this board's physical ethernet 25626145Ssklower * address (as for secondary XNS interfaces), we do so 25726145Ssklower * before putting it on line, and starting receive requests. 25826145Ssklower * If you try this on an older 1010 board, it will total 25926145Ssklower * wedge the board. 26026145Ssklower */ 26126145Ssklower if (is->is_flags & ILF_SETADDR) { 26237476Ssklower bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_isu, 26326145Ssklower sizeof is->is_addr); 26426145Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 26526145Ssklower addr->il_bcr = sizeof is->is_addr; 26626145Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA; 26726145Ssklower if (ilwait(ui, "setaddr")) 26826145Ssklower return; 26926145Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 27026145Ssklower addr->il_bcr = sizeof (struct il_stats); 27126145Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 27226145Ssklower if (ilwait(ui, "verifying setaddr")) 27326145Ssklower return; 27426145Ssklower if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 27526145Ssklower sizeof (is->is_addr)) != 0) { 27626145Ssklower printf("il%d: setaddr didn't work\n", ui->ui_unit); 27726145Ssklower return; 27826145Ssklower } 27926145Ssklower } 28037476Ssklower #ifdef MULTICAST 28137476Ssklower if (is->is_if.if_flags & IFF_PROMISC) { 28237476Ssklower addr->il_csr = ILC_PRMSC; 28337476Ssklower if (ilwait(ui, "all multi")) 28437476Ssklower return; 28537476Ssklower } else if (is->is_if.if_flags & IFF_ALLMULTI) { 28637476Ssklower too_many_multis: 28737476Ssklower addr->il_csr = ILC_ALLMC; 28837476Ssklower if (ilwait(ui, "all multi")) 28937476Ssklower return; 29037476Ssklower else { 29137476Ssklower int i; 29237476Ssklower register struct ether_addr *ep = is->is_maddrs; 29337476Ssklower struct ether_multi *enm; 29437476Ssklower struct ether_multistep step; 29537476Ssklower /* 29637476Ssklower * Step through our list of multicast addresses. If we have 29737476Ssklower * too many multicast addresses, or if we have to listen to 29837476Ssklower * a range of multicast addresses, turn on reception of all 29937476Ssklower * multicasts. 30037476Ssklower */ 30137476Ssklower i = 0; 30237476Ssklower ETHER_FIRST_MULTI(step, &is->is_ac, enm); 30337476Ssklower while (enm != NULL) { 30437476Ssklower if (++i > 63 && k != 0) { 30537476Ssklower break; 30637476Ssklower } 30737476Ssklower *ep++ = *(struct ether_addr *)enm->enm_addrlo; 30837476Ssklower ETHER_NEXT_MULTI(step, enm); 30937476Ssklower } 31037476Ssklower if (i = 0) { 31137476Ssklower /* no multicasts! */ 31237476Ssklower } else if (i <= 63) { 31337476Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 31437476Ssklower addr->il_bcr = i * sizeof (struct ether_addr); 31537476Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)| 31637476Ssklower LC_LDGRPS; 31737476Ssklower if (ilwait(ui, "load multi")) 31837476Ssklower return; 31937476Ssklower } else { 32037476Ssklower is->is_if.if_flags |= IFF_ALLMULTI; 32137476Ssklower goto too_many_multis; 32237476Ssklower } 32337476Ssklower } 32437476Ssklower #endif MULTI 32526145Ssklower /* 3266893Sfeldman * Set board online. 3276893Sfeldman * Hang receive buffer and start any pending 3286893Sfeldman * writes by faking a transmit complete. 32925444Skarels * Receive bcr is not a multiple of 8 so buffer 3306893Sfeldman * chaining can't happen. 3316893Sfeldman */ 3326893Sfeldman addr->il_csr = ILC_ONLINE; 3337220Ssam while ((addr->il_csr & IL_CDONE) == 0) 3347220Ssam ; 3356893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 3369746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 3377261Ssam addr->il_csr = 33813056Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 3397220Ssam while ((addr->il_csr & IL_CDONE) == 0) 3407220Ssam ; 34138888Skarels is->is_if.if_flags |= IFF_RUNNING | IFF_OACTIVE; 34225444Skarels is->is_flags |= ILF_RUNNING; 3437261Ssam is->is_lastcmd = 0; 3446893Sfeldman ilcint(unit); 3456893Sfeldman splx(s); 3466893Sfeldman } 3476893Sfeldman 3486893Sfeldman /* 3496893Sfeldman * Start output on interface. 3506893Sfeldman * Get another datagram to send off of the interface queue, 3516893Sfeldman * and map it to the interface before starting the output. 3526893Sfeldman */ 35337476Ssklower ilstart(ifp) 35437476Ssklower register struct ifnet *ifp; 3556893Sfeldman { 35637476Ssklower int unit = ifp->if_unit, len; 3576893Sfeldman struct uba_device *ui = ilinfo[unit]; 3586893Sfeldman register struct il_softc *is = &il_softc[unit]; 3596893Sfeldman register struct ildevice *addr; 3606893Sfeldman struct mbuf *m; 3617220Ssam short csr; 3626893Sfeldman 3636893Sfeldman IF_DEQUEUE(&is->is_if.if_snd, m); 3647261Ssam addr = (struct ildevice *)ui->ui_addr; 3657261Ssam if (m == 0) { 3667261Ssam if ((is->is_flags & ILF_STATPENDING) == 0) 36737476Ssklower return (0); 3689179Ssam addr->il_bar = is->is_ubaddr & 0xffff; 3697261Ssam addr->il_bcr = sizeof (struct il_stats); 3707261Ssam csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; 3717261Ssam is->is_flags &= ~ILF_STATPENDING; 3727261Ssam goto startcmd; 3737261Ssam } 3746893Sfeldman len = if_wubaput(&is->is_ifuba, m); 3759179Ssam /* 3769179Ssam * Ensure minimum packet length. 3779179Ssam * This makes the safe assumtion that there are no virtual holes 3789179Ssam * after the data. 3799179Ssam * For security, it might be wise to zero out the added bytes, 3809179Ssam * but we're mainly interested in speed at the moment. 3819179Ssam */ 3829746Ssam if (len - sizeof(struct ether_header) < ETHERMIN) 3839746Ssam len = ETHERMIN + sizeof(struct ether_header); 3846893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 3856893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 3866893Sfeldman addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 3876893Sfeldman addr->il_bcr = len; 3887261Ssam csr = 3897261Ssam ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE; 3907261Ssam 3917261Ssam startcmd: 3927261Ssam is->is_lastcmd = csr & IL_CMD; 3937220Ssam addr->il_csr = csr; 39437476Ssklower is->is_if.if_flags |= IFF_OACTIVE; 39537476Ssklower return (0); 3966893Sfeldman } 3976893Sfeldman 3986893Sfeldman /* 3996893Sfeldman * Command done interrupt. 4006893Sfeldman */ 4016893Sfeldman ilcint(unit) 4026893Sfeldman int unit; 4036893Sfeldman { 4046893Sfeldman register struct il_softc *is = &il_softc[unit]; 4057220Ssam struct uba_device *ui = ilinfo[unit]; 4066893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 4077266Ssam short csr; 4086893Sfeldman 40937476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) { 4107220Ssam printf("il%d: stray xmit interrupt, csr=%b\n", unit, 4117261Ssam addr->il_csr, IL_BITS); 4126893Sfeldman return; 4136893Sfeldman } 4147220Ssam 4157266Ssam csr = addr->il_csr; 4166893Sfeldman /* 4177261Ssam * Hang receive buffer if it couldn't 4187261Ssam * be done earlier (in ilrint). 4196893Sfeldman */ 4207261Ssam if (is->is_flags & ILF_RCVPENDING) { 42125444Skarels int s; 42225444Skarels 4236893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 4249746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 4257261Ssam addr->il_csr = 4267261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 42725444Skarels s = splhigh(); 4287220Ssam while ((addr->il_csr & IL_CDONE) == 0) 4297220Ssam ; 43025444Skarels splx(s); 4317261Ssam is->is_flags &= ~ILF_RCVPENDING; 4326893Sfeldman } 43337476Ssklower is->is_if.if_flags &= ~IFF_OACTIVE; 4347266Ssam csr &= IL_STATUS; 4357261Ssam switch (is->is_lastcmd) { 4367261Ssam 4377261Ssam case ILC_XMIT: 4387261Ssam is->is_if.if_opackets++; 4397266Ssam if (csr > ILERR_RETRIES) 4407261Ssam is->is_if.if_oerrors++; 4417261Ssam break; 4427261Ssam 4437261Ssam case ILC_STAT: 4447266Ssam if (csr == ILERR_SUCCESS) 4457261Ssam iltotal(is); 4467261Ssam break; 4477261Ssam } 4486893Sfeldman if (is->is_ifuba.ifu_xtofree) { 4496893Sfeldman m_freem(is->is_ifuba.ifu_xtofree); 4506893Sfeldman is->is_ifuba.ifu_xtofree = 0; 4516893Sfeldman } 45237476Ssklower (void) ilstart(&is->is_if); 4536893Sfeldman } 4546893Sfeldman 4556893Sfeldman /* 4566893Sfeldman * Ethernet interface receiver interrupt. 4576893Sfeldman * If input error just drop packet. 4586893Sfeldman * Otherwise purge input buffered data path and examine 4596893Sfeldman * packet to determine type. If can't determine length 4606893Sfeldman * from type, then have to drop packet. Othewise decapsulate 4616893Sfeldman * packet based on type and pass to type specific higher-level 4626893Sfeldman * input routine. 4636893Sfeldman */ 4646893Sfeldman ilrint(unit) 4656893Sfeldman int unit; 4666893Sfeldman { 4676893Sfeldman register struct il_softc *is = &il_softc[unit]; 4686893Sfeldman struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 4696893Sfeldman register struct il_rheader *il; 4706893Sfeldman struct mbuf *m; 47115787Sleres int len, off, resid, s; 4726893Sfeldman register struct ifqueue *inq; 4736893Sfeldman 4746893Sfeldman is->is_if.if_ipackets++; 4756893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 4766893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 4776893Sfeldman il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 4786893Sfeldman len = il->ilr_length - sizeof(struct il_rheader); 4799746Ssam if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || 4809746Ssam len > ETHERMTU) { 4816893Sfeldman is->is_if.if_ierrors++; 4826893Sfeldman #ifdef notdef 4836893Sfeldman if (is->is_if.if_ierrors % 100 == 0) 4846893Sfeldman printf("il%d: += 100 input errors\n", unit); 4856893Sfeldman #endif 4866893Sfeldman goto setup; 4876893Sfeldman } 4886893Sfeldman 4896893Sfeldman /* 49019865Skarels * Deal with trailer protocol: if type is trailer type 4916893Sfeldman * get true type from first 16-bit word past data. 4926893Sfeldman * Remember that type was trailer by setting off. 4936893Sfeldman */ 4949746Ssam il->ilr_type = ntohs((u_short)il->ilr_type); 4956893Sfeldman #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 49619865Skarels if (il->ilr_type >= ETHERTYPE_TRAIL && 49719865Skarels il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 49819865Skarels off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; 4999746Ssam if (off >= ETHERMTU) 5006893Sfeldman goto setup; /* sanity */ 5019746Ssam il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); 5029746Ssam resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 5036893Sfeldman if (off + resid > len) 5046893Sfeldman goto setup; /* sanity */ 5056893Sfeldman len = off + resid; 5066893Sfeldman } else 5076893Sfeldman off = 0; 5086893Sfeldman if (len == 0) 5096893Sfeldman goto setup; 5106893Sfeldman 5116893Sfeldman /* 5126893Sfeldman * Pull packet off interface. Off is nonzero if packet 5136893Sfeldman * has trailing header; ilget will then force this header 5146893Sfeldman * information to be at the front, but we still have to drop 5156893Sfeldman * the type and length which are at the front of any trailer data. 5166893Sfeldman */ 51724791Skarels m = if_rubaget(&is->is_ifuba, len, off, &is->is_if); 51837476Ssklower if (m) 51937476Ssklower ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m); 5206893Sfeldman setup: 5216893Sfeldman /* 5226893Sfeldman * Reset for next packet if possible. 5236893Sfeldman * If waiting for transmit command completion, set flag 5246893Sfeldman * and wait until command completes. 5256893Sfeldman */ 52637476Ssklower if (is->is_if.if_flags & IFF_OACTIVE) { 5277261Ssam is->is_flags |= ILF_RCVPENDING; 5287220Ssam return; 5297220Ssam } 5307220Ssam addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 5319746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 5327261Ssam addr->il_csr = 5337261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 53425444Skarels s = splhigh(); 5357220Ssam while ((addr->il_csr & IL_CDONE) == 0) 5367220Ssam ; 53725444Skarels splx(s); 5386893Sfeldman } 5396893Sfeldman /* 5407261Ssam * Watchdog routine, request statistics from board. 5417261Ssam */ 5427261Ssam ilwatch(unit) 5437261Ssam int unit; 5447261Ssam { 5457261Ssam register struct il_softc *is = &il_softc[unit]; 5467261Ssam register struct ifnet *ifp = &is->is_if; 5477261Ssam int s; 5487261Ssam 5497261Ssam if (is->is_flags & ILF_STATPENDING) { 5507261Ssam ifp->if_timer = is->is_scaninterval; 5517261Ssam return; 5527261Ssam } 5537261Ssam s = splimp(); 5547261Ssam is->is_flags |= ILF_STATPENDING; 55537476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) 55637476Ssklower (void) ilstart(ifp); 5577261Ssam splx(s); 5587261Ssam ifp->if_timer = is->is_scaninterval; 5597261Ssam } 5607261Ssam 5617261Ssam /* 5627261Ssam * Total up the on-board statistics. 5637261Ssam */ 5647261Ssam iltotal(is) 5657261Ssam register struct il_softc *is; 5667261Ssam { 5677261Ssam register u_short *interval, *sum, *end; 5687261Ssam 5697261Ssam interval = &is->is_stats.ils_frames; 5707261Ssam sum = &is->is_sum.ils_frames; 5717261Ssam end = is->is_sum.ils_fill2; 5727261Ssam while (sum < end) 5737261Ssam *sum++ += *interval++; 5747261Ssam is->is_if.if_collisions = is->is_sum.ils_collis; 57529730Ssklower if ((is->is_flags & ILF_SETADDR) && 57629730Ssklower (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 57729730Ssklower sizeof (is->is_addr)) != 0)) { 57829730Ssklower log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit); 57929730Ssklower is->is_flags &= ~ILF_RUNNING; 58029730Ssklower ilinit(is->is_if.if_unit); 58129730Ssklower } 5827261Ssam } 58313056Ssam 58413056Ssam /* 58513056Ssam * Process an ioctl request. 58613056Ssam */ 58713056Ssam ilioctl(ifp, cmd, data) 58813056Ssam register struct ifnet *ifp; 58913056Ssam int cmd; 59013056Ssam caddr_t data; 59113056Ssam { 59219865Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 59325444Skarels register struct il_softc *is = &il_softc[ifp->if_unit]; 59413056Ssam int s = splimp(), error = 0; 59513056Ssam 59613056Ssam switch (cmd) { 59713056Ssam 59813056Ssam case SIOCSIFADDR: 59919865Skarels ifp->if_flags |= IFF_UP; 60013056Ssam ilinit(ifp->if_unit); 60119865Skarels 60237476Ssklower switch (ifa->ifa_addr->sa_family) { 60323557Ssklower #ifdef INET 60419865Skarels case AF_INET: 60519865Skarels ((struct arpcom *)ifp)->ac_ipaddr = 60619865Skarels IA_SIN(ifa)->sin_addr; 60719865Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 60819865Skarels break; 60923557Ssklower #endif 61023557Ssklower #ifdef NS 61123557Ssklower case AF_NS: 61225976Skarels { 61325976Skarels register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 61425976Skarels 61525976Skarels if (ns_nullhost(*ina)) { 61625976Skarels ina->x_host = * (union ns_host *) 61725976Skarels (il_softc[ifp->if_unit].is_addr); 61825976Skarels } else { 61925976Skarels il_setaddr(ina->x_host.c_host, ifp->if_unit); 62026145Ssklower return (0); 62125976Skarels } 62223557Ssklower break; 62325976Skarels } 62423557Ssklower #endif 62519865Skarels } 62613056Ssam break; 62713056Ssam 62825444Skarels case SIOCSIFFLAGS: 62925444Skarels if ((ifp->if_flags & IFF_UP) == 0 && 63025444Skarels is->is_flags & ILF_RUNNING) { 63125444Skarels ((struct ildevice *) 63225444Skarels (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; 63325444Skarels is->is_flags &= ~ILF_RUNNING; 63425444Skarels } else if (ifp->if_flags & IFF_UP && 63525444Skarels (is->is_flags & ILF_RUNNING) == 0) 63625444Skarels ilinit(ifp->if_unit); 63725444Skarels break; 63825444Skarels 63913056Ssam default: 64013056Ssam error = EINVAL; 64113056Ssam } 64213056Ssam splx(s); 64313056Ssam return (error); 64413056Ssam } 64525976Skarels 64625976Skarels /* 64725976Skarels * set ethernet address for unit 64825976Skarels */ 64925976Skarels il_setaddr(physaddr, unit) 65025976Skarels u_char *physaddr; 65125976Skarels int unit; 65225976Skarels { 65325976Skarels register struct il_softc *is = &il_softc[unit]; 65425976Skarels 65525976Skarels if (! (is->is_flags & ILF_RUNNING)) 65625976Skarels return; 65725976Skarels 65826145Ssklower bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); 65926145Ssklower is->is_flags &= ~ILF_RUNNING; 66026145Ssklower is->is_flags |= ILF_SETADDR; 66126145Ssklower ilinit(unit); 66225976Skarels } 66325274Sbloom #endif 664