123557Ssklower /*
229367Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
335323Sbostic * All rights reserved.
423557Ssklower *
544560Sbostic * %sccs.include.redist.c%
635323Sbostic *
7*45801Sbostic * @(#)if_il.c 7.8 (Berkeley) 12/16/90
823557Ssklower */
96893Sfeldman
106893Sfeldman #include "il.h"
1125274Sbloom #if NIL > 0
126893Sfeldman
136893Sfeldman /*
146893Sfeldman * Interlan Ethernet Communications Controller interface
156893Sfeldman */
16*45801Sbostic #include "../include/pte.h"
179797Ssam
18*45801Sbostic #include "sys/param.h"
19*45801Sbostic #include "sys/systm.h"
20*45801Sbostic #include "sys/mbuf.h"
21*45801Sbostic #include "sys/buf.h"
22*45801Sbostic #include "sys/protosw.h"
23*45801Sbostic #include "sys/socket.h"
24*45801Sbostic #include "sys/vmmac.h"
25*45801Sbostic #include "sys/ioctl.h"
26*45801Sbostic #include "sys/errno.h"
27*45801Sbostic #include "sys/syslog.h"
288463Sroot
29*45801Sbostic #include "net/if.h"
30*45801Sbostic #include "net/netisr.h"
31*45801Sbostic #include "net/route.h"
3223557Ssklower
3323557Ssklower #ifdef INET
34*45801Sbostic #include "netinet/in.h"
35*45801Sbostic #include "netinet/in_systm.h"
36*45801Sbostic #include "netinet/in_var.h"
37*45801Sbostic #include "netinet/ip.h"
38*45801Sbostic #include "netinet/if_ether.h"
3923557Ssklower #endif
4023557Ssklower
4123557Ssklower #ifdef NS
42*45801Sbostic #include "netns/ns.h"
43*45801Sbostic #include "netns/ns_if.h"
4423557Ssklower #endif
4523557Ssklower
46*45801Sbostic #include "../include/cpu.h"
47*45801Sbostic #include "../include/mtpr.h"
4817115Sbloom #include "if_il.h"
4917115Sbloom #include "if_ilreg.h"
5017115Sbloom #include "if_uba.h"
51*45801Sbostic #include "../uba/ubareg.h"
52*45801Sbostic #include "../uba/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
ilprobe(reg)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 */
ilreset(unit,uban)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 */
ilinit(unit)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