xref: /csrg-svn/sys/sparc/sbus/if_le.c (revision 56540)
155139Storek /*-
255139Storek  * Copyright (c) 1982, 1992 The Regents of the University of California.
355139Storek  * All rights reserved.
455139Storek  *
555139Storek  * %sccs.include.redist.c%
655139Storek  *
7*56540Sbostic  *	@(#)if_le.c	7.2 (Berkeley) 10/11/92
855139Storek  *
955139Storek  * from: $Header: if_le.c,v 1.17 92/07/10 06:45:17 torek Exp $
1055139Storek  */
1155139Storek 
1255139Storek #include "bpfilter.h"
1355139Storek 
1455139Storek /*
1555139Storek  * AMD 7990 LANCE
1655139Storek  *
1755139Storek  * This driver will generate and accept tailer encapsulated packets even
1855139Storek  * though it buys us nothing.  The motivation was to avoid incompatibilities
1955139Storek  * with VAXen, SUNs, and others that handle and benefit from them.
2055139Storek  * This reasoning is dubious.
2155139Storek  */
22*56540Sbostic #include <sys/param.h>
23*56540Sbostic #include <sys/device.h>
24*56540Sbostic #include <sys/systm.h>
25*56540Sbostic #include <sys/kernel.h>
26*56540Sbostic #include <sys/mbuf.h>
27*56540Sbostic #include <sys/buf.h>
28*56540Sbostic #include <sys/socket.h>
29*56540Sbostic #include <sys/syslog.h>
30*56540Sbostic #include <sys/ioctl.h>
31*56540Sbostic #include <sys/malloc.h>
32*56540Sbostic #include <sys/errno.h>
3355139Storek 
34*56540Sbostic #include <net/if.h>
35*56540Sbostic #include <net/netisr.h>
36*56540Sbostic #include <net/route.h>
3755139Storek #if NBPFILTER > 0
38*56540Sbostic #include <sys/select.h>
39*56540Sbostic #include <net/bpf.h>
40*56540Sbostic #include <net/bpfdesc.h>
4155139Storek #endif
4255139Storek 
4355139Storek #ifdef INET
44*56540Sbostic #include <netinet/in.h>
45*56540Sbostic #include <netinet/in_systm.h>
46*56540Sbostic #include <netinet/in_var.h>
47*56540Sbostic #include <netinet/ip.h>
48*56540Sbostic #include <netinet/if_ether.h>
4955139Storek #endif
5055139Storek 
5155139Storek #ifdef NS
52*56540Sbostic #include <netns/ns.h>
53*56540Sbostic #include <netns/ns_if.h>
5455139Storek #endif
5555139Storek 
5655139Storek #ifdef APPLETALK
57*56540Sbostic #include <netddp/atalk.h>
5855139Storek #endif
5955139Storek 
60*56540Sbostic #include <machine/autoconf.h>
61*56540Sbostic #include <machine/cpu.h>
62*56540Sbostic #include <machine/pmap.h>
6355139Storek 
64*56540Sbostic #include <sparc/sbus/if_lereg.h>
65*56540Sbostic #include <sparc/sbus/sbusvar.h>
6655139Storek 
6755139Storek /* DVMA address to LANCE address -- the Sbus/MMU will resupply the 0xff */
6855139Storek #define	LANCE_ADDR(x)	((int)(x) & ~0xff000000)
6955139Storek 
7055139Storek int	ledebug = 0;		/* console error messages */
7155139Storek 
7255139Storek #ifdef PACKETSTATS
7355139Storek long	lexpacketsizes[LEMTU+1];
7455139Storek long	lerpacketsizes[LEMTU+1];
7555139Storek #endif
7655139Storek 
7755139Storek /* Per interface statistics */
7855139Storek /* XXX this should go in something like if_levar.h */
7955139Storek struct	lestats {
8055139Storek 	long	lexints;	/* transmitter interrupts */
8155139Storek 	long	lerints;	/* receiver interrupts */
8255139Storek 	long	lerbufs;	/* total buffers received during interrupts */
8355139Storek 	long	lerhits;	/* times current rbuf was full */
8455139Storek 	long	lerscans;	/* rbufs scanned before finding first full */
8555139Storek };
8655139Storek 
8755139Storek /*
8855139Storek  * Ethernet software status per interface.
8955139Storek  *
9055139Storek  * Each interface is referenced by a network interface structure,
9155139Storek  * le_if, which the routing code uses to locate the interface.
9255139Storek  * This structure contains the output queue for the interface, its address, ...
9355139Storek  */
9455139Storek struct le_softc {
9555139Storek 	struct	device sc_dev;		/* base device */
9655139Storek 	struct	sbusdev sc_sd;		/* sbus device */
9755139Storek 	struct	intrhand sc_ih;		/* interrupt vectoring */
9855139Storek 	int	sc_interrupts;		/* number of interrupts taken */
9955139Storek 
10055139Storek 	struct	arpcom sc_ac;		/* common Ethernet structures */
10155139Storek #define	sc_if	sc_ac.ac_if		/* network-visible interface */
10255139Storek #define	sc_addr	sc_ac.ac_enaddr		/* hardware Ethernet address */
10355139Storek 	volatile struct	lereg1 *sc_r1;	/* LANCE registers */
10455139Storek 	volatile struct	lereg2 *sc_r2;	/* dual-port RAM */
10555139Storek 	int	sc_rmd;			/* predicted next rmd to process */
10655139Storek 	int	sc_runt;
10755139Storek 	int	sc_jab;
10855139Storek 	int	sc_merr;
10955139Storek 	int	sc_babl;
11055139Storek 	int	sc_cerr;
11155139Storek 	int	sc_miss;
11255139Storek 	int	sc_xint;
11355139Storek 	int	sc_xown;
11455139Storek 	int	sc_uflo;
11555139Storek 	int	sc_rxlen;
11655139Storek 	int	sc_rxoff;
11755139Storek 	int	sc_txoff;
11855139Storek 	int	sc_busy;
11955139Storek 	short	sc_iflags;
12055139Storek 	struct	lestats sc_lestats;	/* per interface statistics */
12155139Storek #if NBPFILTER > 0
12255139Storek 	caddr_t	sc_bpf;
12355139Storek #endif
12455139Storek };
12555139Storek 
12655139Storek 
12755139Storek /* autoconfiguration driver */
12855139Storek void	leattach(struct device *, struct device *, void *);
12955139Storek struct	cfdriver lecd =
13055139Storek     { NULL, "le", matchbyname, leattach, DV_IFNET, sizeof(struct le_softc) };
13155139Storek 
13255139Storek /* Forwards */
13355139Storek void	leattach(struct device *, struct device *, void *);
13455139Storek #ifdef MULTICAST
13555139Storek void	lesetladrf(struct le_softc *);
13655139Storek #endif
13755139Storek void	lereset(struct device *);
13855139Storek int	leinit(int);
13955139Storek int	lestart(struct ifnet *);
14055139Storek int	leintr(void *);
14155139Storek void	lexint(struct le_softc *);
14255139Storek void	lerint(struct le_softc *);
14355139Storek void	leread(struct le_softc *, char *, int);
14455139Storek int	leput(char *, struct mbuf *);
14555139Storek struct mbuf *leget(char *, int, int, struct ifnet *);
14655139Storek int	leioctl(struct ifnet *, int, caddr_t);
14755139Storek void	leerror(struct le_softc *, int);
14855139Storek void	lererror(struct le_softc *, char *);
14955139Storek void	lexerror(struct le_softc *);
15055139Storek 
15155139Storek /*
15255139Storek  * Interface exists: make available by filling in network interface
15355139Storek  * record.  System will initialize the interface when it is ready
15455139Storek  * to accept packets.
15555139Storek  */
15655139Storek void
15755139Storek leattach(parent, self, args)
15855139Storek 	struct device *parent;
15955139Storek 	struct device *self;
16055139Storek 	void *args;
16155139Storek {
16255139Storek 	register struct le_softc *sc = (struct le_softc *)self;
16355139Storek 	register struct sbus_attach_args *sa = args;
16455139Storek 	register volatile struct lereg2 *ler2;
16555139Storek 	struct ifnet *ifp = &sc->sc_if;
16655139Storek 	register int a, pri;
16755139Storek #define	ISQUADALIGN(a) ((((long) a) & 0x3) == 0)
16855139Storek 
16955139Storek 	/* XXX the following declarations should be elsewhere */
17055139Storek 	extern void myetheraddr(u_char *);
17155139Storek 	extern caddr_t dvma_malloc(size_t);
17255139Storek 
17355139Storek 	if (sa->sa_ra.ra_nintr != 1) {
17455139Storek 		printf(": expected 1 interrupt, got %d\n", sa->sa_ra.ra_nintr);
17555139Storek 		return;
17655139Storek 	}
17755139Storek 	pri = sa->sa_ra.ra_intr[0].int_pri;
17855139Storek 	printf(" pri %d", pri);
17955139Storek 	sc->sc_r1 = (volatile struct lereg1 *)
18055139Storek 	    mapiodev(sa->sa_ra.ra_paddr, sizeof(struct lereg1));
18155139Storek 	ler2 = sc->sc_r2 = (volatile struct lereg2 *)
18255139Storek 	    dvma_malloc(sizeof(struct lereg2));
18355139Storek if (!ISQUADALIGN(ler2))
18455139Storek 	printf("? not quad aligned (0x%x)\n", ler2);
18555139Storek 
18655139Storek 	myetheraddr(sc->sc_addr);
18755139Storek 	printf(": hardware address %s\n", ether_sprintf(sc->sc_addr));
18855139Storek 
18955139Storek 	/*
19055139Storek 	 * Setup for transmit/receive
19155139Storek 	 *
19255139Storek 	 * According to Van, some versions of the Lance only use this
19355139Storek 	 * address to receive packets; it doesn't put them in
19455139Storek 	 * output packets. We'll want to make sure that lestart()
19555139Storek 	 * installs the address.
19655139Storek 	 */
19755139Storek 	ler2->ler2_padr[0] = sc->sc_addr[1];
19855139Storek 	ler2->ler2_padr[1] = sc->sc_addr[0];
19955139Storek 	ler2->ler2_padr[2] = sc->sc_addr[3];
20055139Storek 	ler2->ler2_padr[3] = sc->sc_addr[2];
20155139Storek 	ler2->ler2_padr[4] = sc->sc_addr[5];
20255139Storek 	ler2->ler2_padr[5] = sc->sc_addr[4];
20355139Storek 	a = LANCE_ADDR(&ler2->ler2_rmd);
20455139Storek if (!ISQUADALIGN(a))
20555139Storek 	printf("rdra not quad aligned (0x%x)\n", a);
20655139Storek 	ler2->ler2_rlen = LE_RLEN | (a >> 16);
20755139Storek 	ler2->ler2_rdra = a;
20855139Storek 	a = LANCE_ADDR(&ler2->ler2_tmd);
20955139Storek if (!ISQUADALIGN(a))
21055139Storek 	printf("tdra not quad aligned (0x%x)\n", a);
21155139Storek 	ler2->ler2_tlen = LE_TLEN | (a >> 16);
21255139Storek 	ler2->ler2_tdra = a;
21355139Storek 
21455139Storek 	/*
21555139Storek 	 * Link into sbus, and establish interrupt handler.
21655139Storek 	 */
21755139Storek 	sc->sc_sd.sd_reset = lereset;
21855139Storek 	sbus_establish(&sc->sc_sd, &sc->sc_dev);
21955139Storek 	sc->sc_ih.ih_fun = leintr;
22055139Storek 	sc->sc_ih.ih_arg = sc;
22155139Storek 	intr_establish(pri, &sc->sc_ih);
22255139Storek 
22355139Storek 	ifp->if_unit = sc->sc_dev.dv_unit;
22455139Storek 	ifp->if_name = "le";
22555139Storek 	ifp->if_mtu = ETHERMTU;
22655139Storek 	ifp->if_init = leinit;
22755139Storek 	ifp->if_ioctl = leioctl;
22855139Storek 	ifp->if_output = ether_output;
22955139Storek 	ifp->if_start = lestart;
23055139Storek #ifdef MULTICAST
23155139Storek 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
23255139Storek #else
23355139Storek 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
23455139Storek #endif
23555139Storek #ifdef IFF_NOTRAILERS
23655139Storek 	/* XXX still compile when the blasted things are gone... */
23755139Storek 	ifp->if_flags |= IFF_NOTRAILERS;
23855139Storek #endif
23955139Storek #if NBPFILTER > 0
24055139Storek 	bpfattach(&sc->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
24155139Storek #endif
24255139Storek 	if_attach(ifp);
24355139Storek }
24455139Storek 
24555139Storek #ifdef MULTICAST
24655139Storek /*
24755139Storek  * Setup the logical address filter
24855139Storek  */
24955139Storek void
25055139Storek lesetladrf(sc)
25155139Storek 	register struct le_softc *sc;
25255139Storek {
25355139Storek 	register volatile struct lereg2 *ler2 = sc->sc_r2;
25455139Storek 	register struct ifnet *ifp = &sc->sc_if;
25555139Storek 	register struct ether_multi *enm;
25655139Storek 	register u_char *cp;
25755139Storek 	register u_long crc;
25855139Storek 	register u_long c;
25955139Storek 	register int i, len;
26055139Storek 	struct ether_multistep step;
26155139Storek 
26255139Storek 	/*
26355139Storek 	 * Set up multicast address filter by passing all multicast
26455139Storek 	 * addresses through a crc generator, and then using the high
26555139Storek 	 * order 6 bits as a index into the 64 bit logical address
26655139Storek 	 * filter. The high order two bits select the word, while the
26755139Storek 	 * rest of the bits select the bit within the word.
26855139Storek 	 */
26955139Storek 
27055139Storek 	ler2->ler2_ladrf[0] = 0;
27155139Storek 	ler2->ler2_ladrf[1] = 0;
27255139Storek 	ifp->if_flags &= ~IFF_ALLMULTI;
27355139Storek 	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
27455139Storek 	while (enm != NULL) {
27555139Storek 		if (bcmp((caddr_t)&enm->enm_addrlo,
27655139Storek 		    (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) {
27755139Storek 			/*
27855139Storek 			 * We must listen to a range of multicast
27955139Storek 			 * addresses. For now, just accept all
28055139Storek 			 * multicasts, rather than trying to set only
28155139Storek 			 * those filter bits needed to match the range.
28255139Storek 			 * (At this time, the only use of address
28355139Storek 			 * ranges is for IP multicast routing, for
28455139Storek 			 * which the range is big enough to require all
28555139Storek 			 * bits set.)
28655139Storek 			 */
28755139Storek 			ler2->ler2_ladrf[0] = 0xffffffff;
28855139Storek 			ler2->ler2_ladrf[1] = 0xffffffff;
28955139Storek 			ifp->if_flags |= IFF_ALLMULTI;
29055139Storek 			return;
29155139Storek 		}
29255139Storek 
29355139Storek 		cp = (unsigned char *)&enm->enm_addrlo;
29455139Storek 		c = *cp;
29555139Storek 		crc = 0xffffffff;
29655139Storek 		len = 6;
29755139Storek 		while (len-- > 0) {
29855139Storek 			c = *cp;
29955139Storek 			for (i = 0; i < 8; i++) {
30055139Storek 				if ((c & 0x01) ^ (crc & 0x01)) {
30155139Storek 					crc >>= 1;
30255139Storek 					crc = crc ^ 0xedb88320;
30355139Storek 				}
30455139Storek 				else
30555139Storek 					crc >>= 1;
30655139Storek 				c >>= 1;
30755139Storek 			}
30855139Storek 			cp++;
30955139Storek 		}
31055139Storek 		/* Just want the 6 most significant bits. */
31155139Storek 		crc = crc >> 26;
31255139Storek 
31355139Storek 		/* Turn on the corresponding bit in the filter. */
31455139Storek 		ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f);
31555139Storek 
31655139Storek 		ETHER_NEXT_MULTI(step, enm);
31755139Storek 	}
31855139Storek }
31955139Storek #endif
32055139Storek 
32155139Storek void
32255139Storek lereset(dev)
32355139Storek 	struct device *dev;
32455139Storek {
32555139Storek 	register struct le_softc *sc = (struct le_softc *)dev;
32655139Storek 	register volatile struct lereg1 *ler1 = sc->sc_r1;
32755139Storek 	register volatile struct lereg2 *ler2 = sc->sc_r2;
32855139Storek 	register int i, a, timo, stat;
32955139Storek 
33055139Storek #if NBPFILTER > 0
33155139Storek 	if (sc->sc_if.if_flags & IFF_PROMISC)
33255139Storek 		ler2->ler2_mode = LE_MODE_NORMAL | LE_MODE_PROM;
33355139Storek 	else
33455139Storek #endif
33555139Storek 		ler2->ler2_mode = LE_MODE_NORMAL;
33655139Storek 	ler1->ler1_rap = LE_CSR0;
33755139Storek 	ler1->ler1_rdp = LE_C0_STOP;
33855139Storek 
33955139Storek 	/* Setup the logical address filter */
34055139Storek #ifdef MULTICAST
34155139Storek 	lesetladrf(sc);
34255139Storek #else
34355139Storek 	ler2->ler2_ladrf[0] = 0;
34455139Storek 	ler2->ler2_ladrf[1] = 0;
34555139Storek #endif
34655139Storek 
34755139Storek 	/* init receive and transmit rings */
34855139Storek a = LANCE_ADDR(&ler2->ler2_rbuf[0][0]);
34955139Storek if (!ISQUADALIGN(a))
35055139Storek 	printf("rbuf not quad aligned (0x%x)\n", a);
35155139Storek 	for (i = 0; i < LERBUF; i++) {
35255139Storek 		a = LANCE_ADDR(&ler2->ler2_rbuf[i][0]);
35355139Storek 		ler2->ler2_rmd[i].rmd0 = a;
35455139Storek 		ler2->ler2_rmd[i].rmd1_hadr = a >> 16;
35555139Storek 		ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;
35655139Storek 		ler2->ler2_rmd[i].rmd2 = -LEMTU;
35755139Storek 		ler2->ler2_rmd[i].rmd3 = 0;
35855139Storek 	}
35955139Storek a = LANCE_ADDR(&ler2->ler2_tbuf[0][0]);
36055139Storek if (!ISQUADALIGN(a))
36155139Storek 	printf("tbuf not quad aligned (0x%x)\n", a);
36255139Storek 	for (i = 0; i < LETBUF; i++) {
36355139Storek 		a = LANCE_ADDR(&ler2->ler2_tbuf[i][0]);
36455139Storek 		ler2->ler2_tmd[i].tmd0 = a;
36555139Storek 		ler2->ler2_tmd[i].tmd1_hadr = a >> 16;
36655139Storek 		ler2->ler2_tmd[i].tmd1_bits = 0;
36755139Storek 		ler2->ler2_tmd[i].tmd2 = 0;
36855139Storek 		ler2->ler2_tmd[i].tmd3 = 0;
36955139Storek 	}
37055139Storek 
37155139Storek bzero(&ler2->ler2_rbuf[0][0], (LERBUF + LETBUF) * LEMTU);
37255139Storek 	/* lance will stuff packet into receive buffer 0 next */
37355139Storek 	sc->sc_rmd = 0;
37455139Storek 
37555139Storek 	/* tell the chip where to find the initialization block */
37655139Storek 	a = LANCE_ADDR(&ler2->ler2_mode);
37755139Storek 	ler1->ler1_rap = LE_CSR1;
37855139Storek 	ler1->ler1_rdp = a;
37955139Storek 	ler1->ler1_rap = LE_CSR2;
38055139Storek 	ler1->ler1_rdp = a >> 16;
38155139Storek 	ler1->ler1_rap = LE_CSR3;
38255139Storek 	ler1->ler1_rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
38355139Storek 	ler1->ler1_rap = LE_CSR0;
38455139Storek 	ler1->ler1_rdp = LE_C0_INIT;
38555139Storek 	timo = 100000;
38655139Storek 	while (((stat = ler1->ler1_rdp) & (LE_C0_ERR | LE_C0_IDON)) == 0) {
38755139Storek 		if (--timo == 0) {
38855139Storek 			printf("%s: init timeout, stat=%b\n",
38955139Storek 			    sc->sc_dev.dv_xname, stat, LE_C0_BITS);
39055139Storek 			break;
39155139Storek 		}
39255139Storek 	}
39355139Storek 	if (stat & LE_C0_ERR)
39455139Storek 		printf("%s: init failed, stat=%b\n",
39555139Storek 		    sc->sc_dev.dv_xname, stat, LE_C0_BITS);
39655139Storek 	else
39755139Storek 		ler1->ler1_rdp = LE_C0_IDON;	/* clear IDON */
39855139Storek 	ler1->ler1_rdp = LE_C0_STRT | LE_C0_INEA;
39955139Storek 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
40055139Storek }
40155139Storek 
40255139Storek /*
40355139Storek  * Initialization of interface
40455139Storek  */
40555139Storek int
40655139Storek leinit(unit)
40755139Storek 	int unit;
40855139Storek {
40955139Storek 	register struct le_softc *sc = lecd.cd_devs[unit];
41055139Storek 	register struct ifnet *ifp = &sc->sc_if;
41155139Storek 	register int s;
41255139Storek 
41355139Storek 	/* not yet, if address still unknown */
41455139Storek 	if (ifp->if_addrlist == (struct ifaddr *)0)
41555139Storek 		return (0);
41655139Storek 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
41755139Storek 		s = splimp();
41855139Storek 		ifp->if_flags |= IFF_RUNNING;
41955139Storek 		lereset((struct device *)sc);
42055139Storek 	        lestart(ifp);
42155139Storek 		splx(s);
42255139Storek 	}
42355139Storek 	return (0);
42455139Storek }
42555139Storek 
42655139Storek /*
42755139Storek  * Start output on interface.  Get another datagram to send
42855139Storek  * off of the interface queue, and copy it to the interface
42955139Storek  * before starting the output.
43055139Storek  */
43155139Storek int
43255139Storek lestart(ifp)
43355139Storek 	register struct ifnet *ifp;
43455139Storek {
43555139Storek 	register struct le_softc *sc = lecd.cd_devs[ifp->if_unit];
43655139Storek 	register volatile struct letmd *tmd;
43755139Storek 	register struct mbuf *m;
43855139Storek 	register int len;
43955139Storek 
44055139Storek 	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)
44155139Storek 		return (0);
44255139Storek 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
44355139Storek 	if (m == 0)
44455139Storek 		return (0);
44555139Storek 	len = leput(sc->sc_r2->ler2_tbuf[0], m);
44655139Storek #if NBPFILTER > 0
44755139Storek 	/*
44855139Storek 	 * If bpf is listening on this interface, let it
44955139Storek 	 * see the packet before we commit it to the wire.
45055139Storek 	 */
45155139Storek 	if (sc->sc_bpf)
45255139Storek 		bpf_tap(sc->sc_bpf, sc->sc_r2->ler2_tbuf[0], len);
45355139Storek #endif
45455139Storek 
45555139Storek #ifdef PACKETSTATS
45655139Storek 	if (len <= LEMTU)
45755139Storek 		lexpacketsizes[len]++;
45855139Storek #endif
45955139Storek 	tmd = sc->sc_r2->ler2_tmd;
46055139Storek 	tmd->tmd3 = 0;
46155139Storek 	tmd->tmd2 = -len;
46255139Storek 	tmd->tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
46355139Storek 	sc->sc_if.if_flags |= IFF_OACTIVE;
46455139Storek 	return (0);
46555139Storek }
46655139Storek 
46755139Storek int
46855139Storek leintr(dev)
46955139Storek 	register void *dev;
47055139Storek {
47155139Storek 	register struct le_softc *sc = dev;
47255139Storek 	register volatile struct lereg1 *ler1 = sc->sc_r1;
47355139Storek 	register int csr0;
47455139Storek 
47555139Storek 	csr0 = ler1->ler1_rdp;
47655139Storek 	if ((csr0 & LE_C0_INTR) == 0)
47755139Storek 		return (0);
47855139Storek 	sc->sc_interrupts++;
47955139Storek 
48055139Storek 	if (csr0 & LE_C0_ERR) {
48155139Storek 		leerror(sc, csr0);
48255139Storek 		if (csr0 & LE_C0_MERR) {
48355139Storek 			sc->sc_merr++;
48455139Storek 			lereset((struct device *)sc);
48555139Storek 			return (1);
48655139Storek 		}
48755139Storek 		if (csr0 & LE_C0_BABL)
48855139Storek 			sc->sc_babl++;
48955139Storek 		if (csr0 & LE_C0_CERR)
49055139Storek 			sc->sc_cerr++;
49155139Storek 		if (csr0 & LE_C0_MISS)
49255139Storek 			sc->sc_miss++;
49355139Storek 		ler1->ler1_rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_INEA;
49455139Storek 	}
49555139Storek 	if ((csr0 & LE_C0_RXON) == 0) {
49655139Storek 		sc->sc_rxoff++;
49755139Storek 		lereset((struct device *)sc);
49855139Storek 		return (1);
49955139Storek 	}
50055139Storek 	if ((csr0 & LE_C0_TXON) == 0) {
50155139Storek 		sc->sc_txoff++;
50255139Storek 		lereset((struct device *)sc);
50355139Storek 		return (1);
50455139Storek 	}
50555139Storek 	if (csr0 & LE_C0_RINT) {
50655139Storek 		/* interrupt is cleared in lerint */
50755139Storek 		lerint(sc);
50855139Storek 	}
50955139Storek 	if (csr0 & LE_C0_TINT) {
51055139Storek 		ler1->ler1_rdp = LE_C0_TINT|LE_C0_INEA;
51155139Storek 		lexint(sc);
51255139Storek 	}
51355139Storek 	return (1);
51455139Storek }
51555139Storek 
51655139Storek /*
51755139Storek  * Ethernet interface transmitter interrupt.
51855139Storek  * Start another output if more data to send.
51955139Storek  */
52055139Storek void
52155139Storek lexint(sc)
52255139Storek 	register struct le_softc *sc;
52355139Storek {
52455139Storek 	register volatile struct letmd *tmd = sc->sc_r2->ler2_tmd;
52555139Storek 
52655139Storek 	sc->sc_lestats.lexints++;
52755139Storek 	if ((sc->sc_if.if_flags & IFF_OACTIVE) == 0) {
52855139Storek 		sc->sc_xint++;
52955139Storek 		return;
53055139Storek 	}
53155139Storek 	if (tmd->tmd1_bits & LE_T1_OWN) {
53255139Storek 		sc->sc_xown++;
53355139Storek 		return;
53455139Storek 	}
53555139Storek 	if (tmd->tmd1_bits & LE_T1_ERR) {
53655139Storek err:
53755139Storek 		lexerror(sc);
53855139Storek 		sc->sc_if.if_oerrors++;
53955139Storek 		if (tmd->tmd3 & (LE_T3_BUFF|LE_T3_UFLO)) {
54055139Storek 			sc->sc_uflo++;
54155139Storek 			lereset((struct device *)sc);
54255139Storek 		} else if (tmd->tmd3 & LE_T3_LCOL)
54355139Storek 			sc->sc_if.if_collisions++;
54455139Storek 		else if (tmd->tmd3 & LE_T3_RTRY)
54555139Storek 			sc->sc_if.if_collisions += 16;
54655139Storek 	}
54755139Storek 	else if (tmd->tmd3 & LE_T3_BUFF)
54855139Storek 		/* XXX documentation says BUFF not included in ERR */
54955139Storek 		goto err;
55055139Storek 	else if (tmd->tmd1_bits & LE_T1_ONE)
55155139Storek 		sc->sc_if.if_collisions++;
55255139Storek 	else if (tmd->tmd1_bits & LE_T1_MORE)
55355139Storek 		/* what is the real number? */
55455139Storek 		sc->sc_if.if_collisions += 2;
55555139Storek 	else
55655139Storek 		sc->sc_if.if_opackets++;
55755139Storek 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
55855139Storek 	lestart(&sc->sc_if);
55955139Storek }
56055139Storek 
56155139Storek #define	LENEXTRMP \
56255139Storek 	if (++bix == LERBUF) bix = 0, rmd = sc->sc_r2->ler2_rmd; else ++rmd
56355139Storek 
56455139Storek /*
56555139Storek  * Ethernet interface receiver interrupt.
56655139Storek  * If input error just drop packet.
56755139Storek  * Decapsulate packet based on type and pass to type specific
56855139Storek  * higher-level input routine.
56955139Storek  */
57055139Storek void
57155139Storek lerint(sc)
57255139Storek 	register struct le_softc *sc;
57355139Storek {
57455139Storek 	register int bix = sc->sc_rmd;
57555139Storek 	register volatile struct lermd *rmd = &sc->sc_r2->ler2_rmd[bix];
57655139Storek 
57755139Storek 	sc->sc_lestats.lerints++;
57855139Storek 	/*
57955139Storek 	 * Out of sync with hardware, should never happen?
58055139Storek 	 */
58155139Storek 	if (rmd->rmd1_bits & LE_R1_OWN) {
58255139Storek 		do {
58355139Storek 			sc->sc_lestats.lerscans++;
58455139Storek 			LENEXTRMP;
58555139Storek 		} while ((rmd->rmd1_bits & LE_R1_OWN) && bix != sc->sc_rmd);
58655139Storek 		if (bix == sc->sc_rmd)
58755139Storek 			printf("%s: RINT with no buffer\n",
58855139Storek 			    sc->sc_dev.dv_xname);
58955139Storek 	} else
59055139Storek 		sc->sc_lestats.lerhits++;
59155139Storek 
59255139Storek 	/*
59355139Storek 	 * Process all buffers with valid data
59455139Storek 	 */
59555139Storek 	while ((rmd->rmd1_bits & LE_R1_OWN) == 0) {
59655139Storek 		int len = rmd->rmd3;
59755139Storek 
59855139Storek 		/* Clear interrupt to avoid race condition */
59955139Storek 		sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA;
60055139Storek 
60155139Storek 		if (rmd->rmd1_bits & LE_R1_ERR) {
60255139Storek 			sc->sc_rmd = bix;
60355139Storek 			lererror(sc, "bad packet");
60455139Storek 			sc->sc_if.if_ierrors++;
60555139Storek 		} else if ((rmd->rmd1_bits & (LE_R1_STP|LE_R1_ENP)) !=
60655139Storek 		    (LE_R1_STP|LE_R1_ENP)) {
60755139Storek 			/* XXX make a define for LE_R1_STP|LE_R1_ENP? */
60855139Storek 			/*
60955139Storek 			 * Find the end of the packet so we can see how long
61055139Storek 			 * it was.  We still throw it away.
61155139Storek 			 */
61255139Storek 			do {
61355139Storek 				sc->sc_r1->ler1_rdp = LE_C0_RINT|LE_C0_INEA;
61455139Storek 				rmd->rmd3 = 0;
61555139Storek 				rmd->rmd1_bits = LE_R1_OWN;
61655139Storek 				LENEXTRMP;
61755139Storek 			} while (!(rmd->rmd1_bits &
61855139Storek 			    (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP)));
61955139Storek 			sc->sc_rmd = bix;
62055139Storek 			lererror(sc, "chained buffer");
62155139Storek 			sc->sc_rxlen++;
62255139Storek 			/*
62355139Storek 			 * If search terminated without successful completion
62455139Storek 			 * we reset the hardware (conservative).
62555139Storek 			 */
62655139Storek 			if ((rmd->rmd1_bits &
62755139Storek 			    (LE_R1_OWN|LE_R1_ERR|LE_R1_STP|LE_R1_ENP)) !=
62855139Storek 			    LE_R1_ENP) {
62955139Storek 				lereset((struct device *)sc);
63055139Storek 				return;
63155139Storek 			}
63255139Storek 		} else {
63355139Storek 			leread(sc, sc->sc_r2->ler2_rbuf[bix], len);
63455139Storek #ifdef PACKETSTATS
63555139Storek 			lerpacketsizes[len]++;
63655139Storek #endif
63755139Storek 			sc->sc_lestats.lerbufs++;
63855139Storek 		}
63955139Storek 		rmd->rmd3 = 0;
64055139Storek 		rmd->rmd1_bits = LE_R1_OWN;
64155139Storek 		LENEXTRMP;
64255139Storek 	}
64355139Storek 	sc->sc_rmd = bix;
64455139Storek }
64555139Storek 
64655139Storek void
64755139Storek leread(sc, pkt, len)
64855139Storek 	register struct le_softc *sc;
64955139Storek 	char *pkt;
65055139Storek 	int len;
65155139Storek {
65255139Storek 	register struct ether_header *et;
65355139Storek 	register struct ifnet *ifp = &sc->sc_if;
65455139Storek 	struct mbuf *m;
65555139Storek 	struct ifqueue *inq;
65655139Storek 	int flags;
65755139Storek 
65855139Storek 	ifp->if_ipackets++;
65955139Storek 	et = (struct ether_header *)pkt;
66055139Storek 	et->ether_type = ntohs((u_short)et->ether_type);
66155139Storek 	/* adjust input length to account for header and CRC */
66255139Storek 	len -= sizeof(struct ether_header) + 4;
66355139Storek 
66455139Storek 	if (len <= 0) {
66555139Storek 		if (ledebug)
66655139Storek 			log(LOG_WARNING,
66755139Storek 			    "%s: ierror(runt packet): from %s: len=%d\n",
66855139Storek 			    sc->sc_dev.dv_xname,
66955139Storek 			    ether_sprintf(et->ether_shost), len);
67055139Storek 		sc->sc_runt++;
67155139Storek 		ifp->if_ierrors++;
67255139Storek 		return;
67355139Storek 	}
67455139Storek 
67555139Storek 	/* Setup mbuf flags we'll need later */
67655139Storek 	flags = 0;
67755139Storek 	if (bcmp((caddr_t)etherbroadcastaddr,
67855139Storek 	    (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0)
67955139Storek 		flags |= M_BCAST;
68055139Storek 	if (et->ether_dhost[0] & 1)
68155139Storek 		flags |= M_MCAST;
68255139Storek 
68355139Storek #if NBPFILTER > 0
68455139Storek 	/*
68555139Storek 	 * Check if there's a bpf filter listening on this interface.
68655139Storek 	 * If so, hand off the raw packet to enet.
68755139Storek 	 */
68855139Storek 	if (sc->sc_bpf) {
68955139Storek 		bpf_tap(sc->sc_bpf, pkt, len + sizeof(struct ether_header));
69055139Storek 
69155139Storek 		/*
69255139Storek 		 * Keep the packet if it's a broadcast or has our
69355139Storek 		 * physical ethernet address (or if we support
69455139Storek 		 * multicast and it's one).
69555139Storek 		 */
69655139Storek 		if (
69755139Storek #ifdef MULTICAST
69855139Storek 		    (flags & (M_BCAST | M_MCAST)) == 0 &&
69955139Storek #else
70055139Storek 		    (flags & M_BCAST) == 0 &&
70155139Storek #endif
70255139Storek 		    bcmp(et->ether_dhost, sc->sc_addr,
70355139Storek 			sizeof(et->ether_dhost)) != 0)
70455139Storek 			return;
70555139Storek 	}
70655139Storek #endif
70755139Storek 	m = leget(pkt, len, 0, ifp);
70855139Storek 	if (m == 0)
70955139Storek 		return;
71055139Storek 
71155139Storek 	/* XXX this code comes from ether_input() */
71255139Storek 	ifp->if_lastchange = time;
71355139Storek 	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*et);
71455139Storek 	if (flags) {
71555139Storek 		m->m_flags |= flags;
71655139Storek 		ifp->if_imcasts++;
71755139Storek 	}
71855139Storek 	/* XXX end of code from ether_input() */
71955139Storek 
72055139Storek 	switch (et->ether_type) {
72155139Storek 
72255139Storek #ifdef INET
72355139Storek 	case ETHERTYPE_IP:
72455139Storek 		schednetisr(NETISR_IP);
72555139Storek 		inq = &ipintrq;
72655139Storek 		break;
72755139Storek 
72855139Storek 	case ETHERTYPE_ARP:
72955139Storek 		schednetisr(NETISR_ARP);
73055139Storek 		inq = &arpintrq;
73155139Storek 		break;
73255139Storek #endif
73355139Storek #ifdef NS
73455139Storek 	case ETHERTYPE_NS:
73555139Storek 		schednetisr(NETISR_NS);
73655139Storek 		inq = &nsintrq;
73755139Storek 		break;
73855139Storek #endif
73955139Storek 
74055139Storek #ifdef UTAHONLY
74155139Storek #ifdef APPLETALK
74255139Storek 	case ETHERTYPE_APPLETALK:
74355139Storek 		schednetisr(NETISR_DDP);
74455139Storek 		inq = &ddpintq;
74555139Storek 		break;
74655139Storek 
74755139Storek 	case ETHERTYPE_AARP:
74855139Storek 		aarpinput(&sc->sc_ac, m);
74955139Storek 		return;
75055139Storek #endif
75155139Storek #endif
75255139Storek 	default:
75355139Storek 		m_freem(m);
75455139Storek 		return;
75555139Storek 	}
75655139Storek 
75755139Storek 	if (IF_QFULL(inq)) {
75855139Storek 		IF_DROP(inq);
75955139Storek 		m_freem(m);
76055139Storek 		return;
76155139Storek 	}
76255139Storek 	IF_ENQUEUE(inq, m);
76355139Storek }
76455139Storek 
76555139Storek /*
76655139Storek  * Routine to copy from mbuf chain to transmit
76755139Storek  * buffer in board local memory.
76855139Storek  *
76955139Storek  * ### this can be done by remapping in some cases
77055139Storek  */
77155139Storek int
77255139Storek leput(lebuf, m)
77355139Storek 	register char *lebuf;
77455139Storek 	register struct mbuf *m;
77555139Storek {
77655139Storek 	register struct mbuf *mp;
77755139Storek 	register int len, tlen = 0;
77855139Storek 
77955139Storek 	for (mp = m; mp; mp = mp->m_next) {
78055139Storek 		len = mp->m_len;
78155139Storek 		if (len == 0)
78255139Storek 			continue;
78355139Storek 		tlen += len;
78455139Storek 		bcopy(mtod(mp, char *), lebuf, len);
78555139Storek 		lebuf += len;
78655139Storek 	}
78755139Storek 	m_freem(m);
78855139Storek 	if (tlen < LEMINSIZE) {
78955139Storek 		bzero(lebuf, LEMINSIZE - tlen);
79055139Storek 		tlen = LEMINSIZE;
79155139Storek 	}
79255139Storek 	return (tlen);
79355139Storek }
79455139Storek 
79555139Storek /*
79655139Storek  * Routine to copy from board local memory into mbufs.
79755139Storek  */
79855139Storek struct mbuf *
79955139Storek leget(lebuf, totlen, off0, ifp)
80055139Storek 	char *lebuf;
80155139Storek 	int totlen, off0;
80255139Storek 	struct ifnet *ifp;
80355139Storek {
80455139Storek 	register struct mbuf *m;
80555139Storek 	struct mbuf *top = 0, **mp = &top;
80655139Storek 	register int off = off0, len;
80755139Storek 	register char *cp;
80855139Storek 	char *epkt;
80955139Storek 
81055139Storek 	lebuf += sizeof(struct ether_header);
81155139Storek 	cp = lebuf;
81255139Storek 	epkt = cp + totlen;
81355139Storek 	if (off) {
81455139Storek 		cp += off + 2 * sizeof(u_short);
81555139Storek 		totlen -= 2 * sizeof(u_short);
81655139Storek 	}
81755139Storek 
81855139Storek 	MGETHDR(m, M_DONTWAIT, MT_DATA);
81955139Storek 	if (m == 0)
82055139Storek 		return (0);
82155139Storek 	m->m_pkthdr.rcvif = ifp;
82255139Storek 	m->m_pkthdr.len = totlen;
82355139Storek 	m->m_len = MHLEN;
82455139Storek 
82555139Storek 	while (totlen > 0) {
82655139Storek 		if (top) {
82755139Storek 			MGET(m, M_DONTWAIT, MT_DATA);
82855139Storek 			if (m == 0) {
82955139Storek 				m_freem(top);
83055139Storek 				return (0);
83155139Storek 			}
83255139Storek 			m->m_len = MLEN;
83355139Storek 		}
83455139Storek 		len = min(totlen, epkt - cp);
83555139Storek 		if (len >= MINCLSIZE) {
83655139Storek 			MCLGET(m, M_DONTWAIT);
83755139Storek 			if (m->m_flags & M_EXT)
83855139Storek 				m->m_len = len = min(len, MCLBYTES);
83955139Storek 			else
84055139Storek 				len = m->m_len;
84155139Storek 		} else {
84255139Storek 			/*
84355139Storek 			 * Place initial small packet/header at end of mbuf.
84455139Storek 			 */
84555139Storek 			if (len < m->m_len) {
84655139Storek 				if (top == 0 && len + max_linkhdr <= m->m_len)
84755139Storek 					m->m_data += max_linkhdr;
84855139Storek 				m->m_len = len;
84955139Storek 			} else
85055139Storek 				len = m->m_len;
85155139Storek 		}
85255139Storek 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
85355139Storek 		cp += len;
85455139Storek 		*mp = m;
85555139Storek 		mp = &m->m_next;
85655139Storek 		totlen -= len;
85755139Storek 		if (cp == epkt)
85855139Storek 			cp = lebuf;
85955139Storek 	}
86055139Storek 	return (top);
86155139Storek }
86255139Storek 
86355139Storek /*
86455139Storek  * Process an ioctl request.
86555139Storek  */
86655139Storek int
86755139Storek leioctl(ifp, cmd, data)
86855139Storek 	register struct ifnet *ifp;
86955139Storek 	int cmd;
87055139Storek 	caddr_t data;
87155139Storek {
87255139Storek 	register struct ifaddr *ifa;
87355139Storek 	register struct le_softc *sc = lecd.cd_devs[ifp->if_unit];
87455139Storek 	register volatile struct lereg1 *ler1;
87555139Storek 	int s = splimp(), error = 0;
87655139Storek 
87755139Storek 	switch (cmd) {
87855139Storek 
87955139Storek 	case SIOCSIFADDR:
88055139Storek 		ifa = (struct ifaddr *)data;
88155139Storek 		ifp->if_flags |= IFF_UP;
88255139Storek 		switch (ifa->ifa_addr->sa_family) {
88355139Storek #ifdef INET
88455139Storek 		case AF_INET:
88555139Storek 			(void)leinit(ifp->if_unit);	/* before arpwhohas */
88655139Storek 			((struct arpcom *)ifp)->ac_ipaddr =
88755139Storek 				IA_SIN(ifa)->sin_addr;
88855139Storek 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
88955139Storek 			break;
89055139Storek #endif
89155139Storek #ifdef NS
89255139Storek 		case AF_NS:
89355139Storek 		    {
89455139Storek 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
89555139Storek 
89655139Storek 			if (ns_nullhost(*ina))
89755139Storek 				ina->x_host = *(union ns_host *)(sc->sc_addr);
89855139Storek 			else {
89955139Storek 				/*
90055139Storek 				 * The manual says we can't change the address
90155139Storek 				 * while the receiver is armed,
90255139Storek 				 * so reset everything
90355139Storek 				 */
90455139Storek 				ifp->if_flags &= ~IFF_RUNNING;
90555139Storek 				bcopy((caddr_t)ina->x_host.c_host,
90655139Storek 				    (caddr_t)sc->sc_addr, sizeof(sc->sc_addr));
90755139Storek 			}
90855139Storek 			(void)leinit(ifp->if_unit);	/* does le_setaddr() */
90955139Storek 			break;
91055139Storek 		    }
91155139Storek #endif
91255139Storek 		default:
91355139Storek 			(void)leinit(ifp->if_unit);
91455139Storek 			break;
91555139Storek 		}
91655139Storek 		break;
91755139Storek 
91855139Storek 	case SIOCSIFFLAGS:
91955139Storek 		ler1 = sc->sc_r1;
92055139Storek 		if ((ifp->if_flags & IFF_UP) == 0 &&
92155139Storek 		    ifp->if_flags & IFF_RUNNING) {
92255139Storek 			ler1->ler1_rdp = LE_C0_STOP;
92355139Storek 			ifp->if_flags &= ~IFF_RUNNING;
92455139Storek 		} else if (ifp->if_flags & IFF_UP &&
92555139Storek 		    (ifp->if_flags & IFF_RUNNING) == 0)
92655139Storek 			(void)leinit(ifp->if_unit);
92755139Storek 		/*
92855139Storek 		 * If the state of the promiscuous bit changes, the interface
92955139Storek 		 * must be reset to effect the change.
93055139Storek 		 */
93155139Storek 		if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) &&
93255139Storek 		    (ifp->if_flags & IFF_RUNNING)) {
93355139Storek 			sc->sc_iflags = ifp->if_flags;
93455139Storek 			lereset((struct device *)sc);
93555139Storek 			lestart(ifp);
93655139Storek 		}
93755139Storek 		break;
93855139Storek 
93955139Storek #ifdef MULTICAST
94055139Storek 	case SIOCADDMULTI:
94155139Storek 	case SIOCDELMULTI:
94255139Storek 		/* Update our multicast list  */
94355139Storek 		error = (cmd == SIOCADDMULTI) ?
94455139Storek 		    ether_addmulti((struct ifreq *)data, &sc->sc_ac) :
94555139Storek 		    ether_delmulti((struct ifreq *)data, &sc->sc_ac);
94655139Storek 
94755139Storek 		if (error == ENETRESET) {
94855139Storek 			/*
94955139Storek 			 * Multicast list has changed; set the hardware
95055139Storek 			 * filter accordingly.
95155139Storek 			 */
95255139Storek 			lereset((struct device *)sc);
95355139Storek 			error = 0;
95455139Storek 		}
95555139Storek 		break;
95655139Storek #endif
95755139Storek 
95855139Storek 	default:
95955139Storek 		error = EINVAL;
96055139Storek 	}
96155139Storek 	splx(s);
96255139Storek 	return (error);
96355139Storek }
96455139Storek 
96555139Storek void
96655139Storek leerror(sc, stat)
96755139Storek 	register struct le_softc *sc;
96855139Storek 	int stat;
96955139Storek {
97055139Storek 	if (!ledebug)
97155139Storek 		return;
97255139Storek 
97355139Storek 	/*
97455139Storek 	 * Not all transceivers implement heartbeat
97555139Storek 	 * so we only log CERR once.
97655139Storek 	 */
97755139Storek 	if ((stat & LE_C0_CERR) && sc->sc_cerr)
97855139Storek 		return;
97955139Storek 	log(LOG_WARNING, "%s: error: stat=%b\n",
98055139Storek 	    sc->sc_dev.dv_xname, stat, LE_C0_BITS);
98155139Storek }
98255139Storek 
98355139Storek void
98455139Storek lererror(sc, msg)
98555139Storek 	register struct le_softc *sc;
98655139Storek 	char *msg;
98755139Storek {
98855139Storek 	register volatile struct lermd *rmd;
98955139Storek 	int len;
99055139Storek 
99155139Storek 	if (!ledebug)
99255139Storek 		return;
99355139Storek 
99455139Storek 	rmd = &sc->sc_r2->ler2_rmd[sc->sc_rmd];
99555139Storek 	len = rmd->rmd3;
99655139Storek 	log(LOG_WARNING, "%s: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
99755139Storek 	    sc->sc_dev.dv_xname, msg, len > 11 ?
99855139Storek 	    ether_sprintf((u_char *)&sc->sc_r2->ler2_rbuf[sc->sc_rmd][6]) :
99955139Storek 	    "unknown",
100055139Storek 	    sc->sc_rmd, len, rmd->rmd1_bits, LE_R1_BITS);
100155139Storek }
100255139Storek 
100355139Storek void
100455139Storek lexerror(sc)
100555139Storek 	register struct le_softc *sc;
100655139Storek {
100755139Storek 	register volatile struct letmd *tmd;
100855139Storek 	register int len, tmd3, tdr;
100955139Storek 
101055139Storek 	if (!ledebug)
101155139Storek 		return;
101255139Storek 
101355139Storek 	tmd = sc->sc_r2->ler2_tmd;
101455139Storek 	tmd3 = tmd->tmd3;
101555139Storek 	tdr = tmd3 & LE_T3_TDR_MASK;
101655139Storek 	len = -tmd->tmd2;
101755139Storek 	log(LOG_WARNING,
101855139Storek     "%s: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b, tdr=%d (%d nsecs)\n",
101955139Storek 	    sc->sc_dev.dv_xname, len > 5 ?
102055139Storek 	    ether_sprintf((u_char *)&sc->sc_r2->ler2_tbuf[0][0]) : "unknown",
102155139Storek 	    0, len,
102255139Storek 	    tmd->tmd1_bits, LE_T1_BITS,
102355139Storek 	    tmd3, LE_T3_BITS, tdr, tdr * 100);
102455139Storek }
1025