1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Tim L. Tucker. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)if_we.c 7.5 (Berkeley) 10/11/92 11 */ 12 13 /* 14 * Modification history 15 * 16 * 8/28/89 - Initial version(if_wd.c), Tim L Tucker 17 */ 18 19 #include "we.h" 20 #if NWE > 0 21 /* 22 * Western Digital 8003 ethernet/starlan adapter 23 * 24 * Supports the following interface cards: 25 * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT 26 * 27 * The Western Digital card is one of many AT/MCA ethernet interfaces 28 * based on the National DS8390 Network Interface chip set. 29 */ 30 #include <sys/param.h> 31 #include <sys/mbuf.h> 32 #include <sys/socket.h> 33 #include <sys/ioctl.h> 34 #include <sys/errno.h> 35 #include <sys/syslog.h> 36 37 #include <net/if.h> 38 #include <net/netisr.h> 39 40 #ifdef INET 41 #include <netinet/in.h> 42 #include <netinet/in_systm.h> 43 #include <netinet/in_var.h> 44 #include <netinet/ip.h> 45 #include <netinet/if_ether.h> 46 #endif 47 48 #ifdef NS 49 #include <netns/ns.h> 50 #include <netns/ns_if.h> 51 #endif 52 53 #include <i386/isa/if_wereg.h> 54 #include <i386/isa/isa_device.h> 55 56 /* 57 * This constant should really be 60 because the we adds 4 bytes of crc. 58 * However when set to 60 our packets are ignored by deuna's , 3coms are 59 * okay ?????????????????????????????????????????? 60 */ 61 #define ETHER_MIN_LEN 64 62 #define ETHER_ADDR_LEN 6 63 #define ETHER_HDR_SIZE 14 64 65 /* 66 * Ethernet software status per interface. 67 * 68 * Each interface is referenced by a network interface structure, 69 * qe_if, which the routing code uses to locate the interface. 70 * This structure contains the output queue for the interface, its address, ... 71 */ 72 struct we_softc { 73 struct arpcom we_ac; /* Ethernet common part */ 74 #define we_if we_ac.ac_if /* network-visible interface */ 75 #define we_addr we_ac.ac_enaddr /* hardware Ethernet address */ 76 77 u_char we_flags; /* software state */ 78 #define WDF_RUNNING 0x01 79 #define WDF_TXBUSY 0x02 80 81 u_char we_type; /* interface type code */ 82 u_short we_vector; /* interrupt vector */ 83 short we_io_ctl_addr; /* i/o bus address, control */ 84 short we_io_nic_addr; /* i/o bus address, DS8390 */ 85 86 caddr_t we_vmem_addr; /* card RAM virtual memory base */ 87 u_long we_vmem_size; /* card RAM bytes */ 88 caddr_t we_vmem_ring; /* receive ring RAM vaddress */ 89 caddr_t we_vmem_end; /* receive ring RAM end */ 90 } we_softc[NWE]; 91 92 int weprobe(), weattach(), weintr(), westart(); 93 int weinit(), ether_output(), weioctl(), wereset(), wewatchdog(); 94 95 struct isa_driver wedriver = { 96 weprobe, weattach, "we", 97 }; 98 99 /* 100 * Probe the WD8003 to see if it's there 101 */ 102 weprobe(is) 103 struct isa_device *is; 104 { 105 register int i; 106 register struct we_softc *sc = &we_softc[is->id_unit]; 107 union we_mem_sel wem; 108 u_char sum; 109 110 /* 111 * Here we check the card ROM, if the checksum passes, and the 112 * type code and ethernet address check out, then we know we have 113 * a wd8003 card. 114 * 115 * Autoconfiguration: No warning message is printed on error. 116 */ 117 for (sum = 0, i = 0; i < 8; ++i) 118 sum += inb(is->id_iobase + WD_ROM_OFFSET + i); 119 if (sum != WD_CHECKSUM) 120 return (0); 121 sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6); 122 if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN) 123 && (sc->we_type != WD_ETHER2)) 124 return (0); 125 126 /* 127 * Setup card RAM area and i/o addresses 128 * Kernel Virtual to segment C0000-DFFFF????? 129 */ 130 sc->we_io_ctl_addr = is->id_iobase; 131 sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET; 132 sc->we_vector = is->id_irq; 133 sc->we_vmem_addr = (caddr_t)is->id_maddr; 134 sc->we_vmem_size = is->id_msize; 135 sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE); 136 sc->we_vmem_end = sc->we_vmem_addr + is->id_msize; 137 138 /* 139 * Save board ROM station address 140 */ 141 for (i = 0; i < ETHER_ADDR_LEN; ++i) 142 sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i); 143 144 /* 145 * Mapin interface memory, setup memory select register 146 */ 147 /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */ 148 wem.ms_addr = (u_long)(0xd0000)>> 13; 149 wem.ms_enable = 1; 150 wem.ms_reset = 0; 151 outb(sc->we_io_ctl_addr, wem.ms_byte); 152 153 /* 154 * clear interface memory, then sum to make sure its valid 155 */ 156 for (i = 0; i < sc->we_vmem_size; ++i) 157 sc->we_vmem_addr[i] = 0x0; 158 for (sum = 0, i = 0; i < sc->we_vmem_size; ++i) 159 sum += sc->we_vmem_addr[i]; 160 if (sum != 0x0) { 161 printf("we%d: wd8003 dual port RAM address error\n", is->id_unit); 162 return (0); 163 } 164 165 return (WD_IO_PORTS); 166 } 167 168 /* 169 * Interface exists: make available by filling in network interface 170 * record. System will initialize the interface when it is ready 171 * to accept packets. 172 */ 173 weattach(is) 174 struct isa_device *is; 175 { 176 register struct we_softc *sc = &we_softc[is->id_unit]; 177 register struct ifnet *ifp = &sc->we_if; 178 union we_command wecmd; 179 180 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 181 wecmd.cs_stp = 1; 182 wecmd.cs_sta = 0; 183 wecmd.cs_ps = 0; 184 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 185 /* 186 * Initialize ifnet structure 187 */ 188 ifp->if_unit = is->id_unit; 189 ifp->if_name = "we" ; 190 ifp->if_mtu = ETHERMTU; 191 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ; 192 ifp->if_init = weinit; 193 ifp->if_output = ether_output; 194 ifp->if_start = westart; 195 ifp->if_ioctl = weioctl; 196 ifp->if_reset = wereset; 197 ifp->if_watchdog = wewatchdog; 198 if_attach(ifp); 199 200 /* 201 * Banner... 202 */ 203 printf(" %s address %s", 204 ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"), 205 ether_sprintf(sc->we_addr)); 206 } 207 208 /* 209 * Reset of interface. 210 */ 211 wereset(unit, uban) 212 int unit, uban; 213 { 214 if (unit >= NWE) 215 return; 216 printf("we%d: reset\n", unit); 217 /* we_softc[unit].we_flags &= ~WDF_RUNNING; */ 218 weinit(unit); 219 } 220 221 /* 222 * Take interface offline. 223 */ 224 westop(unit) 225 int unit; 226 { 227 register struct we_softc *sc = &we_softc[unit]; 228 union we_command wecmd; 229 int s; 230 231 /* 232 * Shutdown DS8390 233 */ 234 s = splimp(); 235 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 236 wecmd.cs_stp = 1; 237 wecmd.cs_sta = 0; 238 wecmd.cs_ps = 0; 239 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 240 (void) splx(s); 241 } 242 243 wewatchdog(unit) { 244 245 log(LOG_WARNING,"we%d: soft reset\n", unit); 246 westop(unit); 247 weinit(unit); 248 } 249 250 static Bdry; 251 /* 252 * Initialization of interface (really just DS8390). 253 */ 254 weinit(unit) 255 int unit; 256 { 257 register struct we_softc *sc = &we_softc[unit]; 258 register struct ifnet *ifp = &sc->we_if; 259 union we_command wecmd; 260 int i, s; 261 262 /* address not known */ 263 if (ifp->if_addrlist == (struct ifaddr *)0) 264 return; 265 266 /* already running */ 267 /*if (ifp->if_flags & IFF_RUNNING) return; */ 268 269 /* 270 * Initialize DS8390 in order given in NSC NIC manual. 271 * this is stock code...please see the National manual for details. 272 */ 273 s = splhigh(); 274 Bdry = 0; 275 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 276 wecmd.cs_stp = 1; 277 wecmd.cs_sta = 0; 278 wecmd.cs_ps = 0; 279 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 280 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); 281 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0); 282 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0); 283 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON); 284 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); 285 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0); 286 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); 287 outb(sc->we_io_nic_addr + WD_P0_PSTOP, 288 sc->we_vmem_size / WD_PAGE_SIZE); 289 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); 290 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff); 291 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 292 wecmd.cs_ps = 1; 293 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 294 for (i = 0; i < ETHER_ADDR_LEN; ++i) 295 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]); 296 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ 297 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff); 298 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); 299 wecmd.cs_ps = 0; 300 wecmd.cs_stp = 0; 301 wecmd.cs_sta = 1; 302 wecmd.cs_rd = 0x4; 303 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte); 304 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); 305 306 /* 307 * Take the interface out of reset, program the vector, 308 * enable interrupts, and tell the world we are up. 309 */ 310 ifp->if_flags |= IFF_RUNNING; 311 sc->we_flags &= ~WDF_TXBUSY; 312 (void) splx(s); 313 westart(ifp); 314 } 315 316 /* 317 * Start output on interface. 318 */ 319 westart(ifp) 320 struct ifnet *ifp; 321 { 322 register struct we_softc *sc = &we_softc[ifp->if_unit]; 323 struct mbuf *m0, *m; 324 register caddr_t buffer; 325 int len, s; 326 union we_command wecmd; 327 328 /* 329 * The DS8390 has only one transmit buffer, if it is busy we 330 * must wait until the transmit interrupt completes. 331 */ 332 s = splhigh(); 333 if (sc->we_flags & WDF_TXBUSY) { 334 (void) splx(s); 335 return; 336 } 337 IF_DEQUEUE(&sc->we_if.if_snd, m); 338 if (m == 0) { 339 (void) splx(s); 340 return; 341 } 342 sc->we_flags |= WDF_TXBUSY; 343 (void) splx(s); 344 345 /* 346 * Copy the mbuf chain into the transmit buffer 347 */ 348 buffer = sc->we_vmem_addr; 349 len = 0; 350 for (m0 = m; m != 0; m = m->m_next) { 351 bcopy(mtod(m, caddr_t), buffer, m->m_len); 352 buffer += m->m_len; 353 len += m->m_len; 354 } 355 356 m_freem(m0); 357 358 /* 359 * Init transmit length registers, and set transmit start flag. 360 */ 361 s = splhigh(); 362 len = MAX(len, ETHER_MIN_LEN); 363 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 364 wecmd.cs_ps = 0; 365 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 366 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff); 367 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8); 368 wecmd.cs_txp = 1; 369 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 370 (void) splx(s); 371 } 372 373 /* 374 * Ethernet interface interrupt processor 375 */ 376 weintr(unit) 377 int unit; 378 { 379 register struct we_softc *sc = &we_softc[unit]; 380 union we_command wecmd; 381 union we_interrupt weisr; 382 int nloops = 10; 383 384 unit =0; 385 386 /* disable onboard interrupts, then get interrupt status */ 387 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 388 wecmd.cs_ps = 0; 389 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 390 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 391 loop: 392 outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte); 393 394 /* transmit error */ 395 if (weisr.is_txe) { 396 /* need to read these registers to clear status */ 397 sc->we_if.if_collisions += 398 inb(sc->we_io_nic_addr + WD_P0_TBCR0); 399 ++sc->we_if.if_oerrors; 400 } 401 402 /* receiver error */ 403 if (weisr.is_rxe) { 404 /* need to read these registers to clear status */ 405 (void) inb(sc->we_io_nic_addr + 0xD); 406 (void) inb(sc->we_io_nic_addr + 0xE); 407 (void) inb(sc->we_io_nic_addr + 0xF); 408 ++sc->we_if.if_ierrors; 409 } 410 411 /* normal transmit complete */ 412 if (weisr.is_ptx || weisr.is_txe) 413 wetint (unit); 414 415 /* normal receive notification */ 416 if (weisr.is_prx || weisr.is_rxe) 417 werint (unit); 418 419 /* try to start transmit */ 420 westart(&sc->we_if); 421 422 /* re-enable onboard interrupts */ 423 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 424 wecmd.cs_ps = 0; 425 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 426 outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/); 427 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 428 if (weisr.is_byte) { 429 /* 430 * I caught it looping forever here a couple of times, 431 * but I haven't had time to figure out why. Just 432 * returning seems to be safe, and it does not appear 433 * to interfere with future packets. - Pace 5/19/92 434 */ 435 if (--nloops <= 0) { 436 printf ("we0: weintr is looping\n"); 437 return; 438 } 439 goto loop; 440 } 441 } 442 443 /* 444 * Ethernet interface transmit interrupt. 445 */ 446 wetint(unit) 447 int unit; 448 { 449 register struct we_softc *sc = &we_softc[unit]; 450 451 /* 452 * Do some statistics (assume page zero of NIC mapped in) 453 */ 454 sc->we_flags &= ~WDF_TXBUSY; 455 sc->we_if.if_timer = 0; 456 ++sc->we_if.if_opackets; 457 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0); 458 } 459 460 /* 461 * Ethernet interface receiver interrupt. 462 */ 463 werint(unit) 464 int unit; 465 { 466 register struct we_softc *sc = &we_softc[unit]; 467 u_char bnry, curr; 468 long len; 469 union we_command wecmd; 470 struct we_ring *wer; 471 472 /* 473 * Traverse the receive ring looking for packets to pass back. 474 * The search is complete when we find a descriptor not in use. 475 */ 476 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 477 wecmd.cs_ps = 0; 478 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 479 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY); 480 wecmd.cs_ps = 1; 481 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 482 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 483 if(Bdry) 484 bnry =Bdry; 485 486 while (bnry != curr) 487 { 488 /* get pointer to this buffer header structure */ 489 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8)); 490 491 /* count includes CRC */ 492 len = wer->we_count - 4; 493 if (len > 30 && len <= ETHERMTU+100 494 /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/) 495 weread(sc, (caddr_t)(wer + 1), len); 496 else printf("reject %d", len); 497 498 outofbufs: 499 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 500 wecmd.cs_ps = 0; 501 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 502 503 /* advance on chip Boundry register */ 504 if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) { 505 bnry = WD_TXBUF_SIZE; 506 outb(sc->we_io_nic_addr + WD_P0_BNRY, 507 sc->we_vmem_size / WD_PAGE_SIZE-1); 508 509 } else { 510 if (len > 30 && len <= ETHERMTU+100) 511 bnry = wer->we_next_packet; 512 else bnry = curr; 513 514 /* watch out for NIC overflow, reset Boundry if invalid */ 515 if ((bnry - 1) < WD_TXBUF_SIZE) { 516 outb(sc->we_io_nic_addr + WD_P0_BNRY, 517 (sc->we_vmem_size / WD_PAGE_SIZE) - 1); 518 bnry = WD_TXBUF_SIZE; 519 } else 520 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1); 521 } 522 523 /* refresh our copy of CURR */ 524 wecmd.cs_ps = 1; 525 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 526 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 527 } 528 Bdry = bnry; 529 } 530 531 #ifdef shit 532 /* 533 * Process an ioctl request. 534 */ 535 weioctl(ifp, cmd, data) 536 register struct ifnet *ifp; 537 int cmd; 538 caddr_t data; 539 { 540 struct we_softc *sc = &we_softc[ifp->if_unit]; 541 struct ifaddr *ifa = (struct ifaddr *)data; 542 int s = splimp(), error = 0; 543 544 switch (cmd) { 545 546 case SIOCSIFADDR: 547 ifp->if_flags |= IFF_UP; 548 weinit(ifp->if_unit); 549 switch(ifa->ifa_addr->sa_family) { 550 #ifdef INET 551 case AF_INET: 552 ((struct arpcom *)ifp)->ac_ipaddr = 553 IA_SIN(ifa)->sin_addr; 554 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 555 break; 556 #endif 557 #ifdef NS 558 case AF_NS: 559 { 560 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 561 562 if (ns_nullhost(*ina)) 563 ina->x_host = *(union ns_host *)(sc->we_addr); 564 else 565 wesetaddr(ina->x_host.c_host, ifp->if_unit); 566 break; 567 } 568 #endif 569 } 570 break; 571 572 case SIOCSIFFLAGS: 573 if (((ifp->if_flags & IFF_UP) == 0) && 574 (sc->we_flags & WDF_RUNNING)) { 575 westop(ifp->if_unit); 576 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && 577 ((sc->we_flags & WDF_RUNNING) == 0)) 578 weinit(ifp->if_unit); 579 break; 580 581 default: 582 error = EINVAL; 583 584 } 585 (void) splx(s); 586 return (error); 587 } 588 #endif 589 590 /* 591 * Process an ioctl request. 592 */ 593 weioctl(ifp, cmd, data) 594 register struct ifnet *ifp; 595 int cmd; 596 caddr_t data; 597 { 598 register struct ifaddr *ifa = (struct ifaddr *)data; 599 struct we_softc *sc = &we_softc[ifp->if_unit]; 600 struct ifreq *ifr = (struct ifreq *)data; 601 int s = splimp(), error = 0; 602 603 604 switch (cmd) { 605 606 case SIOCSIFADDR: 607 ifp->if_flags |= IFF_UP; 608 609 switch (ifa->ifa_addr->sa_family) { 610 #ifdef INET 611 case AF_INET: 612 weinit(ifp->if_unit); /* before arpwhohas */ 613 ((struct arpcom *)ifp)->ac_ipaddr = 614 IA_SIN(ifa)->sin_addr; 615 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 616 break; 617 #endif 618 #ifdef NS 619 case AF_NS: 620 { 621 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 622 623 if (ns_nullhost(*ina)) 624 ina->x_host = *(union ns_host *)(sc->ns_addr); 625 else { 626 /* 627 * The manual says we can't change the address 628 * while the receiver is armed, 629 * so reset everything 630 */ 631 ifp->if_flags &= ~IFF_RUNNING; 632 bcopy((caddr_t)ina->x_host.c_host, 633 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); 634 } 635 weinit(ifp->if_unit); /* does ne_setaddr() */ 636 break; 637 } 638 #endif 639 default: 640 weinit(ifp->if_unit); 641 break; 642 } 643 break; 644 645 case SIOCSIFFLAGS: 646 if ((ifp->if_flags & IFF_UP) == 0 && 647 ifp->if_flags & IFF_RUNNING) { 648 ifp->if_flags &= ~IFF_RUNNING; 649 westop(ifp->if_unit); 650 } else if (ifp->if_flags & IFF_UP && 651 (ifp->if_flags & IFF_RUNNING) == 0) 652 weinit(ifp->if_unit); 653 break; 654 655 #ifdef notdef 656 case SIOCGHWADDR: 657 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, 658 sizeof(sc->sc_addr)); 659 break; 660 #endif 661 662 default: 663 error = EINVAL; 664 } 665 splx(s); 666 return (error); 667 } 668 /* 669 * set ethernet address for unit 670 */ 671 wesetaddr(physaddr, unit) 672 u_char *physaddr; 673 int unit; 674 { 675 register struct we_softc *sc = &we_softc[unit]; 676 register int i; 677 678 /* 679 * Rewrite ethernet address, and then force restart of NIC 680 */ 681 for (i = 0; i < ETHER_ADDR_LEN; i++) 682 sc->we_addr[i] = physaddr[i]; 683 sc->we_flags &= ~WDF_RUNNING; 684 weinit(unit); 685 } 686 687 #define wedataaddr(sc, eh, off, type) \ 688 ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \ 689 (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \ 690 + (sc)->we_vmem_ring: \ 691 ((caddr_t)((eh)+1)+(off))) 692 /* 693 * Pass a packet to the higher levels. 694 * We deal with the trailer protocol here. 695 */ 696 weread(sc, buf, len) 697 register struct we_softc *sc; 698 char *buf; 699 int len; 700 { 701 register struct ether_header *eh; 702 struct mbuf *m, *weget(); 703 int off, resid; 704 705 /* 706 * Deal with trailer protocol: if type is trailer type 707 * get true type from first 16-bit word past data. 708 * Remember that type was trailer by setting off. 709 */ 710 eh = (struct ether_header *)buf; 711 eh->ether_type = ntohs((u_short)eh->ether_type); 712 if (eh->ether_type >= ETHERTYPE_TRAIL && 713 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 714 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 715 if (off >= ETHERMTU) return; /* sanity */ 716 eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *)); 717 resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *))); 718 if (off + resid > len) return; /* sanity */ 719 len = off + resid; 720 } else off = 0; 721 722 len -= sizeof(struct ether_header); 723 if (len <= 0) return; 724 725 /* 726 * Pull packet off interface. Off is nonzero if packet 727 * has trailing header; neget will then force this header 728 * information to be at the front, but we still have to drop 729 * the type and length which are at the front of any trailer data. 730 */ 731 m = weget(buf, len, off, &sc->we_if, sc); 732 if (m == 0) return; 733 ether_input(&sc->we_if, eh, m); 734 } 735 736 /* 737 * Supporting routines 738 */ 739 740 /* 741 * Pull read data off a interface. 742 * Len is length of data, with local net header stripped. 743 * Off is non-zero if a trailer protocol was used, and 744 * gives the offset of the trailer information. 745 * We copy the trailer information and then all the normal 746 * data into mbufs. When full cluster sized units are present 747 * we copy into clusters. 748 */ 749 struct mbuf * 750 weget(buf, totlen, off0, ifp, sc) 751 caddr_t buf; 752 int totlen, off0; 753 struct ifnet *ifp; 754 struct we_softc *sc; 755 { 756 struct mbuf *top, **mp, *m, *p; 757 int off = off0, len; 758 register caddr_t cp = buf; 759 char *epkt; 760 int tc =totlen; 761 762 buf += sizeof(struct ether_header); 763 cp = buf; 764 epkt = cp + totlen; 765 766 if (off) { 767 cp += off + 2 * sizeof(u_short); 768 totlen -= 2 * sizeof(u_short); 769 } 770 771 MGETHDR(m, M_DONTWAIT, MT_DATA); 772 if (m == 0) 773 return (0); 774 m->m_pkthdr.rcvif = ifp; 775 m->m_pkthdr.len = totlen; 776 m->m_len = MHLEN; 777 778 top = 0; 779 mp = ⊤ 780 while (totlen > 0) { 781 if (top) { 782 MGET(m, M_DONTWAIT, MT_DATA); 783 if (m == 0) { 784 m_freem(top); 785 return (0); 786 } 787 m->m_len = MLEN; 788 } 789 len = min(totlen, epkt - cp); 790 if (len >= MINCLSIZE) { 791 MCLGET(m, M_DONTWAIT); 792 if (m->m_flags & M_EXT) 793 m->m_len = len = min(len, MCLBYTES); 794 else 795 len = m->m_len; 796 } else { 797 /* 798 * Place initial small packet/header at end of mbuf. 799 */ 800 if (len < m->m_len) { 801 if (top == 0 && len + max_linkhdr <= m->m_len) 802 m->m_data += max_linkhdr; 803 m->m_len = len; 804 } else 805 len = m->m_len; 806 } 807 808 totlen -= len; 809 /* only do up to end of buffer */ 810 if (cp+len > sc->we_vmem_end) { 811 unsigned toend = sc->we_vmem_end - cp; 812 813 bcopy(cp, mtod(m, caddr_t), toend); 814 cp = sc->we_vmem_ring; 815 bcopy(cp, mtod(m, caddr_t)+toend, len - toend); 816 cp += len - toend; 817 epkt = cp + totlen; 818 } else { 819 bcopy(cp, mtod(m, caddr_t), (unsigned)len); 820 cp += len; 821 } 822 *mp = m; 823 mp = &m->m_next; 824 if (cp == epkt) { 825 cp = buf; 826 epkt = cp + tc; 827 } 828 } 829 return (top); 830 } 831 #endif 832