xref: /netbsd-src/sys/arch/amiga/dev/if_le.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: if_le.c,v 1.8 1994/12/01 17:25:16 chopps Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)if_le.c	7.6 (Berkeley) 5/8/91
36  */
37 
38 #include "le.h"
39 #if NLE > 0
40 
41 #include "bpfilter.h"
42 
43 /*
44  * AMD 7990 LANCE
45  *
46  * This driver will generate and accept tailer encapsulated packets even
47  * though it buys us nothing.  The motivation was to avoid incompatibilities
48  * with VAXen, SUNs, and others that handle and benefit from them.
49  * This reasoning is dubious.
50  */
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/mbuf.h>
54 #include <sys/buf.h>
55 #include <sys/protosw.h>
56 #include <sys/socket.h>
57 #include <sys/syslog.h>
58 #include <sys/ioctl.h>
59 #include <sys/errno.h>
60 #include <sys/device.h>
61 
62 #include <net/if.h>
63 #include <net/netisr.h>
64 #include <net/route.h>
65 
66 #ifdef INET
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in_var.h>
70 #include <netinet/ip.h>
71 #include <netinet/if_ether.h>
72 #endif
73 
74 #ifdef NS
75 #include <netns/ns.h>
76 #include <netns/ns_if.h>
77 #endif
78 
79 #include <machine/cpu.h>
80 #include <machine/mtpr.h>
81 #include <amiga/amiga/device.h>
82 #include <amiga/dev/ztwobusvar.h>
83 #include <amiga/dev/if_lereg.h>
84 
85 /*
86  * Ethernet software status per interface.
87  *
88  * Each interface is referenced by a network interface structure,
89  * le_if, which the routing code uses to locate the interface.
90  * This structure contains the output queue for the interface, its address, ...
91  */
92 struct	le_softc {
93 	struct	arpcom sc_ac;	/* common Ethernet structures */
94 #define	sc_if	sc_ac.ac_if	/* network-visible interface */
95 #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
96 	void	*sc_base;	/* base address of board */
97 	struct	lereg1 *sc_r1;	/* LANCE registers */
98 	struct	lereg2 *sc_r2;	/* dual-port RAM */
99 	int	sc_rmd;		/* predicted next rmd to process */
100 	int	sc_runt;
101 	int	sc_jab;
102 	int	sc_merr;
103 	int	sc_babl;
104 	int	sc_cerr;
105 	int	sc_miss;
106 	int	sc_xint;
107 	int	sc_xown;
108 	int	sc_uflo;
109 	int	sc_rxlen;
110 	int	sc_rxoff;
111 	int	sc_txoff;
112 	int	sc_busy;
113 	short	sc_iflags;
114 #if NBPFILTER > 0
115 	caddr_t sc_bpf;
116 #endif
117 } le_softc[NLE];
118 
119 #if NBPFILTER > 0
120 #include <net/bpf.h>
121 #include <net/bpfdesc.h>
122 #endif
123 
124 /* offsets for:	   ID,   REGS,    MEM */
125 int	lestd[] = { 0, 0x4000, 0x8000 };
126 
127 /* console error messages */
128 int	ledebug = 0;
129 
130 int	leintr(), lestart(), leioctl(), ether_output();
131 void	leinit();
132 
133 struct	mbuf *leget();
134 extern	struct ifnet loif;
135 
136 void leattach __P((struct device *, struct device *, void *));
137 int lematch __P((struct device *, struct cfdata *, void *args));
138 
139 struct cfdriver lecd = {
140 	NULL, "le", (cfmatch_t)lematch, leattach, DV_IFNET,
141 	sizeof(struct le_softc), NULL, 0};
142 
143 int
144 lematch(pdp, cfp, auxp)
145 	struct device *pdp;
146 	struct cfdata *cfp;
147 	void *auxp;
148 {
149 
150 	struct ztwobus_args *zap;
151 
152 	zap = (struct ztwobus_args *)auxp;
153 
154 	/* Commodore ethernet card */
155 	if ( zap->manid == 514 && zap->prodid == 112)
156 		return(1);
157 
158 	/* Ameristar ethernet card */
159 	if ( zap->manid == 1053 && zap->prodid == 1)
160 		return(1);
161 
162 	return (0);
163 }
164 
165 /*
166  * Interface exists: make available by filling in network interface
167  * record.  System will initialize the interface when it is ready
168  * to accept packets.
169  */
170 void
171 leattach(pdp, dp, auxp)
172 	struct device *pdp, *dp;
173 	void *auxp;
174 {
175 	register struct lereg0 *ler0;
176 	register struct lereg2 *ler2;
177 	struct ztwobus_args *zap;
178 	struct lereg2 *lemem = (struct lereg2 *) 0x8000;
179 	struct le_softc *le = &le_softc[dp->dv_unit];
180 	struct ifnet *ifp = &le->sc_if;
181 	char *cp;
182 	int i;
183 	unsigned long ser;
184 	int s = splhigh ();
185 
186 	zap =(struct ztwobus_args *)auxp;
187 
188 	/*
189 	 * Make config msgs look nicer.
190 	 */
191 	printf("\n");
192 
193 	ler0 = le->sc_base = zap->va;
194 	le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)zap->va);
195 	ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)zap->va);
196 
197 	/*
198 	 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID.
199 	 */
200 	if ( zap->manid == 514 && zap->prodid == 112) {
201 	    /* Commodore 2065 */
202 	    le->sc_addr[0] = 0x00;
203 	    le->sc_addr[1] = 0x80;
204 	    le->sc_addr[2] = 0x10;
205 	}
206 	if ( zap->manid == 1053 && zap->prodid == 1) {
207 	    le->sc_addr[0] = 0x00;
208 	    le->sc_addr[1] = 0x00;
209 	    le->sc_addr[2] = 0x9f;
210 	}
211 
212 	/*
213 	 * Serial number for board is used as host ID.
214 	 */
215 	ser = (unsigned long) zap->serno;
216 
217 	le->sc_addr[3] = (ser >> 16) & 0xff;
218 	le->sc_addr[4] = (ser >>  8) & 0xff;
219 	le->sc_addr[5] = (ser      ) & 0xff;
220 
221 	printf("le%d: hardware address %s\n", dp->dv_unit,
222 		ether_sprintf(le->sc_addr));
223 
224 	/*
225 	 * Setup for transmit/receive
226 	 */
227 	ler2->ler2_mode = LE_MODE;
228 	ler2->ler2_padr[0] = le->sc_addr[1];
229 	ler2->ler2_padr[1] = le->sc_addr[0];
230 	ler2->ler2_padr[2] = le->sc_addr[3];
231 	ler2->ler2_padr[3] = le->sc_addr[2];
232 	ler2->ler2_padr[4] = le->sc_addr[5];
233 	ler2->ler2_padr[5] = le->sc_addr[4];
234 	ler2->ler2_ladrf0 = 0;
235 	ler2->ler2_ladrf1 = 0;
236 	ler2->ler2_rlen = LE_RLEN;
237 	ler2->ler2_rdra = (int)lemem->ler2_rmd;
238 	ler2->ler2_tlen = LE_TLEN;
239 	ler2->ler2_tdra = (int)lemem->ler2_tmd;
240 
241 	splx (s);
242 
243 	ifp->if_unit = dp->dv_unit;
244 	ifp->if_name = "le";
245 	ifp->if_mtu = ETHERMTU;
246 	ifp->if_ioctl = leioctl;
247 	ifp->if_output = ether_output;
248 	ifp->if_start = lestart;
249 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
250 
251 #if NBPFILTER > 0
252 	bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
253 #endif
254 	if_attach(ifp);
255 	ether_ifattach(ifp);
256 
257 	return;
258 }
259 
260 ledrinit(ler2)
261 	register struct lereg2 *ler2;
262 {
263 	register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
264 	register int i;
265 
266 	for (i = 0; i < LERBUF; i++) {
267 		ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i];
268 		ler2->ler2_rmd[i].rmd1 = LE_OWN;
269 		ler2->ler2_rmd[i].rmd2 = -LEMTU;
270 		ler2->ler2_rmd[i].rmd3 = 0;
271 	}
272 
273 	for (i = 0; i < LETBUF; i++) {
274 		ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i];
275 		ler2->ler2_tmd[i].tmd1 = 0;
276 		ler2->ler2_tmd[i].tmd2 = 0;
277 		ler2->ler2_tmd[i].tmd3 = 0;
278 	}
279 }
280 
281 void
282 lereset(unit)
283 	register int unit;
284 {
285 	register struct le_softc *le = &le_softc[unit];
286 	register struct lereg1 *ler1 = le->sc_r1;
287 	/*
288 	 * This structure is referenced from the CARDS/LANCE point of
289 	 * view, thus the 0x8000 address which is the buffer RAM area of
290 	 * the Commodore and Ameristar cards. This pointer is manipulated
291 	 * with the LANCE's view of memory and NOT the Amiga's. FYI.
292 	 */
293 	register struct lereg2 *lemem = (struct lereg2 *) 0x8000;
294 
295 	register int timo = 100000;
296 	register int stat;
297 
298 #ifdef lint
299 	stat = unit;
300 #endif
301 #if NBPFILTER > 0
302 	if (le->sc_if.if_flags & IFF_PROMISC)
303 		/* set the promiscuous bit */
304 		le->sc_r2->ler2_mode = LE_MODE|0x8000;
305 	else
306 		le->sc_r2->ler2_mode = LE_MODE;
307 #endif
308 	 ler1->ler1_rap =  LE_CSR0;
309 	 ler1->ler1_rdp =  LE_STOP;
310 
311 	 ledrinit(le->sc_r2);
312 
313 	 le->sc_rmd = 0;
314 	 ler1->ler1_rap =  LE_CSR1;
315 	 ler1->ler1_rdp =  (int)&lemem->ler2_mode;
316 	 ler1->ler1_rap =  LE_CSR2;
317 	 ler1->ler1_rdp =  0;
318 	 ler1->ler1_rap =  LE_CSR0;
319 	 ler1->ler1_rdp =  LE_INIT;
320 
321 	do {
322 		if (--timo == 0) {
323 			printf("le%d: init timeout, stat = 0x%x\n",
324 			       unit, stat);
325 			break;
326 		}
327 		 stat =  ler1->ler1_rdp;
328 	} while ((stat & LE_IDON) == 0);
329 
330 	 ler1->ler1_rdp =  LE_STOP;
331 	 ler1->ler1_rap =  LE_CSR3;
332 	 ler1->ler1_rdp =  LE_BSWP;
333 	 ler1->ler1_rap =  LE_CSR0;
334 	 ler1->ler1_rdp =  LE_STRT | LE_INEA;
335 	 le->sc_if.if_flags &= ~IFF_OACTIVE;
336 
337 	return;
338 }
339 
340 /*
341  * Initialization of interface
342  */
343 void
344 leinit(unit)
345 	int unit;
346 {
347 	struct le_softc *le = &le_softc[unit];
348 	register struct ifnet *ifp = &le->sc_if;
349 	int s;
350 
351 	/* not yet, if address still unknown */
352 	if (ifp->if_addrlist == (struct ifaddr *)0)
353 		return;
354 
355 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
356 		s = splimp();
357 		ifp->if_flags |= IFF_RUNNING;
358 		lereset(unit);
359 	        (void) lestart(ifp);
360 		splx(s);
361 	}
362 
363 	return;
364 }
365 
366 /*
367  * Start output on interface.  Get another datagram to send
368  * off of the interface queue, and copy it to the interface
369  * before starting the output.
370  */
371 lestart(ifp)
372 	struct ifnet *ifp;
373 {
374 	register struct le_softc *le = &le_softc[ifp->if_unit];
375 	register struct letmd *tmd;
376 	register struct mbuf *m;
377 	int len;
378 
379 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
380 		return (0);
381 
382 	IF_DEQUEUE(&le->sc_if.if_snd, m);
383 	if (m == 0)
384 		return (0);
385 
386 	len = leput(le->sc_r2->ler2_tbuf[0], m);
387 
388 #if NBPFILTER > 0
389 	/*
390 	 * If bpf is listening on this interface, let it
391 	 * see the packet before we commit it to the wire.
392 	 */
393 	if (le->sc_bpf)
394                 bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len);
395 #endif
396 
397 	tmd = le->sc_r2->ler2_tmd;
398 	tmd->tmd3 = 0;
399 	tmd->tmd2 = -len;
400 	tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
401 	le->sc_if.if_flags |= IFF_OACTIVE;
402 
403 	return (0);
404 }
405 
406 leintr(unit)
407 	register int unit;
408 {
409 	register struct le_softc *le = &le_softc[unit];
410 	register struct lereg1 *ler1;
411 	register int stat;
412 
413 	/* if not even initialized, don't do anything further.. */
414 	if (! le->sc_base)
415 	  return 0;
416 
417 	ler1 = le->sc_r1;
418 	stat =  ler1->ler1_rdp;
419 
420 	if (! (stat & LE_INTR))
421 	  return 0;
422 
423 	if (stat & LE_SERR) {
424 		leerror(unit, stat);
425 		if (stat & LE_MERR) {
426 			le->sc_merr++;
427 			lereset(unit);
428 			return(1);
429 		}
430 		if (stat & LE_BABL)
431 			le->sc_babl++;
432 		if (stat & LE_CERR)
433 			le->sc_cerr++;
434 		if (stat & LE_MISS)
435 			le->sc_miss++;
436 		 ler1->ler1_rdp =  LE_BABL|LE_CERR|LE_MISS|LE_INEA;
437 	}
438 	if ((stat & LE_RXON) == 0) {
439 		le->sc_rxoff++;
440 		lereset(unit);
441 		return(1);
442 	}
443 	if ((stat & LE_TXON) == 0) {
444 		le->sc_txoff++;
445 		lereset(unit);
446 		return(1);
447 	}
448 	if (stat & LE_RINT) {
449 		/* interrupt is cleared in lerint */
450 		lerint(unit);
451 	}
452 	if (stat & LE_TINT) {
453 		 ler1->ler1_rdp =  LE_TINT|LE_INEA;
454 		lexint(unit);
455 	}
456 	return(1);
457 }
458 
459 /*
460  * Ethernet interface transmitter interrupt.
461  * Start another output if more data to send.
462  */
463 lexint(unit)
464 	register int unit;
465 {
466 	register struct le_softc *le = &le_softc[unit];
467 	register struct letmd *tmd = le->sc_r2->ler2_tmd;
468 
469 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
470 		le->sc_xint++;
471 		return;
472 	}
473 	if (tmd->tmd1 & LE_OWN) {
474 		le->sc_xown++;
475 		return;
476 	}
477 	if (tmd->tmd1 & LE_ERR) {
478 err:
479 		lexerror(unit);
480 		le->sc_if.if_oerrors++;
481 		if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
482 			le->sc_uflo++;
483 			lereset(unit);
484 		}
485 		else if (tmd->tmd3 & LE_LCOL)
486 			le->sc_if.if_collisions++;
487 		else if (tmd->tmd3 & LE_RTRY)
488 			le->sc_if.if_collisions += 16;
489 	}
490 	else if (tmd->tmd3 & LE_TBUFF)
491 		/* XXX documentation says BUFF not included in ERR */
492 		goto err;
493 	else if (tmd->tmd1 & LE_ONE)
494 		le->sc_if.if_collisions++;
495 	else if (tmd->tmd1 & LE_MORE)
496 		/* what is the real number? */
497 		le->sc_if.if_collisions += 2;
498 	else
499 		le->sc_if.if_opackets++;
500 
501 	le->sc_if.if_flags &= ~IFF_OACTIVE;
502 
503 	(void) lestart(&le->sc_if);
504 }
505 
506 #define	LENEXTRMP \
507 	if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
508 
509 /*
510  * Ethernet interface receiver interrupt.
511  * If input error just drop packet.
512  * Decapsulate packet based on type and pass to type specific
513  * higher-level input routine.
514  */
515 lerint(unit)
516 	int unit;
517 {
518 	register struct le_softc *le = &le_softc[unit];
519 	register int bix = le->sc_rmd;
520 	register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
521 
522 	/*
523 	 * Out of sync with hardware, should never happen?
524 	 */
525 	if (rmd->rmd1 & LE_OWN) {
526 		 le->sc_r1->ler1_rdp =  LE_RINT|LE_INEA;
527 		return;
528 	}
529 
530 	/*
531 	 * Process all buffers with valid data
532 	 */
533 	while ((rmd->rmd1 & LE_OWN) == 0) {
534 		int len = rmd->rmd3;
535 
536 		/* Clear interrupt to avoid race condition */
537 		 le->sc_r1->ler1_rdp =  LE_RINT|LE_INEA;
538 
539 		if (rmd->rmd1 & LE_ERR) {
540 			le->sc_rmd = bix;
541 			lererror(unit, "bad packet");
542 			le->sc_if.if_ierrors++;
543 		} else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
544 			/*
545 			 * Find the end of the packet so we can see how long
546 			 * it was.  We still throw it away.
547 			 */
548 			do {
549 			        le->sc_r1->ler1_rdp = LE_RINT|LE_INEA;
550 				rmd->rmd3 = 0;
551 				rmd->rmd1 = LE_OWN;
552 				LENEXTRMP;
553 			} while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
554 
555 			le->sc_rmd = bix;
556 			lererror(unit, "chained buffer");
557 			le->sc_rxlen++;
558 
559 			/*
560 			 * If search terminated without successful completion
561 			 * we reset the hardware (conservative).
562 			 */
563 			if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != LE_ENP) {
564 				lereset(unit);
565 				return;
566 			}
567 		} else
568 			leread(unit, le->sc_r2->ler2_rbuf[bix], len);
569 
570 		rmd->rmd3 = 0;
571 		rmd->rmd1 = LE_OWN;
572 		LENEXTRMP;
573 
574 	}
575 
576 	le->sc_rmd = bix;
577 }
578 
579 leread(unit, buf, len)
580 	int unit;
581 	char *buf;
582 	int len;
583 {
584 	register struct le_softc *le = &le_softc[unit];
585 	register struct ether_header *et;
586     	struct mbuf *m;
587 	int off, resid;
588 
589 	le->sc_if.if_ipackets++;
590 
591 	et = (struct ether_header *)buf;
592 	et->ether_type = ntohs((u_short)et->ether_type);
593 
594 	/* adjust input length to account for header and CRC */
595 	len = len - sizeof(struct ether_header) - 4;
596 
597 #define	ledataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
598 	if (et->ether_type >= ETHERTYPE_TRAIL &&
599 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
600 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
601 		if (off >= ETHERMTU)
602 			return;		/* sanity */
603 		et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
604 		resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
605 		if (off + resid > len)
606 			return;		/* sanity */
607 		len = off + resid;
608 	} else
609 		off = 0;
610 
611 	if (len <= 0) {
612 		if (ledebug)
613 			log(LOG_WARNING,
614 			    "le%d: ierror(runt packet): from %s: len=%d\n",
615 			    unit, ether_sprintf(et->ether_shost), len);
616 		le->sc_runt++;
617 		le->sc_if.if_ierrors++;
618 		return;
619 	}
620 #if NBPFILTER > 0
621 	/*
622 	 * Check if there's a bpf filter listening on this interface.
623 	 * If so, hand off the raw packet to bpf, which must deal with
624 	 * trailers in its own way.
625 	 */
626 	if (le->sc_bpf) {
627 		bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header));
628 
629 		/*
630 		 * Note that the interface cannot be in promiscuous mode if
631 		 * there are no bpf listeners.  And if we are in promiscuous
632 		 * mode, we have to check if this packet is really ours.
633 		 *
634 		 * XXX This test does not support multicasts.
635 		 */
636 		if ((le->sc_if.if_flags & IFF_PROMISC)
637 		    && bcmp(et->ether_dhost, le->sc_addr,
638 			    sizeof(et->ether_dhost)) != 0
639 		    && bcmp(et->ether_dhost, etherbroadcastaddr,
640 			    sizeof(et->ether_dhost)) != 0)
641 			return;
642 	}
643 #endif
644 	/*
645 	 * Pull packet off interface.  Off is nonzero if packet
646 	 * has trailing header; leget will then force this header
647 	 * information to be at the front, but we still have to drop
648 	 * the type and length which are at the front of any trailer data.
649 	 */
650 	m = leget(buf, len, off, &le->sc_if);
651 	if (m == 0)
652 		return;
653 
654 	ether_input(&le->sc_if, et, m);
655 }
656 
657 /*
658  * Routine to copy from mbuf chain to transmit
659  * buffer in board local memory.
660  */
661 leput(lebuf, m)
662 	register char *lebuf;
663 	register struct mbuf *m;
664 {
665 	register struct mbuf *mp;
666 	register int len, tlen = 0;
667 
668 	for (mp = m; mp; mp = mp->m_next) {
669 		len = mp->m_len;
670 		if (len == 0)
671 			continue;
672 		tlen += len;
673 		bcopy(mtod(mp, char *), lebuf, len);
674 		lebuf += len;
675 	}
676 
677 	m_freem(m);
678 
679 	if (tlen < LEMINSIZE) {
680 		bzero(lebuf, LEMINSIZE - tlen);
681 		tlen = LEMINSIZE;
682 	}
683 
684 	return(tlen);
685 }
686 
687 /*
688  * Routine to copy from board local memory into mbufs.
689  */
690 struct mbuf *
691 leget(lebuf, totlen, off0, ifp)
692 	char *lebuf;
693 	int totlen, off0;
694 	struct ifnet *ifp;
695 {
696 	register struct mbuf *m;
697 	struct mbuf *top = 0, **mp = &top;
698 	register int off = off0, len;
699 	register char *cp;
700 	char *epkt;
701 
702 	lebuf += sizeof (struct ether_header);
703 	cp = lebuf;
704 	epkt = cp + totlen;
705 	if (off) {
706 		cp += off + 2 * sizeof(u_short);
707 		totlen -= 2 * sizeof(u_short);
708 	}
709 
710 	MGETHDR(m, M_DONTWAIT, MT_DATA);
711 
712 	if (m == 0)
713 		return (0);
714 
715 	m->m_pkthdr.rcvif = ifp;
716 	m->m_pkthdr.len = totlen;
717 	m->m_len = MHLEN;
718 
719 	while (totlen > 0) {
720 
721 		if (top) {
722 			MGET(m, M_DONTWAIT, MT_DATA);
723 			if (m == 0) {
724 				m_freem(top);
725 				return (0);
726 			}
727 			m->m_len = MLEN;
728 		}
729 
730 		len = min(totlen, epkt - cp);
731 		if (len >= MINCLSIZE) {
732 			MCLGET(m, M_DONTWAIT);
733 			if (m->m_flags & M_EXT)
734 				m->m_len = len = min(len, MCLBYTES);
735 			else
736 				len = m->m_len;
737 		} else {
738 			/*
739 			 * Place initial small packet/header at end of mbuf.
740 			 */
741 			if (len < m->m_len) {
742 				if (top == 0 && len + max_linkhdr <= m->m_len)
743 					m->m_data += max_linkhdr;
744 				m->m_len = len;
745 			} else
746 				len = m->m_len;
747 		}
748 
749 		bcopy(cp, mtod(m, caddr_t), (unsigned)len);
750 		cp += len;
751 		*mp = m;
752 		mp = &m->m_next;
753 		totlen -= len;
754 
755 		if (cp == epkt)
756 			cp = lebuf;
757 
758 	}
759 
760 	return (top);
761 }
762 
763 /*
764  * Process an ioctl request.
765  */
766 leioctl(ifp, cmd, data)
767 	register struct ifnet *ifp;
768 	u_long cmd;
769 	caddr_t data;
770 {
771 	register struct ifaddr *ifa = (struct ifaddr *)data;
772 	struct le_softc *le = &le_softc[ifp->if_unit];
773 	struct lereg1 *ler1 = le->sc_r1;
774 	int s = splimp(), error = 0;
775 
776 	switch (cmd) {
777 
778 	case SIOCSIFADDR:
779 		ifp->if_flags |= IFF_UP;
780 		switch (ifa->ifa_addr->sa_family) {
781 #ifdef INET
782 		case AF_INET:
783 			leinit(ifp->if_unit);	/* before arpwhohas */
784 			((struct arpcom *)ifp)->ac_ipaddr =
785 				IA_SIN(ifa)->sin_addr;
786 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
787 			break;
788 #endif
789 #ifdef NS
790 		case AF_NS:
791 		    {
792 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
793 
794 			if (ns_nullhost(*ina))
795 				ina->x_host = *(union ns_host *)(le->sc_addr);
796 			else {
797 				/*
798 				 * The manual says we can't change the address
799 				 * while the receiver is armed,
800 				 * so reset everything
801 				 */
802 				ifp->if_flags &= ~IFF_RUNNING;
803 				bcopy((caddr_t)ina->x_host.c_host,
804 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
805 			}
806 			leinit(ifp->if_unit); /* does le_setaddr() */
807 			break;
808 		    }
809 #endif
810 		default:
811 			leinit(ifp->if_unit);
812 			break;
813 		}
814 		break;
815 
816 	case SIOCSIFFLAGS:
817 		if ((ifp->if_flags & IFF_UP) == 0 &&
818 		    ifp->if_flags & IFF_RUNNING) {
819 			 ler1->ler1_rdp =  LE_STOP;
820 			ifp->if_flags &= ~IFF_RUNNING;
821 		} else if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
822 			leinit(ifp->if_unit);
823 
824 		/*
825 		 * If the state of the promiscuous bit changes, the interface
826 		 * must be reset to effect the change.
827 		 */
828 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && (ifp->if_flags & IFF_RUNNING)) {
829 			le->sc_iflags = ifp->if_flags;
830 			lereset(ifp->if_unit);
831 			(void)lestart(ifp);
832 		}
833 		break;
834 
835 	default:
836 		error = EINVAL;
837 	}
838 
839 	splx(s);
840 	return (error);
841 }
842 
843 leerror(unit, stat)
844 	int unit;
845 	int stat;
846 {
847 	if (!ledebug)
848 		return;
849 
850 	/*
851 	 * Not all transceivers implement heartbeat
852 	 * so we only log CERR once.
853 	 */
854 	if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
855 		return;
856 
857 	log(LOG_WARNING,
858 	    "le%d: error: stat=%b\n", unit,
859 	    stat,
860 	    "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
861 }
862 
863 lererror(unit, msg)
864 	int unit;
865 	char *msg;
866 {
867 	register struct le_softc *le = &le_softc[unit];
868 	register struct lermd *rmd;
869 	int len;
870 
871 	if (!ledebug)
872 		return;
873 
874 	rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
875 	len = rmd->rmd3;
876 
877 	log(LOG_WARNING,
878 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
879 	    unit, msg,
880 	    len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown",
881 	    le->sc_rmd, len,
882 	    rmd->rmd1,
883 	    "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
884 }
885 
886 lexerror(unit)
887 	int unit;
888 {
889 	register struct le_softc *le = &le_softc[unit];
890 	register struct letmd *tmd;
891 	int len;
892 
893 	if (!ledebug)
894 		return;
895 
896 	tmd = le->sc_r2->ler2_tmd;
897 	len = -tmd->tmd2;
898 
899 	log(LOG_WARNING,
900 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
901 	    unit,
902 	    len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown",
903 	    0, len,
904 	    tmd->tmd1,
905 	    "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
906 	    tmd->tmd3,
907 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
908 }
909 
910 #endif
911 
912 
913