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