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*38888Skarels * @(#)if_il.c 7.6 (Berkeley) 08/31/89 1823557Ssklower */ 196893Sfeldman 206893Sfeldman #include "il.h" 2125274Sbloom #if NIL > 0 226893Sfeldman 236893Sfeldman /* 246893Sfeldman * Interlan Ethernet Communications Controller interface 256893Sfeldman */ 2637508Smckusick #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) 7037476Ssklower 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 */ 8537476Ssklower 8637476Ssklower struct ether_addr { 8737476Ssklower u_char addr[6]; 8837476Ssklower }; 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 */ 10237476Ssklower union { 10337476Ssklower struct il_stats isu_stats; /* holds on-board statistics */ 10437476Ssklower struct ether_addr isu_maddrs[63]; /* multicast addrs */ 10537476Ssklower } is_isu; 10637476Ssklower #define is_stats is_isu.isu_stats 10737476Ssklower #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; 17237476Ssklower ifp->if_output = ether_output; 17313056Ssam ifp->if_ioctl = ilioctl; 1748979Sroot ifp->if_reset = ilreset; 17537476Ssklower 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 } 24037476Ssklower is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_isu, 24137476Ssklower 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) { 27237476Ssklower 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 } 29037476Ssklower #ifdef MULTICAST 29137476Ssklower if (is->is_if.if_flags & IFF_PROMISC) { 29237476Ssklower addr->il_csr = ILC_PRMSC; 29337476Ssklower if (ilwait(ui, "all multi")) 29437476Ssklower return; 29537476Ssklower } else if (is->is_if.if_flags & IFF_ALLMULTI) { 29637476Ssklower too_many_multis: 29737476Ssklower addr->il_csr = ILC_ALLMC; 29837476Ssklower if (ilwait(ui, "all multi")) 29937476Ssklower return; 30037476Ssklower else { 30137476Ssklower int i; 30237476Ssklower register struct ether_addr *ep = is->is_maddrs; 30337476Ssklower struct ether_multi *enm; 30437476Ssklower struct ether_multistep step; 30537476Ssklower /* 30637476Ssklower * Step through our list of multicast addresses. If we have 30737476Ssklower * too many multicast addresses, or if we have to listen to 30837476Ssklower * a range of multicast addresses, turn on reception of all 30937476Ssklower * multicasts. 31037476Ssklower */ 31137476Ssklower i = 0; 31237476Ssklower ETHER_FIRST_MULTI(step, &is->is_ac, enm); 31337476Ssklower while (enm != NULL) { 31437476Ssklower if (++i > 63 && k != 0) { 31537476Ssklower break; 31637476Ssklower } 31737476Ssklower *ep++ = *(struct ether_addr *)enm->enm_addrlo; 31837476Ssklower ETHER_NEXT_MULTI(step, enm); 31937476Ssklower } 32037476Ssklower if (i = 0) { 32137476Ssklower /* no multicasts! */ 32237476Ssklower } else if (i <= 63) { 32337476Ssklower addr->il_bar = is->is_ubaddr & 0xffff; 32437476Ssklower addr->il_bcr = i * sizeof (struct ether_addr); 32537476Ssklower addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)| 32637476Ssklower LC_LDGRPS; 32737476Ssklower if (ilwait(ui, "load multi")) 32837476Ssklower return; 32937476Ssklower } else { 33037476Ssklower is->is_if.if_flags |= IFF_ALLMULTI; 33137476Ssklower goto too_many_multis; 33237476Ssklower } 33337476Ssklower } 33437476Ssklower #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*38888Skarels is->is_if.if_flags |= IFF_RUNNING | IFF_OACTIVE; 35225444Skarels is->is_flags |= ILF_RUNNING; 3537261Ssam is->is_lastcmd = 0; 3546893Sfeldman ilcint(unit); 3556893Sfeldman splx(s); 3566893Sfeldman } 3576893Sfeldman 3586893Sfeldman /* 3596893Sfeldman * Start output on interface. 3606893Sfeldman * Get another datagram to send off of the interface queue, 3616893Sfeldman * and map it to the interface before starting the output. 3626893Sfeldman */ 36337476Ssklower ilstart(ifp) 36437476Ssklower register struct ifnet *ifp; 3656893Sfeldman { 36637476Ssklower int unit = ifp->if_unit, len; 3676893Sfeldman struct uba_device *ui = ilinfo[unit]; 3686893Sfeldman register struct il_softc *is = &il_softc[unit]; 3696893Sfeldman register struct ildevice *addr; 3706893Sfeldman struct mbuf *m; 3717220Ssam short csr; 3726893Sfeldman 3736893Sfeldman IF_DEQUEUE(&is->is_if.if_snd, m); 3747261Ssam addr = (struct ildevice *)ui->ui_addr; 3757261Ssam if (m == 0) { 3767261Ssam if ((is->is_flags & ILF_STATPENDING) == 0) 37737476Ssklower return (0); 3789179Ssam addr->il_bar = is->is_ubaddr & 0xffff; 3797261Ssam addr->il_bcr = sizeof (struct il_stats); 3807261Ssam csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; 3817261Ssam is->is_flags &= ~ILF_STATPENDING; 3827261Ssam goto startcmd; 3837261Ssam } 3846893Sfeldman len = if_wubaput(&is->is_ifuba, m); 3859179Ssam /* 3869179Ssam * Ensure minimum packet length. 3879179Ssam * This makes the safe assumtion that there are no virtual holes 3889179Ssam * after the data. 3899179Ssam * For security, it might be wise to zero out the added bytes, 3909179Ssam * but we're mainly interested in speed at the moment. 3919179Ssam */ 3929746Ssam if (len - sizeof(struct ether_header) < ETHERMIN) 3939746Ssam len = ETHERMIN + sizeof(struct ether_header); 3946893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 3956893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 3966893Sfeldman addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 3976893Sfeldman addr->il_bcr = len; 3987261Ssam csr = 3997261Ssam ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE; 4007261Ssam 4017261Ssam startcmd: 4027261Ssam is->is_lastcmd = csr & IL_CMD; 4037220Ssam addr->il_csr = csr; 40437476Ssklower is->is_if.if_flags |= IFF_OACTIVE; 40537476Ssklower return (0); 4066893Sfeldman } 4076893Sfeldman 4086893Sfeldman /* 4096893Sfeldman * Command done interrupt. 4106893Sfeldman */ 4116893Sfeldman ilcint(unit) 4126893Sfeldman int unit; 4136893Sfeldman { 4146893Sfeldman register struct il_softc *is = &il_softc[unit]; 4157220Ssam struct uba_device *ui = ilinfo[unit]; 4166893Sfeldman register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 4177266Ssam short csr; 4186893Sfeldman 41937476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) { 4207220Ssam printf("il%d: stray xmit interrupt, csr=%b\n", unit, 4217261Ssam addr->il_csr, IL_BITS); 4226893Sfeldman return; 4236893Sfeldman } 4247220Ssam 4257266Ssam csr = addr->il_csr; 4266893Sfeldman /* 4277261Ssam * Hang receive buffer if it couldn't 4287261Ssam * be done earlier (in ilrint). 4296893Sfeldman */ 4307261Ssam if (is->is_flags & ILF_RCVPENDING) { 43125444Skarels int s; 43225444Skarels 4336893Sfeldman addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 4349746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 4357261Ssam addr->il_csr = 4367261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 43725444Skarels s = splhigh(); 4387220Ssam while ((addr->il_csr & IL_CDONE) == 0) 4397220Ssam ; 44025444Skarels splx(s); 4417261Ssam is->is_flags &= ~ILF_RCVPENDING; 4426893Sfeldman } 44337476Ssklower is->is_if.if_flags &= ~IFF_OACTIVE; 4447266Ssam csr &= IL_STATUS; 4457261Ssam switch (is->is_lastcmd) { 4467261Ssam 4477261Ssam case ILC_XMIT: 4487261Ssam is->is_if.if_opackets++; 4497266Ssam if (csr > ILERR_RETRIES) 4507261Ssam is->is_if.if_oerrors++; 4517261Ssam break; 4527261Ssam 4537261Ssam case ILC_STAT: 4547266Ssam if (csr == ILERR_SUCCESS) 4557261Ssam iltotal(is); 4567261Ssam break; 4577261Ssam } 4586893Sfeldman if (is->is_ifuba.ifu_xtofree) { 4596893Sfeldman m_freem(is->is_ifuba.ifu_xtofree); 4606893Sfeldman is->is_ifuba.ifu_xtofree = 0; 4616893Sfeldman } 46237476Ssklower (void) ilstart(&is->is_if); 4636893Sfeldman } 4646893Sfeldman 4656893Sfeldman /* 4666893Sfeldman * Ethernet interface receiver interrupt. 4676893Sfeldman * If input error just drop packet. 4686893Sfeldman * Otherwise purge input buffered data path and examine 4696893Sfeldman * packet to determine type. If can't determine length 4706893Sfeldman * from type, then have to drop packet. Othewise decapsulate 4716893Sfeldman * packet based on type and pass to type specific higher-level 4726893Sfeldman * input routine. 4736893Sfeldman */ 4746893Sfeldman ilrint(unit) 4756893Sfeldman int unit; 4766893Sfeldman { 4776893Sfeldman register struct il_softc *is = &il_softc[unit]; 4786893Sfeldman struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 4796893Sfeldman register struct il_rheader *il; 4806893Sfeldman struct mbuf *m; 48115787Sleres int len, off, resid, s; 4826893Sfeldman register struct ifqueue *inq; 4836893Sfeldman 4846893Sfeldman is->is_if.if_ipackets++; 4856893Sfeldman if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 4866893Sfeldman UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 4876893Sfeldman il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 4886893Sfeldman len = il->ilr_length - sizeof(struct il_rheader); 4899746Ssam if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || 4909746Ssam len > ETHERMTU) { 4916893Sfeldman is->is_if.if_ierrors++; 4926893Sfeldman #ifdef notdef 4936893Sfeldman if (is->is_if.if_ierrors % 100 == 0) 4946893Sfeldman printf("il%d: += 100 input errors\n", unit); 4956893Sfeldman #endif 4966893Sfeldman goto setup; 4976893Sfeldman } 4986893Sfeldman 4996893Sfeldman /* 50019865Skarels * Deal with trailer protocol: if type is trailer type 5016893Sfeldman * get true type from first 16-bit word past data. 5026893Sfeldman * Remember that type was trailer by setting off. 5036893Sfeldman */ 5049746Ssam il->ilr_type = ntohs((u_short)il->ilr_type); 5056893Sfeldman #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 50619865Skarels if (il->ilr_type >= ETHERTYPE_TRAIL && 50719865Skarels il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 50819865Skarels off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; 5099746Ssam if (off >= ETHERMTU) 5106893Sfeldman goto setup; /* sanity */ 5119746Ssam il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); 5129746Ssam resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 5136893Sfeldman if (off + resid > len) 5146893Sfeldman goto setup; /* sanity */ 5156893Sfeldman len = off + resid; 5166893Sfeldman } else 5176893Sfeldman off = 0; 5186893Sfeldman if (len == 0) 5196893Sfeldman goto setup; 5206893Sfeldman 5216893Sfeldman /* 5226893Sfeldman * Pull packet off interface. Off is nonzero if packet 5236893Sfeldman * has trailing header; ilget will then force this header 5246893Sfeldman * information to be at the front, but we still have to drop 5256893Sfeldman * the type and length which are at the front of any trailer data. 5266893Sfeldman */ 52724791Skarels m = if_rubaget(&is->is_ifuba, len, off, &is->is_if); 52837476Ssklower if (m) 52937476Ssklower ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m); 5306893Sfeldman setup: 5316893Sfeldman /* 5326893Sfeldman * Reset for next packet if possible. 5336893Sfeldman * If waiting for transmit command completion, set flag 5346893Sfeldman * and wait until command completes. 5356893Sfeldman */ 53637476Ssklower if (is->is_if.if_flags & IFF_OACTIVE) { 5377261Ssam is->is_flags |= ILF_RCVPENDING; 5387220Ssam return; 5397220Ssam } 5407220Ssam addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 5419746Ssam addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 5427261Ssam addr->il_csr = 5437261Ssam ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 54425444Skarels s = splhigh(); 5457220Ssam while ((addr->il_csr & IL_CDONE) == 0) 5467220Ssam ; 54725444Skarels splx(s); 5486893Sfeldman } 5496893Sfeldman /* 5507261Ssam * Watchdog routine, request statistics from board. 5517261Ssam */ 5527261Ssam ilwatch(unit) 5537261Ssam int unit; 5547261Ssam { 5557261Ssam register struct il_softc *is = &il_softc[unit]; 5567261Ssam register struct ifnet *ifp = &is->is_if; 5577261Ssam int s; 5587261Ssam 5597261Ssam if (is->is_flags & ILF_STATPENDING) { 5607261Ssam ifp->if_timer = is->is_scaninterval; 5617261Ssam return; 5627261Ssam } 5637261Ssam s = splimp(); 5647261Ssam is->is_flags |= ILF_STATPENDING; 56537476Ssklower if ((is->is_if.if_flags & IFF_OACTIVE) == 0) 56637476Ssklower (void) ilstart(ifp); 5677261Ssam splx(s); 5687261Ssam ifp->if_timer = is->is_scaninterval; 5697261Ssam } 5707261Ssam 5717261Ssam /* 5727261Ssam * Total up the on-board statistics. 5737261Ssam */ 5747261Ssam iltotal(is) 5757261Ssam register struct il_softc *is; 5767261Ssam { 5777261Ssam register u_short *interval, *sum, *end; 5787261Ssam 5797261Ssam interval = &is->is_stats.ils_frames; 5807261Ssam sum = &is->is_sum.ils_frames; 5817261Ssam end = is->is_sum.ils_fill2; 5827261Ssam while (sum < end) 5837261Ssam *sum++ += *interval++; 5847261Ssam is->is_if.if_collisions = is->is_sum.ils_collis; 58529730Ssklower if ((is->is_flags & ILF_SETADDR) && 58629730Ssklower (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 58729730Ssklower sizeof (is->is_addr)) != 0)) { 58829730Ssklower log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit); 58929730Ssklower is->is_flags &= ~ILF_RUNNING; 59029730Ssklower ilinit(is->is_if.if_unit); 59129730Ssklower } 5927261Ssam } 59313056Ssam 59413056Ssam /* 59513056Ssam * Process an ioctl request. 59613056Ssam */ 59713056Ssam ilioctl(ifp, cmd, data) 59813056Ssam register struct ifnet *ifp; 59913056Ssam int cmd; 60013056Ssam caddr_t data; 60113056Ssam { 60219865Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 60325444Skarels register struct il_softc *is = &il_softc[ifp->if_unit]; 60413056Ssam int s = splimp(), error = 0; 60513056Ssam 60613056Ssam switch (cmd) { 60713056Ssam 60813056Ssam case SIOCSIFADDR: 60919865Skarels ifp->if_flags |= IFF_UP; 61013056Ssam ilinit(ifp->if_unit); 61119865Skarels 61237476Ssklower switch (ifa->ifa_addr->sa_family) { 61323557Ssklower #ifdef INET 61419865Skarels case AF_INET: 61519865Skarels ((struct arpcom *)ifp)->ac_ipaddr = 61619865Skarels IA_SIN(ifa)->sin_addr; 61719865Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 61819865Skarels break; 61923557Ssklower #endif 62023557Ssklower #ifdef NS 62123557Ssklower case AF_NS: 62225976Skarels { 62325976Skarels register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 62425976Skarels 62525976Skarels if (ns_nullhost(*ina)) { 62625976Skarels ina->x_host = * (union ns_host *) 62725976Skarels (il_softc[ifp->if_unit].is_addr); 62825976Skarels } else { 62925976Skarels il_setaddr(ina->x_host.c_host, ifp->if_unit); 63026145Ssklower return (0); 63125976Skarels } 63223557Ssklower break; 63325976Skarels } 63423557Ssklower #endif 63519865Skarels } 63613056Ssam break; 63713056Ssam 63825444Skarels case SIOCSIFFLAGS: 63925444Skarels if ((ifp->if_flags & IFF_UP) == 0 && 64025444Skarels is->is_flags & ILF_RUNNING) { 64125444Skarels ((struct ildevice *) 64225444Skarels (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; 64325444Skarels is->is_flags &= ~ILF_RUNNING; 64425444Skarels } else if (ifp->if_flags & IFF_UP && 64525444Skarels (is->is_flags & ILF_RUNNING) == 0) 64625444Skarels ilinit(ifp->if_unit); 64725444Skarels break; 64825444Skarels 64913056Ssam default: 65013056Ssam error = EINVAL; 65113056Ssam } 65213056Ssam splx(s); 65313056Ssam return (error); 65413056Ssam } 65525976Skarels 65625976Skarels /* 65725976Skarels * set ethernet address for unit 65825976Skarels */ 65925976Skarels il_setaddr(physaddr, unit) 66025976Skarels u_char *physaddr; 66125976Skarels int unit; 66225976Skarels { 66325976Skarels register struct il_softc *is = &il_softc[unit]; 66425976Skarels 66525976Skarels if (! (is->is_flags & ILF_RUNNING)) 66625976Skarels return; 66725976Skarels 66826145Ssklower bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); 66926145Ssklower is->is_flags &= ~ILF_RUNNING; 67026145Ssklower is->is_flags |= ILF_SETADDR; 67126145Ssklower ilinit(unit); 67225976Skarels } 67325274Sbloom #endif 674