xref: /csrg-svn/sys/vax/if/if_il.c (revision 37476)
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