xref: /netbsd-src/sys/dev/ic/am7990.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: am7990.c,v 1.71 2008/04/28 20:23:49 martin 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.71 2008/04/28 20:23:49 martin Exp $");
69 
70 #include "bpfilter.h"
71 #include "rnd.h"
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/mbuf.h>
76 #include <sys/syslog.h>
77 #include <sys/socket.h>
78 #include <sys/device.h>
79 #include <sys/malloc.h>
80 #include <sys/ioctl.h>
81 #include <sys/errno.h>
82 #if NRND > 0
83 #include <sys/rnd.h>
84 #endif
85 
86 #include <net/if.h>
87 #include <net/if_dl.h>
88 #include <net/if_ether.h>
89 #include <net/if_media.h>
90 
91 #if NBPFILTER > 0
92 #include <net/bpf.h>
93 #include <net/bpfdesc.h>
94 #endif
95 
96 #include <dev/ic/lancereg.h>
97 #include <dev/ic/lancevar.h>
98 #include <dev/ic/am7990reg.h>
99 #include <dev/ic/am7990var.h>
100 
101 static void	am7990_meminit(struct lance_softc *);
102 static void	am7990_start(struct ifnet *);
103 
104 #if defined(_KERNEL_OPT)
105 #include "opt_ddb.h"
106 #endif
107 
108 #ifdef LEDEBUG
109 static void	am7990_recv_print(struct lance_softc *, int);
110 static void	am7990_xmit_print(struct lance_softc *, int);
111 #endif
112 
113 #define	ifp	(&sc->sc_ethercom.ec_if)
114 
115 void
116 am7990_config(struct am7990_softc *sc)
117 {
118 	int mem, i;
119 
120 	sc->lsc.sc_meminit = am7990_meminit;
121 	sc->lsc.sc_start = am7990_start;
122 
123 	lance_config(&sc->lsc);
124 
125 	mem = 0;
126 	sc->lsc.sc_initaddr = mem;
127 	mem += sizeof(struct leinit);
128 	sc->lsc.sc_rmdaddr = mem;
129 	mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
130 	sc->lsc.sc_tmdaddr = mem;
131 	mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
132 	for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
133 		sc->lsc.sc_rbufaddr[i] = mem;
134 	for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
135 		sc->lsc.sc_tbufaddr[i] = mem;
136 #ifdef notyet
137 	if (mem > ...)
138 		panic(...);
139 #endif
140 }
141 
142 /*
143  * Set up the initialization block and the descriptor rings.
144  */
145 static void
146 am7990_meminit(struct lance_softc *sc)
147 {
148 	u_long a;
149 	int bix;
150 	struct leinit init;
151 	struct lermd rmd;
152 	struct letmd tmd;
153 	uint8_t *myaddr;
154 
155 #if NBPFILTER > 0
156 	if (ifp->if_flags & IFF_PROMISC)
157 		init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
158 	else
159 #endif
160 		init.init_mode = LE_MODE_NORMAL;
161 	if (sc->sc_initmodemedia == 1)
162 		init.init_mode |= LE_MODE_PSEL0;
163 
164 	/*
165 	 * Update our private copy of the Ethernet address.
166 	 * We NEED the copy so we can ensure its alignment!
167 	 */
168 	memcpy(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
169 	myaddr = sc->sc_enaddr;
170 
171 	init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
172 	init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
173 	init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
174 	lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
175 
176 	sc->sc_last_rd = 0;
177 	sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
178 
179 	a = sc->sc_addr + LE_RMDADDR(sc, 0);
180 	init.init_rdra = a;
181 	init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
182 
183 	a = sc->sc_addr + LE_TMDADDR(sc, 0);
184 	init.init_tdra = a;
185 	init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
186 
187 	(*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
188 
189 	/*
190 	 * Set up receive ring descriptors.
191 	 */
192 	for (bix = 0; bix < sc->sc_nrbuf; bix++) {
193 		a = sc->sc_addr + LE_RBUFADDR(sc, bix);
194 		rmd.rmd0 = a;
195 		rmd.rmd1_hadr = a >> 16;
196 		rmd.rmd1_bits = LE_R1_OWN;
197 		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
198 		rmd.rmd3 = 0;
199 		(*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
200 		    sizeof(rmd));
201 	}
202 
203 	/*
204 	 * Set up transmit ring descriptors.
205 	 */
206 	for (bix = 0; bix < sc->sc_ntbuf; bix++) {
207 		a = sc->sc_addr + LE_TBUFADDR(sc, bix);
208 		tmd.tmd0 = a;
209 		tmd.tmd1_hadr = a >> 16;
210 		tmd.tmd1_bits = 0;
211 		tmd.tmd2 = 0 | LE_XMD2_ONES;
212 		tmd.tmd3 = 0;
213 		(*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
214 		    sizeof(tmd));
215 	}
216 }
217 
218 static void
219 am7990_rint(struct lance_softc *sc)
220 {
221 	int bix;
222 	int rp;
223 	struct lermd rmd;
224 
225 	bix = sc->sc_last_rd;
226 
227 	/* Process all buffers with valid data. */
228 	for (;;) {
229 		rp = LE_RMDADDR(sc, bix);
230 		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
231 
232 		if (rmd.rmd1_bits & LE_R1_OWN)
233 			break;
234 
235 		if (rmd.rmd1_bits & LE_R1_ERR) {
236 			if (rmd.rmd1_bits & LE_R1_ENP) {
237 #ifdef LEDEBUG
238 				if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
239 					if (rmd.rmd1_bits & LE_R1_FRAM)
240 						printf("%s: framing error\n",
241 						    device_xname(sc->sc_dev));
242 					if (rmd.rmd1_bits & LE_R1_CRC)
243 						printf("%s: crc mismatch\n",
244 						    device_xname(sc->sc_dev));
245 				}
246 #endif
247 			} else {
248 				if (rmd.rmd1_bits & LE_R1_OFLO)
249 					printf("%s: overflow\n",
250 					    device_xname(sc->sc_dev));
251 			}
252 			if (rmd.rmd1_bits & LE_R1_BUFF)
253 				printf("%s: receive buffer error\n",
254 				    device_xname(sc->sc_dev));
255 			ifp->if_ierrors++;
256 		} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
257 		    (LE_R1_STP | LE_R1_ENP)) {
258 			printf("%s: dropping chained buffer\n",
259 			    device_xname(sc->sc_dev));
260 			ifp->if_ierrors++;
261 		} else {
262 #ifdef LEDEBUG
263 			if (sc->sc_debug > 1)
264 				am7990_recv_print(sc, sc->sc_last_rd);
265 #endif
266 			lance_read(sc, LE_RBUFADDR(sc, bix),
267 				   (int)rmd.rmd3 - 4);
268 		}
269 
270 		rmd.rmd1_bits = LE_R1_OWN;
271 		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
272 		rmd.rmd3 = 0;
273 		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
274 
275 #ifdef LEDEBUG
276 		if (sc->sc_debug)
277 			printf("sc->sc_last_rd = %x, rmd: "
278 			       "ladr %04x, hadr %02x, flags %02x, "
279 			       "bcnt %04x, mcnt %04x\n",
280 				sc->sc_last_rd,
281 				rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
282 				rmd.rmd2, rmd.rmd3);
283 #endif
284 
285 		if (++bix == sc->sc_nrbuf)
286 			bix = 0;
287 	}
288 
289 	sc->sc_last_rd = bix;
290 }
291 
292 static void
293 am7990_tint(struct lance_softc *sc)
294 {
295 	int bix;
296 	struct letmd tmd;
297 
298 	bix = sc->sc_first_td;
299 
300 	for (;;) {
301 		if (sc->sc_no_td <= 0)
302 			break;
303 
304 		(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
305 		    sizeof(tmd));
306 
307 #ifdef LEDEBUG
308 		if (sc->sc_debug)
309 			printf("trans tmd: "
310 			    "ladr %04x, hadr %02x, flags %02x, "
311 			    "bcnt %04x, mcnt %04x\n",
312 			    tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
313 			    tmd.tmd2, tmd.tmd3);
314 #endif
315 
316 		if (tmd.tmd1_bits & LE_T1_OWN)
317 			break;
318 
319 		ifp->if_flags &= ~IFF_OACTIVE;
320 
321 		if (tmd.tmd1_bits & LE_T1_ERR) {
322 			if (tmd.tmd3 & LE_T3_BUFF)
323 				printf("%s: transmit buffer error\n",
324 				    device_xname(sc->sc_dev));
325 			else if (tmd.tmd3 & LE_T3_UFLO)
326 				printf("%s: underflow\n",
327 				    device_xname(sc->sc_dev));
328 			if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
329 				lance_reset(sc);
330 				return;
331 			}
332 			if (tmd.tmd3 & LE_T3_LCAR) {
333 				sc->sc_havecarrier = 0;
334 				if (sc->sc_nocarrier)
335 					(*sc->sc_nocarrier)(sc);
336 				else
337 					printf("%s: lost carrier\n",
338 					    device_xname(sc->sc_dev));
339 			}
340 			if (tmd.tmd3 & LE_T3_LCOL)
341 				ifp->if_collisions++;
342 			if (tmd.tmd3 & LE_T3_RTRY) {
343 #ifdef LEDEBUG
344 				printf("%s: excessive collisions, tdr %d\n",
345 				    device_xname(sc->sc_dev),
346 				    tmd.tmd3 & LE_T3_TDR_MASK);
347 #endif
348 				ifp->if_collisions += 16;
349 			}
350 			ifp->if_oerrors++;
351 		} else {
352 			if (tmd.tmd1_bits & LE_T1_ONE)
353 				ifp->if_collisions++;
354 			else if (tmd.tmd1_bits & LE_T1_MORE)
355 				/* Real number is unknown. */
356 				ifp->if_collisions += 2;
357 			ifp->if_opackets++;
358 		}
359 
360 		if (++bix == sc->sc_ntbuf)
361 			bix = 0;
362 
363 		--sc->sc_no_td;
364 	}
365 
366 	sc->sc_first_td = bix;
367 
368 	am7990_start(ifp);
369 
370 	if (sc->sc_no_td == 0)
371 		ifp->if_timer = 0;
372 }
373 
374 /*
375  * Controller interrupt.
376  */
377 int
378 am7990_intr(void *arg)
379 {
380 	struct lance_softc *sc = arg;
381 	uint16_t isr;
382 
383 	isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
384 	sc->sc_saved_csr0 = 0;
385 #if defined(LEDEBUG) && LEDEBUG > 1
386 	if (sc->sc_debug)
387 		printf("%s: am7990_intr entering with isr=%04x\n",
388 		    device_xname(sc->sc_dev), isr);
389 #endif
390 	if ((isr & LE_C0_INTR) == 0)
391 		return (0);
392 
393 #ifdef __vax__
394 	/*
395 	 * DEC needs this write order to the registers, don't know
396 	 * the results on other arch's.  Ragge 991029
397 	 */
398 	isr &= ~LE_C0_INEA;
399 	(*sc->sc_wrcsr)(sc, LE_CSR0, isr);
400 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
401 #else
402 	(*sc->sc_wrcsr)(sc, LE_CSR0,
403 	    isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
404 		   LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
405 #endif
406 	if (isr & LE_C0_ERR) {
407 		if (isr & LE_C0_BABL) {
408 #ifdef LEDEBUG
409 			printf("%s: babble\n", device_xname(sc->sc_dev));
410 #endif
411 			ifp->if_oerrors++;
412 		}
413 #if 0
414 		if (isr & LE_C0_CERR) {
415 			printf("%s: collision error\n",
416 			    device_xname(sc->sc_dev));
417 			ifp->if_collisions++;
418 		}
419 #endif
420 		if (isr & LE_C0_MISS) {
421 #ifdef LEDEBUG
422 			printf("%s: missed packet\n", device_xname(sc->sc_dev));
423 #endif
424 			ifp->if_ierrors++;
425 		}
426 		if (isr & LE_C0_MERR) {
427 			printf("%s: memory error\n", device_xname(sc->sc_dev));
428 			lance_reset(sc);
429 			return (1);
430 		}
431 	}
432 
433 	if ((isr & LE_C0_RXON) == 0) {
434 		printf("%s: receiver disabled\n", device_xname(sc->sc_dev));
435 		ifp->if_ierrors++;
436 		lance_reset(sc);
437 		return (1);
438 	}
439 	if ((isr & LE_C0_TXON) == 0) {
440 		printf("%s: transmitter disabled\n", device_xname(sc->sc_dev));
441 		ifp->if_oerrors++;
442 		lance_reset(sc);
443 		return (1);
444 	}
445 
446 	/*
447 	 * Pretend we have carrier; if we don't this will be cleared
448 	 * shortly.
449 	 */
450 	sc->sc_havecarrier = 1;
451 
452 	if (isr & LE_C0_RINT)
453 		am7990_rint(sc);
454 	if (isr & LE_C0_TINT)
455 		am7990_tint(sc);
456 
457 #if NRND > 0
458 	rnd_add_uint32(&sc->rnd_source, isr);
459 #endif
460 
461 	return (1);
462 }
463 
464 #undef ifp
465 
466 /*
467  * Setup output on interface.
468  * Get another datagram to send off of the interface queue, and map it to the
469  * interface before starting the output.
470  * Called only at splnet or interrupt level.
471  */
472 static void
473 am7990_start(struct ifnet *ifp)
474 {
475 	struct lance_softc *sc = ifp->if_softc;
476 	int bix;
477 	struct mbuf *m;
478 	struct letmd tmd;
479 	int rp;
480 	int len;
481 
482 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
483 		return;
484 
485 	bix = sc->sc_last_td;
486 
487 	for (;;) {
488 		rp = LE_TMDADDR(sc, bix);
489 		(*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
490 
491 		if (tmd.tmd1_bits & LE_T1_OWN) {
492 			ifp->if_flags |= IFF_OACTIVE;
493 			printf("missing buffer, no_td = %d, last_td = %d\n",
494 			    sc->sc_no_td, sc->sc_last_td);
495 		}
496 
497 		IFQ_DEQUEUE(&ifp->if_snd, m);
498 		if (m == 0)
499 			break;
500 
501 #if NBPFILTER > 0
502 		/*
503 		 * If BPF is listening on this interface, let it see the packet
504 		 * before we commit it to the wire.
505 		 */
506 		if (ifp->if_bpf)
507 			bpf_mtap(ifp->if_bpf, m);
508 #endif
509 
510 		/*
511 		 * Copy the mbuf chain into the transmit buffer.
512 		 */
513 		len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
514 
515 #ifdef LEDEBUG
516 		if (len > ETHERMTU + sizeof(struct ether_header))
517 			printf("packet length %d\n", len);
518 #endif
519 
520 		ifp->if_timer = 5;
521 
522 		/*
523 		 * Init transmit registers, and set transmit start flag.
524 		 */
525 		tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
526 		tmd.tmd2 = -len | LE_XMD2_ONES;
527 		tmd.tmd3 = 0;
528 
529 		(*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
530 
531 #ifdef LEDEBUG
532 		if (sc->sc_debug > 1)
533 			am7990_xmit_print(sc, sc->sc_last_td);
534 #endif
535 
536 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
537 
538 		if (++bix == sc->sc_ntbuf)
539 			bix = 0;
540 
541 		if (++sc->sc_no_td == sc->sc_ntbuf) {
542 			ifp->if_flags |= IFF_OACTIVE;
543 			break;
544 		}
545 
546 	}
547 
548 	sc->sc_last_td = bix;
549 }
550 
551 #ifdef LEDEBUG
552 static void
553 am7990_recv_print(struct lance_softc *sc, int no)
554 {
555 	struct lermd rmd;
556 	uint16_t len;
557 	struct ether_header eh;
558 
559 	(*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
560 	len = rmd.rmd3;
561 	printf("%s: receive buffer %d, len = %d\n",
562 	    device_xname(sc->sc_dev), no, len);
563 	printf("%s: status %04x\n", device_xname(sc->sc_dev),
564 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
565 	printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
566 	    device_xname(sc->sc_dev),
567 	    rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
568 	if (len >= sizeof(eh)) {
569 		(*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
570 		printf("%s: dst %s", device_xname(sc->sc_dev),
571 			ether_sprintf(eh.ether_dhost));
572 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
573 			ntohs(eh.ether_type));
574 	}
575 }
576 
577 static void
578 am7990_xmit_print(struct lance_softc *sc, int no)
579 {
580 	struct letmd tmd;
581 	uint16_t len;
582 	struct ether_header eh;
583 
584 	(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
585 	len = -tmd.tmd2;
586 	printf("%s: transmit buffer %d, len = %d\n",
587 	    device_xname(sc->sc_dev), no, len);
588 	printf("%s: status %04x\n", device_xname(sc->sc_dev),
589 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
590 	printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
591 	    device_xname(sc->sc_dev),
592 	    tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
593 	if (len >= sizeof(eh)) {
594 		(*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
595 		printf("%s: dst %s", device_xname(sc->sc_dev),
596 			ether_sprintf(eh.ether_dhost));
597 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
598 		    ntohs(eh.ether_type));
599 	}
600 }
601 #endif /* LEDEBUG */
602