1 /* $NetBSD: if_eg.c,v 1.55 2001/11/13 08:01:17 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1993 Dean Huxley <dean@fsa.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Dean Huxley. 18 * 4. The name of Dean Huxley may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 /* 33 * Support for 3Com 3c505 Etherlink+ card. 34 */ 35 36 /* To do: 37 * - multicast 38 * - promiscuous 39 * - get rid of isa indirect stuff 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: if_eg.c,v 1.55 2001/11/13 08:01:17 lukem Exp $"); 44 45 #include "opt_inet.h" 46 #include "opt_ns.h" 47 #include "bpfilter.h" 48 #include "rnd.h" 49 50 #include <sys/types.h> 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/mbuf.h> 54 #include <sys/socket.h> 55 #include <sys/ioctl.h> 56 #include <sys/errno.h> 57 #include <sys/syslog.h> 58 #include <sys/select.h> 59 #include <sys/device.h> 60 #if NRND > 0 61 #include <sys/rnd.h> 62 #endif 63 64 #include <net/if.h> 65 #include <net/if_dl.h> 66 #include <net/if_types.h> 67 68 #include <net/if_ether.h> 69 70 #ifdef INET 71 #include <netinet/in.h> 72 #include <netinet/in_systm.h> 73 #include <netinet/in_var.h> 74 #include <netinet/ip.h> 75 #include <netinet/if_inarp.h> 76 #endif 77 78 #ifdef NS 79 #include <netns/ns.h> 80 #include <netns/ns_if.h> 81 #endif 82 83 #if NBPFILTER > 0 84 #include <net/bpf.h> 85 #include <net/bpfdesc.h> 86 #endif 87 88 #include <machine/cpu.h> 89 #include <machine/intr.h> 90 #include <machine/bus.h> 91 92 #include <dev/isa/isavar.h> 93 #include <dev/isa/if_egreg.h> 94 #include <dev/isa/elink.h> 95 96 /* for debugging convenience */ 97 #ifdef EGDEBUG 98 #define DPRINTF(x) printf x 99 #else 100 #define DPRINTF(x) 101 #endif 102 103 #define EG_INLEN 10 104 #define EG_BUFLEN 0x0670 105 106 #define EG_PCBLEN 64 107 108 /* 109 * Ethernet software status per interface. 110 */ 111 struct eg_softc { 112 struct device sc_dev; 113 void *sc_ih; 114 struct ethercom sc_ethercom; /* Ethernet common part */ 115 bus_space_tag_t sc_iot; /* bus space identifier */ 116 bus_space_handle_t sc_ioh; /* i/o handle */ 117 u_int8_t eg_rom_major; /* Cards ROM version (major number) */ 118 u_int8_t eg_rom_minor; /* Cards ROM version (minor number) */ 119 short eg_ram; /* Amount of RAM on the card */ 120 u_int8_t eg_pcb[EG_PCBLEN]; /* Primary Command Block buffer */ 121 u_int8_t eg_incount; /* Number of buffers currently used */ 122 caddr_t eg_inbuf; /* Incoming packet buffer */ 123 caddr_t eg_outbuf; /* Outgoing packet buffer */ 124 125 #if NRND > 0 126 rndsource_element_t rnd_source; 127 #endif 128 }; 129 130 int egprobe __P((struct device *, struct cfdata *, void *)); 131 void egattach __P((struct device *, struct device *, void *)); 132 133 struct cfattach eg_ca = { 134 sizeof(struct eg_softc), egprobe, egattach 135 }; 136 137 int egintr __P((void *)); 138 void eginit __P((struct eg_softc *)); 139 int egioctl __P((struct ifnet *, u_long, caddr_t)); 140 void egrecv __P((struct eg_softc *)); 141 void egstart __P((struct ifnet *)); 142 void egwatchdog __P((struct ifnet *)); 143 void egreset __P((struct eg_softc *)); 144 void egread __P((struct eg_softc *, caddr_t, int)); 145 struct mbuf *egget __P((struct eg_softc *, caddr_t, int)); 146 void egstop __P((struct eg_softc *)); 147 148 static inline void egprintpcb __P((u_int8_t *)); 149 static inline void egprintstat __P((u_char)); 150 static int egoutPCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t)); 151 static int egreadPCBstat __P((bus_space_tag_t, bus_space_handle_t, u_int8_t)); 152 static int egreadPCBready __P((bus_space_tag_t, bus_space_handle_t)); 153 static int egwritePCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *)); 154 static int egreadPCB __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *)); 155 156 /* 157 * Support stuff 158 */ 159 160 static inline void 161 egprintpcb(pcb) 162 u_int8_t *pcb; 163 { 164 int i; 165 166 for (i = 0; i < pcb[1] + 2; i++) 167 DPRINTF(("pcb[%2d] = %x\n", i, pcb[i])); 168 } 169 170 171 static inline void 172 egprintstat(b) 173 u_char b; 174 { 175 DPRINTF(("%s %s %s %s %s %s %s\n", 176 (b & EG_STAT_HCRE)?"HCRE":"", 177 (b & EG_STAT_ACRF)?"ACRF":"", 178 (b & EG_STAT_DIR )?"DIR ":"", 179 (b & EG_STAT_DONE)?"DONE":"", 180 (b & EG_STAT_ASF3)?"ASF3":"", 181 (b & EG_STAT_ASF2)?"ASF2":"", 182 (b & EG_STAT_ASF1)?"ASF1":"")); 183 } 184 185 static int 186 egoutPCB(iot, ioh, b) 187 bus_space_tag_t iot; 188 bus_space_handle_t ioh; 189 u_int8_t b; 190 { 191 int i; 192 193 for (i=0; i < 4000; i++) { 194 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) { 195 bus_space_write_1(iot, ioh, EG_COMMAND, b); 196 return 0; 197 } 198 delay(10); 199 } 200 DPRINTF(("egoutPCB failed\n")); 201 return 1; 202 } 203 204 static int 205 egreadPCBstat(iot, ioh, statb) 206 bus_space_tag_t iot; 207 bus_space_handle_t ioh; 208 u_int8_t statb; 209 { 210 int i; 211 212 for (i=0; i < 5000; i++) { 213 if ((bus_space_read_1(iot, ioh, EG_STATUS) & 214 EG_PCB_STAT) != EG_PCB_NULL) 215 break; 216 delay(10); 217 } 218 if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) == statb) 219 return 0; 220 return 1; 221 } 222 223 static int 224 egreadPCBready(iot, ioh) 225 bus_space_tag_t iot; 226 bus_space_handle_t ioh; 227 { 228 int i; 229 230 for (i=0; i < 10000; i++) { 231 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) 232 return 0; 233 delay(5); 234 } 235 DPRINTF(("PCB read not ready\n")); 236 return 1; 237 } 238 239 static int 240 egwritePCB(iot, ioh, pcb) 241 bus_space_tag_t iot; 242 bus_space_handle_t ioh; 243 u_int8_t *pcb; 244 { 245 int i; 246 u_int8_t len; 247 248 bus_space_write_1(iot, ioh, EG_CONTROL, 249 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL); 250 251 len = pcb[1] + 2; 252 for (i = 0; i < len; i++) 253 egoutPCB(iot, ioh, pcb[i]); 254 255 for (i=0; i < 4000; i++) { 256 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) 257 break; 258 delay(10); 259 } 260 261 bus_space_write_1(iot, ioh, EG_CONTROL, 262 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_DONE); 263 264 egoutPCB(iot, ioh, len); 265 266 if (egreadPCBstat(iot, ioh, EG_PCB_ACCEPT)) 267 return 1; 268 return 0; 269 } 270 271 static int 272 egreadPCB(iot, ioh, pcb) 273 bus_space_tag_t iot; 274 bus_space_handle_t ioh; 275 u_int8_t *pcb; 276 { 277 int i; 278 u_int8_t b; 279 280 bus_space_write_1(iot, ioh, EG_CONTROL, 281 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL); 282 283 memset(pcb, 0, EG_PCBLEN); 284 285 if (egreadPCBready(iot, ioh)) 286 return 1; 287 288 pcb[0] = bus_space_read_1(iot, ioh, EG_COMMAND); 289 290 if (egreadPCBready(iot, ioh)) 291 return 1; 292 293 pcb[1] = bus_space_read_1(iot, ioh, EG_COMMAND); 294 295 if (pcb[1] > 62) { 296 DPRINTF(("len %d too large\n", pcb[1])); 297 return 1; 298 } 299 300 for (i = 0; i < pcb[1]; i++) { 301 if (egreadPCBready(iot, ioh)) 302 return 1; 303 pcb[2+i] = bus_space_read_1(iot, ioh, EG_COMMAND); 304 } 305 if (egreadPCBready(iot, ioh)) 306 return 1; 307 if (egreadPCBstat(iot, ioh, EG_PCB_DONE)) 308 return 1; 309 if ((b = bus_space_read_1(iot, ioh, EG_COMMAND)) != pcb[1] + 2) { 310 DPRINTF(("%d != %d\n", b, pcb[1] + 2)); 311 return 1; 312 } 313 314 bus_space_write_1(iot, ioh, EG_CONTROL, 315 (bus_space_read_1(iot, ioh, EG_CONTROL) & 316 ~EG_PCB_STAT) | EG_PCB_ACCEPT); 317 318 return 0; 319 } 320 321 /* 322 * Real stuff 323 */ 324 325 int 326 egprobe(parent, match, aux) 327 struct device *parent; 328 struct cfdata *match; 329 void *aux; 330 { 331 struct isa_attach_args *ia = aux; 332 bus_space_tag_t iot = ia->ia_iot; 333 bus_space_handle_t ioh; 334 int i, rval; 335 static u_int8_t pcb[EG_PCBLEN]; 336 337 rval = 0; 338 339 if ((ia->ia_iobase & ~0x07f0) != 0) { 340 DPRINTF(("Weird iobase %x\n", ia->ia_iobase)); 341 return 0; 342 } 343 344 /* Disallow wildcarded i/o address. */ 345 if (ia->ia_iobase == ISACF_PORT_DEFAULT) 346 return (0); 347 348 /* Map i/o space. */ 349 if (bus_space_map(iot, ia->ia_iobase, 0x08, 0, &ioh)) { 350 DPRINTF(("egprobe: can't map i/o space in probe\n")); 351 return 0; 352 } 353 354 /* hard reset card */ 355 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_RESET); 356 bus_space_write_1(iot, ioh, EG_CONTROL, 0); 357 for (i = 0; i < 5000; i++) { 358 delay(1000); 359 if ((bus_space_read_1(iot, ioh, EG_STATUS) & 360 EG_PCB_STAT) == EG_PCB_NULL) 361 break; 362 } 363 if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) != EG_PCB_NULL) { 364 DPRINTF(("egprobe: Reset failed\n")); 365 goto out; 366 } 367 pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */ 368 pcb[1] = 0; 369 if (egwritePCB(iot, ioh, pcb) != 0) 370 goto out; 371 372 if ((egreadPCB(iot, ioh, pcb) != 0) || 373 pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */ 374 pcb[1] != 0x0a) { 375 egprintpcb(pcb); 376 goto out; 377 } 378 379 ia->ia_iosize = 0x08; 380 ia->ia_msize = 0; 381 rval = 1; 382 383 out: 384 bus_space_unmap(iot, ioh, 0x08); 385 return rval; 386 } 387 388 void 389 egattach(parent, self, aux) 390 struct device *parent, *self; 391 void *aux; 392 { 393 struct eg_softc *sc = (void *)self; 394 struct isa_attach_args *ia = aux; 395 bus_space_tag_t iot = ia->ia_iot; 396 bus_space_handle_t ioh; 397 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 398 u_int8_t myaddr[ETHER_ADDR_LEN]; 399 400 printf("\n"); 401 402 /* Map i/o space. */ 403 if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) { 404 printf("%s: can't map i/o space\n", self->dv_xname); 405 return; 406 } 407 408 sc->sc_iot = iot; 409 sc->sc_ioh = ioh; 410 411 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */ 412 sc->eg_pcb[1] = 0; 413 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 414 printf("%s: error requesting adapter info\n", self->dv_xname); 415 return; 416 } 417 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 418 egprintpcb(sc->eg_pcb); 419 printf("%s: error reading adapter info\n", self->dv_xname); 420 return; 421 } 422 423 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */ 424 sc->eg_pcb[1] != 0x0a) { 425 egprintpcb(sc->eg_pcb); 426 printf("%s: bogus adapter info\n", self->dv_xname); 427 return; 428 } 429 430 sc->eg_rom_major = sc->eg_pcb[3]; 431 sc->eg_rom_minor = sc->eg_pcb[2]; 432 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 433 434 egstop(sc); 435 436 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */ 437 sc->eg_pcb[1] = 0; 438 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 439 printf("%s: can't send Get Station Address\n", self->dv_xname); 440 return; 441 } 442 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 443 printf("%s: can't read station address\n", self->dv_xname); 444 egprintpcb(sc->eg_pcb); 445 return; 446 } 447 448 /* check Get station address response */ 449 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) { 450 printf("%s: card responded with garbage (1)\n", 451 self->dv_xname); 452 egprintpcb(sc->eg_pcb); 453 return; 454 } 455 memcpy(myaddr, &sc->eg_pcb[2], ETHER_ADDR_LEN); 456 457 printf("%s: ROM v%d.%02d %dk address %s\n", self->dv_xname, 458 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram, 459 ether_sprintf(myaddr)); 460 461 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */ 462 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 463 printf("%s: can't send Set Station Address\n", self->dv_xname); 464 return; 465 } 466 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 467 printf("%s: can't read Set Station Address status\n", 468 self->dv_xname); 469 egprintpcb(sc->eg_pcb); 470 return; 471 } 472 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 || 473 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) { 474 printf("%s: card responded with garbage (2)\n", 475 self->dv_xname); 476 egprintpcb(sc->eg_pcb); 477 return; 478 } 479 480 /* Initialize ifnet structure. */ 481 strcpy(ifp->if_xname, sc->sc_dev.dv_xname); 482 ifp->if_softc = sc; 483 ifp->if_start = egstart; 484 ifp->if_ioctl = egioctl; 485 ifp->if_watchdog = egwatchdog; 486 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 487 IFQ_SET_READY(&ifp->if_snd); 488 489 /* Now we can attach the interface. */ 490 if_attach(ifp); 491 ether_ifattach(ifp, myaddr); 492 493 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 494 IPL_NET, egintr, sc); 495 496 #if NRND > 0 497 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname, 498 RND_TYPE_NET, 0); 499 #endif 500 } 501 502 void 503 eginit(sc) 504 struct eg_softc *sc; 505 { 506 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 507 bus_space_tag_t iot = sc->sc_iot; 508 bus_space_handle_t ioh = sc->sc_ioh; 509 510 /* soft reset the board */ 511 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_FLSH); 512 delay(100); 513 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_ATTN); 514 delay(100); 515 bus_space_write_1(iot, ioh, EG_CONTROL, 0); 516 delay(200); 517 518 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */ 519 sc->eg_pcb[1] = 2; 520 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */ 521 sc->eg_pcb[3] = 0; 522 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) 523 printf("%s: can't send Configure 82586\n", 524 sc->sc_dev.dv_xname); 525 526 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) { 527 printf("%s: can't read Configure 82586 status\n", 528 sc->sc_dev.dv_xname); 529 egprintpcb(sc->eg_pcb); 530 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) 531 printf("%s: configure card command failed\n", 532 sc->sc_dev.dv_xname); 533 534 if (sc->eg_inbuf == NULL) { 535 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT); 536 if (sc->eg_inbuf == NULL) { 537 printf("%s: can't allocate inbuf\n", 538 sc->sc_dev.dv_xname); 539 panic("eginit"); 540 } 541 } 542 sc->eg_incount = 0; 543 544 if (sc->eg_outbuf == NULL) { 545 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT); 546 if (sc->eg_outbuf == NULL) { 547 printf("%s: can't allocate outbuf\n", 548 sc->sc_dev.dv_xname); 549 panic("eginit"); 550 } 551 } 552 553 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_CMDE); 554 555 sc->eg_incount = 0; 556 egrecv(sc); 557 558 /* Interface is now `running', with no output active. */ 559 ifp->if_flags |= IFF_RUNNING; 560 ifp->if_flags &= ~IFF_OACTIVE; 561 562 /* Attempt to start output, if any. */ 563 egstart(ifp); 564 } 565 566 void 567 egrecv(sc) 568 struct eg_softc *sc; 569 { 570 571 while (sc->eg_incount < EG_INLEN) { 572 sc->eg_pcb[0] = EG_CMD_RECVPACKET; 573 sc->eg_pcb[1] = 0x08; 574 sc->eg_pcb[2] = 0; /* address not used.. we send zero */ 575 sc->eg_pcb[3] = 0; 576 sc->eg_pcb[4] = 0; 577 sc->eg_pcb[5] = 0; 578 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */ 579 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff; 580 sc->eg_pcb[8] = 0; /* timeout, 0 == none */ 581 sc->eg_pcb[9] = 0; 582 if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) 583 break; 584 sc->eg_incount++; 585 } 586 } 587 588 void 589 egstart(ifp) 590 struct ifnet *ifp; 591 { 592 struct eg_softc *sc = ifp->if_softc; 593 bus_space_tag_t iot = sc->sc_iot; 594 bus_space_handle_t ioh = sc->sc_ioh; 595 struct mbuf *m0, *m; 596 caddr_t buffer; 597 int len; 598 u_int16_t *ptr; 599 600 /* Don't transmit if interface is busy or not running */ 601 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) 602 return; 603 604 loop: 605 /* Dequeue the next datagram. */ 606 IFQ_DEQUEUE(&ifp->if_snd, m0); 607 if (m0 == 0) 608 return; 609 610 ifp->if_flags |= IFF_OACTIVE; 611 612 /* We need to use m->m_pkthdr.len, so require the header */ 613 if ((m0->m_flags & M_PKTHDR) == 0) { 614 printf("%s: no header mbuf\n", sc->sc_dev.dv_xname); 615 panic("egstart"); 616 } 617 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN); 618 619 #if NBPFILTER > 0 620 if (ifp->if_bpf) 621 bpf_mtap(ifp->if_bpf, m0); 622 #endif 623 624 sc->eg_pcb[0] = EG_CMD_SENDPACKET; 625 sc->eg_pcb[1] = 0x06; 626 sc->eg_pcb[2] = 0; /* address not used, we send zero */ 627 sc->eg_pcb[3] = 0; 628 sc->eg_pcb[4] = 0; 629 sc->eg_pcb[5] = 0; 630 sc->eg_pcb[6] = len; /* length of packet */ 631 sc->eg_pcb[7] = len >> 8; 632 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) { 633 printf("%s: can't send Send Packet command\n", 634 sc->sc_dev.dv_xname); 635 ifp->if_oerrors++; 636 ifp->if_flags &= ~IFF_OACTIVE; 637 m_freem(m0); 638 goto loop; 639 } 640 641 buffer = sc->eg_outbuf; 642 for (m = m0; m != 0; m = m->m_next) { 643 memcpy(buffer, mtod(m, caddr_t), m->m_len); 644 buffer += m->m_len; 645 } 646 647 /* set direction bit: host -> adapter */ 648 bus_space_write_1(iot, ioh, EG_CONTROL, 649 bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_CTL_DIR); 650 651 for (ptr = (u_int16_t *) sc->eg_outbuf; len > 0; len -= 2) { 652 bus_space_write_2(iot, ioh, EG_DATA, *ptr++); 653 while (!(bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HRDY)) 654 ; /* XXX need timeout here */ 655 } 656 657 m_freem(m0); 658 } 659 660 int 661 egintr(arg) 662 void *arg; 663 { 664 struct eg_softc *sc = arg; 665 bus_space_tag_t iot = sc->sc_iot; 666 bus_space_handle_t ioh = sc->sc_ioh; 667 int i, len, serviced; 668 u_int16_t *ptr; 669 670 serviced = 0; 671 672 while (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) { 673 egreadPCB(iot, ioh, sc->eg_pcb); 674 switch (sc->eg_pcb[0]) { 675 case EG_RSP_RECVPACKET: 676 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8); 677 678 /* Set direction bit : Adapter -> host */ 679 bus_space_write_1(iot, ioh, EG_CONTROL, 680 bus_space_read_1(iot, ioh, EG_CONTROL) | EG_CTL_DIR); 681 682 for (ptr = (u_int16_t *) sc->eg_inbuf; 683 len > 0; len -= 2) { 684 while (!(bus_space_read_1(iot, ioh, EG_STATUS) & 685 EG_STAT_HRDY)) 686 ; 687 *ptr++ = bus_space_read_2(iot, ioh, EG_DATA); 688 } 689 690 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8); 691 egread(sc, sc->eg_inbuf, len); 692 693 sc->eg_incount--; 694 egrecv(sc); 695 serviced = 1; 696 break; 697 698 case EG_RSP_SENDPACKET: 699 if (sc->eg_pcb[6] || sc->eg_pcb[7]) { 700 DPRINTF(("%s: packet dropped\n", 701 sc->sc_dev.dv_xname)); 702 sc->sc_ethercom.ec_if.if_oerrors++; 703 } else 704 sc->sc_ethercom.ec_if.if_opackets++; 705 sc->sc_ethercom.ec_if.if_collisions += 706 sc->eg_pcb[8] & 0xf; 707 sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; 708 egstart(&sc->sc_ethercom.ec_if); 709 serviced = 1; 710 break; 711 712 /* XXX byte-order and type-size bugs here... */ 713 case EG_RSP_GETSTATS: 714 DPRINTF(("%s: Card Statistics\n", 715 sc->sc_dev.dv_xname)); 716 memcpy(&i, &sc->eg_pcb[2], sizeof(i)); 717 DPRINTF(("Receive Packets %d\n", i)); 718 memcpy(&i, &sc->eg_pcb[6], sizeof(i)); 719 DPRINTF(("Transmit Packets %d\n", i)); 720 DPRINTF(("CRC errors %d\n", 721 *(short *) &sc->eg_pcb[10])); 722 DPRINTF(("alignment errors %d\n", 723 *(short *) &sc->eg_pcb[12])); 724 DPRINTF(("no resources errors %d\n", 725 *(short *) &sc->eg_pcb[14])); 726 DPRINTF(("overrun errors %d\n", 727 *(short *) &sc->eg_pcb[16])); 728 serviced = 1; 729 break; 730 731 default: 732 printf("%s: egintr: Unknown response %x??\n", 733 sc->sc_dev.dv_xname, sc->eg_pcb[0]); 734 egprintpcb(sc->eg_pcb); 735 break; 736 } 737 738 #if NRND > 0 739 rnd_add_uint32(&sc->rnd_source, sc->eg_pcb[0]); 740 #endif 741 } 742 743 return serviced; 744 } 745 746 /* 747 * Pass a packet up to the higher levels. 748 */ 749 void 750 egread(sc, buf, len) 751 struct eg_softc *sc; 752 caddr_t buf; 753 int len; 754 { 755 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 756 struct mbuf *m; 757 758 if (len <= sizeof(struct ether_header) || 759 len > ETHER_MAX_LEN) { 760 printf("%s: invalid packet size %d; dropping\n", 761 sc->sc_dev.dv_xname, len); 762 ifp->if_ierrors++; 763 return; 764 } 765 766 /* Pull packet off interface. */ 767 m = egget(sc, buf, len); 768 if (m == 0) { 769 ifp->if_ierrors++; 770 return; 771 } 772 773 ifp->if_ipackets++; 774 775 #if NBPFILTER > 0 776 /* 777 * Check if there's a BPF listener on this interface. 778 * If so, hand off the raw packet to BPF. 779 */ 780 if (ifp->if_bpf) 781 bpf_mtap(ifp->if_bpf, m); 782 #endif 783 784 (*ifp->if_input)(ifp, m); 785 } 786 787 /* 788 * convert buf into mbufs 789 */ 790 struct mbuf * 791 egget(sc, buf, totlen) 792 struct eg_softc *sc; 793 caddr_t buf; 794 int totlen; 795 { 796 struct ifnet *ifp = &sc->sc_ethercom.ec_if; 797 struct mbuf *m, *m0, *newm; 798 int len; 799 800 MGETHDR(m0, M_DONTWAIT, MT_DATA); 801 if (m0 == 0) 802 return (0); 803 m0->m_pkthdr.rcvif = ifp; 804 m0->m_pkthdr.len = totlen; 805 len = MHLEN; 806 m = m0; 807 808 while (totlen > 0) { 809 if (totlen >= MINCLSIZE) { 810 MCLGET(m, M_DONTWAIT); 811 if ((m->m_flags & M_EXT) == 0) 812 goto bad; 813 len = MCLBYTES; 814 } 815 816 m->m_len = len = min(totlen, len); 817 memcpy(mtod(m, caddr_t), (caddr_t)buf, len); 818 buf += len; 819 820 totlen -= len; 821 if (totlen > 0) { 822 MGET(newm, M_DONTWAIT, MT_DATA); 823 if (newm == 0) 824 goto bad; 825 len = MLEN; 826 m = m->m_next = newm; 827 } 828 } 829 830 return (m0); 831 832 bad: 833 m_freem(m0); 834 return (0); 835 } 836 837 int 838 egioctl(ifp, cmd, data) 839 struct ifnet *ifp; 840 u_long cmd; 841 caddr_t data; 842 { 843 struct eg_softc *sc = ifp->if_softc; 844 struct ifaddr *ifa = (struct ifaddr *)data; 845 int s, error = 0; 846 847 s = splnet(); 848 849 switch (cmd) { 850 851 case SIOCSIFADDR: 852 ifp->if_flags |= IFF_UP; 853 854 switch (ifa->ifa_addr->sa_family) { 855 #ifdef INET 856 case AF_INET: 857 eginit(sc); 858 arp_ifinit(ifp, ifa); 859 break; 860 #endif 861 #ifdef NS 862 case AF_NS: 863 { 864 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 865 866 if (ns_nullhost(*ina)) 867 ina->x_host = 868 *(union ns_host *)LLADDR(ifp->if_sadl); 869 else 870 memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host, 871 ETHER_ADDR_LEN); 872 /* Set new address. */ 873 eginit(sc); 874 break; 875 } 876 #endif 877 default: 878 eginit(sc); 879 break; 880 } 881 break; 882 883 case SIOCSIFFLAGS: 884 if ((ifp->if_flags & IFF_UP) == 0 && 885 (ifp->if_flags & IFF_RUNNING) != 0) { 886 /* 887 * If interface is marked down and it is running, then 888 * stop it. 889 */ 890 egstop(sc); 891 ifp->if_flags &= ~IFF_RUNNING; 892 } else if ((ifp->if_flags & IFF_UP) != 0 && 893 (ifp->if_flags & IFF_RUNNING) == 0) { 894 /* 895 * If interface is marked up and it is stopped, then 896 * start it. 897 */ 898 eginit(sc); 899 } else { 900 sc->eg_pcb[0] = EG_CMD_GETSTATS; 901 sc->eg_pcb[1] = 0; 902 if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) 903 DPRINTF(("write error\n")); 904 /* 905 * XXX deal with flags changes: 906 * IFF_MULTICAST, IFF_PROMISC, 907 * IFF_LINK0, IFF_LINK1, 908 */ 909 } 910 break; 911 912 default: 913 error = EINVAL; 914 break; 915 } 916 917 splx(s); 918 return error; 919 } 920 921 void 922 egreset(sc) 923 struct eg_softc *sc; 924 { 925 int s; 926 927 DPRINTF(("%s: egreset()\n", sc->sc_dev.dv_xname)); 928 s = splnet(); 929 egstop(sc); 930 eginit(sc); 931 splx(s); 932 } 933 934 void 935 egwatchdog(ifp) 936 struct ifnet *ifp; 937 { 938 struct eg_softc *sc = ifp->if_softc; 939 940 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); 941 sc->sc_ethercom.ec_if.if_oerrors++; 942 943 egreset(sc); 944 } 945 946 void 947 egstop(sc) 948 struct eg_softc *sc; 949 { 950 951 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EG_CONTROL, 0); 952 } 953