xref: /csrg-svn/sys/pmax/dev/if_le.c (revision 56819)
1*56819Sralph /*-
2*56819Sralph  * Copyright (c) 1992 The Regents of the University of California.
352130Smckusick  * All rights reserved.
452130Smckusick  *
552130Smckusick  * This code is derived from software contributed to Berkeley by
6*56819Sralph  * Ralph Campbell and Rick Macklem.
752130Smckusick  *
852130Smckusick  * %sccs.include.redist.c%
952130Smckusick  *
10*56819Sralph  *	@(#)if_le.c	7.8 (Berkeley) 11/15/92
1152130Smckusick  */
1252130Smckusick 
13*56819Sralph #include <le.h>
1452130Smckusick #if NLE > 0
1552130Smckusick 
16*56819Sralph #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  */
2656522Sbostic #include <sys/param.h>
2756522Sbostic #include <sys/systm.h>
2856522Sbostic #include <sys/mbuf.h>
2956522Sbostic #include <sys/buf.h>
3056522Sbostic #include <sys/protosw.h>
3156522Sbostic #include <sys/socket.h>
3256522Sbostic #include <sys/syslog.h>
3356522Sbostic #include <sys/ioctl.h>
3456522Sbostic #include <sys/errno.h>
3552130Smckusick 
3656522Sbostic #include <net/if.h>
3756522Sbostic #include <net/netisr.h>
3856522Sbostic #include <net/route.h>
3952130Smckusick 
4052130Smckusick #ifdef INET
4156522Sbostic #include <netinet/in.h>
4256522Sbostic #include <netinet/in_systm.h>
4356522Sbostic #include <netinet/in_var.h>
4456522Sbostic #include <netinet/ip.h>
4556522Sbostic #include <netinet/if_ether.h>
4652130Smckusick #endif
4752130Smckusick 
4852130Smckusick #ifdef NS
4956522Sbostic #include <netns/ns.h>
5056522Sbostic #include <netns/ns_if.h>
5152130Smckusick #endif
5252130Smckusick 
5352130Smckusick #ifdef RMP
5456522Sbostic #include <netrmp/rmp.h>
5556522Sbostic #include <netrmp/rmp_var.h>
5652130Smckusick #endif
5752130Smckusick 
5856522Sbostic #include <machine/machConst.h>
59*56819Sralph 
60*56819Sralph #include <pmax/pmax/pmaxtype.h>
61*56819Sralph #include <pmax/pmax/kn01.h>
62*56819Sralph #include <pmax/pmax/kmin.h>
63*56819Sralph #include <pmax/pmax/asic.h>
64*56819Sralph 
6556525Sbostic #include <pmax/dev/device.h>
6656525Sbostic #include <pmax/dev/if_lereg.h>
6752130Smckusick 
6852130Smckusick #if NBPFILTER > 0
6956522Sbostic #include <net/bpf.h>
7056522Sbostic #include <net/bpfdesc.h>
7152130Smckusick #endif
7252130Smckusick 
7352130Smckusick int	leprobe();
7452695Sralph void	leintr();
7552130Smckusick struct	driver ledriver = {
7652695Sralph 	"le", leprobe, 0, 0, leintr,
7752130Smckusick };
7852130Smckusick 
7952130Smckusick int	ledebug = 1;		/* console error messages */
8052130Smckusick 
8152130Smckusick /*
8252130Smckusick  * Ethernet software status per interface.
8352130Smckusick  *
8452130Smckusick  * Each interface is referenced by a network interface structure,
8552130Smckusick  * le_if, which the routing code uses to locate the interface.
8652130Smckusick  * This structure contains the output queue for the interface, its address, ...
8752130Smckusick  */
8852130Smckusick struct	le_softc {
8952130Smckusick 	struct	arpcom sc_ac;	/* common Ethernet structures */
9052130Smckusick #define	sc_if	sc_ac.ac_if	/* network-visible interface */
9152130Smckusick #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
9252130Smckusick 	volatile struct	lereg1 *sc_r1;	/* LANCE registers */
93*56819Sralph 	volatile void *sc_r2;	/* dual-port RAM */
94*56819Sralph 	int	sc_ler2pad;	/* Do ring descriptors require short pads? */
95*56819Sralph 	void	(*sc_copytobuf)(); /* Copy to buffer */
96*56819Sralph 	void	(*sc_copyfrombuf)(); /* Copy from buffer */
97*56819Sralph 	void	(*sc_zerobuf)(); /* and Zero bytes in buffer */
9852130Smckusick 	int	sc_rmd;		/* predicted next rmd to process */
9952130Smckusick 	int	sc_tmd;		/* last tmd processed */
10052130Smckusick 	int	sc_tmdnext;	/* next tmd to transmit with */
10152130Smckusick 	int	sc_runt;
10252130Smckusick 	int	sc_jab;
10352130Smckusick 	int	sc_merr;
10452130Smckusick 	int	sc_babl;
10552130Smckusick 	int	sc_cerr;
10652130Smckusick 	int	sc_miss;
10752130Smckusick 	int	sc_xint;
10852130Smckusick 	int	sc_xown;
10952130Smckusick 	int	sc_uflo;
11052130Smckusick 	int	sc_rxlen;
11152130Smckusick 	int	sc_rxoff;
11252130Smckusick 	int	sc_txoff;
11352130Smckusick 	int	sc_busy;
11452130Smckusick 	short	sc_iflags;
11552130Smckusick #if NBPFILTER > 0
11652130Smckusick 	caddr_t sc_bpf;
11752130Smckusick #endif
11852130Smckusick } le_softc[NLE];
11952130Smckusick 
12052130Smckusick /* access LANCE registers */
121*56819Sralph static void lewritereg();
12252130Smckusick #define	LERDWR(cntl, src, dst)	{ (dst) = (src); DELAY(10); }
123*56819Sralph #define	LEWREG(src, dst)	lewritereg(&(dst), (src))
12452130Smckusick 
12552130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \
12652695Sralph 	((unsigned)(&(((struct lereg2 *)0)->cpu)))
12752695Sralph 
12852695Sralph #define LE_OFFSET_RAM		0x0
12952695Sralph #define LE_OFFSET_LANCE		0x100000
13052695Sralph #define LE_OFFSET_ROM		0x1c0000
13152695Sralph 
132*56819Sralph void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig();
133*56819Sralph void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2();
134*56819Sralph void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16();
135*56819Sralph 
136*56819Sralph extern int pmax_boardtype;
137*56819Sralph extern u_long le_iomem;
138*56819Sralph 
13952130Smckusick /*
14052130Smckusick  * Test to see if device is present.
14152130Smckusick  * Return true if found and initialized ok.
14252130Smckusick  * If interface exists, make available by filling in network interface
14352130Smckusick  * record.  System will initialize the interface when it is ready
14452130Smckusick  * to accept packets.
14552130Smckusick  */
14652130Smckusick leprobe(dp)
14752130Smckusick 	struct pmax_ctlr *dp;
14852130Smckusick {
14952130Smckusick 	volatile struct lereg1 *ler1;
15052130Smckusick 	struct le_softc *le = &le_softc[dp->pmax_unit];
15152130Smckusick 	struct ifnet *ifp = &le->sc_if;
15252130Smckusick 	u_char *cp;
15352130Smckusick 	int i;
15452695Sralph 	extern int leinit(), leioctl(), lestart(), ether_output();
15552130Smckusick 
156*56819Sralph 	switch (pmax_boardtype) {
157*56819Sralph 	case DS_PMAX:
158*56819Sralph 		le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr;
159*56819Sralph 		le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000);
160*56819Sralph 		cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1);
161*56819Sralph 		le->sc_ler2pad = 1;
162*56819Sralph 		le->sc_copytobuf = copytobuf_gap2;
163*56819Sralph 		le->sc_copyfrombuf = copyfrombuf_gap2;
164*56819Sralph 		le->sc_zerobuf = bzerobuf_gap2;
165*56819Sralph 		break;
166*56819Sralph 	case DS_3MIN:
167*56819Sralph 	case DS_MAXINE:
168*56819Sralph 		if (dp->pmax_unit == 0) {
169*56819Sralph 			volatile u_int *ssr, *ldp;
17052130Smckusick 
171*56819Sralph 			le->sc_r1 = ler1 = (volatile struct lereg1 *)
172*56819Sralph 				MACH_PHYS_TO_UNCACHED(KMIN_SYS_LANCE);
173*56819Sralph 			le->sc_r2 = (volatile void *)
174*56819Sralph 				MACH_PHYS_TO_UNCACHED(le_iomem);
175*56819Sralph 			cp = (u_char *)MACH_PHYS_TO_UNCACHED(
176*56819Sralph 				KMIN_SYS_ETHER_ADDRESS);
177*56819Sralph 			le->sc_ler2pad = 1;
178*56819Sralph 			le->sc_copytobuf = copytobuf_gap16;
179*56819Sralph 			le->sc_copyfrombuf = copyfrombuf_gap16;
180*56819Sralph 			le->sc_zerobuf = bzerobuf_gap16;
18152130Smckusick 
182*56819Sralph 			/*
183*56819Sralph 			 * And enable Lance dma through the asic.
184*56819Sralph 			 */
185*56819Sralph 			ssr = (volatile u_int *)
186*56819Sralph 				MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR);
187*56819Sralph 			ldp = (volatile u_int *)
188*56819Sralph 				MACH_PHYS_TO_UNCACHED(KMIN_REG_LANCE_DMAPTR);
189*56819Sralph 			*ldp = (le_iomem << 3);	/* phys addr << 3 */
190*56819Sralph 			*ssr |= ASIC_CSR_DMAEN_LANCE;
191*56819Sralph 			break;
192*56819Sralph 		}
193*56819Sralph 		/*
194*56819Sralph 		 * Units other than 0 are turbochannel option boards and fall
195*56819Sralph 		 * through to DS_3MAX.
196*56819Sralph 		 */
197*56819Sralph 	case DS_3MAX:
198*56819Sralph 		le->sc_r1 = ler1 = (volatile struct lereg1 *)
199*56819Sralph 			(dp->pmax_addr + LE_OFFSET_LANCE);
200*56819Sralph 		le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM);
201*56819Sralph 		cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2);
202*56819Sralph 		le->sc_ler2pad = 0;
203*56819Sralph 		le->sc_copytobuf = copytobuf_contig;
204*56819Sralph 		le->sc_copyfrombuf = copyfrombuf_contig;
205*56819Sralph 		le->sc_zerobuf = bzerobuf_contig;
206*56819Sralph 		break;
207*56819Sralph 	default:
208*56819Sralph 		printf("Unknown CPU board type %d\n", pmax_boardtype);
209*56819Sralph 		return (0);
210*56819Sralph 	};
211*56819Sralph 
21252695Sralph 	/*
213*56819Sralph 	 * Get the ethernet address out of rom
21452695Sralph 	 */
21552695Sralph 	for (i = 0; i < sizeof(le->sc_addr); i++) {
21652695Sralph 		le->sc_addr[i] = *cp;
21752695Sralph 		cp += 4;
21852695Sralph 	}
21952695Sralph 
22052130Smckusick 	/* make sure the chip is stopped */
221*56819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
222*56819Sralph 	LEWREG(LE_STOP, ler1->ler1_rdp);
22352130Smckusick 
22452130Smckusick 	ifp->if_unit = dp->pmax_unit;
22552130Smckusick 	ifp->if_name = "le";
22652130Smckusick 	ifp->if_mtu = ETHERMTU;
22752130Smckusick 	ifp->if_init = leinit;
22852130Smckusick 	ifp->if_ioctl = leioctl;
22952130Smckusick 	ifp->if_output = ether_output;
23052130Smckusick 	ifp->if_start = lestart;
23152130Smckusick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
23252130Smckusick #if NBPFILTER > 0
23352130Smckusick 	bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
23452130Smckusick #endif
23552130Smckusick 	if_attach(ifp);
23652130Smckusick 
23752695Sralph 	printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n",
23852695Sralph 		dp->pmax_unit, dp->pmax_addr, dp->pmax_pri,
23952695Sralph 		ether_sprintf(le->sc_addr));
24052130Smckusick 	return (1);
24152130Smckusick }
24252130Smckusick 
243*56819Sralph ledrinit(le)
244*56819Sralph 	struct le_softc *le;
24552130Smckusick {
246*56819Sralph 	register volatile void *rp;
24752130Smckusick 	register int i;
24852130Smckusick 
24952130Smckusick 	for (i = 0; i < LERBUF; i++) {
250*56819Sralph 		rp = LER2_RMDADDR(le->sc_r2, i);
251*56819Sralph 		LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0]));
252*56819Sralph 		LER2_rmd1(rp, LE_OWN);
253*56819Sralph 		LER2_rmd2(rp, -LEMTU);
254*56819Sralph 		LER2_rmd3(rp, 0);
25552130Smckusick 	}
25652130Smckusick 	for (i = 0; i < LETBUF; i++) {
257*56819Sralph 		rp = LER2_TMDADDR(le->sc_r2, i);
258*56819Sralph 		LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0]));
259*56819Sralph 		LER2_tmd1(rp, 0);
260*56819Sralph 		LER2_tmd2(rp, 0);
261*56819Sralph 		LER2_tmd3(rp, 0);
26252130Smckusick 	}
26352130Smckusick }
26452130Smckusick 
26552130Smckusick lereset(unit)
26652130Smckusick 	register int unit;
26752130Smckusick {
26852130Smckusick 	register struct le_softc *le = &le_softc[unit];
26952130Smckusick 	register volatile struct lereg1 *ler1 = le->sc_r1;
270*56819Sralph 	register volatile void *ler2 = le->sc_r2;
27152130Smckusick 	register int timo = 100000;
27252130Smckusick 	register int stat;
27352130Smckusick 
27452130Smckusick #ifdef lint
27552130Smckusick 	stat = unit;
27652130Smckusick #endif
277*56819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
278*56819Sralph 	LEWREG(LE_STOP, ler1->ler1_rdp);
279*56819Sralph 
280*56819Sralph 	/*
281*56819Sralph 	 * Setup for transmit/receive
282*56819Sralph 	 */
28352130Smckusick #if NBPFILTER > 0
28452130Smckusick 	if (le->sc_if.if_flags & IFF_PROMISC)
28552130Smckusick 		/* set the promiscuous bit */
286*56819Sralph 		LER2_mode(ler2, LE_MODE|0x8000);
28752130Smckusick 	else
28852130Smckusick #endif
289*56819Sralph 		LER2_mode(ler2, LE_MODE);
290*56819Sralph 	LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]);
291*56819Sralph 	LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]);
292*56819Sralph 	LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]);
29352130Smckusick #ifdef RMP
29452130Smckusick 	/*
29552130Smckusick 	 * Set up logical addr filter to accept multicast 9:0:9:0:0:4
29652130Smckusick 	 * This should be an ioctl() to the driver.  (XXX)
29752130Smckusick 	 */
298*56819Sralph 	LER2_ladrf0(ler2, 0x0010);
299*56819Sralph 	LER2_ladrf1(ler2, 0x0);
300*56819Sralph 	LER2_ladrf2(ler2, 0x0);
301*56819Sralph 	LER2_ladrf3(ler2, 0x0);
30252130Smckusick #else
303*56819Sralph 	LER2_ladrf0(ler2, 0);
304*56819Sralph 	LER2_ladrf1(ler2, 0);
305*56819Sralph 	LER2_ladrf2(ler2, 0);
306*56819Sralph 	LER2_ladrf3(ler2, 0);
30752130Smckusick #endif
308*56819Sralph 	LER2_rlen(ler2, LE_RLEN);
309*56819Sralph 	LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0]));
310*56819Sralph 	LER2_tlen(ler2, LE_TLEN);
311*56819Sralph 	LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0]));
312*56819Sralph 	ledrinit(le);
31352130Smckusick 	le->sc_rmd = 0;
31452130Smckusick 	le->sc_tmd = LETBUF - 1;
31552130Smckusick 	le->sc_tmdnext = 0;
31652130Smckusick 
317*56819Sralph 	LEWREG(LE_CSR1, ler1->ler1_rap);
318*56819Sralph 	LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp);
319*56819Sralph 	LEWREG(LE_CSR2, ler1->ler1_rap);
320*56819Sralph 	LEWREG(0, ler1->ler1_rdp);
321*56819Sralph 	LEWREG(LE_CSR3, ler1->ler1_rap);
322*56819Sralph 	LEWREG(0, ler1->ler1_rdp);
323*56819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
32452130Smckusick 	LERDWR(ler0, LE_INIT, ler1->ler1_rdp);
32552130Smckusick 	do {
32652130Smckusick 		if (--timo == 0) {
32752130Smckusick 			printf("le%d: init timeout, stat = 0x%x\n",
32852130Smckusick 			       unit, stat);
32952130Smckusick 			break;
33052130Smckusick 		}
331*56819Sralph 		stat = ler1->ler1_rdp;
33252130Smckusick 	} while ((stat & LE_IDON) == 0);
33352130Smckusick 	LERDWR(ler0, LE_IDON, ler1->ler1_rdp);
33452130Smckusick 	LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp);
33552130Smckusick 	le->sc_if.if_flags &= ~IFF_OACTIVE;
33652130Smckusick }
33752130Smckusick 
33852130Smckusick /*
33952130Smckusick  * Initialization of interface
34052130Smckusick  */
34152130Smckusick leinit(unit)
34252130Smckusick 	int unit;
34352130Smckusick {
34452130Smckusick 	struct le_softc *le = &le_softc[unit];
34552130Smckusick 	register struct ifnet *ifp = &le->sc_if;
34652130Smckusick 	int s;
34752130Smckusick 
34852130Smckusick 	/* not yet, if address still unknown */
34952130Smckusick 	if (ifp->if_addrlist == (struct ifaddr *)0)
35052130Smckusick 		return;
35152130Smckusick 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
35252130Smckusick 		s = splnet();
35352130Smckusick 		ifp->if_flags |= IFF_RUNNING;
35452130Smckusick 		lereset(unit);
35552130Smckusick 	        (void) lestart(ifp);
35652130Smckusick 		splx(s);
35752130Smckusick 	}
35852130Smckusick }
35952130Smckusick 
36052130Smckusick #define	LENEXTTMP \
361*56819Sralph 	if (++bix == LETBUF) \
362*56819Sralph 		bix = 0; \
363*56819Sralph 	tmd = LER2_TMDADDR(le->sc_r2, bix)
36452130Smckusick 
36552130Smckusick /*
36652130Smckusick  * Start output on interface.  Get another datagram to send
36752130Smckusick  * off of the interface queue, and copy it to the interface
36852130Smckusick  * before starting the output.
36952130Smckusick  */
37052130Smckusick lestart(ifp)
37152130Smckusick 	struct ifnet *ifp;
37252130Smckusick {
37352130Smckusick 	register struct le_softc *le = &le_softc[ifp->if_unit];
37452130Smckusick 	register int bix = le->sc_tmdnext;
375*56819Sralph 	register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix);
37652130Smckusick 	register struct mbuf *m;
37752130Smckusick 	int len = 0;
37852130Smckusick 
37952130Smckusick 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
38052130Smckusick 		return (0);
38152130Smckusick 	while (bix != le->sc_tmd) {
382*56819Sralph 		if (LER2V_tmd1(tmd) & LE_OWN)
38352130Smckusick 			panic("lestart");
38452130Smckusick 		IF_DEQUEUE(&le->sc_if.if_snd, m);
38552130Smckusick 		if (m == 0)
38652130Smckusick 			break;
38752130Smckusick #if NBPFILTER > 0
38852130Smckusick 		/*
38952130Smckusick 		 * If bpf is listening on this interface, let it
39052130Smckusick 		 * see the packet before we commit it to the wire.
39152130Smckusick 		 */
39252130Smckusick 		if (le->sc_bpf)
393*56819Sralph 			bpf_mtap(le->sc_bpf, m);
39452130Smckusick #endif
395*56819Sralph 		len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m);
396*56819Sralph 		LER2_tmd3(tmd, 0);
397*56819Sralph 		LER2_tmd2(tmd, -len);
398*56819Sralph 		LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP);
39952130Smckusick 		LENEXTTMP;
40052130Smckusick 	}
40152130Smckusick 	if (len != 0) {
40252130Smckusick 		le->sc_if.if_flags |= IFF_OACTIVE;
40352130Smckusick 		LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp);
40452130Smckusick 	}
40552130Smckusick 	le->sc_tmdnext = bix;
40652130Smckusick 	return (0);
40752130Smckusick }
40852130Smckusick 
40952130Smckusick /*
41052130Smckusick  * Process interrupts from the 7990 chip.
41152130Smckusick  */
41252695Sralph void
41352695Sralph leintr(unit)
41452695Sralph 	int unit;
41552130Smckusick {
41652130Smckusick 	register struct le_softc *le;
41752130Smckusick 	register volatile struct lereg1 *ler1;
41852695Sralph 	register int stat;
41952130Smckusick 
42052130Smckusick 	le = &le_softc[unit];
42152130Smckusick 	ler1 = le->sc_r1;
42252130Smckusick 	stat = ler1->ler1_rdp;
42352130Smckusick 	if (!(stat & LE_INTR)) {
42453081Sralph 		printf("le%d: spurrious interrupt\n", unit);
42552130Smckusick 		return;
42652130Smckusick 	}
42752130Smckusick 	if (stat & LE_SERR) {
42852130Smckusick 		leerror(unit, stat);
42952130Smckusick 		if (stat & LE_MERR) {
43052130Smckusick 			le->sc_merr++;
43152130Smckusick 			lereset(unit);
43252130Smckusick 			return;
43352130Smckusick 		}
43452130Smckusick 		if (stat & LE_BABL)
43552130Smckusick 			le->sc_babl++;
43652130Smckusick 		if (stat & LE_CERR)
43752130Smckusick 			le->sc_cerr++;
43852130Smckusick 		if (stat & LE_MISS)
43952130Smckusick 			le->sc_miss++;
44052130Smckusick 		LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
44152130Smckusick 	}
44252130Smckusick 	if ((stat & LE_RXON) == 0) {
44352130Smckusick 		le->sc_rxoff++;
44452130Smckusick 		lereset(unit);
44552130Smckusick 		return;
44652130Smckusick 	}
44752130Smckusick 	if ((stat & LE_TXON) == 0) {
44852130Smckusick 		le->sc_txoff++;
44952130Smckusick 		lereset(unit);
45052130Smckusick 		return;
45152130Smckusick 	}
45252130Smckusick 	if (stat & LE_RINT) {
45352130Smckusick 		/* interrupt is cleared in lerint */
45452130Smckusick 		lerint(unit);
45552130Smckusick 	}
45652130Smckusick 	if (stat & LE_TINT) {
45752130Smckusick 		LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp);
45852130Smckusick 		lexint(unit);
45952130Smckusick 	}
46052130Smckusick }
46152130Smckusick 
46252130Smckusick /*
46352130Smckusick  * Ethernet interface transmitter interrupt.
46452130Smckusick  * Start another output if more data to send.
46552130Smckusick  */
46652130Smckusick lexint(unit)
46752130Smckusick 	register int unit;
46852130Smckusick {
46952130Smckusick 	register struct le_softc *le = &le_softc[unit];
47052130Smckusick 	register int bix = le->sc_tmd;
471*56819Sralph 	register volatile void *tmd;
47252130Smckusick 
47352130Smckusick 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
47452130Smckusick 		le->sc_xint++;
47552130Smckusick 		return;
47652130Smckusick 	}
47752130Smckusick 	LENEXTTMP;
478*56819Sralph 	while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) {
47952130Smckusick 		le->sc_tmd = bix;
480*56819Sralph 		if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) {
48152130Smckusick 			lexerror(unit);
48252130Smckusick 			le->sc_if.if_oerrors++;
483*56819Sralph 			if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) {
48452130Smckusick 				le->sc_uflo++;
48552130Smckusick 				lereset(unit);
48652130Smckusick 				break;
48752130Smckusick 			}
488*56819Sralph 			else if (LER2V_tmd3(tmd) & LE_LCOL)
48952130Smckusick 				le->sc_if.if_collisions++;
490*56819Sralph 			else if (LER2V_tmd3(tmd) & LE_RTRY)
49152130Smckusick 				le->sc_if.if_collisions += 16;
49252130Smckusick 		}
493*56819Sralph 		else if (LER2V_tmd1(tmd) & LE_ONE)
49452130Smckusick 			le->sc_if.if_collisions++;
495*56819Sralph 		else if (LER2V_tmd1(tmd) & LE_MORE)
49652130Smckusick 			/* what is the real number? */
49752130Smckusick 			le->sc_if.if_collisions += 2;
49852130Smckusick 		else
49952130Smckusick 			le->sc_if.if_opackets++;
50052130Smckusick 		LENEXTTMP;
50152130Smckusick 	}
50252130Smckusick 	if (bix == le->sc_tmdnext)
50352130Smckusick 		le->sc_if.if_flags &= ~IFF_OACTIVE;
50452130Smckusick 	(void) lestart(&le->sc_if);
50552130Smckusick }
50652130Smckusick 
50752130Smckusick #define	LENEXTRMP \
508*56819Sralph 	if (++bix == LERBUF) \
509*56819Sralph 		bix = 0; \
510*56819Sralph 	rmd = LER2_RMDADDR(le->sc_r2, bix)
51152130Smckusick 
51252130Smckusick /*
51352130Smckusick  * Ethernet interface receiver interrupt.
51452130Smckusick  * If input error just drop packet.
51552130Smckusick  * Decapsulate packet based on type and pass to type specific
51652130Smckusick  * higher-level input routine.
51752130Smckusick  */
51852130Smckusick lerint(unit)
51952130Smckusick 	int unit;
52052130Smckusick {
52152130Smckusick 	register struct le_softc *le = &le_softc[unit];
52252130Smckusick 	register int bix = le->sc_rmd;
523*56819Sralph 	register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix);
52452130Smckusick 
52552130Smckusick 	/*
52652130Smckusick 	 * Out of sync with hardware, should never happen?
52752130Smckusick 	 */
528*56819Sralph 	if (LER2V_rmd1(rmd) & LE_OWN) {
52952130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
53052130Smckusick 		return;
53152130Smckusick 	}
53252130Smckusick 
53352130Smckusick 	/*
53452130Smckusick 	 * Process all buffers with valid data
53552130Smckusick 	 */
536*56819Sralph 	while ((LER2V_rmd1(rmd) & LE_OWN) == 0) {
537*56819Sralph 		int len = LER2V_rmd3(rmd);
53852130Smckusick 
53952130Smckusick 		/* Clear interrupt to avoid race condition */
54052130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
54152130Smckusick 
542*56819Sralph 		if (LER2V_rmd1(rmd) & LE_ERR) {
54352130Smckusick 			le->sc_rmd = bix;
54452130Smckusick 			lererror(unit, "bad packet");
54552130Smckusick 			le->sc_if.if_ierrors++;
546*56819Sralph 		} else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
54752130Smckusick 			/*
54852130Smckusick 			 * Find the end of the packet so we can see how long
54952130Smckusick 			 * it was.  We still throw it away.
55052130Smckusick 			 */
55152130Smckusick 			do {
55252130Smckusick 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
55352130Smckusick 				       le->sc_r1->ler1_rdp);
554*56819Sralph 				LER2_rmd3(rmd, 0);
555*56819Sralph 				LER2_rmd1(rmd, LE_OWN);
55652130Smckusick 				LENEXTRMP;
557*56819Sralph 			} while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
55852130Smckusick 			le->sc_rmd = bix;
55952130Smckusick 			lererror(unit, "chained buffer");
56052130Smckusick 			le->sc_rxlen++;
56152130Smckusick 			/*
56252130Smckusick 			 * If search terminated without successful completion
56352130Smckusick 			 * we reset the hardware (conservative).
56452130Smckusick 			 */
565*56819Sralph 			if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
56652130Smckusick 			    LE_ENP) {
56752130Smckusick 				lereset(unit);
56852130Smckusick 				return;
56952130Smckusick 			}
57052130Smckusick 		} else
571*56819Sralph 			leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len);
572*56819Sralph 		LER2_rmd3(rmd, 0);
573*56819Sralph 		LER2_rmd1(rmd, LE_OWN);
57452130Smckusick 		LENEXTRMP;
57552130Smckusick 	}
57652130Smckusick 	MachEmptyWriteBuffer();		/* Paranoia */
57752130Smckusick 	le->sc_rmd = bix;
57852130Smckusick }
57952130Smckusick 
58052130Smckusick /*
58152130Smckusick  * Look at the packet in network buffer memory so we can be smart about how
58252130Smckusick  * we copy the data into mbufs.
58352130Smckusick  * This needs work since we can't just read network buffer memory like
58452130Smckusick  * regular memory.
58552130Smckusick  */
58652130Smckusick leread(unit, buf, len)
58752130Smckusick 	int unit;
588*56819Sralph 	volatile void *buf;
58952130Smckusick 	int len;
59052130Smckusick {
59152130Smckusick 	register struct le_softc *le = &le_softc[unit];
59252130Smckusick 	struct ether_header et;
593*56819Sralph     	struct mbuf *m, **hdrmp, **tailmp;
59452130Smckusick 	int off, resid;
595*56819Sralph 	u_short sbuf[2], eth_type;
59652695Sralph 	extern struct mbuf *leget();
59752130Smckusick 
59852130Smckusick 	le->sc_if.if_ipackets++;
599*56819Sralph 	(*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et));
600*56819Sralph 	eth_type = ntohs(et.ether_type);
60152130Smckusick 	/* adjust input length to account for header and CRC */
60252130Smckusick 	len = len - sizeof(struct ether_header) - 4;
60352130Smckusick 
60452130Smckusick #ifdef RMP
60552130Smckusick 	/*  (XXX)
60652130Smckusick 	 *
60752130Smckusick 	 *  If Ethernet Type field is < MaxPacketSize, we probably have
60852130Smckusick 	 *  a IEEE802 packet here.  Make sure that the size is at least
60952130Smckusick 	 *  that of the HP LLC.  Also do sanity checks on length of LLC
61052130Smckusick 	 *  (old Ethernet Type field) and packet length.
61152130Smckusick 	 *
61252130Smckusick 	 *  Provided the above checks succeed, change `len' to reflect
61352130Smckusick 	 *  the length of the LLC (i.e. et.ether_type) and change the
61452130Smckusick 	 *  type field to ETHERTYPE_IEEE so we can switch() on it later.
61552130Smckusick 	 *  Yes, this is a hack and will eventually be done "right".
61652130Smckusick 	 */
617*56819Sralph 	if (eth_type <= IEEE802LEN_MAX && len >= sizeof(struct hp_llc) &&
618*56819Sralph 	    len >= eth_type && len >= IEEE802LEN_MIN) {
619*56819Sralph 		len = eth_type;
620*56819Sralph 		eth_type = ETHERTYPE_IEEE;	/* hack! */
62152130Smckusick 	}
62252130Smckusick #endif
62352130Smckusick 
624*56819Sralph 	if (eth_type >= ETHERTYPE_TRAIL &&
625*56819Sralph 	    eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
626*56819Sralph 		off = (eth_type - ETHERTYPE_TRAIL) * 512;
62752130Smckusick 		if (off >= ETHERMTU)
62852130Smckusick 			return;		/* sanity */
629*56819Sralph 		(*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf,
630*56819Sralph 			sizeof (sbuf));
631*56819Sralph 		eth_type = ntohs(sbuf[0]);
63252130Smckusick 		resid = ntohs(sbuf[1]);
63352130Smckusick 		if (off + resid > len)
63452130Smckusick 			return;		/* sanity */
63552130Smckusick 		len = off + resid;
63652130Smckusick 	} else
63752130Smckusick 		off = 0;
63852130Smckusick 
63952130Smckusick 	if (len <= 0) {
64052130Smckusick 		if (ledebug)
64152130Smckusick 			log(LOG_WARNING,
64252130Smckusick 			    "le%d: ierror(runt packet): from %s: len=%d\n",
64352130Smckusick 			    unit, ether_sprintf(et.ether_shost), len);
64452130Smckusick 		le->sc_runt++;
64552130Smckusick 		le->sc_if.if_ierrors++;
64652130Smckusick 		return;
64752130Smckusick 	}
64852130Smckusick 
64952130Smckusick 	/*
65052130Smckusick 	 * Pull packet off interface.  Off is nonzero if packet
65152130Smckusick 	 * has trailing header; leget will then force this header
65252130Smckusick 	 * information to be at the front, but we still have to drop
65352130Smckusick 	 * the type and length which are at the front of any trailer data.
654*56819Sralph 	 * The hdrmp and tailmp pointers are used by lebpf_tap() to
655*56819Sralph 	 * temporarily reorder the mbuf list. See the comment at the beginning
656*56819Sralph 	 * of lebpf_tap() for all the ugly details.
65752130Smckusick 	 */
658*56819Sralph 	m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp);
65952130Smckusick 	if (m == 0)
66052130Smckusick 		return;
661*56819Sralph #if NBPFILTER > 0
662*56819Sralph 	if (le->sc_bpf)
663*56819Sralph 		if (lebpf_tap(le, m, hdrmp, tailmp, off, &et, sbuf))
664*56819Sralph 			return;
665*56819Sralph #endif
66652130Smckusick #ifdef RMP
66752130Smckusick 	/*
66852130Smckusick 	 * (XXX)
66952130Smckusick 	 * This needs to be integrated with the ISO stuff in ether_input()
67052130Smckusick 	 */
671*56819Sralph 	if (eth_type == ETHERTYPE_IEEE) {
67252130Smckusick 		/*
67352130Smckusick 		 *  Snag the Logical Link Control header (IEEE 802.2).
67452130Smckusick 		 */
67552130Smckusick 		struct hp_llc *llc = &(mtod(m, struct rmp_packet *)->hp_llc);
67652130Smckusick 
67752130Smckusick 		/*
67852130Smckusick 		 *  If the DSAP (and HP's extended DXSAP) indicate this
67952130Smckusick 		 *  is an RMP packet, hand it to the raw input routine.
68052130Smckusick 		 */
68152130Smckusick 		if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) {
68252130Smckusick 			static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT};
68352130Smckusick 			static struct sockaddr rmp_src = {AF_RMP};
68452130Smckusick 			static struct sockaddr rmp_dst = {AF_RMP};
68552130Smckusick 
68652130Smckusick 			bcopy(et.ether_shost, rmp_src.sa_data,
68752130Smckusick 			      sizeof(et.ether_shost));
68852130Smckusick 			bcopy(et.ether_dhost, rmp_dst.sa_data,
68952130Smckusick 			      sizeof(et.ether_dhost));
69052130Smckusick 
69152130Smckusick 			raw_input(m, &rmp_sp, &rmp_src, &rmp_dst);
69252130Smckusick 			return;
69352130Smckusick 		}
69452130Smckusick 	}
69552130Smckusick #endif
696*56819Sralph 	et.ether_type = eth_type;
69752130Smckusick 	ether_input(&le->sc_if, &et, m);
69852130Smckusick }
69952130Smckusick 
70052130Smckusick /*
70152130Smckusick  * Routine to copy from mbuf chain to transmit buffer in
70252130Smckusick  * network buffer memory.
70352130Smckusick  */
704*56819Sralph leput(le, lebuf, m)
705*56819Sralph 	struct le_softc *le;
706*56819Sralph 	register volatile void *lebuf;
70752130Smckusick 	register struct mbuf *m;
70852130Smckusick {
70952130Smckusick 	register struct mbuf *mp;
71052695Sralph 	register int len, tlen = 0;
711*56819Sralph 	register int boff = 0;
71252130Smckusick 
71352130Smckusick 	for (mp = m; mp; mp = mp->m_next) {
71452130Smckusick 		len = mp->m_len;
71552130Smckusick 		if (len == 0)
71652130Smckusick 			continue;
717*56819Sralph 		(*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len);
71852130Smckusick 		tlen += len;
719*56819Sralph 		boff += len;
72052130Smckusick 	}
72152130Smckusick 	m_freem(m);
72252695Sralph 	if (tlen < LEMINSIZE) {
723*56819Sralph 		(*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen);
72452130Smckusick 		tlen = LEMINSIZE;
72552695Sralph 	}
72652130Smckusick 	return(tlen);
72752130Smckusick }
72852130Smckusick 
72952130Smckusick /*
73052130Smckusick  * Routine to copy from network buffer memory into mbufs.
73152130Smckusick  */
73252130Smckusick struct mbuf *
733*56819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp)
734*56819Sralph 	struct le_softc *le;
735*56819Sralph 	volatile void *lebuf;
73652130Smckusick 	int totlen, off;
73752130Smckusick 	struct ifnet *ifp;
738*56819Sralph 	struct mbuf ***hdrmp, ***tailmp;
73952130Smckusick {
74052130Smckusick 	register struct mbuf *m;
74152130Smckusick 	struct mbuf *top = 0, **mp = &top;
742*56819Sralph 	register int len, resid, boff;
74352130Smckusick 
74452130Smckusick 	/* NOTE: sizeof(struct ether_header) should be even */
745*56819Sralph 	boff = sizeof(struct ether_header);
74652130Smckusick 	if (off) {
74752130Smckusick 		/* NOTE: off should be even */
748*56819Sralph 		boff += off + 2 * sizeof(u_short);
74952130Smckusick 		totlen -= 2 * sizeof(u_short);
75052130Smckusick 		resid = totlen - off;
75152130Smckusick 	} else
75252130Smckusick 		resid = totlen;
75352130Smckusick 
75452130Smckusick 	MGETHDR(m, M_DONTWAIT, MT_DATA);
75552130Smckusick 	if (m == 0)
75652130Smckusick 		return (0);
75752130Smckusick 	m->m_pkthdr.rcvif = ifp;
75852130Smckusick 	m->m_pkthdr.len = totlen;
75952130Smckusick 	m->m_len = MHLEN;
76052130Smckusick 
76152130Smckusick 	while (totlen > 0) {
76252130Smckusick 		if (top) {
76352130Smckusick 			MGET(m, M_DONTWAIT, MT_DATA);
76452130Smckusick 			if (m == 0) {
76552130Smckusick 				m_freem(top);
76652130Smckusick 				return (0);
76752130Smckusick 			}
76852130Smckusick 			m->m_len = MLEN;
76952130Smckusick 		}
77052130Smckusick 
77152130Smckusick 		if (resid >= MINCLSIZE)
77252130Smckusick 			MCLGET(m, M_DONTWAIT);
77352130Smckusick 		if (m->m_flags & M_EXT)
77455745Sralph 			m->m_len = min(resid, MCLBYTES);
77552130Smckusick 		else if (resid < m->m_len) {
77652130Smckusick 			/*
77752130Smckusick 			 * Place initial small packet/header at end of mbuf.
77852130Smckusick 			 */
77952130Smckusick 			if (top == 0 && resid + max_linkhdr <= m->m_len)
78052130Smckusick 				m->m_data += max_linkhdr;
78152130Smckusick 			m->m_len = resid;
78252130Smckusick 		}
78352130Smckusick 		len = m->m_len;
784*56819Sralph 		(*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len);
785*56819Sralph 		boff += len;
78652130Smckusick 		*mp = m;
78752130Smckusick 		mp = &m->m_next;
78852130Smckusick 		totlen -= len;
78952130Smckusick 		resid -= len;
79052130Smckusick 		if (resid == 0) {
791*56819Sralph 			boff = sizeof (struct ether_header);
79252130Smckusick 			resid = totlen;
793*56819Sralph 			*hdrmp = mp;
79452130Smckusick 		}
79552130Smckusick 	}
796*56819Sralph 	*tailmp = mp;
79752130Smckusick 	return (top);
79852130Smckusick }
79952130Smckusick 
80052130Smckusick /*
80152130Smckusick  * Process an ioctl request.
80252130Smckusick  */
80352130Smckusick leioctl(ifp, cmd, data)
80452130Smckusick 	register struct ifnet *ifp;
80552130Smckusick 	int cmd;
80652130Smckusick 	caddr_t data;
80752130Smckusick {
80852130Smckusick 	register struct ifaddr *ifa = (struct ifaddr *)data;
80952130Smckusick 	struct le_softc *le = &le_softc[ifp->if_unit];
81052130Smckusick 	volatile struct lereg1 *ler1 = le->sc_r1;
81152130Smckusick 	int s, error = 0;
81252130Smckusick 
81352130Smckusick 	s = splnet();
81452130Smckusick 	switch (cmd) {
81552130Smckusick 
81652130Smckusick 	case SIOCSIFADDR:
81752130Smckusick 		ifp->if_flags |= IFF_UP;
81852130Smckusick 		switch (ifa->ifa_addr->sa_family) {
81952130Smckusick #ifdef INET
82052130Smckusick 		case AF_INET:
82152130Smckusick 			leinit(ifp->if_unit);	/* before arpwhohas */
82252130Smckusick 			((struct arpcom *)ifp)->ac_ipaddr =
82352130Smckusick 				IA_SIN(ifa)->sin_addr;
82452130Smckusick 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
82552130Smckusick 			break;
82652130Smckusick #endif
82752130Smckusick #ifdef NS
82852130Smckusick 		case AF_NS:
82952130Smckusick 		    {
83052130Smckusick 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
83152130Smckusick 
83252130Smckusick 			if (ns_nullhost(*ina))
83352130Smckusick 				ina->x_host = *(union ns_host *)(le->sc_addr);
83452130Smckusick 			else {
83552130Smckusick 				/*
83652130Smckusick 				 * The manual says we can't change the address
83752130Smckusick 				 * while the receiver is armed,
83852130Smckusick 				 * so reset everything
83952130Smckusick 				 */
84052130Smckusick 				ifp->if_flags &= ~IFF_RUNNING;
84152130Smckusick 				bcopy((caddr_t)ina->x_host.c_host,
84252130Smckusick 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
84352130Smckusick 			}
84452130Smckusick 			leinit(ifp->if_unit); /* does le_setaddr() */
84552130Smckusick 			break;
84652130Smckusick 		    }
84752130Smckusick #endif
84852130Smckusick 		default:
84952130Smckusick 			leinit(ifp->if_unit);
85052130Smckusick 			break;
85152130Smckusick 		}
85252130Smckusick 		break;
85352130Smckusick 
85452130Smckusick 	case SIOCSIFFLAGS:
85552130Smckusick 		if ((ifp->if_flags & IFF_UP) == 0 &&
85652130Smckusick 		    ifp->if_flags & IFF_RUNNING) {
857*56819Sralph 			LEWREG(LE_STOP, ler1->ler1_rdp);
85852130Smckusick 			ifp->if_flags &= ~IFF_RUNNING;
85952130Smckusick 		} else if (ifp->if_flags & IFF_UP &&
86052130Smckusick 		    (ifp->if_flags & IFF_RUNNING) == 0)
86152130Smckusick 			leinit(ifp->if_unit);
86252130Smckusick 		/*
86352130Smckusick 		 * If the state of the promiscuous bit changes, the interface
86452130Smckusick 		 * must be reset to effect the change.
86552130Smckusick 		 */
86652130Smckusick 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
86752130Smckusick 		    (ifp->if_flags & IFF_RUNNING)) {
86852130Smckusick 			le->sc_iflags = ifp->if_flags;
86952130Smckusick 			lereset(ifp->if_unit);
87052130Smckusick 			lestart(ifp);
87152130Smckusick 		}
87252130Smckusick 		break;
87352130Smckusick 
87452130Smckusick 	default:
87552130Smckusick 		error = EINVAL;
87652130Smckusick 	}
87752130Smckusick 	splx(s);
87852130Smckusick 	return (error);
87952130Smckusick }
88052130Smckusick 
88152130Smckusick leerror(unit, stat)
88252130Smckusick 	int unit;
88352130Smckusick 	int stat;
88452130Smckusick {
88552130Smckusick 	if (!ledebug)
88652130Smckusick 		return;
88752130Smckusick 
88852130Smckusick 	/*
88952130Smckusick 	 * Not all transceivers implement heartbeat
89052130Smckusick 	 * so we only log CERR once.
89152130Smckusick 	 */
89252130Smckusick 	if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
89352130Smckusick 		return;
89452130Smckusick 	log(LOG_WARNING,
89552130Smckusick 	    "le%d: error: stat=%b\n", unit,
89652130Smckusick 	    stat,
89752130Smckusick 	    "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
89852130Smckusick }
89952130Smckusick 
90052130Smckusick lererror(unit, msg)
90152130Smckusick 	int unit;
90252130Smckusick 	char *msg;
90352130Smckusick {
90452130Smckusick 	register struct le_softc *le = &le_softc[unit];
905*56819Sralph 	register volatile void *rmd;
90654144Sralph 	u_char eaddr[6];
90752130Smckusick 	int len;
90852130Smckusick 
90952130Smckusick 	if (!ledebug)
91052130Smckusick 		return;
91152130Smckusick 
912*56819Sralph 	rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd);
913*56819Sralph 	len = LER2V_rmd3(rmd);
914*56819Sralph 	if (len > 11)
915*56819Sralph 		(*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd),
916*56819Sralph 			6, eaddr, 6);
91752130Smckusick 	log(LOG_WARNING,
91852130Smckusick 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
919*56819Sralph 	    unit, msg,
920*56819Sralph 	    len > 11 ? ether_sprintf(eaddr) : "unknown",
921*56819Sralph 	    le->sc_rmd, len,
922*56819Sralph 	    LER2V_rmd1(rmd),
92352130Smckusick 	    "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
92452130Smckusick }
92552130Smckusick 
92652130Smckusick lexerror(unit)
92752130Smckusick 	int unit;
92852130Smckusick {
92952130Smckusick 	register struct le_softc *le = &le_softc[unit];
930*56819Sralph 	register volatile void *tmd;
93154144Sralph 	u_char eaddr[6];
93252130Smckusick 	int len;
93352130Smckusick 
93452130Smckusick 	if (!ledebug)
93552130Smckusick 		return;
93652130Smckusick 
937*56819Sralph 	tmd = LER2_TMDADDR(le->sc_r2, 0);
938*56819Sralph 	len = -LER2V_tmd2(tmd);
939*56819Sralph 	if (len > 5)
940*56819Sralph 		(*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6);
94152130Smckusick 	log(LOG_WARNING,
94252130Smckusick 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
943*56819Sralph 	    unit,
944*56819Sralph 	    len > 5 ? ether_sprintf(eaddr) : "unknown",
945*56819Sralph 	    0, len,
946*56819Sralph 	    LER2V_tmd1(tmd),
94752130Smckusick 	    "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
948*56819Sralph 	    LER2V_tmd3(tmd),
94952130Smckusick 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
95052130Smckusick }
951*56819Sralph 
952*56819Sralph /*
953*56819Sralph  * Write a lance register port, reading it back to ensure success. This seems
954*56819Sralph  * to be necessary during initialization, since the chip appears to be a bit
955*56819Sralph  * pokey sometimes.
956*56819Sralph  */
957*56819Sralph static void
958*56819Sralph lewritereg(regptr, val)
959*56819Sralph 	register volatile u_short *regptr;
960*56819Sralph 	register u_short val;
961*56819Sralph {
962*56819Sralph 	register int i = 0;
963*56819Sralph 
964*56819Sralph 	while (*regptr != val) {
965*56819Sralph 		*regptr = val;
966*56819Sralph 		MachEmptyWriteBuffer();
967*56819Sralph 		if (++i > 10000) {
968*56819Sralph 			printf("le: Reg did not settle (to x%x): x%x\n",
969*56819Sralph 			       val, *regptr);
970*56819Sralph 			return;
971*56819Sralph 		}
972*56819Sralph 		DELAY(100);
973*56819Sralph 	}
974*56819Sralph }
975*56819Sralph 
976*56819Sralph /*
977*56819Sralph  * Routines for accessing the transmit and receive buffers. Unfortunately,
978*56819Sralph  * CPU addressing of these buffers is done in one of 3 ways:
979*56819Sralph  * - contiguous (for the 3max and turbochannel option card)
980*56819Sralph  * - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
981*56819Sralph  *   spaces (for the pmax)
982*56819Sralph  * - gap16, which means 16bytes interspersed with 16byte spaces
983*56819Sralph  *   for buffers which must begin on a 32byte boundary (for 3min and maxine)
984*56819Sralph  * The buffer offset is the logical byte offset, assuming contiguous storage.
985*56819Sralph  */
986*56819Sralph void
987*56819Sralph copytobuf_contig(from, lebuf, boff, len)
988*56819Sralph 	char *from;
989*56819Sralph 	volatile void *lebuf;
990*56819Sralph 	int boff;
991*56819Sralph 	int len;
992*56819Sralph {
993*56819Sralph 
994*56819Sralph 	/*
995*56819Sralph 	 * Just call bcopy() to do the work.
996*56819Sralph 	 */
997*56819Sralph 	bcopy(from, ((char *)lebuf) + boff, len);
998*56819Sralph }
999*56819Sralph 
1000*56819Sralph void
1001*56819Sralph copyfrombuf_contig(lebuf, boff, to, len)
1002*56819Sralph 	volatile void *lebuf;
1003*56819Sralph 	int boff;
1004*56819Sralph 	char *to;
1005*56819Sralph 	int len;
1006*56819Sralph {
1007*56819Sralph 
1008*56819Sralph 	/*
1009*56819Sralph 	 * Just call bcopy() to do the work.
1010*56819Sralph 	 */
1011*56819Sralph 	bcopy(((char *)lebuf) + boff, to, len);
1012*56819Sralph }
1013*56819Sralph 
1014*56819Sralph void
1015*56819Sralph bzerobuf_contig(lebuf, boff, len)
1016*56819Sralph 	volatile void *lebuf;
1017*56819Sralph 	int boff;
1018*56819Sralph 	int len;
1019*56819Sralph {
1020*56819Sralph 
1021*56819Sralph 	/*
1022*56819Sralph 	 * Just let bzero() do the work
1023*56819Sralph 	 */
1024*56819Sralph 	bzero(((char *)lebuf) + boff, len);
1025*56819Sralph }
1026*56819Sralph 
1027*56819Sralph /*
1028*56819Sralph  * For the pmax the buffer consists of shorts (2 bytes) interspersed with
1029*56819Sralph  * short (2 byte) spaces and must be accessed with halfword load/stores.
1030*56819Sralph  * (don't worry about doing an extra byte)
1031*56819Sralph  */
1032*56819Sralph void
1033*56819Sralph copytobuf_gap2(from, lebuf, boff, len)
1034*56819Sralph 	register char *from;
1035*56819Sralph 	volatile void *lebuf;
1036*56819Sralph 	int boff;
1037*56819Sralph 	register int len;
1038*56819Sralph {
1039*56819Sralph 	register volatile u_short *bptr;
1040*56819Sralph 	register int xfer;
1041*56819Sralph 
1042*56819Sralph 	if (boff & 0x1) {
1043*56819Sralph 		/* handle unaligned first byte */
1044*56819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
1045*56819Sralph 		*bptr = (*from++ << 8) | (*bptr & 0xff);
1046*56819Sralph 		bptr += 2;
1047*56819Sralph 		len--;
1048*56819Sralph 	} else
1049*56819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
1050*56819Sralph 	if ((unsigned)from & 0x1) {
1051*56819Sralph 		while (len > 1) {
1052*56819Sralph 			*bptr = (from[1] << 8) | from[0];
1053*56819Sralph 			bptr += 2;
1054*56819Sralph 			from += 2;
1055*56819Sralph 			len -= 2;
1056*56819Sralph 		}
1057*56819Sralph 	} else {
1058*56819Sralph 		/* optimize for aligned transfers */
1059*56819Sralph 		xfer = (int)((unsigned)len & ~0x1);
1060*56819Sralph 		CopyToBuffer((u_short *)from, bptr, xfer);
1061*56819Sralph 		bptr += xfer;
1062*56819Sralph 		from += xfer;
1063*56819Sralph 		len -= xfer;
1064*56819Sralph 	}
1065*56819Sralph 	if (len == 1)
1066*56819Sralph 		*bptr = (u_short)*from;
1067*56819Sralph }
1068*56819Sralph 
1069*56819Sralph void
1070*56819Sralph copyfrombuf_gap2(lebuf, boff, to, len)
1071*56819Sralph 	volatile void *lebuf;
1072*56819Sralph 	int boff;
1073*56819Sralph 	register char *to;
1074*56819Sralph 	register int len;
1075*56819Sralph {
1076*56819Sralph 	register volatile u_short *bptr;
1077*56819Sralph 	register u_short tmp;
1078*56819Sralph 	register int xfer;
1079*56819Sralph 
1080*56819Sralph 	if (boff & 0x1) {
1081*56819Sralph 		/* handle unaligned first byte */
1082*56819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
1083*56819Sralph 		*to++ = (*bptr >> 8) & 0xff;
1084*56819Sralph 		bptr += 2;
1085*56819Sralph 		len--;
1086*56819Sralph 	} else
1087*56819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
1088*56819Sralph 	if ((unsigned)to & 0x1) {
1089*56819Sralph 		while (len > 1) {
1090*56819Sralph 			tmp = *bptr;
1091*56819Sralph 			*to++ = tmp & 0xff;
1092*56819Sralph 			*to++ = (tmp >> 8) & 0xff;
1093*56819Sralph 			bptr += 2;
1094*56819Sralph 			len -= 2;
1095*56819Sralph 		}
1096*56819Sralph 	} else {
1097*56819Sralph 		/* optimize for aligned transfers */
1098*56819Sralph 		xfer = (int)((unsigned)len & ~0x1);
1099*56819Sralph 		CopyFromBuffer(bptr, to, xfer);
1100*56819Sralph 		bptr += xfer;
1101*56819Sralph 		to += xfer;
1102*56819Sralph 		len -= xfer;
1103*56819Sralph 	}
1104*56819Sralph 	if (len == 1)
1105*56819Sralph 		*to = *bptr & 0xff;
1106*56819Sralph }
1107*56819Sralph 
1108*56819Sralph void
1109*56819Sralph bzerobuf_gap2(lebuf, boff, len)
1110*56819Sralph 	volatile void *lebuf;
1111*56819Sralph 	int boff;
1112*56819Sralph 	int len;
1113*56819Sralph {
1114*56819Sralph 	register volatile u_short *bptr;
1115*56819Sralph 
1116*56819Sralph 	if ((unsigned)boff & 0x1) {
1117*56819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
1118*56819Sralph 		*bptr &= 0xff;
1119*56819Sralph 		bptr += 2;
1120*56819Sralph 		len--;
1121*56819Sralph 	} else
1122*56819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
1123*56819Sralph 	while (len > 0) {
1124*56819Sralph 		*bptr = 0;
1125*56819Sralph 		bptr += 2;
1126*56819Sralph 		len -= 2;
1127*56819Sralph 	}
1128*56819Sralph }
1129*56819Sralph 
1130*56819Sralph /*
1131*56819Sralph  * For the 3min and maxine, the buffers are in main memory filled in with
1132*56819Sralph  * 16byte blocks interspersed with 16byte spaces.
1133*56819Sralph  */
1134*56819Sralph void
1135*56819Sralph copytobuf_gap16(from, lebuf, boff, len)
1136*56819Sralph 	register char *from;
1137*56819Sralph 	volatile void *lebuf;
1138*56819Sralph 	int boff;
1139*56819Sralph 	register int len;
1140*56819Sralph {
1141*56819Sralph 	register char *bptr;
1142*56819Sralph 	register int xfer;
1143*56819Sralph 
1144*56819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
1145*56819Sralph 	boff &= 0xf;
1146*56819Sralph 	xfer = min(len, 16 - boff);
1147*56819Sralph 	while (len > 0) {
1148*56819Sralph 		bcopy(from, ((char *)bptr) + boff, xfer);
1149*56819Sralph 		from += xfer;
1150*56819Sralph 		bptr += 32;
1151*56819Sralph 		boff = 0;
1152*56819Sralph 		len -= xfer;
1153*56819Sralph 		xfer = min(len, 16);
1154*56819Sralph 	}
1155*56819Sralph }
1156*56819Sralph 
1157*56819Sralph void
1158*56819Sralph copyfrombuf_gap16(lebuf, boff, to, len)
1159*56819Sralph 	volatile void *lebuf;
1160*56819Sralph 	int boff;
1161*56819Sralph 	register char *to;
1162*56819Sralph 	register int len;
1163*56819Sralph {
1164*56819Sralph 	register char *bptr;
1165*56819Sralph 	register int xfer;
1166*56819Sralph 
1167*56819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
1168*56819Sralph 	boff &= 0xf;
1169*56819Sralph 	xfer = min(len, 16 - boff);
1170*56819Sralph 	while (len > 0) {
1171*56819Sralph 		bcopy(((char *)bptr) + boff, to, xfer);
1172*56819Sralph 		to += xfer;
1173*56819Sralph 		bptr += 32;
1174*56819Sralph 		boff = 0;
1175*56819Sralph 		len -= xfer;
1176*56819Sralph 		xfer = min(len, 16);
1177*56819Sralph 	}
1178*56819Sralph }
1179*56819Sralph 
1180*56819Sralph void
1181*56819Sralph bzerobuf_gap16(lebuf, boff, len)
1182*56819Sralph 	volatile void *lebuf;
1183*56819Sralph 	int boff;
1184*56819Sralph 	register int len;
1185*56819Sralph {
1186*56819Sralph 	register char *bptr;
1187*56819Sralph 	register int xfer;
1188*56819Sralph 
1189*56819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
1190*56819Sralph 	boff &= 0xf;
1191*56819Sralph 	xfer = min(len, 16 - boff);
1192*56819Sralph 	while (len > 0) {
1193*56819Sralph 		bzero(((char *)bptr) + boff, xfer);
1194*56819Sralph 		bptr += 32;
1195*56819Sralph 		boff = 0;
1196*56819Sralph 		len -= xfer;
1197*56819Sralph 		xfer = min(len, 16);
1198*56819Sralph 	}
1199*56819Sralph }
1200*56819Sralph 
1201*56819Sralph #if NBPFILTER > 0
1202*56819Sralph /*
1203*56819Sralph  * This is exceptionally ugly, but since the lance buffers are not always
1204*56819Sralph  * contiguous in cpu address space, this was the best I could think of.
1205*56819Sralph  * Essentially build an mbuf list with the entire raw packet in it and
1206*56819Sralph  * then dismantle it again if it is a local packet. I can't believe I am
1207*56819Sralph  * rebuilding the trailer encapsulation, but...
1208*56819Sralph  * Return true if the packet has been thrown away.
1209*56819Sralph  */
1210*56819Sralph static int
1211*56819Sralph lebpf_tap(le, m, hdrmp, tailmp, off, ep, sbuf)
1212*56819Sralph 	struct le_softc *le;
1213*56819Sralph 	struct mbuf *m;
1214*56819Sralph 	struct mbuf **hdrmp;
1215*56819Sralph 	struct mbuf **tailmp;
1216*56819Sralph 	int off;
1217*56819Sralph 	struct ether_header *ep;
1218*56819Sralph 	u_short *sbuf;
1219*56819Sralph {
1220*56819Sralph 	register struct mbuf *em, *sm;
1221*56819Sralph 	u_short *sp;
1222*56819Sralph 
1223*56819Sralph 	MGET(em, M_DONTWAIT, MT_DATA);
1224*56819Sralph 	if (off && em) {
1225*56819Sralph 		MGET(sm, M_DONTWAIT, MT_DATA);
1226*56819Sralph 		if (sm == (struct mbuf *)0) {
1227*56819Sralph 			m_freem(em);
1228*56819Sralph 			em = (struct mbuf *)0;
1229*56819Sralph 		}
1230*56819Sralph 	}
1231*56819Sralph 	if (em) {
1232*56819Sralph 		bcopy((caddr_t)ep, mtod(em, caddr_t), sizeof (*ep));
1233*56819Sralph 		em->m_len = sizeof (*ep);
1234*56819Sralph 		if (off) {
1235*56819Sralph 			sp = mtod(sm, u_short *);
1236*56819Sralph 			*sp++ = *sbuf++;
1237*56819Sralph 			*sp = *sbuf;
1238*56819Sralph 			sm->m_len = 2 * sizeof (u_short);
1239*56819Sralph 			em->m_next = *hdrmp;
1240*56819Sralph 			*hdrmp = (struct mbuf *)0;
1241*56819Sralph 			*tailmp = sm;
1242*56819Sralph 			sm->m_next = m;
1243*56819Sralph 		} else
1244*56819Sralph 			em->m_next = m;
1245*56819Sralph 		bpf_tap(le->sc_bpf, em);
1246*56819Sralph 	}
1247*56819Sralph 	/*
1248*56819Sralph 	 * Note that the interface cannot be in promiscuous mode if
1249*56819Sralph 	 * there are no bpf listeners.  And if we are in promiscuous
1250*56819Sralph 	 * mode, we have to check if this packet is really ours.
1251*56819Sralph 	 *
1252*56819Sralph 	 * XXX This test does not support multicasts.
1253*56819Sralph 	 */
1254*56819Sralph 	if ((le->sc_if.if_flags & IFF_PROMISC)
1255*56819Sralph 	    && bcmp(ep->ether_dhost, le->sc_addr,
1256*56819Sralph 		    sizeof(ep->ether_dhost)) != 0
1257*56819Sralph 	    && bcmp(ep->ether_dhost, etherbroadcastaddr,
1258*56819Sralph 		    sizeof(ep->ether_dhost)) != 0) {
1259*56819Sralph 		if (em)
1260*56819Sralph 			m_freem(em);
1261*56819Sralph 		else
1262*56819Sralph 			m_freem(m);
1263*56819Sralph 		return (1);
1264*56819Sralph 	}
1265*56819Sralph 	if (em == (struct mbuf *)0)
1266*56819Sralph 		return (0);
1267*56819Sralph 	if (off) {
1268*56819Sralph 		MFREE(em, *hdrmp);
1269*56819Sralph 		*tailmp = (struct mbuf *)0;
1270*56819Sralph 		MFREE(sm, em);
1271*56819Sralph 	} else {
1272*56819Sralph 		MFREE(em, sm);
1273*56819Sralph 	}
1274*56819Sralph 	return (0);
1275*56819Sralph }
1276*56819Sralph #endif /* NBPFILTER */
1277*56819Sralph #endif /* NLE */
1278