xref: /csrg-svn/sys/news3400/if/if_en.c (revision 53897)
1*53897Smckusick /*
2*53897Smckusick  * Copyright (c) 1992 The Regents of the University of California.
3*53897Smckusick  * All rights reserved.
4*53897Smckusick  *
5*53897Smckusick  * This code is derived from software contributed to Berkeley by
6*53897Smckusick  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7*53897Smckusick  *
8*53897Smckusick  * %sccs.include.redist.c%
9*53897Smckusick  *
10*53897Smckusick  * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY
11*53897Smckusick  *
12*53897Smckusick  *	@(#)if_en.c	7.1 (Berkeley) 06/04/92
13*53897Smckusick  */
14*53897Smckusick 
15*53897Smckusick #include "en.h"
16*53897Smckusick #include "rawether.h"
17*53897Smckusick #include "bpfilter.h"
18*53897Smckusick 
19*53897Smckusick #if NEN > 0
20*53897Smckusick 
21*53897Smckusick /*
22*53897Smckusick  * Interlan Ethernet Communications Controller interface
23*53897Smckusick  */
24*53897Smckusick #include "types.h"
25*53897Smckusick #include "../include/fix_machine_type.h"
26*53897Smckusick #include "../include/pte.h"
27*53897Smckusick 
28*53897Smckusick #include "param.h"
29*53897Smckusick #include "systm.h"
30*53897Smckusick #include "mbuf.h"
31*53897Smckusick #include "buf.h"
32*53897Smckusick #include "protosw.h"
33*53897Smckusick #include "socket.h"
34*53897Smckusick #include "ioctl.h"
35*53897Smckusick #include "errno.h"
36*53897Smckusick #include "time.h"
37*53897Smckusick #include "cdefs.h"
38*53897Smckusick 
39*53897Smckusick #include "net/if.h"
40*53897Smckusick #include "net/netisr.h"
41*53897Smckusick #include "net/route.h"
42*53897Smckusick 
43*53897Smckusick #ifdef INET
44*53897Smckusick #include "netinet/in.h"
45*53897Smckusick #include "netinet/in_systm.h"
46*53897Smckusick #include "netinet/in_var.h"
47*53897Smckusick #include "netinet/ip.h"
48*53897Smckusick #include "netinet/if_ether.h"
49*53897Smckusick #endif
50*53897Smckusick 
51*53897Smckusick #include "../if/if_news.h"
52*53897Smckusick #include "../if/if_en.h"
53*53897Smckusick 
54*53897Smckusick #ifdef CPU_SINGLE
55*53897Smckusick #include "../hbdev/hbvar.h"
56*53897Smckusick #define	iop_device	hb_device
57*53897Smckusick #define	iop_driver	hb_driver
58*53897Smckusick #define	ii_unit		hi_unit
59*53897Smckusick #define	ii_intr		hi_intr
60*53897Smckusick #define	ii_alive	hi_alive
61*53897Smckusick #else
62*53897Smckusick #include "../iop/iopvar.h"
63*53897Smckusick #endif
64*53897Smckusick 
65*53897Smckusick int	enprobe(), enattach(), enrint(), enxint();
66*53897Smckusick struct	mbuf *m_devget();
67*53897Smckusick 
68*53897Smckusick #ifdef CPU_SINGLE
69*53897Smckusick struct	hb_device *eninfo[NEN];
70*53897Smckusick struct	hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo };
71*53897Smckusick #else
72*53897Smckusick struct	iop_device *eninfo[NEN];
73*53897Smckusick struct	iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo };
74*53897Smckusick #endif
75*53897Smckusick 
76*53897Smckusick #define	ENUNIT(x)	minor(x)
77*53897Smckusick 
78*53897Smckusick int	eninit(),enoutput(),enioctl(),enreset(),enwatch(),enstart();
79*53897Smckusick int	endebug = 0;
80*53897Smckusick 
81*53897Smckusick struct ether_addr {
82*53897Smckusick 	u_char	addr[6];
83*53897Smckusick };
84*53897Smckusick 
85*53897Smckusick extern struct ifnet loif;
86*53897Smckusick 
87*53897Smckusick struct en_softc en_softc[NEN];
88*53897Smckusick struct ether_addr myether[NEN];
89*53897Smckusick 
90*53897Smckusick #if NBPFILTER > 0
91*53897Smckusick #include "../net/bpf.h"
92*53897Smckusick caddr_t	en_bpf[NEN];
93*53897Smckusick #endif
94*53897Smckusick 
95*53897Smckusick enprobe(ii)
96*53897Smckusick 	struct iop_device *ii;
97*53897Smckusick {
98*53897Smckusick 
99*53897Smckusick 	return (en_probe(ii));
100*53897Smckusick }
101*53897Smckusick 
102*53897Smckusick /*
103*53897Smckusick  * Interface exists: make available by filling in network interface
104*53897Smckusick  * record.  System will initialize the interface when it is ready
105*53897Smckusick  * to accept packets.  A STATUS command is done to get the ethernet
106*53897Smckusick  * address and other interesting data.
107*53897Smckusick  */
108*53897Smckusick enattach(ii)
109*53897Smckusick 	register struct iop_device *ii;
110*53897Smckusick {
111*53897Smckusick 	register struct en_softc *es = &en_softc[ii->ii_unit];
112*53897Smckusick 	register struct ifnet *ifp = &es->es_if;
113*53897Smckusick 	extern char *ether_sprintf();
114*53897Smckusick 
115*53897Smckusick 	en_attach(ii->ii_unit);
116*53897Smckusick 	bcopy((caddr_t)es->es_addr, &myether[ii->ii_unit],
117*53897Smckusick 		sizeof(struct ether_addr));
118*53897Smckusick 	printf("en%d: hardware address %s\n",
119*53897Smckusick 		ii->ii_unit, ether_sprintf((u_char *)es->es_addr));
120*53897Smckusick 	ifp->if_unit = ii->ii_unit;
121*53897Smckusick 	ifp->if_name = "en";
122*53897Smckusick 	ifp->if_mtu = ETHERMTU;
123*53897Smckusick 	ifp->if_init = eninit;
124*53897Smckusick 	ifp->if_ioctl = enioctl;
125*53897Smckusick 	ifp->if_output = ether_output;
126*53897Smckusick #ifdef NOTDEF /* KU:XXX if_reset is obsolete */
127*53897Smckusick 	ifp->if_reset = enreset;
128*53897Smckusick #endif
129*53897Smckusick 	ifp->if_start = enstart;
130*53897Smckusick 	ifp->if_flags = IFF_BROADCAST;
131*53897Smckusick #if NBPFILTER > 0
132*53897Smckusick 	{
133*53897Smckusick 		static struct bpf_devp dev =
134*53897Smckusick 			{ DLT_EN10MB, sizeof(struct ether_header) };
135*53897Smckusick 
136*53897Smckusick 		bpfattach(&en_bpf[ii->ii_unit], ifp, &dev);
137*53897Smckusick 	}
138*53897Smckusick #endif
139*53897Smckusick 	if_attach(ifp);
140*53897Smckusick }
141*53897Smckusick 
142*53897Smckusick /*
143*53897Smckusick  * Reset of interface after IOP reset.
144*53897Smckusick  */
145*53897Smckusick enreset(unit)
146*53897Smckusick 	int unit;
147*53897Smckusick {
148*53897Smckusick 	register struct iop_device *ii;
149*53897Smckusick 
150*53897Smckusick 	if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0)
151*53897Smckusick 		return;
152*53897Smckusick 	printf(" en%d", unit);
153*53897Smckusick 	en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
154*53897Smckusick 	en_softc[unit].es_flags &= ~ENF_RUNNING;
155*53897Smckusick 	eninit(unit);
156*53897Smckusick }
157*53897Smckusick 
158*53897Smckusick /*
159*53897Smckusick  * Initialization of interface; clear recorded pending
160*53897Smckusick  * operations, and reinitialize IOP usage.
161*53897Smckusick  */
162*53897Smckusick eninit(unit)
163*53897Smckusick 	int unit;
164*53897Smckusick {
165*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
166*53897Smckusick 	register struct ifnet *ifp = &es->es_if;
167*53897Smckusick 	int s;
168*53897Smckusick 
169*53897Smckusick 	/* not yet, if address still unknown */
170*53897Smckusick 	if (ifp->if_addrlist == (struct ifaddr *)0)
171*53897Smckusick 		return;
172*53897Smckusick 	if (es->es_flags & ENF_RUNNING)
173*53897Smckusick 		return;
174*53897Smckusick 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
175*53897Smckusick 		if (if_newsinit(&es->es_ifnews,
176*53897Smckusick 		    sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) {
177*53897Smckusick 			printf("en%d: can't initialize\n", unit);
178*53897Smckusick 			es->es_if.if_flags &= ~IFF_UP;
179*53897Smckusick 			return;
180*53897Smckusick 		}
181*53897Smckusick 		ifp->if_watchdog = enwatch;
182*53897Smckusick 		es->es_interval = ENWATCHINTERVAL;
183*53897Smckusick 		ifp->if_timer = es->es_interval;
184*53897Smckusick 		s = splimp();
185*53897Smckusick 		en_init(unit);
186*53897Smckusick 		splx(s);
187*53897Smckusick 	}
188*53897Smckusick 	es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS;
189*53897Smckusick 	es->es_flags |= ENF_RUNNING;
190*53897Smckusick }
191*53897Smckusick 
192*53897Smckusick /*
193*53897Smckusick  * Start output on interface.
194*53897Smckusick  * Get another datagram to send off of the interface queue,
195*53897Smckusick  * and map it to the interface before starting the output.
196*53897Smckusick  */
197*53897Smckusick enstart(ifp)
198*53897Smckusick 	register struct ifnet *ifp;
199*53897Smckusick {
200*53897Smckusick         int unit = ifp->if_unit, len;
201*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
202*53897Smckusick 	register struct mbuf *m;
203*53897Smckusick 
204*53897Smckusick 	IF_DEQUEUE(&es->es_if.if_snd, m);
205*53897Smckusick 	if (m == 0)
206*53897Smckusick 		return(0);
207*53897Smckusick #ifdef CPU_SINGLE
208*53897Smckusick 	es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit);
209*53897Smckusick #endif
210*53897Smckusick 	len = if_wnewsput(&es->es_ifnews, m);
211*53897Smckusick 	/*
212*53897Smckusick 	 * Ensure minimum packet length.
213*53897Smckusick 	 * This makes the safe assumtion that there are no virtual holes
214*53897Smckusick 	 * after the data.
215*53897Smckusick 	 * For security, it might be wise to zero out the added bytes,
216*53897Smckusick 	 * but we're mainly interested in speed at the moment.
217*53897Smckusick 	 */
218*53897Smckusick 	if (len - sizeof(struct ether_header) < ETHERMIN)
219*53897Smckusick 		len = ETHERMIN + sizeof(struct ether_header);
220*53897Smckusick 	en_start(unit, len);
221*53897Smckusick #if NBPFILTER > 0
222*53897Smckusick 	/*
223*53897Smckusick 	 * If bpf is listening on this interface, let it
224*53897Smckusick 	 * see the packet before we commit it to the wire.
225*53897Smckusick 	 */
226*53897Smckusick 	if (en_bpf[unit]) {
227*53897Smckusick #ifdef CPU_SINGLE
228*53897Smckusick 		bpf_tap(en_bpf[unit], es->es_ifnews.ifn_waddr, len);
229*53897Smckusick #else
230*53897Smckusick 		bpf_mtap(en_bpf[unit], m);
231*53897Smckusick #endif
232*53897Smckusick 	}
233*53897Smckusick #endif /* NBPFILTER > 0 */
234*53897Smckusick 	es->es_if.if_flags |= IFF_OACTIVE;
235*53897Smckusick 	return(0);
236*53897Smckusick }
237*53897Smckusick 
238*53897Smckusick /*
239*53897Smckusick  * Transmit done interrupt.
240*53897Smckusick  */
241*53897Smckusick _enxint(unit, error, collision)
242*53897Smckusick 	int unit;
243*53897Smckusick 	int error, collision;
244*53897Smckusick {
245*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
246*53897Smckusick 
247*53897Smckusick #ifdef notyet /* KU:XXX */
248*53897Smckusick 	intrcnt[INTR_ETHER0 + unit]++;
249*53897Smckusick #endif
250*53897Smckusick 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0) {
251*53897Smckusick 		printf("en%d: stray xmit interrupt\n", unit);
252*53897Smckusick /*
253*53897Smckusick 		return;
254*53897Smckusick */
255*53897Smckusick 	} else {
256*53897Smckusick 		es->es_if.if_flags &= ~IFF_OACTIVE;
257*53897Smckusick 		es->es_if.if_opackets++;
258*53897Smckusick 	}
259*53897Smckusick 	if (error)
260*53897Smckusick 		es->es_if.if_oerrors++;
261*53897Smckusick 	if (collision)
262*53897Smckusick 		es->es_if.if_collisions++;
263*53897Smckusick 	enstart(&es->es_if);
264*53897Smckusick }
265*53897Smckusick 
266*53897Smckusick /*
267*53897Smckusick  * Ethernet interface receiver interrupt.
268*53897Smckusick  * If input error just drop packet.
269*53897Smckusick  * Otherwise purge input buffered data path and examine
270*53897Smckusick  * packet to determine type.  If can't determine length
271*53897Smckusick  * from type, then have to drop packet.  Othewise decapsulate
272*53897Smckusick  * packet based on type and pass to type specific higher-level
273*53897Smckusick  * input routine.
274*53897Smckusick  */
275*53897Smckusick _enrint(unit, len)
276*53897Smckusick 	int unit;
277*53897Smckusick 	register int len;
278*53897Smckusick {
279*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
280*53897Smckusick 	register struct en_rheader *en;
281*53897Smckusick     	struct mbuf *m;
282*53897Smckusick 	int off, resid, s;
283*53897Smckusick 	int	type;
284*53897Smckusick 	register struct ensw *esp;
285*53897Smckusick 	extern struct mbuf *if_rnewsget();
286*53897Smckusick 
287*53897Smckusick #ifdef notyet /* KU:XXX */
288*53897Smckusick 	intrcnt[INTR_ETHER0 + unit]++;
289*53897Smckusick #endif
290*53897Smckusick 	es->es_if.if_ipackets++;
291*53897Smckusick 	if ((es->es_flags & ENF_RUNNING) == 0)
292*53897Smckusick 		return;
293*53897Smckusick 	en = (struct en_rheader *)(es->es_ifnews.ifn_raddr);
294*53897Smckusick 	if (len < ETHERMIN || len > ETHERMTU) {
295*53897Smckusick 		es->es_if.if_ierrors++;
296*53897Smckusick 		return;
297*53897Smckusick 	}
298*53897Smckusick #if NBPFILTER > 0
299*53897Smckusick #if NRAWETHER > 0
300*53897Smckusick 	etherinput(unit, en, len + sizeof(struct en_rheader));
301*53897Smckusick #endif
302*53897Smckusick 	/*
303*53897Smckusick 	 * Check if there's a bpf filter listening on this interface.
304*53897Smckusick 	 * If so, hand off the raw packet to enet.
305*53897Smckusick 	 */
306*53897Smckusick 	if (en_bpf[unit]) {
307*53897Smckusick 		bpf_tap(en_bpf[unit], es->es_ifnews.ifn_raddr,
308*53897Smckusick 			len + sizeof(struct en_rheader));
309*53897Smckusick 		/*
310*53897Smckusick 		 * Note that the interface cannot be in promiscuous mode if
311*53897Smckusick 		 * there are no bpf listeners.	And if we are in promiscuous
312*53897Smckusick 		 * mode, we have to check if this packet is really ours.
313*53897Smckusick 		 *
314*53897Smckusick 		 * XXX This test does not support multicasts.
315*53897Smckusick 		 */
316*53897Smckusick 		 if ((es->es_if.if_flags & IFF_PROMISC)
317*53897Smckusick 		     && bcmp(en->enr_dhost, es->es_addr,
318*53897Smckusick 				sizeof(en->enr_dhost)) != 0
319*53897Smckusick 		     && bcmp(en->enr_dhost, etherbroadcastaddr,
320*53897Smckusick 				sizeof(en->enr_dhost)) != 0)
321*53897Smckusick 			return;
322*53897Smckusick 	}
323*53897Smckusick #else /* NBPFILTER > 0 */
324*53897Smckusick #if NRAWETHER > 0
325*53897Smckusick 	if (etherinput(unit, en, len + sizeof(struct en_rheader)))
326*53897Smckusick 		return;
327*53897Smckusick #endif
328*53897Smckusick #endif /* NBPFILTER > 0 */
329*53897Smckusick 	/*
330*53897Smckusick 	 * Deal with trailer protocol: if type is trailer type
331*53897Smckusick 	 * get true type from first 16-bit word past data.
332*53897Smckusick 	 * Remember that type was trailer by setting off.
333*53897Smckusick 	 */
334*53897Smckusick 	en->enr_type = ntohs((u_short)en->enr_type);
335*53897Smckusick #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
336*53897Smckusick 	if (en->enr_type >= ETHERTYPE_TRAIL &&
337*53897Smckusick 	    en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
338*53897Smckusick 		off = (en->enr_type - ETHERTYPE_TRAIL) * 512;
339*53897Smckusick 		if (off >= ETHERMTU)
340*53897Smckusick 			return;
341*53897Smckusick 		en->enr_type = ntohs(*endataaddr(en, off, u_short *));
342*53897Smckusick 		resid = ntohs(*(endataaddr(en, off+2, u_short *)));
343*53897Smckusick 		if (off + resid > len)
344*53897Smckusick 			return;
345*53897Smckusick 		len = off + resid;
346*53897Smckusick 	} else
347*53897Smckusick 		off = 0;
348*53897Smckusick 	/*
349*53897Smckusick 	 * Pull packet off interface.  Off is nonzero if packet
350*53897Smckusick 	 * has trailing header; m_devget will then force this header
351*53897Smckusick 	 * information to be at the front, but we still have to drop
352*53897Smckusick 	 * the type and length which are at the front of any trailer data.
353*53897Smckusick 	 * KU:XXX really?
354*53897Smckusick 	 */
355*53897Smckusick 	type = en->enr_type;
356*53897Smckusick 	m = m_devget((char *)(en + 1), len, off, &es->es_if, 0);
357*53897Smckusick 	if (m == 0)
358*53897Smckusick 		return;
359*53897Smckusick 	ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m);
360*53897Smckusick }
361*53897Smckusick 
362*53897Smckusick /*
363*53897Smckusick  * Watchdog routine, request statistics from board.
364*53897Smckusick  */
365*53897Smckusick enwatch(unit)
366*53897Smckusick 	int unit;
367*53897Smckusick {
368*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
369*53897Smckusick 	register struct ifnet *ifp = &es->es_if;
370*53897Smckusick 
371*53897Smckusick 	ifp->if_timer = es->es_interval;
372*53897Smckusick }
373*53897Smckusick 
374*53897Smckusick /*
375*53897Smckusick  * Process an ioctl request.
376*53897Smckusick  */
377*53897Smckusick enioctl(ifp, cmd, data)
378*53897Smckusick 	register struct ifnet *ifp;
379*53897Smckusick 	int cmd;
380*53897Smckusick 	caddr_t data;
381*53897Smckusick {
382*53897Smckusick 	register struct ifaddr *ifa = (struct ifaddr *)data;
383*53897Smckusick 	register struct en_softc *es = &en_softc[ifp->if_unit];
384*53897Smckusick 	register struct ensw *esp;
385*53897Smckusick 	register int family;
386*53897Smckusick 	int s = splimp(), error = 0;
387*53897Smckusick 
388*53897Smckusick 	switch (cmd) {
389*53897Smckusick 
390*53897Smckusick 	case SIOCSIFADDR:
391*53897Smckusick 		ifp->if_flags |= IFF_UP;
392*53897Smckusick 		eninit(ifp->if_unit);
393*53897Smckusick 		switch (ifa->ifa_addr->sa_family) {
394*53897Smckusick #ifdef INET
395*53897Smckusick 		case AF_INET:
396*53897Smckusick 			((struct arpcom *)ifp)->ac_ipaddr =
397*53897Smckusick 				IA_SIN(ifa)->sin_addr;
398*53897Smckusick 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
399*53897Smckusick 			break;
400*53897Smckusick #endif
401*53897Smckusick 		}
402*53897Smckusick 		break;
403*53897Smckusick 
404*53897Smckusick 	case SIOCSIFFLAGS:
405*53897Smckusick 		if ((ifp->if_flags & IFF_UP) == 0 &&
406*53897Smckusick 		    es->es_flags & ENF_RUNNING) {
407*53897Smckusick 			es->es_flags &= ~ENF_RUNNING;
408*53897Smckusick 		} else if (ifp->if_flags & IFF_UP &&
409*53897Smckusick 		    (es->es_flags & ENF_RUNNING) == 0)
410*53897Smckusick 			eninit(ifp->if_unit);
411*53897Smckusick #if NBPFILTER > 0
412*53897Smckusick 		else if (ifp->if_flags & IFF_UP &&
413*53897Smckusick 		    (ifp->if_flags & IFF_RUNNING) == 0) {
414*53897Smckusick 			en_prom_mode(ifp->if_unit,
415*53897Smckusick 				ifp->if_flags & IFF_PROMISC);
416*53897Smckusick 			ifp->if_flags |= IFF_RUNNING;
417*53897Smckusick 		}
418*53897Smckusick #endif
419*53897Smckusick 		break;
420*53897Smckusick 
421*53897Smckusick 	default:
422*53897Smckusick 		error = EINVAL;
423*53897Smckusick 	}
424*53897Smckusick 	splx(s);
425*53897Smckusick 	return (error);
426*53897Smckusick }
427*53897Smckusick 
428*53897Smckusick /*
429*53897Smckusick  * set ethernet address for unit
430*53897Smckusick  */
431*53897Smckusick ensetaddr(physaddr, unit)
432*53897Smckusick 	u_char *physaddr;
433*53897Smckusick 	int unit;
434*53897Smckusick {
435*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
436*53897Smckusick 
437*53897Smckusick 	if (!(es->es_flags & ENF_RUNNING))
438*53897Smckusick 		return;
439*53897Smckusick 
440*53897Smckusick 	bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr);
441*53897Smckusick 	es->es_flags &= ~ENF_RUNNING;
442*53897Smckusick 	es->es_flags |= ENF_SETADDR;
443*53897Smckusick 	eninit(unit);
444*53897Smckusick }
445*53897Smckusick 
446*53897Smckusick /*
447*53897Smckusick  * Machine dependent functions
448*53897Smckusick  *
449*53897Smckusick  *	en_probe();
450*53897Smckusick  *	en_attach();
451*53897Smckusick  *	en_init();
452*53897Smckusick  *	enxint();
453*53897Smckusick  *	enrint();
454*53897Smckusick  *	en_prom_mode()
455*53897Smckusick  */
456*53897Smckusick #ifdef CPU_SINGLE
457*53897Smckusick #include "../include/cpu.h"
458*53897Smckusick 
459*53897Smckusick en_probe(hi)
460*53897Smckusick 	struct hb_device *hi;
461*53897Smckusick {
462*53897Smckusick 
463*53897Smckusick 	return (lance_probe(hi->hi_unit));
464*53897Smckusick }
465*53897Smckusick 
466*53897Smckusick en_attach(unit)
467*53897Smckusick 	int unit;
468*53897Smckusick {
469*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
470*53897Smckusick 	register u_char *p;
471*53897Smckusick 	register int i;
472*53897Smckusick 	extern lance_intr();
473*53897Smckusick 
474*53897Smckusick #if !defined(news700) && !defined(mips)
475*53897Smckusick 	register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr);
476*53897Smckusick #endif
477*53897Smckusick 	if (lance_open(unit) < 0)
478*53897Smckusick 		printf("lance initialize error\n");
479*53897Smckusick 	lance_get_addr(unit, (caddr_t)es->es_addr);
480*53897Smckusick }
481*53897Smckusick 
482*53897Smckusick en_init(unit)
483*53897Smckusick 	int unit;
484*53897Smckusick {
485*53897Smckusick 
486*53897Smckusick }
487*53897Smckusick 
488*53897Smckusick en_start(unit, len)
489*53897Smckusick 	int unit;
490*53897Smckusick 	int len;
491*53897Smckusick {
492*53897Smckusick 
493*53897Smckusick 	lance_transmit(unit, len);
494*53897Smckusick }
495*53897Smckusick 
496*53897Smckusick enxint(unit)
497*53897Smckusick 	register int unit;
498*53897Smckusick {
499*53897Smckusick 
500*53897Smckusick 	_enxint(unit, lance_xmit_error(unit), lance_collision(unit));
501*53897Smckusick }
502*53897Smckusick 
503*53897Smckusick enrint(unit)
504*53897Smckusick 	register int unit;
505*53897Smckusick {
506*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
507*53897Smckusick 	caddr_t get_recv_buffer();
508*53897Smckusick 
509*53897Smckusick 	while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) {
510*53897Smckusick 		_enrint(unit,
511*53897Smckusick 		    get_recv_length(unit) - sizeof(struct en_rheader));
512*53897Smckusick 		free_recv_buffer(unit);
513*53897Smckusick 	}
514*53897Smckusick }
515*53897Smckusick 
516*53897Smckusick en_prom_mode(unit, mode)
517*53897Smckusick 	int unit, mode;
518*53897Smckusick {
519*53897Smckusick 
520*53897Smckusick 	lance_prom_mode(unit, mode);
521*53897Smckusick }
522*53897Smckusick #endif /* CPU_SINGLE */
523*53897Smckusick 
524*53897Smckusick #ifdef IPC_MRX
525*53897Smckusick #include "../ipc/newsipc.h"
526*53897Smckusick #include "../mrx/h/lancereg.h"
527*53897Smckusick #include "../mrx/h/lance.h"
528*53897Smckusick 
529*53897Smckusick int	port_enxmit[NEN];
530*53897Smckusick int	port_enrecv[NEN];
531*53897Smckusick int	port_enctrl[NEN];
532*53897Smckusick int	port_enxmit_iop[NEN];
533*53897Smckusick int	port_enrecv_iop[NEN];
534*53897Smckusick int	port_enctrl_iop[NEN];
535*53897Smckusick 
536*53897Smckusick en_probe(ii)
537*53897Smckusick 	register struct iop_device *ii;
538*53897Smckusick {
539*53897Smckusick 	int unit = ii->ii_unit;
540*53897Smckusick 	int lance_func, *reply;
541*53897Smckusick 	char name[32];
542*53897Smckusick 	extern char *make_name();
543*53897Smckusick 
544*53897Smckusick 	if (port_enrecv[unit] == 0) {
545*53897Smckusick 
546*53897Smckusick #define	PT_CREATE(buf, name, unit, func)	\
547*53897Smckusick 	port_create(make_name(buf, name, unit), func, unit)
548*53897Smckusick #define	OB_QUERY(buf, name, unit) \
549*53897Smckusick 	object_query(make_name(buf, name, unit))
550*53897Smckusick 
551*53897Smckusick 		make_name(name, "@enrecvX", unit);
552*53897Smckusick 		port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint);
553*53897Smckusick 		port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint);
554*53897Smckusick 		port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL);
555*53897Smckusick 		/* use NULL action port */
556*53897Smckusick 		port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit);
557*53897Smckusick 		port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit);
558*53897Smckusick 		port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit);
559*53897Smckusick 	}
560*53897Smckusick 	if (port_enctrl_iop[unit] < 0)
561*53897Smckusick 		goto bad;
562*53897Smckusick 	lance_func = EN_START;
563*53897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
564*53897Smckusick 	    sizeof(lance_func), 0);
565*53897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
566*53897Smckusick 	if (*reply < 0)
567*53897Smckusick 		goto bad;
568*53897Smckusick 	lance_func = EN_STOP;
569*53897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
570*53897Smckusick 	    sizeof(lance_func), 0);
571*53897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
572*53897Smckusick 	return (1);
573*53897Smckusick bad:
574*53897Smckusick 	return (0);
575*53897Smckusick }
576*53897Smckusick 
577*53897Smckusick en_attach(unit)
578*53897Smckusick 	int unit;
579*53897Smckusick {
580*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
581*53897Smckusick 	int lance_func;
582*53897Smckusick 	struct ether_addr *ether_addr;
583*53897Smckusick 
584*53897Smckusick 	lance_func = EN_GETADDR;
585*53897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
586*53897Smckusick 	    sizeof(lance_func), 0);
587*53897Smckusick 	msg_recv(port_enctrl[unit], NULL, &ether_addr, NULL, 0);
588*53897Smckusick 	bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr));
589*53897Smckusick 	msg_free(port_enctrl[unit]);
590*53897Smckusick }
591*53897Smckusick 
592*53897Smckusick en_init(unit)
593*53897Smckusick 	int unit;
594*53897Smckusick {
595*53897Smckusick 	register struct en_softc *es = &en_softc[unit];
596*53897Smckusick 	register int port;
597*53897Smckusick 	struct lance_ctrl_req req;
598*53897Smckusick 	int *reply;
599*53897Smckusick 
600*53897Smckusick 	req.lance_func = EN_SETXMITBUF;
601*53897Smckusick 	mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr,
602*53897Smckusick 		ETHERMTU + sizeof(struct en_rheader));
603*53897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
604*53897Smckusick 	    &req, sizeof(req), 0);
605*53897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
606*53897Smckusick 
607*53897Smckusick 	req.lance_func = EN_START;
608*53897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
609*53897Smckusick 	    &req, sizeof(req), 0);
610*53897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
611*53897Smckusick 	msg_free(port_enctrl[unit]);
612*53897Smckusick 
613*53897Smckusick 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
614*53897Smckusick 	    es->es_ifnews.ifn_raddr,
615*53897Smckusick 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
616*53897Smckusick }
617*53897Smckusick 
618*53897Smckusick en_start(unit, len)
619*53897Smckusick 	int unit;
620*53897Smckusick 	int len;
621*53897Smckusick {
622*53897Smckusick 
623*53897Smckusick 	msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0);
624*53897Smckusick }
625*53897Smckusick 
626*53897Smckusick enxint(unit)
627*53897Smckusick 	register int unit;
628*53897Smckusick {
629*53897Smckusick 	int *len;
630*53897Smckusick 	struct en_softc *es = &en_softc[unit];
631*53897Smckusick 
632*53897Smckusick 	if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) {
633*53897Smckusick 		printf("stray enxint\n");
634*53897Smckusick 		return;
635*53897Smckusick 	}
636*53897Smckusick 	if (es->es_ifnews.ifn_mbuf)
637*53897Smckusick 		m_freem(es->es_ifnews.ifn_mbuf);
638*53897Smckusick 	_enxint(unit, *len < 0, *len & 0x10000);
639*53897Smckusick }
640*53897Smckusick 
641*53897Smckusick enrint(unit)
642*53897Smckusick 	int unit;
643*53897Smckusick {
644*53897Smckusick 	int len;
645*53897Smckusick 	int *reply;
646*53897Smckusick 
647*53897Smckusick 	if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) {
648*53897Smckusick 		printf("stray enrint\n");
649*53897Smckusick 		return;
650*53897Smckusick 	}
651*53897Smckusick 	len = *reply - sizeof(struct en_rheader);
652*53897Smckusick 	msg_free(port_enrecv[unit]);
653*53897Smckusick #ifdef mips
654*53897Smckusick 	/*
655*53897Smckusick 	 * cache flush address must aligned long word boundary.
656*53897Smckusick 	 * so, add 3 for sanity.
657*53897Smckusick 	 */
658*53897Smckusick 	clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03,
659*53897Smckusick 	    len + sizeof (struct en_rheader) + 3);
660*53897Smckusick #endif
661*53897Smckusick 	_enrint(unit, len);
662*53897Smckusick 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
663*53897Smckusick 	    en_softc[unit].es_ifnews.ifn_raddr,
664*53897Smckusick 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
665*53897Smckusick }
666*53897Smckusick 
667*53897Smckusick en_prom_mode(unit, mode)
668*53897Smckusick 	int unit, mode;
669*53897Smckusick {
670*53897Smckusick 	static int port;
671*53897Smckusick 	struct lance_ctrl_req req;
672*53897Smckusick 	extern int port_enctrl_iop[];
673*53897Smckusick 
674*53897Smckusick 	req.lance_func = EN_PROMMODE;
675*53897Smckusick 	req.lance_mode = mode;
676*53897Smckusick 	msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0);
677*53897Smckusick }
678*53897Smckusick #endif /* IPC_MRX */
679*53897Smckusick #endif /* NEN > 0 */
680