xref: /netbsd-src/sys/dev/ic/am7990.c (revision 7f21db1c0118155e0dd40b75182e30c589d9f63e)
1 /*	$NetBSD: am7990.c,v 1.72 2010/01/19 22:06:24 pooka Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9  * Simulation Facility, NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*-
34  * Copyright (c) 1992, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * Ralph Campbell and Rick Macklem.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
65  */
66 
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: am7990.c,v 1.72 2010/01/19 22:06:24 pooka Exp $");
69 
70 #include "rnd.h"
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/mbuf.h>
75 #include <sys/syslog.h>
76 #include <sys/socket.h>
77 #include <sys/device.h>
78 #include <sys/malloc.h>
79 #include <sys/ioctl.h>
80 #include <sys/errno.h>
81 #if NRND > 0
82 #include <sys/rnd.h>
83 #endif
84 
85 #include <net/if.h>
86 #include <net/if_dl.h>
87 #include <net/if_ether.h>
88 #include <net/if_media.h>
89 
90 #include <net/bpf.h>
91 #include <net/bpfdesc.h>
92 
93 #include <dev/ic/lancereg.h>
94 #include <dev/ic/lancevar.h>
95 #include <dev/ic/am7990reg.h>
96 #include <dev/ic/am7990var.h>
97 
98 static void	am7990_meminit(struct lance_softc *);
99 static void	am7990_start(struct ifnet *);
100 
101 #if defined(_KERNEL_OPT)
102 #include "opt_ddb.h"
103 #endif
104 
105 #ifdef LEDEBUG
106 static void	am7990_recv_print(struct lance_softc *, int);
107 static void	am7990_xmit_print(struct lance_softc *, int);
108 #endif
109 
110 #define	ifp	(&sc->sc_ethercom.ec_if)
111 
112 void
113 am7990_config(struct am7990_softc *sc)
114 {
115 	int mem, i;
116 
117 	sc->lsc.sc_meminit = am7990_meminit;
118 	sc->lsc.sc_start = am7990_start;
119 
120 	lance_config(&sc->lsc);
121 
122 	mem = 0;
123 	sc->lsc.sc_initaddr = mem;
124 	mem += sizeof(struct leinit);
125 	sc->lsc.sc_rmdaddr = mem;
126 	mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
127 	sc->lsc.sc_tmdaddr = mem;
128 	mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
129 	for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
130 		sc->lsc.sc_rbufaddr[i] = mem;
131 	for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
132 		sc->lsc.sc_tbufaddr[i] = mem;
133 #ifdef notyet
134 	if (mem > ...)
135 		panic(...);
136 #endif
137 }
138 
139 /*
140  * Set up the initialization block and the descriptor rings.
141  */
142 static void
143 am7990_meminit(struct lance_softc *sc)
144 {
145 	u_long a;
146 	int bix;
147 	struct leinit init;
148 	struct lermd rmd;
149 	struct letmd tmd;
150 	uint8_t *myaddr;
151 
152 	if (ifp->if_flags & IFF_PROMISC)
153 		init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
154 	else
155 		init.init_mode = LE_MODE_NORMAL;
156 	if (sc->sc_initmodemedia == 1)
157 		init.init_mode |= LE_MODE_PSEL0;
158 
159 	/*
160 	 * Update our private copy of the Ethernet address.
161 	 * We NEED the copy so we can ensure its alignment!
162 	 */
163 	memcpy(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
164 	myaddr = sc->sc_enaddr;
165 
166 	init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
167 	init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
168 	init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
169 	lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
170 
171 	sc->sc_last_rd = 0;
172 	sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
173 
174 	a = sc->sc_addr + LE_RMDADDR(sc, 0);
175 	init.init_rdra = a;
176 	init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
177 
178 	a = sc->sc_addr + LE_TMDADDR(sc, 0);
179 	init.init_tdra = a;
180 	init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
181 
182 	(*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
183 
184 	/*
185 	 * Set up receive ring descriptors.
186 	 */
187 	for (bix = 0; bix < sc->sc_nrbuf; bix++) {
188 		a = sc->sc_addr + LE_RBUFADDR(sc, bix);
189 		rmd.rmd0 = a;
190 		rmd.rmd1_hadr = a >> 16;
191 		rmd.rmd1_bits = LE_R1_OWN;
192 		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
193 		rmd.rmd3 = 0;
194 		(*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
195 		    sizeof(rmd));
196 	}
197 
198 	/*
199 	 * Set up transmit ring descriptors.
200 	 */
201 	for (bix = 0; bix < sc->sc_ntbuf; bix++) {
202 		a = sc->sc_addr + LE_TBUFADDR(sc, bix);
203 		tmd.tmd0 = a;
204 		tmd.tmd1_hadr = a >> 16;
205 		tmd.tmd1_bits = 0;
206 		tmd.tmd2 = 0 | LE_XMD2_ONES;
207 		tmd.tmd3 = 0;
208 		(*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
209 		    sizeof(tmd));
210 	}
211 }
212 
213 static void
214 am7990_rint(struct lance_softc *sc)
215 {
216 	int bix;
217 	int rp;
218 	struct lermd rmd;
219 
220 	bix = sc->sc_last_rd;
221 
222 	/* Process all buffers with valid data. */
223 	for (;;) {
224 		rp = LE_RMDADDR(sc, bix);
225 		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
226 
227 		if (rmd.rmd1_bits & LE_R1_OWN)
228 			break;
229 
230 		if (rmd.rmd1_bits & LE_R1_ERR) {
231 			if (rmd.rmd1_bits & LE_R1_ENP) {
232 #ifdef LEDEBUG
233 				if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
234 					if (rmd.rmd1_bits & LE_R1_FRAM)
235 						printf("%s: framing error\n",
236 						    device_xname(sc->sc_dev));
237 					if (rmd.rmd1_bits & LE_R1_CRC)
238 						printf("%s: crc mismatch\n",
239 						    device_xname(sc->sc_dev));
240 				}
241 #endif
242 			} else {
243 				if (rmd.rmd1_bits & LE_R1_OFLO)
244 					printf("%s: overflow\n",
245 					    device_xname(sc->sc_dev));
246 			}
247 			if (rmd.rmd1_bits & LE_R1_BUFF)
248 				printf("%s: receive buffer error\n",
249 				    device_xname(sc->sc_dev));
250 			ifp->if_ierrors++;
251 		} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
252 		    (LE_R1_STP | LE_R1_ENP)) {
253 			printf("%s: dropping chained buffer\n",
254 			    device_xname(sc->sc_dev));
255 			ifp->if_ierrors++;
256 		} else {
257 #ifdef LEDEBUG
258 			if (sc->sc_debug > 1)
259 				am7990_recv_print(sc, sc->sc_last_rd);
260 #endif
261 			lance_read(sc, LE_RBUFADDR(sc, bix),
262 				   (int)rmd.rmd3 - 4);
263 		}
264 
265 		rmd.rmd1_bits = LE_R1_OWN;
266 		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
267 		rmd.rmd3 = 0;
268 		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
269 
270 #ifdef LEDEBUG
271 		if (sc->sc_debug)
272 			printf("sc->sc_last_rd = %x, rmd: "
273 			       "ladr %04x, hadr %02x, flags %02x, "
274 			       "bcnt %04x, mcnt %04x\n",
275 				sc->sc_last_rd,
276 				rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
277 				rmd.rmd2, rmd.rmd3);
278 #endif
279 
280 		if (++bix == sc->sc_nrbuf)
281 			bix = 0;
282 	}
283 
284 	sc->sc_last_rd = bix;
285 }
286 
287 static void
288 am7990_tint(struct lance_softc *sc)
289 {
290 	int bix;
291 	struct letmd tmd;
292 
293 	bix = sc->sc_first_td;
294 
295 	for (;;) {
296 		if (sc->sc_no_td <= 0)
297 			break;
298 
299 		(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
300 		    sizeof(tmd));
301 
302 #ifdef LEDEBUG
303 		if (sc->sc_debug)
304 			printf("trans tmd: "
305 			    "ladr %04x, hadr %02x, flags %02x, "
306 			    "bcnt %04x, mcnt %04x\n",
307 			    tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
308 			    tmd.tmd2, tmd.tmd3);
309 #endif
310 
311 		if (tmd.tmd1_bits & LE_T1_OWN)
312 			break;
313 
314 		ifp->if_flags &= ~IFF_OACTIVE;
315 
316 		if (tmd.tmd1_bits & LE_T1_ERR) {
317 			if (tmd.tmd3 & LE_T3_BUFF)
318 				printf("%s: transmit buffer error\n",
319 				    device_xname(sc->sc_dev));
320 			else if (tmd.tmd3 & LE_T3_UFLO)
321 				printf("%s: underflow\n",
322 				    device_xname(sc->sc_dev));
323 			if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
324 				lance_reset(sc);
325 				return;
326 			}
327 			if (tmd.tmd3 & LE_T3_LCAR) {
328 				sc->sc_havecarrier = 0;
329 				if (sc->sc_nocarrier)
330 					(*sc->sc_nocarrier)(sc);
331 				else
332 					printf("%s: lost carrier\n",
333 					    device_xname(sc->sc_dev));
334 			}
335 			if (tmd.tmd3 & LE_T3_LCOL)
336 				ifp->if_collisions++;
337 			if (tmd.tmd3 & LE_T3_RTRY) {
338 #ifdef LEDEBUG
339 				printf("%s: excessive collisions, tdr %d\n",
340 				    device_xname(sc->sc_dev),
341 				    tmd.tmd3 & LE_T3_TDR_MASK);
342 #endif
343 				ifp->if_collisions += 16;
344 			}
345 			ifp->if_oerrors++;
346 		} else {
347 			if (tmd.tmd1_bits & LE_T1_ONE)
348 				ifp->if_collisions++;
349 			else if (tmd.tmd1_bits & LE_T1_MORE)
350 				/* Real number is unknown. */
351 				ifp->if_collisions += 2;
352 			ifp->if_opackets++;
353 		}
354 
355 		if (++bix == sc->sc_ntbuf)
356 			bix = 0;
357 
358 		--sc->sc_no_td;
359 	}
360 
361 	sc->sc_first_td = bix;
362 
363 	am7990_start(ifp);
364 
365 	if (sc->sc_no_td == 0)
366 		ifp->if_timer = 0;
367 }
368 
369 /*
370  * Controller interrupt.
371  */
372 int
373 am7990_intr(void *arg)
374 {
375 	struct lance_softc *sc = arg;
376 	uint16_t isr;
377 
378 	isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
379 	sc->sc_saved_csr0 = 0;
380 #if defined(LEDEBUG) && LEDEBUG > 1
381 	if (sc->sc_debug)
382 		printf("%s: am7990_intr entering with isr=%04x\n",
383 		    device_xname(sc->sc_dev), isr);
384 #endif
385 	if ((isr & LE_C0_INTR) == 0)
386 		return (0);
387 
388 #ifdef __vax__
389 	/*
390 	 * DEC needs this write order to the registers, don't know
391 	 * the results on other arch's.  Ragge 991029
392 	 */
393 	isr &= ~LE_C0_INEA;
394 	(*sc->sc_wrcsr)(sc, LE_CSR0, isr);
395 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
396 #else
397 	(*sc->sc_wrcsr)(sc, LE_CSR0,
398 	    isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
399 		   LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
400 #endif
401 	if (isr & LE_C0_ERR) {
402 		if (isr & LE_C0_BABL) {
403 #ifdef LEDEBUG
404 			printf("%s: babble\n", device_xname(sc->sc_dev));
405 #endif
406 			ifp->if_oerrors++;
407 		}
408 #if 0
409 		if (isr & LE_C0_CERR) {
410 			printf("%s: collision error\n",
411 			    device_xname(sc->sc_dev));
412 			ifp->if_collisions++;
413 		}
414 #endif
415 		if (isr & LE_C0_MISS) {
416 #ifdef LEDEBUG
417 			printf("%s: missed packet\n", device_xname(sc->sc_dev));
418 #endif
419 			ifp->if_ierrors++;
420 		}
421 		if (isr & LE_C0_MERR) {
422 			printf("%s: memory error\n", device_xname(sc->sc_dev));
423 			lance_reset(sc);
424 			return (1);
425 		}
426 	}
427 
428 	if ((isr & LE_C0_RXON) == 0) {
429 		printf("%s: receiver disabled\n", device_xname(sc->sc_dev));
430 		ifp->if_ierrors++;
431 		lance_reset(sc);
432 		return (1);
433 	}
434 	if ((isr & LE_C0_TXON) == 0) {
435 		printf("%s: transmitter disabled\n", device_xname(sc->sc_dev));
436 		ifp->if_oerrors++;
437 		lance_reset(sc);
438 		return (1);
439 	}
440 
441 	/*
442 	 * Pretend we have carrier; if we don't this will be cleared
443 	 * shortly.
444 	 */
445 	sc->sc_havecarrier = 1;
446 
447 	if (isr & LE_C0_RINT)
448 		am7990_rint(sc);
449 	if (isr & LE_C0_TINT)
450 		am7990_tint(sc);
451 
452 #if NRND > 0
453 	rnd_add_uint32(&sc->rnd_source, isr);
454 #endif
455 
456 	return (1);
457 }
458 
459 #undef ifp
460 
461 /*
462  * Setup output on interface.
463  * Get another datagram to send off of the interface queue, and map it to the
464  * interface before starting the output.
465  * Called only at splnet or interrupt level.
466  */
467 static void
468 am7990_start(struct ifnet *ifp)
469 {
470 	struct lance_softc *sc = ifp->if_softc;
471 	int bix;
472 	struct mbuf *m;
473 	struct letmd tmd;
474 	int rp;
475 	int len;
476 
477 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
478 		return;
479 
480 	bix = sc->sc_last_td;
481 
482 	for (;;) {
483 		rp = LE_TMDADDR(sc, bix);
484 		(*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
485 
486 		if (tmd.tmd1_bits & LE_T1_OWN) {
487 			ifp->if_flags |= IFF_OACTIVE;
488 			printf("missing buffer, no_td = %d, last_td = %d\n",
489 			    sc->sc_no_td, sc->sc_last_td);
490 		}
491 
492 		IFQ_DEQUEUE(&ifp->if_snd, m);
493 		if (m == 0)
494 			break;
495 
496 		/*
497 		 * If BPF is listening on this interface, let it see the packet
498 		 * before we commit it to the wire.
499 		 */
500 		if (ifp->if_bpf)
501 			bpf_ops->bpf_mtap(ifp->if_bpf, m);
502 
503 		/*
504 		 * Copy the mbuf chain into the transmit buffer.
505 		 */
506 		len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
507 
508 #ifdef LEDEBUG
509 		if (len > ETHERMTU + sizeof(struct ether_header))
510 			printf("packet length %d\n", len);
511 #endif
512 
513 		ifp->if_timer = 5;
514 
515 		/*
516 		 * Init transmit registers, and set transmit start flag.
517 		 */
518 		tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
519 		tmd.tmd2 = -len | LE_XMD2_ONES;
520 		tmd.tmd3 = 0;
521 
522 		(*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
523 
524 #ifdef LEDEBUG
525 		if (sc->sc_debug > 1)
526 			am7990_xmit_print(sc, sc->sc_last_td);
527 #endif
528 
529 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
530 
531 		if (++bix == sc->sc_ntbuf)
532 			bix = 0;
533 
534 		if (++sc->sc_no_td == sc->sc_ntbuf) {
535 			ifp->if_flags |= IFF_OACTIVE;
536 			break;
537 		}
538 
539 	}
540 
541 	sc->sc_last_td = bix;
542 }
543 
544 #ifdef LEDEBUG
545 static void
546 am7990_recv_print(struct lance_softc *sc, int no)
547 {
548 	struct lermd rmd;
549 	uint16_t len;
550 	struct ether_header eh;
551 
552 	(*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
553 	len = rmd.rmd3;
554 	printf("%s: receive buffer %d, len = %d\n",
555 	    device_xname(sc->sc_dev), no, len);
556 	printf("%s: status %04x\n", device_xname(sc->sc_dev),
557 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
558 	printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
559 	    device_xname(sc->sc_dev),
560 	    rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
561 	if (len >= sizeof(eh)) {
562 		(*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
563 		printf("%s: dst %s", device_xname(sc->sc_dev),
564 			ether_sprintf(eh.ether_dhost));
565 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
566 			ntohs(eh.ether_type));
567 	}
568 }
569 
570 static void
571 am7990_xmit_print(struct lance_softc *sc, int no)
572 {
573 	struct letmd tmd;
574 	uint16_t len;
575 	struct ether_header eh;
576 
577 	(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
578 	len = -tmd.tmd2;
579 	printf("%s: transmit buffer %d, len = %d\n",
580 	    device_xname(sc->sc_dev), no, len);
581 	printf("%s: status %04x\n", device_xname(sc->sc_dev),
582 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
583 	printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
584 	    device_xname(sc->sc_dev),
585 	    tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
586 	if (len >= sizeof(eh)) {
587 		(*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
588 		printf("%s: dst %s", device_xname(sc->sc_dev),
589 			ether_sprintf(eh.ether_dhost));
590 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
591 		    ntohs(eh.ether_type));
592 	}
593 }
594 #endif /* LEDEBUG */
595