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.1 (Berkeley) 05/09/91 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 "param.h" 31 #include "mbuf.h" 32 #include "socket.h" 33 #include "ioctl.h" 34 #include "errno.h" 35 #include "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 printf("we: reset!\n"); 247 westop(unit); 248 DELAY(100000); 249 weinit(unit); 250 } 251 252 static Bdry; 253 /* 254 * Initialization of interface (really just DS8390). 255 */ 256 weinit(unit) 257 int unit; 258 { 259 register struct we_softc *sc = &we_softc[unit]; 260 register struct ifnet *ifp = &sc->we_if; 261 union we_command wecmd; 262 int i, s; 263 264 /* address not known */ 265 if (ifp->if_addrlist == (struct ifaddr *)0) 266 return; 267 268 /* already running */ 269 /* if (sc->we_flags & WDF_RUNNING)*/ 270 /*if (ifp->if_flags & IFF_RUNNING) return; */ 271 272 /* 273 * Initialize DS8390 in order given in NSC NIC manual. 274 * this is stock code...please see the National manual for details. 275 */ 276 s = splhigh(); 277 Bdry = 0; 278 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 279 wecmd.cs_stp = 1; 280 wecmd.cs_sta = 0; 281 wecmd.cs_ps = 0; 282 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 283 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); 284 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0); 285 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0); 286 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON); 287 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); 288 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0); 289 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); 290 outb(sc->we_io_nic_addr + WD_P0_PSTOP, 291 sc->we_vmem_size / WD_PAGE_SIZE); 292 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); 293 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff); 294 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 295 wecmd.cs_ps = 1; 296 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 297 for (i = 0; i < ETHER_ADDR_LEN; ++i) 298 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]); 299 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ 300 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff); 301 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); 302 wecmd.cs_ps = 0; 303 wecmd.cs_stp = 0; 304 wecmd.cs_sta = 1; 305 wecmd.cs_rd = 0x4; 306 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte); 307 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); 308 309 /* 310 * Take the interface out of reset, program the vector, 311 * enable interrupts, and tell the world we are up. 312 */ 313 ifp->if_flags |= IFF_RUNNING; 314 sc->we_flags &= ~WDF_TXBUSY; 315 (void) splx(s); 316 westart(ifp); 317 } 318 319 /* 320 * Start output on interface. 321 */ 322 westart(ifp) 323 struct ifnet *ifp; 324 { 325 register struct we_softc *sc = &we_softc[ifp->if_unit]; 326 struct mbuf *m0, *m; 327 register caddr_t buffer; 328 int len, s; 329 union we_command wecmd; 330 331 /* 332 * The DS8390 has only one transmit buffer, if it is busy we 333 * must wait until the transmit interrupt completes. 334 */ 335 s = splhigh(); 336 if (sc->we_flags & WDF_TXBUSY) { 337 (void) splx(s); 338 return; 339 } 340 IF_DEQUEUE(&sc->we_if.if_snd, m); 341 if (m == 0) { 342 (void) splx(s); 343 return; 344 } 345 sc->we_flags |= WDF_TXBUSY; 346 (void) splx(s); 347 348 /* 349 * Copy the mbuf chain into the transmit buffer 350 */ 351 buffer = sc->we_vmem_addr; 352 len = 0; 353 /*printf("\nT "); */ 354 for (m0 = m; m != 0; m = m->m_next) { 355 /*int j;*/ 356 bcopy(mtod(m, caddr_t), buffer, m->m_len); 357 /*for(j=0; j < m->m_len;j++) { 358 359 puthex(buffer[j]); 360 if (j == sizeof(struct ether_header)-1) 361 printf("|"); 362 }*/ 363 buffer += m->m_len; 364 len += m->m_len; 365 } 366 /*printf("|%d ", len);*/ 367 368 m_freem(m0); 369 370 /* 371 * Init transmit length registers, and set transmit start flag. 372 */ 373 s = splhigh(); 374 len = MAX(len, ETHER_MIN_LEN); 375 /*printf("L %d ", len); 376 if (len < 70) len=70;*/ 377 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 378 wecmd.cs_ps = 0; 379 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 380 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff); 381 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8); 382 wecmd.cs_txp = 1; 383 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 384 (void) splx(s); 385 } 386 387 /* 388 * Ethernet interface interrupt processor 389 */ 390 weintr(unit) 391 int unit; 392 { 393 register struct we_softc *sc = &we_softc[unit]; 394 union we_command wecmd; 395 union we_interrupt weisr; 396 397 unit =0; 398 399 /* disable onboard interrupts, then get interrupt status */ 400 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 401 wecmd.cs_ps = 0; 402 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 403 /*outb(sc->we_io_nic_addr + WD_P0_IMR, 0);*/ 404 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 405 loop: 406 outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte); 407 408 /* transmit error */ 409 if (weisr.is_txe) { 410 /* need to read these registers to clear status */ 411 sc->we_if.if_collisions += 412 inb(sc->we_io_nic_addr + WD_P0_TBCR0); 413 ++sc->we_if.if_oerrors; 414 } 415 416 /* receiver error */ 417 if (weisr.is_rxe) { 418 /* need to read these registers to clear status */ 419 (void) inb(sc->we_io_nic_addr + 0xD); 420 (void) inb(sc->we_io_nic_addr + 0xE); 421 (void) inb(sc->we_io_nic_addr + 0xF); 422 ++sc->we_if.if_ierrors; 423 } 424 425 /* normal transmit complete */ 426 if (weisr.is_ptx || weisr.is_txe) 427 wetint (unit); 428 429 /* normal receive notification */ 430 if (weisr.is_prx || weisr.is_rxe) 431 werint (unit); 432 433 /* try to start transmit */ 434 westart(&sc->we_if); 435 436 /* re-enable onboard interrupts */ 437 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 438 wecmd.cs_ps = 0; 439 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 440 outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/); 441 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 442 if (weisr.is_byte) goto loop; 443 } 444 445 /* 446 * Ethernet interface transmit interrupt. 447 */ 448 wetint(unit) 449 int unit; 450 { 451 register struct we_softc *sc = &we_softc[unit]; 452 453 /* 454 * Do some statistics (assume page zero of NIC mapped in) 455 */ 456 sc->we_flags &= ~WDF_TXBUSY; 457 sc->we_if.if_timer = 0; 458 ++sc->we_if.if_opackets; 459 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0); 460 } 461 462 /* 463 * Ethernet interface receiver interrupt. 464 */ 465 werint(unit) 466 int unit; 467 { 468 register struct we_softc *sc = &we_softc[unit]; 469 u_char bnry, curr; 470 long len; 471 union we_command wecmd; 472 struct we_ring *wer; 473 474 /* 475 * Traverse the receive ring looking for packets to pass back. 476 * The search is complete when we find a descriptor not in use. 477 */ 478 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 479 wecmd.cs_ps = 0; 480 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 481 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY); 482 wecmd.cs_ps = 1; 483 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 484 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 485 if(Bdry) 486 bnry =Bdry; 487 488 /*printf("B %d c %d ", bnry, curr);*/ 489 while (bnry != curr) 490 { 491 /* get pointer to this buffer header structure */ 492 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8)); 493 494 /* count includes CRC */ 495 len = wer->we_count - 4; 496 if (len > 30 && len <= ETHERMTU+100 497 /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/) 498 weread(sc, (caddr_t)(wer + 1), len); 499 else printf("reject %d", len); 500 501 outofbufs: 502 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 503 wecmd.cs_ps = 0; 504 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 505 506 /* advance on chip Boundry register */ 507 if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) { 508 bnry = WD_TXBUF_SIZE; 509 outb(sc->we_io_nic_addr + WD_P0_BNRY, 510 sc->we_vmem_size / WD_PAGE_SIZE-1); 511 512 } else { 513 if (len > 30 && len <= ETHERMTU+100) 514 bnry = wer->we_next_packet; 515 else bnry = curr; 516 517 /* watch out for NIC overflow, reset Boundry if invalid */ 518 if ((bnry - 1) < WD_TXBUF_SIZE) { 519 outb(sc->we_io_nic_addr + WD_P0_BNRY, 520 (sc->we_vmem_size / WD_PAGE_SIZE) - 1); 521 bnry = WD_TXBUF_SIZE; 522 } else 523 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1); 524 } 525 526 /* refresh our copy of CURR */ 527 wecmd.cs_ps = 1; 528 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 529 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 530 /*printf("b %d c %d ", bnry, curr); */ 531 } 532 Bdry = bnry; 533 } 534 535 #ifdef shit 536 /* 537 * Process an ioctl request. 538 */ 539 weioctl(ifp, cmd, data) 540 register struct ifnet *ifp; 541 int cmd; 542 caddr_t data; 543 { 544 struct we_softc *sc = &we_softc[ifp->if_unit]; 545 struct ifaddr *ifa = (struct ifaddr *)data; 546 int s = splimp(), error = 0; 547 548 switch (cmd) { 549 550 case SIOCSIFADDR: 551 ifp->if_flags |= IFF_UP; 552 weinit(ifp->if_unit); 553 switch(ifa->ifa_addr->sa_family) { 554 #ifdef INET 555 case AF_INET: 556 ((struct arpcom *)ifp)->ac_ipaddr = 557 IA_SIN(ifa)->sin_addr; 558 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 559 break; 560 #endif 561 #ifdef NS 562 case AF_NS: 563 { 564 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 565 566 if (ns_nullhost(*ina)) 567 ina->x_host = *(union ns_host *)(sc->we_addr); 568 else 569 wesetaddr(ina->x_host.c_host, ifp->if_unit); 570 break; 571 } 572 #endif 573 } 574 break; 575 576 case SIOCSIFFLAGS: 577 if (((ifp->if_flags & IFF_UP) == 0) && 578 (sc->we_flags & WDF_RUNNING)) { 579 westop(ifp->if_unit); 580 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && 581 ((sc->we_flags & WDF_RUNNING) == 0)) 582 weinit(ifp->if_unit); 583 break; 584 585 default: 586 error = EINVAL; 587 588 } 589 (void) splx(s); 590 return (error); 591 } 592 #endif 593 594 /* 595 * Process an ioctl request. 596 */ 597 weioctl(ifp, cmd, data) 598 register struct ifnet *ifp; 599 int cmd; 600 caddr_t data; 601 { 602 register struct ifaddr *ifa = (struct ifaddr *)data; 603 struct we_softc *sc = &we_softc[ifp->if_unit]; 604 struct ifreq *ifr = (struct ifreq *)data; 605 int s = splimp(), error = 0; 606 607 608 switch (cmd) { 609 610 case SIOCSIFADDR: 611 ifp->if_flags |= IFF_UP; 612 613 switch (ifa->ifa_addr->sa_family) { 614 #ifdef INET 615 case AF_INET: 616 weinit(ifp->if_unit); /* before arpwhohas */ 617 ((struct arpcom *)ifp)->ac_ipaddr = 618 IA_SIN(ifa)->sin_addr; 619 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 620 break; 621 #endif 622 #ifdef NS 623 case AF_NS: 624 { 625 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 626 627 if (ns_nullhost(*ina)) 628 ina->x_host = *(union ns_host *)(sc->ns_addr); 629 else { 630 /* 631 * The manual says we can't change the address 632 * while the receiver is armed, 633 * so reset everything 634 */ 635 ifp->if_flags &= ~IFF_RUNNING; 636 bcopy((caddr_t)ina->x_host.c_host, 637 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); 638 } 639 weinit(ifp->if_unit); /* does ne_setaddr() */ 640 break; 641 } 642 #endif 643 default: 644 weinit(ifp->if_unit); 645 break; 646 } 647 break; 648 649 case SIOCSIFFLAGS: 650 if ((ifp->if_flags & IFF_UP) == 0 && 651 ifp->if_flags & IFF_RUNNING) { 652 ifp->if_flags &= ~IFF_RUNNING; 653 westop(ifp->if_unit); 654 } else if (ifp->if_flags & IFF_UP && 655 (ifp->if_flags & IFF_RUNNING) == 0) 656 weinit(ifp->if_unit); 657 break; 658 659 #ifdef notdef 660 case SIOCGHWADDR: 661 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, 662 sizeof(sc->sc_addr)); 663 break; 664 #endif 665 666 default: 667 error = EINVAL; 668 } 669 splx(s); 670 return (error); 671 } 672 /* 673 * set ethernet address for unit 674 */ 675 wesetaddr(physaddr, unit) 676 u_char *physaddr; 677 int unit; 678 { 679 register struct we_softc *sc = &we_softc[unit]; 680 register int i; 681 682 /* 683 * Rewrite ethernet address, and then force restart of NIC 684 */ 685 for (i = 0; i < ETHER_ADDR_LEN; i++) 686 sc->we_addr[i] = physaddr[i]; 687 sc->we_flags &= ~WDF_RUNNING; 688 weinit(unit); 689 } 690 691 #define wedataaddr(sc, eh, off, type) \ 692 ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \ 693 (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \ 694 + (sc)->we_vmem_ring: \ 695 ((caddr_t)((eh)+1)+(off))) 696 /* 697 * Pass a packet to the higher levels. 698 * We deal with the trailer protocol here. 699 */ 700 weread(sc, buf, len) 701 register struct we_softc *sc; 702 char *buf; 703 int len; 704 { 705 register struct ether_header *eh; 706 struct mbuf *m, *weget(); 707 int off, resid; 708 709 /* 710 * Deal with trailer protocol: if type is trailer type 711 * get true type from first 16-bit word past data. 712 * Remember that type was trailer by setting off. 713 */ 714 eh = (struct ether_header *)buf; 715 eh->ether_type = ntohs((u_short)eh->ether_type); 716 if (eh->ether_type >= ETHERTYPE_TRAIL && 717 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 718 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 719 if (off >= ETHERMTU) return; /* sanity */ 720 eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *)); 721 resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *))); 722 if (off + resid > len) return; /* sanity */ 723 len = off + resid; 724 } else off = 0; 725 726 len -= sizeof(struct ether_header); 727 if (len <= 0) return; 728 729 /* 730 * Pull packet off interface. Off is nonzero if packet 731 * has trailing header; neget will then force this header 732 * information to be at the front, but we still have to drop 733 * the type and length which are at the front of any trailer data. 734 */ 735 m = weget(buf, len, off, &sc->we_if, sc); 736 if (m == 0) return; 737 ether_input(&sc->we_if, eh, m); 738 } 739 740 /* 741 * Supporting routines 742 */ 743 744 /* 745 * Pull read data off a interface. 746 * Len is length of data, with local net header stripped. 747 * Off is non-zero if a trailer protocol was used, and 748 * gives the offset of the trailer information. 749 * We copy the trailer information and then all the normal 750 * data into mbufs. When full cluster sized units are present 751 * we copy into clusters. 752 */ 753 struct mbuf * 754 weget(buf, totlen, off0, ifp, sc) 755 caddr_t buf; 756 int totlen, off0; 757 struct ifnet *ifp; 758 struct we_softc *sc; 759 { 760 struct mbuf *top, **mp, *m, *p; 761 int off = off0, len; 762 register caddr_t cp = buf; 763 char *epkt; 764 int tc =totlen; 765 766 /* 767 printf("\nR"); 768 { int j; 769 for(j=0; j < sizeof(struct ether_header);j++) puthex(buf[j]); 770 printf("|"); 771 }*/ 772 buf += sizeof(struct ether_header); 773 cp = buf; 774 epkt = cp + totlen; 775 776 if (off) { 777 cp += off + 2 * sizeof(u_short); 778 totlen -= 2 * sizeof(u_short); 779 } 780 781 MGETHDR(m, M_DONTWAIT, MT_DATA); 782 if (m == 0) 783 return (0); 784 m->m_pkthdr.rcvif = ifp; 785 m->m_pkthdr.len = totlen; 786 m->m_len = MHLEN; 787 788 top = 0; 789 mp = ⊤ 790 while (totlen > 0) { 791 if (top) { 792 MGET(m, M_DONTWAIT, MT_DATA); 793 if (m == 0) { 794 m_freem(top); 795 return (0); 796 } 797 m->m_len = MLEN; 798 } 799 len = min(totlen, epkt - cp); 800 #ifdef nope 801 /* only do up to end of buffer */ 802 if (epkt > sc->we_vmem_end) 803 len = min(len, sc->we_vmem_end - cp); 804 #endif 805 if (len >= MINCLSIZE) { 806 MCLGET(m, M_DONTWAIT); 807 if (m->m_flags & M_EXT) 808 m->m_len = len = min(len, MCLBYTES); 809 else 810 len = m->m_len; 811 } else { 812 /* 813 * Place initial small packet/header at end of mbuf. 814 */ 815 if (len < m->m_len) { 816 if (top == 0 && len + max_linkhdr <= m->m_len) 817 m->m_data += max_linkhdr; 818 m->m_len = len; 819 } else 820 len = m->m_len; 821 } 822 823 totlen -= len; 824 /* only do up to end of buffer */ 825 if (cp+len > sc->we_vmem_end) { 826 unsigned toend = sc->we_vmem_end - cp; 827 828 bcopy(cp, mtod(m, caddr_t), toend); 829 cp = sc->we_vmem_ring; 830 bcopy(cp, mtod(m, caddr_t)+toend, len - toend); 831 cp += len - toend; 832 epkt = cp + totlen; 833 } else { 834 bcopy(cp, mtod(m, caddr_t), (unsigned)len); 835 cp += len; 836 } 837 /*{ int j; 838 for(j=0; j < m->m_len;j++) puthex(mtod(m, char *)[j]); 839 printf("|"); 840 }*/ 841 *mp = m; 842 mp = &m->m_next; 843 if (cp == epkt) { 844 cp = buf; 845 epkt = cp + tc; 846 } 847 } 848 /*printf("%d ",tc); */ 849 return (top); 850 } 851 852 puthex(c){ 853 printf("%x",(c>>4)&0xf); 854 printf("%x",c&0xf); 855 } 856 #endif 857