xref: /csrg-svn/sys/pmax/dev/if_le.c (revision 54144)
152130Smckusick /*
252130Smckusick  * Copyright (c) 1992 Regents of the University of California.
352130Smckusick  * All rights reserved.
452130Smckusick  *
552130Smckusick  * This code is derived from software contributed to Berkeley by
652130Smckusick  * Ralph Campbell.
752130Smckusick  *
852130Smckusick  * %sccs.include.redist.c%
952130Smckusick  *
10*54144Sralph  *	@(#)if_le.c	7.4 (Berkeley) 06/20/92
1152130Smckusick  */
1252130Smckusick 
1352130Smckusick #include "le.h"
1452130Smckusick #if NLE > 0
1552130Smckusick 
1652130Smckusick #include "bpfilter.h"
1752130Smckusick 
1852130Smckusick /*
1952130Smckusick  * AMD 7990 LANCE
2052130Smckusick  *
2152130Smckusick  * This driver will generate and accept trailer encapsulated packets even
2252130Smckusick  * though it buys us nothing.  The motivation was to avoid incompatibilities
2352130Smckusick  * with VAXen, SUNs, and others that handle and benefit from them.
2452130Smckusick  * This reasoning is dubious.
2552130Smckusick  */
2652130Smckusick #include "param.h"
2752130Smckusick #include "systm.h"
2852130Smckusick #include "mbuf.h"
2952130Smckusick #include "buf.h"
3052130Smckusick #include "protosw.h"
3152130Smckusick #include "socket.h"
3252130Smckusick #include "syslog.h"
3352130Smckusick #include "ioctl.h"
3452130Smckusick #include "errno.h"
3552130Smckusick 
3652130Smckusick #include "net/if.h"
3752130Smckusick #include "net/netisr.h"
3852130Smckusick #include "net/route.h"
3952130Smckusick 
4052130Smckusick #ifdef INET
4152130Smckusick #include "netinet/in.h"
4252130Smckusick #include "netinet/in_systm.h"
4352130Smckusick #include "netinet/in_var.h"
4452130Smckusick #include "netinet/ip.h"
4552130Smckusick #include "netinet/if_ether.h"
4652130Smckusick #endif
4752130Smckusick 
4852130Smckusick #ifdef NS
4952130Smckusick #include "netns/ns.h"
5052130Smckusick #include "netns/ns_if.h"
5152130Smckusick #endif
5252130Smckusick 
5352130Smckusick #ifdef RMP
5452130Smckusick #include "netrmp/rmp.h"
5552130Smckusick #include "netrmp/rmp_var.h"
5652130Smckusick #endif
5752130Smckusick 
5852130Smckusick #include "machine/machConst.h"
5952130Smckusick #include "device.h"
6052130Smckusick #include "if_lereg.h"
6152130Smckusick 
6252130Smckusick #if NBPFILTER > 0
6352130Smckusick #include "../net/bpf.h"
6452130Smckusick #include "../net/bpfdesc.h"
6552130Smckusick #endif
6652130Smckusick 
6752130Smckusick int	leprobe();
6852695Sralph void	leintr();
6952130Smckusick struct	driver ledriver = {
7052695Sralph 	"le", leprobe, 0, 0, leintr,
7152130Smckusick };
7252130Smckusick 
7352130Smckusick int	ledebug = 1;		/* console error messages */
7452130Smckusick 
7552130Smckusick /*
7652130Smckusick  * Ethernet software status per interface.
7752130Smckusick  *
7852130Smckusick  * Each interface is referenced by a network interface structure,
7952130Smckusick  * le_if, which the routing code uses to locate the interface.
8052130Smckusick  * This structure contains the output queue for the interface, its address, ...
8152130Smckusick  */
8252130Smckusick struct	le_softc {
8352130Smckusick 	struct	arpcom sc_ac;	/* common Ethernet structures */
8452130Smckusick #define	sc_if	sc_ac.ac_if	/* network-visible interface */
8552130Smckusick #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
8652130Smckusick 	volatile struct	lereg1 *sc_r1;	/* LANCE registers */
8752130Smckusick 	volatile struct	lereg2 *sc_r2;	/* dual-port RAM */
8852130Smckusick 	int	sc_rmd;		/* predicted next rmd to process */
8952130Smckusick 	int	sc_tmd;		/* last tmd processed */
9052130Smckusick 	int	sc_tmdnext;	/* next tmd to transmit with */
9152130Smckusick 	int	sc_runt;
9252130Smckusick 	int	sc_jab;
9352130Smckusick 	int	sc_merr;
9452130Smckusick 	int	sc_babl;
9552130Smckusick 	int	sc_cerr;
9652130Smckusick 	int	sc_miss;
9752130Smckusick 	int	sc_xint;
9852130Smckusick 	int	sc_xown;
9952130Smckusick 	int	sc_uflo;
10052130Smckusick 	int	sc_rxlen;
10152130Smckusick 	int	sc_rxoff;
10252130Smckusick 	int	sc_txoff;
10352130Smckusick 	int	sc_busy;
10452130Smckusick 	short	sc_iflags;
10552130Smckusick #if NBPFILTER > 0
10652130Smckusick 	caddr_t sc_bpf;
10752130Smckusick #endif
10852130Smckusick } le_softc[NLE];
10952130Smckusick 
11052695Sralph #ifdef DS3100
11152130Smckusick /* access LANCE registers */
11252130Smckusick #define	LERDWR(cntl, src, dst)	{ (dst) = (src); DELAY(10); }
11352130Smckusick 
11452130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \
11552130Smckusick 	(((unsigned)(&(((struct lereg2 *)0)->cpu))) >> 1)
11652695Sralph #endif
11752130Smckusick 
11852695Sralph #ifdef DS5000
11952695Sralph /* access LANCE registers */
12052695Sralph #define	LERDWR(cntl, src, dst)	(dst) = (src);
12152695Sralph 
12252695Sralph #define CPU_TO_CHIP_ADDR(cpu) \
12352695Sralph 	((unsigned)(&(((struct lereg2 *)0)->cpu)))
12452695Sralph 
12552695Sralph #define LE_OFFSET_RAM		0x0
12652695Sralph #define LE_OFFSET_LANCE		0x100000
12752695Sralph #define LE_OFFSET_ROM		0x1c0000
12852695Sralph #endif
12952695Sralph 
13052130Smckusick /*
13152130Smckusick  * Test to see if device is present.
13252130Smckusick  * Return true if found and initialized ok.
13352130Smckusick  * If interface exists, make available by filling in network interface
13452130Smckusick  * record.  System will initialize the interface when it is ready
13552130Smckusick  * to accept packets.
13652130Smckusick  */
13752130Smckusick leprobe(dp)
13852130Smckusick 	struct pmax_ctlr *dp;
13952130Smckusick {
14052130Smckusick 	volatile struct lereg1 *ler1;
14152130Smckusick 	struct le_softc *le = &le_softc[dp->pmax_unit];
14252130Smckusick 	struct ifnet *ifp = &le->sc_if;
14352130Smckusick 	u_char *cp;
14452130Smckusick 	int i;
14552695Sralph 	extern int leinit(), leioctl(), lestart(), ether_output();
14652130Smckusick 
14752695Sralph #ifdef DS3100
14852130Smckusick 	le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr;
14952130Smckusick 	le->sc_r2 = (volatile struct lereg2 *)MACH_NETWORK_BUFFER_ADDR;
15052130Smckusick 
15152130Smckusick 	/*
15252130Smckusick 	 * Read the ethernet address.
15352130Smckusick 	 * See "DECstation 3100 Desktop Workstation Functional Specification".
15452130Smckusick 	 */
15552130Smckusick 	cp = (u_char *)(MACH_CLOCK_ADDR + 1);
15652130Smckusick 	for (i = 0; i < sizeof(le->sc_addr); i++) {
15752130Smckusick 		le->sc_addr[i] = *cp;
15852130Smckusick 		cp += 4;
15952130Smckusick 	}
16052695Sralph #endif
16152695Sralph #ifdef DS5000
16252695Sralph 	le->sc_r1 = ler1 = (volatile struct lereg1 *)
16352695Sralph 		(dp->pmax_addr + LE_OFFSET_LANCE);
16452695Sralph 	le->sc_r2 = (volatile struct lereg2 *)(dp->pmax_addr + LE_OFFSET_RAM);
16552130Smckusick 
16652695Sralph 	/*
16752695Sralph 	 * Read the ethernet address.
16852695Sralph 	 */
16952695Sralph 	cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2);
17052695Sralph 	for (i = 0; i < sizeof(le->sc_addr); i++) {
17152695Sralph 		le->sc_addr[i] = *cp;
17252695Sralph 		cp += 4;
17352695Sralph 	}
17452695Sralph #endif
17552695Sralph 
17652130Smckusick 	/* make sure the chip is stopped */
17752130Smckusick 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
17852130Smckusick 	LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
17952130Smckusick 
18052130Smckusick 	ifp->if_unit = dp->pmax_unit;
18152130Smckusick 	ifp->if_name = "le";
18252130Smckusick 	ifp->if_mtu = ETHERMTU;
18352130Smckusick 	ifp->if_init = leinit;
18452130Smckusick 	ifp->if_ioctl = leioctl;
18552130Smckusick 	ifp->if_output = ether_output;
18652130Smckusick 	ifp->if_start = lestart;
18752130Smckusick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
18852130Smckusick #if NBPFILTER > 0
18952130Smckusick 	bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
19052130Smckusick #endif
19152130Smckusick 	if_attach(ifp);
19252130Smckusick 
19352695Sralph 	printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n",
19452695Sralph 		dp->pmax_unit, dp->pmax_addr, dp->pmax_pri,
19552695Sralph 		ether_sprintf(le->sc_addr));
19652130Smckusick 	return (1);
19752130Smckusick }
19852130Smckusick 
19952130Smckusick ledrinit(ler2)
20052130Smckusick 	register volatile struct lereg2 *ler2;
20152130Smckusick {
20252130Smckusick 	register int i;
20352130Smckusick 
20452130Smckusick 	for (i = 0; i < LERBUF; i++) {
20552130Smckusick 		ler2->ler2_rmd[i].rmd0 = CPU_TO_CHIP_ADDR(ler2_rbuf[i][0]);
20652130Smckusick 		ler2->ler2_rmd[i].rmd1 = LE_OWN;
20752130Smckusick 		ler2->ler2_rmd[i].rmd2 = -LEMTU;
20852130Smckusick 		ler2->ler2_rmd[i].rmd3 = 0;
20952130Smckusick 	}
21052130Smckusick 	for (i = 0; i < LETBUF; i++) {
21152130Smckusick 		ler2->ler2_tmd[i].tmd0 = CPU_TO_CHIP_ADDR(ler2_tbuf[i][0]);
21252130Smckusick 		ler2->ler2_tmd[i].tmd1 = 0;
21352130Smckusick 		ler2->ler2_tmd[i].tmd2 = 0;
21452130Smckusick 		ler2->ler2_tmd[i].tmd3 = 0;
21552130Smckusick 	}
21652130Smckusick }
21752130Smckusick 
21852130Smckusick lereset(unit)
21952130Smckusick 	register int unit;
22052130Smckusick {
22152130Smckusick 	register struct le_softc *le = &le_softc[unit];
22252130Smckusick 	register volatile struct lereg1 *ler1 = le->sc_r1;
22352130Smckusick 	register volatile struct lereg2 *ler2 = le->sc_r2;
22452130Smckusick 	register int timo = 100000;
22552130Smckusick 	register int stat;
22652130Smckusick 
22752130Smckusick #ifdef lint
22852130Smckusick 	stat = unit;
22952130Smckusick #endif
23052130Smckusick #if NBPFILTER > 0
23152130Smckusick 	if (le->sc_if.if_flags & IFF_PROMISC)
23252130Smckusick 		/* set the promiscuous bit */
23352130Smckusick 		le->sc_r2->ler2_mode = LE_MODE|0x8000;
23452130Smckusick 	else
23552130Smckusick 		le->sc_r2->ler2_mode = LE_MODE;
23652130Smckusick #endif
23752130Smckusick 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
23852130Smckusick 	LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
23952130Smckusick 
24052130Smckusick 	/*
24152130Smckusick 	 * Setup for transmit/receive
24252130Smckusick 	 */
24352130Smckusick 	ler2->ler2_mode = LE_MODE;
24452130Smckusick 	ler2->ler2_padr0 = (le->sc_addr[1] << 8) | le->sc_addr[0];
24552130Smckusick 	ler2->ler2_padr1 = (le->sc_addr[3] << 8) | le->sc_addr[2];
24652130Smckusick 	ler2->ler2_padr2 = (le->sc_addr[5] << 8) | le->sc_addr[4];
24752130Smckusick #ifdef RMP
24852130Smckusick 	/*
24952130Smckusick 	 * Set up logical addr filter to accept multicast 9:0:9:0:0:4
25052130Smckusick 	 * This should be an ioctl() to the driver.  (XXX)
25152130Smckusick 	 */
25252130Smckusick 	ler2->ler2_ladrf0 = 0x0010;
25352130Smckusick 	ler2->ler2_ladrf1 = 0x0;
25452130Smckusick 	ler2->ler2_ladrf2 = 0x0;
25552130Smckusick 	ler2->ler2_ladrf3 = 0x0;
25652130Smckusick #else
25752130Smckusick 	ler2->ler2_ladrf0 = 0;
25852130Smckusick 	ler2->ler2_ladrf1 = 0;
25952130Smckusick 	ler2->ler2_ladrf2 = 0;
26052130Smckusick 	ler2->ler2_ladrf3 = 0;
26152130Smckusick #endif
26252130Smckusick 	ler2->ler2_rlen = LE_RLEN;
26352130Smckusick 	ler2->ler2_rdra = CPU_TO_CHIP_ADDR(ler2_rmd[0]);
26452130Smckusick 	ler2->ler2_tlen = LE_TLEN;
26552130Smckusick 	ler2->ler2_tdra = CPU_TO_CHIP_ADDR(ler2_tmd[0]);
26652130Smckusick 	ledrinit(ler2);
26752130Smckusick 	le->sc_rmd = 0;
26852130Smckusick 	le->sc_tmd = LETBUF - 1;
26952130Smckusick 	le->sc_tmdnext = 0;
27052130Smckusick 
27152130Smckusick 	LERDWR(ler0, LE_CSR1, ler1->ler1_rap);
27252130Smckusick 	LERDWR(ler0, CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp);
27352130Smckusick 	LERDWR(ler0, LE_CSR2, ler1->ler1_rap);
27452130Smckusick 	LERDWR(ler0, 0, ler1->ler1_rdp);
27552130Smckusick 	LERDWR(ler0, LE_CSR3, ler1->ler1_rap);
27652130Smckusick 	LERDWR(ler0, 0, ler1->ler1_rdp);
27752130Smckusick 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
27852130Smckusick 	LERDWR(ler0, LE_INIT, ler1->ler1_rdp);
27952130Smckusick 	MachEmptyWriteBuffer();
28052130Smckusick 	do {
28152130Smckusick 		if (--timo == 0) {
28252130Smckusick 			printf("le%d: init timeout, stat = 0x%x\n",
28352130Smckusick 			       unit, stat);
28452130Smckusick 			break;
28552130Smckusick 		}
28652130Smckusick 		LERDWR(ler0, ler1->ler1_rdp, stat);
28752130Smckusick 	} while ((stat & LE_IDON) == 0);
28852130Smckusick 	LERDWR(ler0, LE_IDON, ler1->ler1_rdp);
28952130Smckusick 	LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp);
29052130Smckusick 	MachEmptyWriteBuffer();
29152130Smckusick 	le->sc_if.if_flags &= ~IFF_OACTIVE;
29252130Smckusick }
29352130Smckusick 
29452130Smckusick /*
29552130Smckusick  * Initialization of interface
29652130Smckusick  */
29752130Smckusick leinit(unit)
29852130Smckusick 	int unit;
29952130Smckusick {
30052130Smckusick 	struct le_softc *le = &le_softc[unit];
30152130Smckusick 	register struct ifnet *ifp = &le->sc_if;
30252130Smckusick 	int s;
30352130Smckusick 
30452130Smckusick 	/* not yet, if address still unknown */
30552130Smckusick 	if (ifp->if_addrlist == (struct ifaddr *)0)
30652130Smckusick 		return;
30752130Smckusick 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
30852130Smckusick 		s = splnet();
30952130Smckusick 		ifp->if_flags |= IFF_RUNNING;
31052130Smckusick 		lereset(unit);
31152130Smckusick 	        (void) lestart(ifp);
31252130Smckusick 		splx(s);
31352130Smckusick 	}
31452130Smckusick }
31552130Smckusick 
31652130Smckusick #define	LENEXTTMP \
31752130Smckusick 	if (++bix == LETBUF) bix = 0, tmd = le->sc_r2->ler2_tmd; else ++tmd
31852130Smckusick 
31952130Smckusick /*
32052130Smckusick  * Start output on interface.  Get another datagram to send
32152130Smckusick  * off of the interface queue, and copy it to the interface
32252130Smckusick  * before starting the output.
32352130Smckusick  */
32452130Smckusick lestart(ifp)
32552130Smckusick 	struct ifnet *ifp;
32652130Smckusick {
32752130Smckusick 	register struct le_softc *le = &le_softc[ifp->if_unit];
32852130Smckusick 	register int bix = le->sc_tmdnext;
32952130Smckusick 	register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix];
33052130Smckusick 	register struct mbuf *m;
33152130Smckusick 	int len = 0;
33252130Smckusick 
33352130Smckusick 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
33452130Smckusick 		return (0);
33552130Smckusick 	while (bix != le->sc_tmd) {
33652130Smckusick 		if (tmd->tmd1 & LE_OWN)
33752130Smckusick 			panic("lestart");
33852130Smckusick 		IF_DEQUEUE(&le->sc_if.if_snd, m);
33952130Smckusick 		if (m == 0)
34052130Smckusick 			break;
34152130Smckusick 		len = leput(le->sc_r2->ler2_tbuf[bix], m);
34252130Smckusick #if NBPFILTER > 0
34352130Smckusick 		/*
34452130Smckusick 		 * If bpf is listening on this interface, let it
34552130Smckusick 		 * see the packet before we commit it to the wire.
34652130Smckusick 		 */
34752130Smckusick 		if (le->sc_bpf)
34852130Smckusick 			bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[bix], len);
34952130Smckusick #endif
35052130Smckusick 		tmd->tmd3 = 0;
35152130Smckusick 		tmd->tmd2 = -len;
35252130Smckusick 		tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
35352130Smckusick 		LENEXTTMP;
35452130Smckusick 	}
35552130Smckusick 	if (len != 0) {
35652130Smckusick 		le->sc_if.if_flags |= IFF_OACTIVE;
35752130Smckusick 		LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp);
35852130Smckusick 		MachEmptyWriteBuffer();
35952130Smckusick 	}
36052130Smckusick 	le->sc_tmdnext = bix;
36152130Smckusick 	return (0);
36252130Smckusick }
36352130Smckusick 
36452130Smckusick /*
36552130Smckusick  * Process interrupts from the 7990 chip.
36652130Smckusick  */
36752695Sralph void
36852695Sralph leintr(unit)
36952695Sralph 	int unit;
37052130Smckusick {
37152130Smckusick 	register struct le_softc *le;
37252130Smckusick 	register volatile struct lereg1 *ler1;
37352695Sralph 	register int stat;
37452130Smckusick 
37552130Smckusick 	le = &le_softc[unit];
37652130Smckusick 	ler1 = le->sc_r1;
37752130Smckusick 	stat = ler1->ler1_rdp;
37852130Smckusick 	if (!(stat & LE_INTR)) {
37953081Sralph 		printf("le%d: spurrious interrupt\n", unit);
38052130Smckusick 		return;
38152130Smckusick 	}
38252130Smckusick 	if (stat & LE_SERR) {
38352130Smckusick 		leerror(unit, stat);
38452130Smckusick 		if (stat & LE_MERR) {
38552130Smckusick 			le->sc_merr++;
38652130Smckusick 			lereset(unit);
38752130Smckusick 			return;
38852130Smckusick 		}
38952130Smckusick 		if (stat & LE_BABL)
39052130Smckusick 			le->sc_babl++;
39152130Smckusick 		if (stat & LE_CERR)
39252130Smckusick 			le->sc_cerr++;
39352130Smckusick 		if (stat & LE_MISS)
39452130Smckusick 			le->sc_miss++;
39552130Smckusick 		LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
39652130Smckusick 		MachEmptyWriteBuffer();
39752130Smckusick 	}
39852130Smckusick 	if ((stat & LE_RXON) == 0) {
39952130Smckusick 		le->sc_rxoff++;
40052130Smckusick 		lereset(unit);
40152130Smckusick 		return;
40252130Smckusick 	}
40352130Smckusick 	if ((stat & LE_TXON) == 0) {
40452130Smckusick 		le->sc_txoff++;
40552130Smckusick 		lereset(unit);
40652130Smckusick 		return;
40752130Smckusick 	}
40852130Smckusick 	if (stat & LE_RINT) {
40952130Smckusick 		/* interrupt is cleared in lerint */
41052130Smckusick 		lerint(unit);
41152130Smckusick 	}
41252130Smckusick 	if (stat & LE_TINT) {
41352130Smckusick 		LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp);
41452130Smckusick 		MachEmptyWriteBuffer();
41552130Smckusick 		lexint(unit);
41652130Smckusick 	}
41752130Smckusick }
41852130Smckusick 
41952130Smckusick /*
42052130Smckusick  * Ethernet interface transmitter interrupt.
42152130Smckusick  * Start another output if more data to send.
42252130Smckusick  */
42352130Smckusick lexint(unit)
42452130Smckusick 	register int unit;
42552130Smckusick {
42652130Smckusick 	register struct le_softc *le = &le_softc[unit];
42752130Smckusick 	register int bix = le->sc_tmd;
42852130Smckusick 	register volatile struct letmd *tmd = &le->sc_r2->ler2_tmd[bix];
42952130Smckusick 
43052130Smckusick 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
43152130Smckusick 		le->sc_xint++;
43252130Smckusick 		return;
43352130Smckusick 	}
43452130Smckusick 	LENEXTTMP;
43552130Smckusick 	while (bix != le->sc_tmdnext && (tmd->tmd1 & LE_OWN) == 0) {
43652130Smckusick 		le->sc_tmd = bix;
43752130Smckusick 		if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) {
43852130Smckusick 			lexerror(unit);
43952130Smckusick 			le->sc_if.if_oerrors++;
44052130Smckusick 			if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
44152130Smckusick 				le->sc_uflo++;
44252130Smckusick 				lereset(unit);
44352130Smckusick 				break;
44452130Smckusick 			}
44552130Smckusick 			else if (tmd->tmd3 & LE_LCOL)
44652130Smckusick 				le->sc_if.if_collisions++;
44752130Smckusick 			else if (tmd->tmd3 & LE_RTRY)
44852130Smckusick 				le->sc_if.if_collisions += 16;
44952130Smckusick 		}
45052130Smckusick 		else if (tmd->tmd1 & LE_ONE)
45152130Smckusick 			le->sc_if.if_collisions++;
45252130Smckusick 		else if (tmd->tmd1 & LE_MORE)
45352130Smckusick 			/* what is the real number? */
45452130Smckusick 			le->sc_if.if_collisions += 2;
45552130Smckusick 		else
45652130Smckusick 			le->sc_if.if_opackets++;
45752130Smckusick 		LENEXTTMP;
45852130Smckusick 	}
45952130Smckusick 	if (bix == le->sc_tmdnext)
46052130Smckusick 		le->sc_if.if_flags &= ~IFF_OACTIVE;
46152130Smckusick 	(void) lestart(&le->sc_if);
46252130Smckusick }
46352130Smckusick 
46452130Smckusick #define	LENEXTRMP \
46552130Smckusick 	if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
46652130Smckusick 
46752130Smckusick /*
46852130Smckusick  * Ethernet interface receiver interrupt.
46952130Smckusick  * If input error just drop packet.
47052130Smckusick  * Decapsulate packet based on type and pass to type specific
47152130Smckusick  * higher-level input routine.
47252130Smckusick  */
47352130Smckusick lerint(unit)
47452130Smckusick 	int unit;
47552130Smckusick {
47652130Smckusick 	register struct le_softc *le = &le_softc[unit];
47752130Smckusick 	register int bix = le->sc_rmd;
47852130Smckusick 	register volatile struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
47952130Smckusick 
48052130Smckusick 	/*
48152130Smckusick 	 * Out of sync with hardware, should never happen?
48252130Smckusick 	 */
48352130Smckusick 	if (rmd->rmd1 & LE_OWN) {
48452130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
48552130Smckusick 		MachEmptyWriteBuffer();
48652130Smckusick 		return;
48752130Smckusick 	}
48852130Smckusick 
48952130Smckusick 	/*
49052130Smckusick 	 * Process all buffers with valid data
49152130Smckusick 	 */
49252130Smckusick 	while ((rmd->rmd1 & LE_OWN) == 0) {
49352130Smckusick 		int len = rmd->rmd3;
49452130Smckusick 
49552130Smckusick 		/* Clear interrupt to avoid race condition */
49652130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
49752130Smckusick 		MachEmptyWriteBuffer();
49852130Smckusick 
49952130Smckusick 		if (rmd->rmd1 & LE_ERR) {
50052130Smckusick 			le->sc_rmd = bix;
50152130Smckusick 			lererror(unit, "bad packet");
50252130Smckusick 			le->sc_if.if_ierrors++;
50352130Smckusick 		} else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
50452130Smckusick 			/*
50552130Smckusick 			 * Find the end of the packet so we can see how long
50652130Smckusick 			 * it was.  We still throw it away.
50752130Smckusick 			 */
50852130Smckusick 			do {
50952130Smckusick 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
51052130Smckusick 				       le->sc_r1->ler1_rdp);
51152130Smckusick 				MachEmptyWriteBuffer();
51252130Smckusick 				rmd->rmd3 = 0;
51352130Smckusick 				rmd->rmd1 = LE_OWN;
51452130Smckusick 				LENEXTRMP;
51552130Smckusick 			} while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
51652130Smckusick 			le->sc_rmd = bix;
51752130Smckusick 			lererror(unit, "chained buffer");
51852130Smckusick 			le->sc_rxlen++;
51952130Smckusick 			/*
52052130Smckusick 			 * If search terminated without successful completion
52152130Smckusick 			 * we reset the hardware (conservative).
52252130Smckusick 			 */
52352130Smckusick 			if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
52452130Smckusick 			    LE_ENP) {
52552130Smckusick 				lereset(unit);
52652130Smckusick 				return;
52752130Smckusick 			}
52852130Smckusick 		} else
52952130Smckusick 			leread(unit, le->sc_r2->ler2_rbuf[bix], len);
53052130Smckusick 		rmd->rmd3 = 0;
53152130Smckusick 		rmd->rmd1 = LE_OWN;
53252130Smckusick 		LENEXTRMP;
53352130Smckusick 	}
53452130Smckusick 	MachEmptyWriteBuffer();		/* Paranoia */
53552130Smckusick 	le->sc_rmd = bix;
53652130Smckusick }
53752130Smckusick 
53852130Smckusick /*
53952130Smckusick  * Look at the packet in network buffer memory so we can be smart about how
54052130Smckusick  * we copy the data into mbufs.
54152130Smckusick  * This needs work since we can't just read network buffer memory like
54252130Smckusick  * regular memory.
54352130Smckusick  */
54452130Smckusick leread(unit, buf, len)
54552130Smckusick 	int unit;
54652695Sralph 	le_buf_t *buf;
54752130Smckusick 	int len;
54852130Smckusick {
54952130Smckusick 	register struct le_softc *le = &le_softc[unit];
55052130Smckusick 	struct ether_header et;
55152130Smckusick     	struct mbuf *m;
55252130Smckusick 	int off, resid;
55352695Sralph #ifdef DS3100
55452130Smckusick 	u_short sbuf[2];
55552695Sralph #endif
55652695Sralph 	extern struct mbuf *leget();
55752130Smckusick 
55852130Smckusick 	le->sc_if.if_ipackets++;
55952695Sralph #ifdef DS3100
56052130Smckusick 	CopyFromBuffer(buf, (char *)&et, sizeof(et));
56152695Sralph #endif
56252695Sralph #ifdef DS5000
56352695Sralph 	bcopy(buf, (char *)&et, sizeof(et));
56452695Sralph #endif
56552130Smckusick 	et.ether_type = ntohs(et.ether_type);
56652130Smckusick 	/* adjust input length to account for header and CRC */
56752130Smckusick 	len = len - sizeof(struct ether_header) - 4;
56852130Smckusick 
56952130Smckusick #ifdef RMP
57052130Smckusick 	/*  (XXX)
57152130Smckusick 	 *
57252130Smckusick 	 *  If Ethernet Type field is < MaxPacketSize, we probably have
57352130Smckusick 	 *  a IEEE802 packet here.  Make sure that the size is at least
57452130Smckusick 	 *  that of the HP LLC.  Also do sanity checks on length of LLC
57552130Smckusick 	 *  (old Ethernet Type field) and packet length.
57652130Smckusick 	 *
57752130Smckusick 	 *  Provided the above checks succeed, change `len' to reflect
57852130Smckusick 	 *  the length of the LLC (i.e. et.ether_type) and change the
57952130Smckusick 	 *  type field to ETHERTYPE_IEEE so we can switch() on it later.
58052130Smckusick 	 *  Yes, this is a hack and will eventually be done "right".
58152130Smckusick 	 */
58252130Smckusick 	if (et.ether_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) &&
58352130Smckusick 	    len >= et.ether_type && len >= IEEE802LEN_MIN) {
58452130Smckusick 		len = et.ether_type;
58552130Smckusick 		et.ether_type = ETHERTYPE_IEEE;	/* hack! */
58652130Smckusick 	}
58752130Smckusick #endif
58852130Smckusick 
58952130Smckusick 	if (et.ether_type >= ETHERTYPE_TRAIL &&
59052130Smckusick 	    et.ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
59152130Smckusick 		off = (et.ether_type - ETHERTYPE_TRAIL) * 512;
59252130Smckusick 		if (off >= ETHERMTU)
59352130Smckusick 			return;		/* sanity */
59452695Sralph #ifdef DS3100
59552130Smckusick 		CopyFromBuffer(buf + (sizeof(et) + off),
59652130Smckusick 			(char *)sbuf, sizeof(sbuf));
59752130Smckusick 		et.ether_type = ntohs(sbuf[0]);
59852130Smckusick 		resid = ntohs(sbuf[1]);
59952695Sralph #endif
60052695Sralph #ifdef DS5000
601*54144Sralph 		et.ether_type = ntohs(((u_short *)(buf + (sizeof(et) + off)))[0]);
602*54144Sralph 		resid = ntohs(((u_short *)(buf + (sizeof(et) + off)))[1]);
60352695Sralph #endif
60452130Smckusick 		if (off + resid > len)
60552130Smckusick 			return;		/* sanity */
60652130Smckusick 		len = off + resid;
60752130Smckusick 	} else
60852130Smckusick 		off = 0;
60952130Smckusick 
61052130Smckusick 	if (len <= 0) {
61152130Smckusick 		if (ledebug)
61252130Smckusick 			log(LOG_WARNING,
61352130Smckusick 			    "le%d: ierror(runt packet): from %s: len=%d\n",
61452130Smckusick 			    unit, ether_sprintf(et.ether_shost), len);
61552130Smckusick 		le->sc_runt++;
61652130Smckusick 		le->sc_if.if_ierrors++;
61752130Smckusick 		return;
61852130Smckusick 	}
61952130Smckusick #if NBPFILTER > 0
62052130Smckusick 	/*
62152130Smckusick 	 * Check if there's a bpf filter listening on this interface.
62252130Smckusick 	 * If so, hand off the raw packet to bpf, which must deal with
62352130Smckusick 	 * trailers in its own way.
62452130Smckusick 	 */
62552130Smckusick 	if (le->sc_bpf) {
62652130Smckusick 		bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
62752130Smckusick 
62852130Smckusick 		/*
62952130Smckusick 		 * Note that the interface cannot be in promiscuous mode if
63052130Smckusick 		 * there are no bpf listeners.  And if we are in promiscuous
63152130Smckusick 		 * mode, we have to check if this packet is really ours.
63252130Smckusick 		 *
63352130Smckusick 		 * XXX This test does not support multicasts.
63452130Smckusick 		 */
63552130Smckusick 		if ((le->sc_if.if_flags & IFF_PROMISC)
63652130Smckusick 		    && bcmp(et.ether_dhost, le->sc_addr,
63752130Smckusick 			    sizeof(et.ether_dhost)) != 0
63852130Smckusick 		    && bcmp(et.ether_dhost, etherbroadcastaddr,
63952130Smckusick 			    sizeof(et.ether_dhost)) != 0)
64052130Smckusick 			return;
64152130Smckusick 	}
64252130Smckusick #endif
64352130Smckusick 	/*
64452130Smckusick 	 * Pull packet off interface.  Off is nonzero if packet
64552130Smckusick 	 * has trailing header; leget will then force this header
64652130Smckusick 	 * information to be at the front, but we still have to drop
64752130Smckusick 	 * the type and length which are at the front of any trailer data.
64852130Smckusick 	 */
64952130Smckusick 	m = leget(buf, len, off, &le->sc_if);
65052130Smckusick 	if (m == 0)
65152130Smckusick 		return;
65252130Smckusick #ifdef RMP
65352130Smckusick 	/*
65452130Smckusick 	 * (XXX)
65552130Smckusick 	 * This needs to be integrated with the ISO stuff in ether_input()
65652130Smckusick 	 */
65752130Smckusick 	if (et.ether_type == ETHERTYPE_IEEE) {
65852130Smckusick 		/*
65952130Smckusick 		 *  Snag the Logical Link Control header (IEEE 802.2).
66052130Smckusick 		 */
66152130Smckusick 		struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc);
66252130Smckusick 
66352130Smckusick 		/*
66452130Smckusick 		 *  If the DSAP (and HP's extended DXSAP) indicate this
66552130Smckusick 		 *  is an RMP packet, hand it to the raw input routine.
66652130Smckusick 		 */
66752130Smckusick 		if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
66852130Smckusick 			static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
66952130Smckusick 			static struct sockaddr rmp_src = {AF_RMP};
67052130Smckusick 			static struct sockaddr rmp_dst = {AF_RMP};
67152130Smckusick 
67252130Smckusick 			bcopy(et.ether_shost, rmp_src.sa_data,
67352130Smckusick 			      sizeof(et.ether_shost));
67452130Smckusick 			bcopy(et.ether_dhost, rmp_dst.sa_data,
67552130Smckusick 			      sizeof(et.ether_dhost));
67652130Smckusick 
67752130Smckusick 			raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
67852130Smckusick 			return;
67952130Smckusick 		}
68052130Smckusick 	}
68152130Smckusick #endif
68252130Smckusick 	ether_input(&le->sc_if, &et, m);
68352130Smckusick }
68452130Smckusick 
68552130Smckusick /*
68652130Smckusick  * Routine to copy from mbuf chain to transmit buffer in
68752130Smckusick  * network buffer memory.
68852695Sralph  * NOTE: On the DS3100, network memory can only be written one short at
68952695Sralph  *	every other address.
69052130Smckusick  */
69152130Smckusick leput(lebuf, m)
69252695Sralph 	register le_buf_t *lebuf;
69352130Smckusick 	register struct mbuf *m;
69452130Smckusick {
69552130Smckusick 	register struct mbuf *mp;
69652695Sralph 	register int len, tlen = 0;
69752695Sralph #ifdef DS3100
69852130Smckusick 	register char *cp;
69952695Sralph 	int tmp, xfer;
70052695Sralph #endif
70152130Smckusick 
70252130Smckusick 	for (mp = m; mp; mp = mp->m_next) {
70352130Smckusick 		len = mp->m_len;
70452130Smckusick 		if (len == 0)
70552130Smckusick 			continue;
70652695Sralph #ifdef DS3100
70752130Smckusick 		/* copy data for this mbuf */
70852130Smckusick 		cp = mtod(mp, char *);
70952130Smckusick 		if (tlen & 1) {
71052130Smckusick 			/* handle odd length from previous mbuf */
71152130Smckusick 			*lebuf = (cp[0] << 8) | tmp;
71252130Smckusick 			lebuf += 2;
71352130Smckusick 			cp++;
71452130Smckusick 			len--;
71552130Smckusick 			tlen++;
71652130Smckusick 		}
71752130Smckusick 		tlen += len;
71852130Smckusick 		if ((unsigned)cp & 1) {
71952130Smckusick 			while (len > 1) {
72052130Smckusick 				*lebuf = (cp[1] << 8) | cp[0];
72152130Smckusick 				lebuf += 2;
72252130Smckusick 				cp += 2;
72352130Smckusick 				len -= 2;
72452130Smckusick 			}
72552130Smckusick 		} else {
72652130Smckusick 			/* optimize for aligned transfers */
72752130Smckusick 			xfer = (int)((unsigned)len & ~0x1);
72852130Smckusick 			CopyToBuffer((u_short *)cp, lebuf, xfer);
72952130Smckusick 			lebuf += xfer;
73052130Smckusick 			cp += xfer;
73152130Smckusick 			len -= xfer;
73252130Smckusick 		}
73352130Smckusick 		if (len == 1)
73452130Smckusick 			tmp = *cp;
73552695Sralph #endif
73652695Sralph #ifdef DS5000
73752695Sralph 		tlen += len;
73852695Sralph 		bcopy(mtod(mp, char *), lebuf, len);
73952695Sralph 		lebuf += len;
74052695Sralph #endif
74152130Smckusick 	}
74252130Smckusick 	m_freem(m);
74352695Sralph #ifdef DS3100
74452130Smckusick 	/* handle odd length from previous mbuf */
74552130Smckusick 	if (tlen & 1)
74652130Smckusick 		*lebuf = tmp;
74752695Sralph #endif
74852695Sralph 	if (tlen < LEMINSIZE) {
74952695Sralph #ifdef DS3100
75052695Sralph 		tlen = (tlen + 1) & ~1;
75152695Sralph 		while (tlen < LEMINSIZE) {
75252695Sralph 			*lebuf++ = 0;
75352695Sralph 			tlen += 2;
75452695Sralph 		}
75552695Sralph #endif
75652695Sralph #ifdef DS5000
75752695Sralph 		bzero(lebuf, LEMINSIZE - tlen);
75852695Sralph #endif
75952130Smckusick 		tlen = LEMINSIZE;
76052695Sralph 	}
76152130Smckusick 	return(tlen);
76252130Smckusick }
76352130Smckusick 
76452130Smckusick /*
76552130Smckusick  * Routine to copy from network buffer memory into mbufs.
76652695Sralph  * NOTE: On the DS3100, network memory can only be written one short at
76752695Sralph  *	every other address.
76852130Smckusick  */
76952130Smckusick struct mbuf *
77052130Smckusick leget(lebuf, totlen, off, ifp)
77152695Sralph 	le_buf_t *lebuf;
77252130Smckusick 	int totlen, off;
77352130Smckusick 	struct ifnet *ifp;
77452130Smckusick {
77552130Smckusick 	register struct mbuf *m;
77652130Smckusick 	struct mbuf *top = 0, **mp = &top;
77752130Smckusick 	register int len, resid;
77852695Sralph 	register le_buf_t *sp;
77952130Smckusick 
78052130Smckusick 	/* NOTE: sizeof(struct ether_header) should be even */
78152130Smckusick 	lebuf += sizeof(struct ether_header);
78252130Smckusick 	sp = lebuf;
78352130Smckusick 	if (off) {
78452130Smckusick 		/* NOTE: off should be even */
78552130Smckusick 		sp += off + 2 * sizeof(u_short);
78652130Smckusick 		totlen -= 2 * sizeof(u_short);
78752130Smckusick 		resid = totlen - off;
78852130Smckusick 	} else
78952130Smckusick 		resid = totlen;
79052130Smckusick 
79152130Smckusick 	MGETHDR(m, M_DONTWAIT, MT_DATA);
79252130Smckusick 	if (m == 0)
79352130Smckusick 		return (0);
79452130Smckusick 	m->m_pkthdr.rcvif = ifp;
79552130Smckusick 	m->m_pkthdr.len = totlen;
79652130Smckusick 	m->m_len = MHLEN;
79752130Smckusick 
79852130Smckusick 	while (totlen > 0) {
79952130Smckusick 		if (top) {
80052130Smckusick 			MGET(m, M_DONTWAIT, MT_DATA);
80152130Smckusick 			if (m == 0) {
80252130Smckusick 				m_freem(top);
80352130Smckusick 				return (0);
80452130Smckusick 			}
80552130Smckusick 			m->m_len = MLEN;
80652130Smckusick 		}
80752130Smckusick 
80852130Smckusick 		if (resid >= MINCLSIZE)
80952130Smckusick 			MCLGET(m, M_DONTWAIT);
81052130Smckusick 		if (m->m_flags & M_EXT)
81152130Smckusick 			m->m_len = MIN(resid, MCLBYTES);
81252130Smckusick 		else if (resid < m->m_len) {
81352130Smckusick 			/*
81452130Smckusick 			 * Place initial small packet/header at end of mbuf.
81552130Smckusick 			 */
81652130Smckusick 			if (top == 0 && resid + max_linkhdr <= m->m_len)
81752130Smckusick 				m->m_data += max_linkhdr;
81852130Smckusick 			m->m_len = resid;
81952130Smckusick 		}
82052130Smckusick 		len = m->m_len;
82152695Sralph #ifdef DS3100
82252130Smckusick 		if ((unsigned)sp & 2) {
82352130Smckusick 			/*
82452130Smckusick 			 * Previous len was odd. Copy the single byte specially.
82552130Smckusick 			 * XXX Can this ever happen??
82652130Smckusick 			 */
82752130Smckusick 			panic("le odd rcv");
82852130Smckusick 			*mtod(m, char *) = ((volatile char *)sp)[-1];
82952130Smckusick 			CopyFromBuffer(sp + 1, mtod(m, char *) + 1, len - 1);
83052130Smckusick 		} else
83152130Smckusick 			CopyFromBuffer(sp, mtod(m, char *), len);
83252695Sralph #endif
83352695Sralph #ifdef DS5000
83452695Sralph 		bcopy(sp, mtod(m, char *), len);
83552695Sralph #endif
83652130Smckusick 		sp += len;
83752130Smckusick 		*mp = m;
83852130Smckusick 		mp = &m->m_next;
83952130Smckusick 		totlen -= len;
84052130Smckusick 		resid -= len;
84152130Smckusick 		if (resid == 0) {
84252130Smckusick 			sp = lebuf;
84352130Smckusick 			resid = totlen;
84452130Smckusick 		}
84552130Smckusick 	}
84652130Smckusick 	return (top);
84752130Smckusick }
84852130Smckusick 
84952130Smckusick /*
85052130Smckusick  * Process an ioctl request.
85152130Smckusick  */
85252130Smckusick leioctl(ifp, cmd, data)
85352130Smckusick 	register struct ifnet *ifp;
85452130Smckusick 	int cmd;
85552130Smckusick 	caddr_t data;
85652130Smckusick {
85752130Smckusick 	register struct ifaddr *ifa = (struct ifaddr *)data;
85852130Smckusick 	struct le_softc *le = &le_softc[ifp->if_unit];
85952130Smckusick 	volatile struct lereg1 *ler1 = le->sc_r1;
86052130Smckusick 	int s, error = 0;
86152130Smckusick 
86252130Smckusick 	s = splnet();
86352130Smckusick 	switch (cmd) {
86452130Smckusick 
86552130Smckusick 	case SIOCSIFADDR:
86652130Smckusick 		ifp->if_flags |= IFF_UP;
86752130Smckusick 		switch (ifa->ifa_addr->sa_family) {
86852130Smckusick #ifdef INET
86952130Smckusick 		case AF_INET:
87052130Smckusick 			leinit(ifp->if_unit);	/* before arpwhohas */
87152130Smckusick 			((struct arpcom *)ifp)->ac_ipaddr =
87252130Smckusick 				IA_SIN(ifa)->sin_addr;
87352130Smckusick 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
87452130Smckusick 			break;
87552130Smckusick #endif
87652130Smckusick #ifdef NS
87752130Smckusick 		case AF_NS:
87852130Smckusick 		    {
87952130Smckusick 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
88052130Smckusick 
88152130Smckusick 			if (ns_nullhost(*ina))
88252130Smckusick 				ina->x_host = *(union ns_host *)(le->sc_addr);
88352130Smckusick 			else {
88452130Smckusick 				/*
88552130Smckusick 				 * The manual says we can't change the address
88652130Smckusick 				 * while the receiver is armed,
88752130Smckusick 				 * so reset everything
88852130Smckusick 				 */
88952130Smckusick 				ifp->if_flags &= ~IFF_RUNNING;
89052130Smckusick 				bcopy((caddr_t)ina->x_host.c_host,
89152130Smckusick 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
89252130Smckusick 			}
89352130Smckusick 			leinit(ifp->if_unit); /* does le_setaddr() */
89452130Smckusick 			break;
89552130Smckusick 		    }
89652130Smckusick #endif
89752130Smckusick 		default:
89852130Smckusick 			leinit(ifp->if_unit);
89952130Smckusick 			break;
90052130Smckusick 		}
90152130Smckusick 		break;
90252130Smckusick 
90352130Smckusick 	case SIOCSIFFLAGS:
90452130Smckusick 		if ((ifp->if_flags & IFF_UP) == 0 &&
90552130Smckusick 		    ifp->if_flags & IFF_RUNNING) {
90652130Smckusick 			LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
90752130Smckusick 			MachEmptyWriteBuffer();
90852130Smckusick 			ifp->if_flags &= ~IFF_RUNNING;
90952130Smckusick 		} else if (ifp->if_flags & IFF_UP &&
91052130Smckusick 		    (ifp->if_flags & IFF_RUNNING) == 0)
91152130Smckusick 			leinit(ifp->if_unit);
91252130Smckusick 		/*
91352130Smckusick 		 * If the state of the promiscuous bit changes, the interface
91452130Smckusick 		 * must be reset to effect the change.
91552130Smckusick 		 */
91652130Smckusick 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
91752130Smckusick 		    (ifp->if_flags & IFF_RUNNING)) {
91852130Smckusick 			le->sc_iflags = ifp->if_flags;
91952130Smckusick 			lereset(ifp->if_unit);
92052130Smckusick 			lestart(ifp);
92152130Smckusick 		}
92252130Smckusick 		break;
92352130Smckusick 
92452130Smckusick 	default:
92552130Smckusick 		error = EINVAL;
92652130Smckusick 	}
92752130Smckusick 	splx(s);
92852130Smckusick 	return (error);
92952130Smckusick }
93052130Smckusick 
93152130Smckusick leerror(unit, stat)
93252130Smckusick 	int unit;
93352130Smckusick 	int stat;
93452130Smckusick {
93552130Smckusick 	if (!ledebug)
93652130Smckusick 		return;
93752130Smckusick 
93852130Smckusick 	/*
93952130Smckusick 	 * Not all transceivers implement heartbeat
94052130Smckusick 	 * so we only log CERR once.
94152130Smckusick 	 */
94252130Smckusick 	if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
94352130Smckusick 		return;
94452130Smckusick 	log(LOG_WARNING,
94552130Smckusick 	    "le%d: error: stat=%b\n", unit,
94652130Smckusick 	    stat,
94752130Smckusick 	    "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
94852130Smckusick }
94952130Smckusick 
95052130Smckusick lererror(unit, msg)
95152130Smckusick 	int unit;
95252130Smckusick 	char *msg;
95352130Smckusick {
95452130Smckusick 	register struct le_softc *le = &le_softc[unit];
95552130Smckusick 	register volatile struct lermd *rmd;
956*54144Sralph 	u_char eaddr[6];
957*54144Sralph 	char *cp;
95852130Smckusick 	int len;
95952130Smckusick 
96052130Smckusick 	if (!ledebug)
96152130Smckusick 		return;
96252130Smckusick 
96352130Smckusick 	rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
96452130Smckusick 	len = rmd->rmd3;
965*54144Sralph 	if (len > 11) {
966*54144Sralph #ifdef DS3100
967*54144Sralph 		CopyFromBuffer((char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6],
968*54144Sralph 			eaddr, sizeof(eaddr));
969*54144Sralph #endif
970*54144Sralph #ifdef DS5000
971*54144Sralph 		bcopy((char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6],
972*54144Sralph 			eaddr, sizeof(eaddr));
973*54144Sralph #endif
974*54144Sralph 		cp = ether_sprintf(eaddr);
975*54144Sralph 	} else
976*54144Sralph 		cp = "unknown";
97752130Smckusick 	log(LOG_WARNING,
97852130Smckusick 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
979*54144Sralph 	    unit, msg, cp, le->sc_rmd, len,
98052130Smckusick 	    rmd->rmd1,
98152130Smckusick 	    "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
98252130Smckusick }
98352130Smckusick 
98452130Smckusick lexerror(unit)
98552130Smckusick 	int unit;
98652130Smckusick {
98752130Smckusick 	register struct le_softc *le = &le_softc[unit];
98852130Smckusick 	register volatile struct letmd *tmd;
989*54144Sralph 	u_char eaddr[6];
990*54144Sralph 	char *cp;
99152130Smckusick 	int len;
99252130Smckusick 
99352130Smckusick 	if (!ledebug)
99452130Smckusick 		return;
99552130Smckusick 
99652130Smckusick 	tmd = le->sc_r2->ler2_tmd;
99752130Smckusick 	len = -tmd->tmd2;
998*54144Sralph 	if (len > 5) {
999*54144Sralph #ifdef DS3100
1000*54144Sralph 		CopyFromBuffer((char *)&le->sc_r2->ler2_tbuf[le->sc_tmd][0],
1001*54144Sralph 			eaddr, sizeof(eaddr));
1002*54144Sralph #endif
1003*54144Sralph #ifdef DS5000
1004*54144Sralph 		bcopy((char *)&le->sc_r2->ler2_tbuf[le->sc_tmd][0],
1005*54144Sralph 			eaddr, sizeof(eaddr));
1006*54144Sralph #endif
1007*54144Sralph 		cp = ether_sprintf(eaddr);
1008*54144Sralph 	} else
1009*54144Sralph 		cp = "unknown";
101052130Smckusick 	log(LOG_WARNING,
101152130Smckusick 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
1012*54144Sralph 	    unit, cp, le->sc_tmd, len,
101352130Smckusick 	    tmd->tmd1,
101452130Smckusick 	    "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
101552130Smckusick 	    tmd->tmd3,
101652130Smckusick 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
101752130Smckusick }
101852130Smckusick #endif
1019