|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: if_3c501.c ! 28: * Author: Philippe Bernadat ! 29: * Date: 1989 ! 30: * Copyright (c) 1989 OSF Research Institute ! 31: * ! 32: * 3COM Etherlink 3C501 Mach Ethernet drvier ! 33: */ ! 34: /* ! 35: Copyright 1990 by Open Software Foundation, ! 36: Cambridge, MA. ! 37: ! 38: All Rights Reserved ! 39: ! 40: Permission to use, copy, modify, and distribute this software and ! 41: its documentation for any purpose and without fee is hereby granted, ! 42: provided that the above copyright notice appears in all copies and ! 43: that both the copyright notice and this permission notice appear in ! 44: supporting documentation, and that the name of OSF or Open Software ! 45: Foundation not be used in advertising or publicity pertaining to ! 46: distribution of the software without specific, written prior ! 47: permission. ! 48: ! 49: OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 50: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, ! 51: IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR ! 52: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 53: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, ! 54: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ! 55: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 56: */ ! 57: ! 58: #include <at3c501.h> ! 59: ! 60: #ifdef MACH_KERNEL ! 61: #include <kern/time_out.h> ! 62: #include <device/device_types.h> ! 63: #include <device/errno.h> ! 64: #include <device/io_req.h> ! 65: #include <device/if_hdr.h> ! 66: #include <device/if_ether.h> ! 67: #include <device/net_status.h> ! 68: #include <device/net_io.h> ! 69: #else MACH_KERNEL ! 70: #include <sys/param.h> ! 71: #include <mach/machine/vm_param.h> ! 72: #include <sys/systm.h> ! 73: #include <sys/mbuf.h> ! 74: #include <sys/buf.h> ! 75: #include <sys/protosw.h> ! 76: #include <sys/socket.h> ! 77: #include <sys/vmmac.h> ! 78: #include <sys/ioctl.h> ! 79: #include <sys/errno.h> ! 80: #include <sys/syslog.h> ! 81: ! 82: #include <net/if.h> ! 83: #include <net/netisr.h> ! 84: #include <net/route.h> ! 85: ! 86: #ifdef INET ! 87: #include <netinet/in.h> ! 88: #include <netinet/in_systm.h> ! 89: #include <netinet/in_var.h> ! 90: #include <netinet/ip.h> ! 91: #include <netinet/if_ether.h> ! 92: #endif ! 93: ! 94: #ifdef NS ! 95: #include <netns/ns.h> ! 96: #include <netns/ns_if.h> ! 97: #endif ! 98: #endif MACH_KERNEL ! 99: ! 100: #include <i386/ipl.h> ! 101: #include <chips/busses.h> ! 102: #include <i386at/if_3c501.h> ! 103: ! 104: #define SPLNET spl6 ! 105: ! 106: int at3c501probe(); ! 107: void at3c501attach(); ! 108: int at3c501intr(); ! 109: int at3c501init(); ! 110: int at3c501output(); ! 111: int at3c501ioctl(); ! 112: int at3c501reset(); ! 113: int at3c501watch(); ! 114: ! 115: static vm_offset_t at3c501_std[NAT3C501] = { 0 }; ! 116: static struct bus_device *at3c501_info[NAT3C501]; ! 117: struct bus_driver at3c501driver = ! 118: {at3c501probe, 0, at3c501attach, 0, at3c501_std, "et", at3c501_info, }; ! 119: ! 120: int watchdog_id; ! 121: ! 122: typedef struct { ! 123: #ifdef MACH_KERNEL ! 124: struct ifnet ds_if; /* generic interface header */ ! 125: u_char ds_addr[6]; /* Ethernet hardware address */ ! 126: #else MACH_KERNEL ! 127: struct arpcom at3c501_ac; ! 128: #define ds_if at3c501_ac.ac_if ! 129: #define ds_addr at3c501_ac.ac_enaddr ! 130: #endif MACH_KERNEL ! 131: int flags; ! 132: int timer; ! 133: char *base; ! 134: u_char address[ETHER_ADD_SIZE]; ! 135: short mode; ! 136: int badxmt; ! 137: int badrcv; ! 138: int spurious; ! 139: int rcv; ! 140: int xmt; ! 141: } at3c501_softc_t; ! 142: ! 143: at3c501_softc_t at3c501_softc[NAT3C501]; ! 144: ! 145: /* ! 146: * at3c501probe: ! 147: * ! 148: * This function "probes" or checks for the 3c501 board on the bus to see ! 149: * if it is there. As far as I can tell, the best break between this ! 150: * routine and the attach code is to simply determine whether the board ! 151: * is configured in properly. Currently my approach to this is to write ! 152: * and read a string from the Packet Buffer on the board being probed. ! 153: * If the string comes back properly then we assume the board is there. ! 154: * The config code expects to see a successful return from the probe ! 155: * routine before attach will be called. ! 156: * ! 157: * input : address device is mapped to, and unit # being checked ! 158: * output : a '1' is returned if the board exists, and a 0 otherwise ! 159: * ! 160: */ ! 161: at3c501probe(port, dev) ! 162: struct bus_device *dev; ! 163: { ! 164: caddr_t base = (caddr_t)dev->address; ! 165: int unit = dev->unit; ! 166: char inbuf[50]; ! 167: char *str = "3c501 ethernet board %d out of range\n"; ! 168: int strsize = strlen(str); ! 169: ! 170: if ((unit < 0) || (unit >= NAT3C501)) { ! 171: printf(str, unit); ! 172: return(0); ! 173: } ! 174: ! 175: /* reset */ ! 176: outb(IE_CSR(base), IE_RESET); ! 177: ! 178: /* write a string to the packet buffer */ ! 179: ! 180: outb(IE_CSR(base), IE_RIDE | IE_SYSBFR); ! 181: outw(IE_GP(base), 0); ! 182: loutb(IE_BFR(base), str, strsize); ! 183: ! 184: /* read it back */ ! 185: ! 186: outb(IE_CSR(base), IE_RIDE | IE_SYSBFR); ! 187: outw(IE_GP(base), 0); ! 188: linb(IE_BFR(base), inbuf, strsize); ! 189: /* compare them */ ! 190: ! 191: #ifdef MACH_KERNEL ! 192: if (strncmp(str, inbuf, strsize)) ! 193: #else MACH_KERNEL ! 194: if (bcmp(str, inbuf, strsize)) ! 195: #endif MACH_KERNEL ! 196: { ! 197: return(0); ! 198: } ! 199: at3c501_softc[unit].base = base; ! 200: ! 201: return(1); ! 202: } ! 203: ! 204: /* ! 205: * at3c501attach: ! 206: * ! 207: * This function attaches a 3C501 board to the "system". The rest of ! 208: * runtime structures are initialized here (this routine is called after ! 209: * a successful probe of the board). Once the ethernet address is read ! 210: * and stored, the board's ifnet structure is attached and readied. ! 211: * ! 212: * input : bus_device structure setup in autoconfig ! 213: * output : board structs and ifnet is setup ! 214: * ! 215: */ ! 216: void at3c501attach(dev) ! 217: struct bus_device *dev; ! 218: { ! 219: at3c501_softc_t *sp; ! 220: struct ifnet *ifp; ! 221: u_char unit; ! 222: caddr_t base; ! 223: #ifdef MACH_KERNEL ! 224: #else MACH_KERNEL ! 225: extern int tcp_recvspace; ! 226: tcp_recvspace = 0x300; /* empircal messure */ ! 227: #endif MACH_KERNEL ! 228: ! 229: take_dev_irq(dev); ! 230: unit = (u_char)dev->unit; ! 231: printf(", port = %x, spl = %d, pic = %d. ", ! 232: dev->address, dev->sysdep, dev->sysdep1); ! 233: ! 234: sp = &at3c501_softc[unit]; ! 235: base = sp->base; ! 236: if (base != (caddr_t)dev->address) { ! 237: printf("3C501 board %d attach address error\n", unit); ! 238: return; ! 239: } ! 240: sp->timer = -1; ! 241: sp->flags = 0; ! 242: sp->mode = 0; ! 243: outb(IE_CSR(sp->base), IE_RESET); ! 244: at3c501geteh(base, sp->ds_addr); ! 245: at3c501geteh(base, sp->address); ! 246: at3c501seteh(base, sp->address); ! 247: printf("ethernet id [%x:%x:%x:%x:%x:%x]", ! 248: sp->address[0],sp->address[1],sp->address[2], ! 249: sp->address[3],sp->address[4],sp->address[5]); ! 250: ifp = &(sp->ds_if); ! 251: ifp->if_unit = unit; ! 252: ifp->if_mtu = ETHERMTU; ! 253: ifp->if_flags = IFF_BROADCAST; ! 254: #ifdef MACH_KERNEL ! 255: ifp->if_header_size = sizeof(struct ether_header); ! 256: ifp->if_header_format = HDR_ETHERNET; ! 257: ifp->if_address_size = 6; ! 258: ifp->if_address = (char *)&sp->address[0]; ! 259: if_init_queues(ifp); ! 260: #else MACH_KERNEL ! 261: ifp->if_name = "et"; ! 262: ifp->if_init = at3c501init; ! 263: ifp->if_output = at3c501output; ! 264: ifp->if_ioctl = at3c501ioctl; ! 265: ifp->if_reset = at3c501reset; ! 266: ifp->if_next = NULL; ! 267: if_attach(ifp); ! 268: #ifdef notdef ! 269: watchdog_id = timeout(at3c501watch, &(ifp->if_unit), 20*HZ); ! 270: #endif ! 271: #endif MACH_KERNEL ! 272: } ! 273: ! 274: /* ! 275: * at3c501watch(): ! 276: * ! 277: */ ! 278: at3c501watch(b_ptr) ! 279: ! 280: caddr_t b_ptr; ! 281: ! 282: { ! 283: int x, ! 284: y, ! 285: opri, ! 286: unit; ! 287: at3c501_softc_t *is; ! 288: ! 289: unit = *b_ptr; ! 290: #ifdef MACH_KERNEL ! 291: timeout(at3c501watch,b_ptr,20*hz); ! 292: #else MACH_KERNEL ! 293: watchdog_id = timeout(at3c501watch,b_ptr,20*HZ); ! 294: #endif MACH_KERNEL ! 295: is = &at3c501_softc[unit]; ! 296: printf("\nxmt/bad rcv/bad spurious\n"); ! 297: printf("%d/%d %d/%d %d\n", is->xmt, is->badxmt, \ ! 298: is->rcv, is->badrcv, is->spurious); ! 299: is->rcv=is->badrcv=is->xmt=is->badxmt=is->spurious=0; ! 300: } ! 301: ! 302: /* ! 303: * at3c501geteh: ! 304: * ! 305: * This function gets the ethernet address (array of 6 unsigned ! 306: * bytes) from the 3c501 board prom. ! 307: * ! 308: */ ! 309: ! 310: at3c501geteh(base, ep) ! 311: caddr_t base; ! 312: char *ep; ! 313: { ! 314: int i; ! 315: ! 316: for (i = 0; i < ETHER_ADD_SIZE; i++) { ! 317: outw(IE_GP(base), i); ! 318: *ep++ = inb(IE_SAPROM(base)); ! 319: } ! 320: } ! 321: ! 322: /* ! 323: * at3c501seteh: ! 324: * ! 325: * This function sets the ethernet address (array of 6 unsigned ! 326: * bytes) on the 3c501 board. ! 327: * ! 328: */ ! 329: ! 330: at3c501seteh(base, ep) ! 331: caddr_t base; ! 332: char *ep; ! 333: { ! 334: int i; ! 335: ! 336: for (i = 0; i < ETHER_ADD_SIZE; i++) { ! 337: outb(EDLC_ADDR(base) + i, *ep++); ! 338: } ! 339: } ! 340: ! 341: #ifdef MACH_KERNEL ! 342: int at3c501start(); /* forward */ ! 343: ! 344: at3c501output(dev, ior) ! 345: dev_t dev; ! 346: io_req_t ior; ! 347: { ! 348: register int unit = minor(dev); ! 349: ! 350: if (unit < 0 || unit >= NAT3C501 || ! 351: at3c501_softc[unit].base == 0) ! 352: return (ENXIO); ! 353: ! 354: return (net_write(&at3c501_softc[unit].ds_if, at3c501start, ior)); ! 355: } ! 356: ! 357: at3c501setinput(dev, receive_port, priority, filter, filter_count) ! 358: dev_t dev; ! 359: mach_port_t receive_port; ! 360: int priority; ! 361: filter_t filter[]; ! 362: u_int filter_count; ! 363: { ! 364: register int unit = minor(dev); ! 365: ! 366: if (unit < 0 || unit >= NAT3C501 || ! 367: at3c501_softc[unit].base == 0) ! 368: return (ENXIO); ! 369: ! 370: return (net_set_filter(&at3c501_softc[unit].ds_if, ! 371: receive_port, priority, ! 372: filter, filter_count)); ! 373: } ! 374: ! 375: #else MACH_KERNEL ! 376: /* ! 377: * at3c501output: ! 378: * ! 379: * This routine is called by the "if" layer to output a packet to ! 380: * the network. This code resolves the local ethernet address, and ! 381: * puts it into the mbuf if there is room. If not, then a new mbuf ! 382: * is allocated with the header information and precedes the data ! 383: * to be transmitted. ! 384: * ! 385: * input: ifnet structure pointer, an mbuf with data, and address ! 386: * to be resolved ! 387: * output: mbuf is updated to hold enet address, or a new mbuf ! 388: * with the address is added ! 389: * ! 390: */ ! 391: at3c501output(ifp, m0, dst) ! 392: struct ifnet *ifp; ! 393: struct mbuf *m0; ! 394: struct sockaddr *dst; ! 395: { ! 396: int type, error; ! 397: spl_t opri; ! 398: u_char edst[6]; ! 399: struct in_addr idst; ! 400: register at3c501_softc_t *is; ! 401: register struct mbuf *m = m0; ! 402: register struct ether_header *eh; ! 403: register int off; ! 404: int usetrailers; ! 405: ! 406: is = &at3c501_softc[ifp->if_unit]; ! 407: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 408: printf("3C501 Turning off board %d\n", ifp->if_unit); ! 409: at3c501intoff(ifp->if_unit); ! 410: error = ENETDOWN; ! 411: goto bad; ! 412: } ! 413: switch (dst->sa_family) { ! 414: ! 415: #ifdef INET ! 416: case AF_INET: ! 417: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 418: if (!arpresolve(&is->at3c501_ac, m, &idst, edst, &usetrailers)){ ! 419: return (0); /* if not yet resolved */ ! 420: } ! 421: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 422: ! 423: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 424: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 425: type = ETHERTYPE_TRAIL + (off>>9); ! 426: m->m_off -= 2 * sizeof (u_short); ! 427: m->m_len += 2 * sizeof (u_short); ! 428: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); ! 429: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 430: goto gottrailertype; ! 431: } ! 432: type = ETHERTYPE_IP; ! 433: off = 0; ! 434: goto gottype; ! 435: #endif ! 436: #ifdef NS ! 437: case AF_NS: ! 438: type = ETHERTYPE_NS; ! 439: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 440: (caddr_t)edst, sizeof (edst)); ! 441: off = 0; ! 442: goto gottype; ! 443: #endif ! 444: ! 445: case AF_UNSPEC: ! 446: eh = (struct ether_header *)dst->sa_data; ! 447: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 448: type = eh->ether_type; ! 449: goto gottype; ! 450: ! 451: default: ! 452: printf("at3c501%d: can't handle af%d\n", ifp->if_unit, ! 453: dst->sa_family); ! 454: error = EAFNOSUPPORT; ! 455: goto bad; ! 456: } ! 457: ! 458: gottrailertype: ! 459: /* ! 460: * Packet to be sent as trailer: move first packet ! 461: * (control information) to end of chain. ! 462: */ ! 463: while (m->m_next) ! 464: m = m->m_next; ! 465: m->m_next = m0; ! 466: m = m0->m_next; ! 467: m0->m_next = 0; ! 468: m0 = m; ! 469: ! 470: gottype: ! 471: /* ! 472: * Add local net header. If no space in first mbuf, ! 473: * allocate another. ! 474: */ ! 475: if (m->m_off > MMAXOFF || ! 476: MMINOFF + sizeof (struct ether_header) > m->m_off) { ! 477: m = m_get(M_DONTWAIT, MT_HEADER); ! 478: if (m == 0) { ! 479: error = ENOBUFS; ! 480: goto bad; ! 481: } ! 482: m->m_next = m0; ! 483: m->m_off = MMINOFF; ! 484: m->m_len = sizeof (struct ether_header); ! 485: } else { ! 486: m->m_off -= sizeof (struct ether_header); ! 487: m->m_len += sizeof (struct ether_header); ! 488: } ! 489: eh = mtod(m, struct ether_header *); ! 490: eh->ether_type = htons((u_short)type); ! 491: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); ! 492: bcopy((caddr_t)is->address,(caddr_t)eh->ether_shost, ! 493: sizeof(edst)); ! 494: /* ! 495: * Queue message on interface, and start output if interface ! 496: * not yet active. ! 497: */ ! 498: opri = SPLNET(); ! 499: if (IF_QFULL(&ifp->if_snd)) { ! 500: IF_DROP(&ifp->if_snd); ! 501: splx(opri); ! 502: m_freem(m); ! 503: return (ENOBUFS); ! 504: } ! 505: IF_ENQUEUE(&ifp->if_snd, m); ! 506: /* ! 507: * Some action needs to be added here for checking whether the ! 508: * board is already transmitting. If it is, we don't want to ! 509: * start it up (ie call at3c501start()). We will attempt to send ! 510: * packets that are queued up after an interrupt occurs. Some ! 511: * flag checking action has to happen here and/or in the start ! 512: * routine. This note is here to remind me that some thought ! 513: * is needed and there is a potential problem here. ! 514: * ! 515: */ ! 516: at3c501start(ifp->if_unit); ! 517: splx(opri); ! 518: return (0); ! 519: ! 520: bad: ! 521: m_freem(m0); ! 522: return (error); ! 523: } ! 524: #endif MACH_KERNEL ! 525: ! 526: /* ! 527: * at3c501reset: ! 528: * ! 529: * This routine is in part an entry point for the "if" code. Since most ! 530: * of the actual initialization has already (we hope already) been done ! 531: * by calling at3c501attach(). ! 532: * ! 533: * input : unit number or board number to reset ! 534: * output : board is reset ! 535: * ! 536: */ ! 537: at3c501reset(unit) ! 538: int unit; ! 539: { ! 540: at3c501_softc[unit].ds_if.if_flags &= ~IFF_RUNNING; ! 541: return(at3c501init(unit)); ! 542: } ! 543: ! 544: ! 545: ! 546: /* ! 547: * at3c501init: ! 548: * ! 549: * Another routine that interfaces the "if" layer to this driver. ! 550: * Simply resets the structures that are used by "upper layers". ! 551: * As well as calling at3c501hwrst that does reset the at3c501 board. ! 552: * ! 553: * input : board number ! 554: * output : structures (if structs) and board are reset ! 555: * ! 556: */ ! 557: at3c501init(unit) ! 558: int unit; ! 559: { ! 560: struct ifnet *ifp; ! 561: int stat; ! 562: spl_t oldpri; ! 563: ! 564: ifp = &(at3c501_softc[unit].ds_if); ! 565: #ifdef MACH_KERNEL ! 566: #else MACH_KERNEL ! 567: if (ifp->if_addrlist == (struct ifaddr *)0) { ! 568: return; ! 569: } ! 570: #endif MACH_KERNEL ! 571: oldpri = SPLNET(); ! 572: if ((stat = at3c501hwrst(unit)) == TRUE) { ! 573: at3c501_softc[unit].ds_if.if_flags |= IFF_RUNNING; ! 574: at3c501_softc[unit].flags |= DSF_RUNNING; ! 575: at3c501start(unit); ! 576: } ! 577: else ! 578: printf("3C501 trouble resetting board %d\n", unit); ! 579: at3c501_softc[unit].timer = 5; ! 580: splx(oldpri); ! 581: return(stat); ! 582: ! 583: } ! 584: ! 585: #ifdef MACH_KERNEL ! 586: /*ARGSUSED*/ ! 587: at3c501open(dev, flag) ! 588: dev_t dev; ! 589: int flag; ! 590: { ! 591: register int unit = minor(dev); ! 592: ! 593: if (unit < 0 || unit >= NAT3C501 || ! 594: at3c501_softc[unit].base == 0) ! 595: return (ENXIO); ! 596: ! 597: at3c501_softc[unit].ds_if.if_flags |= IFF_UP; ! 598: at3c501init(unit); ! 599: return(0); ! 600: } ! 601: #endif MACH_KERNEL ! 602: ! 603: /* ! 604: * at3c501start: ! 605: * ! 606: * This is yet another interface routine that simply tries to output a ! 607: * in an mbuf after a reset. ! 608: * ! 609: * input : board number ! 610: * output : stuff sent to board if any there ! 611: * ! 612: */ ! 613: at3c501start(unit) ! 614: int unit; ! 615: ! 616: { ! 617: #ifdef MACH_KERNEL ! 618: io_req_t m; ! 619: #else MACH_KERNEL ! 620: struct mbuf *m; ! 621: #endif MACH_KERNEL ! 622: struct ifnet *ifp; ! 623: ! 624: ifp = &(at3c501_softc[unit].ds_if); ! 625: for(;;) { ! 626: IF_DEQUEUE(&ifp->if_snd, m); ! 627: #ifdef MACH_KERNEL ! 628: if (m != 0) ! 629: #else MACH_KERNEL ! 630: if (m != (struct mbuf *)0) ! 631: #endif MACH_KERNEL ! 632: at3c501xmt(unit, m); ! 633: else ! 634: return; ! 635: } ! 636: } ! 637: ! 638: #ifdef MACH_KERNEL ! 639: /*ARGSUSED*/ ! 640: at3c501getstat(dev, flavor, status, count) ! 641: dev_t dev; ! 642: int flavor; ! 643: dev_status_t status; /* pointer to OUT array */ ! 644: u_int *count; /* out */ ! 645: { ! 646: register int unit = minor(dev); ! 647: ! 648: if (unit < 0 || unit >= NAT3C501 || ! 649: at3c501_softc[unit].base == 0) ! 650: return (ENXIO); ! 651: ! 652: return (net_getstat(&at3c501_softc[unit].ds_if, ! 653: flavor, ! 654: status, ! 655: count)); ! 656: } ! 657: ! 658: at3c501setstat(dev, flavor, status, count) ! 659: dev_t dev; ! 660: int flavor; ! 661: dev_status_t status; ! 662: u_int count; ! 663: { ! 664: register int unit = minor(dev); ! 665: register at3c501_softc_t *sp; ! 666: ! 667: if (unit < 0 || unit >= NAT3C501 || ! 668: at3c501_softc[unit].base == 0) ! 669: return (ENXIO); ! 670: ! 671: sp = &at3c501_softc[unit]; ! 672: ! 673: switch (flavor) { ! 674: case NET_STATUS: ! 675: { ! 676: /* ! 677: * All we can change are flags, and not many of those. ! 678: */ ! 679: register struct net_status *ns = (struct net_status *)status; ! 680: int mode = 0; ! 681: ! 682: if (count < NET_STATUS_COUNT) ! 683: return (D_INVALID_SIZE); ! 684: ! 685: if (ns->flags & IFF_ALLMULTI) ! 686: mode |= MOD_ENAL; ! 687: if (ns->flags & IFF_PROMISC) ! 688: mode |= MOD_PROM; ! 689: ! 690: /* ! 691: * Force a compilete reset if the receive mode changes ! 692: * so that these take effect immediately. ! 693: */ ! 694: if (sp->mode != mode) { ! 695: sp->mode = mode; ! 696: if (sp->flags & DSF_RUNNING) { ! 697: sp->flags &= ~(DSF_LOCK | DSF_RUNNING); ! 698: at3c501init(unit); ! 699: } ! 700: } ! 701: break; ! 702: } ! 703: case NET_ADDRESS: ! 704: { ! 705: register union ether_cvt { ! 706: char addr[6]; ! 707: int lwd[2]; ! 708: } *ec = (union ether_cvt *)status; ! 709: ! 710: if (count < sizeof(*ec)/sizeof(int)) ! 711: return (D_INVALID_SIZE); ! 712: ! 713: ec->lwd[0] = ntohl(ec->lwd[0]); ! 714: ec->lwd[1] = ntohl(ec->lwd[1]); ! 715: at3c501seteh(sp->base, ec->addr); ! 716: break; ! 717: } ! 718: ! 719: default: ! 720: return (D_INVALID_OPERATION); ! 721: } ! 722: return (D_SUCCESS); ! 723: } ! 724: #else MACH_KERNEL ! 725: ! 726: /* ! 727: * at3c501ioctl: ! 728: * ! 729: * This routine processes an ioctl request from the "if" layer ! 730: * above. ! 731: * ! 732: * input : pointer the appropriate "if" struct, command, and data ! 733: * output : based on command appropriate action is taken on the ! 734: * at3c501 board(s) or related structures ! 735: * return : error is returned containing exit conditions ! 736: * ! 737: */ ! 738: int curr_ipl; ! 739: u_short curr_pic_mask; ! 740: u_short pic_mask[]; ! 741: ! 742: at3c501ioctl(ifp, cmd, data) ! 743: struct ifnet *ifp; ! 744: int cmd; ! 745: caddr_t data; ! 746: { ! 747: register struct ifaddr *ifa = (struct ifaddr *)data; ! 748: register at3c501_softc_t *is; ! 749: int error; ! 750: spl_t opri; ! 751: short mode = 0; ! 752: ! 753: is = &at3c501_softc[ifp->if_unit]; ! 754: opri = SPLNET(); ! 755: error = 0; ! 756: switch (cmd) { ! 757: case SIOCSIFADDR: ! 758: ifp->if_flags |= IFF_UP; ! 759: at3c501init(ifp->if_unit); ! 760: switch (ifa->ifa_addr.sa_family) { ! 761: #ifdef INET ! 762: case AF_INET: ! 763: ((struct arpcom *)ifp)->ac_ipaddr = ! 764: IA_SIN(ifa)->sin_addr; ! 765: arpwhohas((struct arpcom *)ifp, ! 766: &IA_SIN(ifa)->sin_addr); ! 767: break; ! 768: #endif ! 769: #ifdef NS ! 770: case AF_NS: ! 771: { ! 772: register struct ns_addr *ina = ! 773: &(IA_SNS(ifa)->sns_addr); ! 774: if (ns_nullhost(*ina)) ! 775: ina->x_host = ! 776: *(union ns_host *)(ds->ds_addr); ! 777: else ! 778: at3c501seteh(ina->x_host.c_host, ! 779: at3c501_softc[ifp->if_unit].base); ! 780: break; ! 781: } ! 782: #endif ! 783: } ! 784: break; ! 785: case SIOCSIFFLAGS: ! 786: if (ifp->if_flags & IFF_ALLMULTI) ! 787: mode |= MOD_ENAL; ! 788: if (ifp->if_flags & IFF_PROMISC) ! 789: mode |= MOD_PROM; ! 790: /* ! 791: * force a complete reset if the receive multicast/ ! 792: * promiscuous mode changes so that these take ! 793: * effect immediately. ! 794: * ! 795: */ ! 796: if (is->mode != mode) { ! 797: is->mode = mode; ! 798: if (is->flags & DSF_RUNNING) { ! 799: is->flags &= ! 800: ~(DSF_LOCK|DSF_RUNNING); ! 801: at3c501init(ifp->if_unit); ! 802: } ! 803: } ! 804: if ((ifp->if_flags & IFF_UP) == 0 && ! 805: is->flags & DSF_RUNNING) { ! 806: printf("AT3C501 ioctl: turning off board %d\n", ! 807: ifp->if_unit); ! 808: is->flags &= ~(DSF_LOCK | DSF_RUNNING); ! 809: is->timer = -1; ! 810: at3c501intoff(ifp->if_unit); ! 811: } else ! 812: if (ifp->if_flags & IFF_UP && ! 813: (is->flags & DSF_RUNNING) == 0) ! 814: at3c501init(ifp->if_unit); ! 815: break; ! 816: default: ! 817: error = EINVAL; ! 818: } ! 819: splx(opri); ! 820: return (error); ! 821: } ! 822: #endif MACH_KERNEL ! 823: ! 824: ! 825: /* ! 826: * at3c501hwrst: ! 827: * ! 828: * This routine resets the at3c501 board that corresponds to the ! 829: * board number passed in. ! 830: * ! 831: * input : board number to do a hardware reset ! 832: * output : board is reset ! 833: * ! 834: */ ! 835: #define XMT_STAT (EDLC_16|EDLC_JAM|EDLC_UNDER|EDLC_IDLE) ! 836: #define RCV_STAT (EDLC_STALE|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_OVER|EDLC_FCS) ! 837: int ! 838: at3c501hwrst(unit) ! 839: int unit; ! 840: { ! 841: u_char stat; ! 842: caddr_t base = at3c501_softc[unit].base; ! 843: ! 844: outb(IE_CSR(base), IE_RESET); ! 845: outb(IE_CSR(base), 0); ! 846: at3c501seteh(base, at3c501_softc[unit].address); ! 847: if ((stat = inb(IE_CSR(base))) != IE_RESET) { ! 848: printf("at3c501reset: can't reset CSR: %x\n", stat); ! 849: return(FALSE); ! 850: } ! 851: if ((stat = inb(EDLC_XMT(base))) & XMT_STAT) { ! 852: printf("at3c501reset: can't reset XMT: %x\n", stat); ! 853: return(FALSE); ! 854: } ! 855: if (((stat = inb(EDLC_RCV(base))) & RCV_STAT) != EDLC_STALE) { ! 856: printf("at3c501reset: can't reset RCV: %x\n", stat); ! 857: return(FALSE); ! 858: } ! 859: if (at3c501config(unit) == FALSE) { ! 860: printf("at3c501hwrst(): failed to config\n"); ! 861: return(FALSE); ! 862: } ! 863: outb(IE_RP(base), 0); ! 864: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 865: return(TRUE); ! 866: } ! 867: ! 868: /* ! 869: * at3c501intr: ! 870: * ! 871: * This function is the interrupt handler for the at3c501 ethernet ! 872: * board. This routine will be called whenever either a packet ! 873: * is received, or a packet has successfully been transfered and ! 874: * the unit is ready to transmit another packet. ! 875: * ! 876: * input : board number that interrupted ! 877: * output : either a packet is received, or a packet is transfered ! 878: * ! 879: */ ! 880: at3c501intr(unit) ! 881: int unit; ! 882: { ! 883: at3c501rcv(unit); ! 884: at3c501start(unit); ! 885: ! 886: return(0); ! 887: } ! 888: ! 889: ! 890: /* ! 891: * at3c501rcv: ! 892: * ! 893: * This routine is called by the interrupt handler to initiate a ! 894: * packet transfer from the board to the "if" layer above this ! 895: * driver. This routine checks if a buffer has been successfully ! 896: * received by the at3c501. If so, the routine at3c501read is called ! 897: * to do the actual transfer of the board data (including the ! 898: * ethernet header) into a packet (consisting of an mbuf chain). ! 899: * ! 900: * input : number of the board to check ! 901: * output : if a packet is available, it is "sent up" ! 902: * ! 903: */ ! 904: at3c501rcv(unit) ! 905: int unit; ! 906: { ! 907: int stat; ! 908: caddr_t base; ! 909: #ifdef MACH_KERNEL ! 910: ipc_kmsg_t new_kmsg; ! 911: struct ether_header *ehp; ! 912: struct packet_header *pkt; ! 913: #else MACH_KERNEL ! 914: struct mbuf *m, *tm; ! 915: #endif MACH_KERNEL ! 916: u_short len; ! 917: register struct ifnet *ifp; ! 918: struct ether_header header; ! 919: int tlen; ! 920: register at3c501_softc_t *is; ! 921: register struct ifqueue *inq; ! 922: spl_t opri; ! 923: struct ether_header eh; ! 924: ! 925: is = &at3c501_softc[unit]; ! 926: ifp = &is->ds_if; ! 927: base = at3c501_softc[unit].base; ! 928: is->rcv++; ! 929: if (inb(IE_CSR(base)) & IE_RCVBSY) ! 930: is->spurious++; ! 931: while (!((stat=inb(EDLC_RCV(base))) & EDLC_STALE)) { ! 932: outb(IE_CSR(base), IE_SYSBFR); ! 933: if (!(stat & EDLC_ANY)) { ! 934: outw(IE_GP(base), 0); ! 935: len = inw(IE_RP(base))-sizeof(struct ether_header); ! 936: outb(IE_RP(base), 0); ! 937: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 938: is->badrcv++; ! 939: #ifdef DEBUG ! 940: printf("at3c501rcv: received %d bad bytes", len); ! 941: if (stat & EDLC_SHORT) ! 942: printf(" Short frame"); ! 943: if (stat & EDLC_OVER) ! 944: printf(" Data overflow"); ! 945: if (stat & EDLC_DRIBBLE) ! 946: printf(" Dribble error"); ! 947: if (stat & EDLC_FCS) ! 948: printf(" CRC error"); ! 949: printf("\n"); ! 950: #endif DEBUG ! 951: } else { ! 952: outw(IE_GP(base), 0); ! 953: len = inw(IE_RP(base)); ! 954: if (len < 60) { ! 955: outb(IE_RP(base), 0); ! 956: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 957: return; ! 958: } ! 959: linb(IE_BFR(base), &eh, sizeof(struct ether_header)); ! 960: #ifdef MACH_KERNEL ! 961: new_kmsg = net_kmsg_get(); ! 962: if (new_kmsg == IKM_NULL) { ! 963: /* ! 964: * Drop the packet. ! 965: */ ! 966: is->ds_if.if_rcvdrops++; ! 967: ! 968: outb(IE_RP(base), 0); ! 969: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 970: return; ! 971: } ! 972: ! 973: ehp = (struct ether_header *) ! 974: (&net_kmsg(new_kmsg)->header[0]); ! 975: pkt = (struct packet_header *) ! 976: (&net_kmsg(new_kmsg)->packet[0]); ! 977: ! 978: /* ! 979: * Get header. ! 980: */ ! 981: *ehp = eh; ! 982: ! 983: /* ! 984: * Get body ! 985: */ ! 986: linb(IE_BFR(base), ! 987: (char *)(pkt + 1), ! 988: len - sizeof(struct ether_header)); ! 989: ! 990: outb(IE_RP(base), 0); ! 991: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 992: ! 993: pkt->type = ehp->ether_type; ! 994: pkt->length = len - sizeof(struct ether_header) ! 995: + sizeof(struct packet_header); ! 996: ! 997: /* ! 998: * Hand the packet to the network module. ! 999: */ ! 1000: net_packet(ifp, new_kmsg, pkt->length, ! 1001: ethernet_priority(new_kmsg)); ! 1002: ! 1003: #else MACH_KERNEL ! 1004: eh.ether_type = htons(eh.ether_type); ! 1005: m =(struct mbuf *)0; ! 1006: #ifdef DEBUG ! 1007: printf("received %d bytes\n", len); ! 1008: #endif DEBUG ! 1009: len -= sizeof(struct ether_header); ! 1010: while ( len ) { ! 1011: if (m == (struct mbuf *)0) { ! 1012: m = m_get(M_DONTWAIT, MT_DATA); ! 1013: if (m == (struct mbuf *)0) { ! 1014: printf("at3c501rcv: Lost frame\n"); ! 1015: outb(IE_RP(base), 0); ! 1016: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 1017: ! 1018: return; ! 1019: } ! 1020: tm = m; ! 1021: tm->m_off = MMINOFF; ! 1022: /* ! 1023: * first mbuf in the packet must contain a pointer to the ! 1024: * ifnet structure. other mbufs that follow and make up ! 1025: * the packet do not need this pointer in the mbuf. ! 1026: * ! 1027: */ ! 1028: *(mtod(tm, struct ifnet **)) = ifp; ! 1029: tm->m_len = sizeof(struct ifnet **); ! 1030: } ! 1031: else { ! 1032: tm->m_next = m_get(M_DONTWAIT, MT_DATA); ! 1033: tm = tm->m_next; ! 1034: tm->m_off = MMINOFF; ! 1035: tm->m_len = 0; ! 1036: if (tm == (struct mbuf *)0) { ! 1037: m_freem(m); ! 1038: printf("at3c501rcv: No mbufs, lost frame\n"); ! 1039: outb(IE_RP(base), 0); ! 1040: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 1041: return; ! 1042: } ! 1043: } ! 1044: tlen = MIN( MLEN - tm->m_len, len ); ! 1045: tm->m_next = (struct mbuf *)0; ! 1046: linb(IE_BFR(base), mtod(tm, char *)+tm->m_len, tlen ); ! 1047: tm->m_len += tlen; ! 1048: len -= tlen; ! 1049: } ! 1050: outb(IE_RP(base), 0); ! 1051: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 1052: /* ! 1053: * received packet is now in a chain of mbuf's. next step is ! 1054: * to pass the packet upwards. ! 1055: * ! 1056: */ ! 1057: switch (eh.ether_type) { ! 1058: #ifdef INET ! 1059: case ETHERTYPE_IP: ! 1060: schednetisr(NETISR_IP); ! 1061: inq = &ipintrq; ! 1062: break; ! 1063: case ETHERTYPE_ARP: ! 1064: arpinput(&is->at3c501_ac, m); ! 1065: return; ! 1066: #endif ! 1067: #ifdef NS ! 1068: case ETHERTYPE_NS: ! 1069: schednetisr(NETISR_NS); ! 1070: inq = &nsintrq; ! 1071: break; ! 1072: #endif ! 1073: default: ! 1074: m_freem(m); ! 1075: return; ! 1076: } ! 1077: opri = SPLNET(); ! 1078: if (IF_QFULL(inq)) { ! 1079: IF_DROP(inq); ! 1080: splx(opri); ! 1081: m_freem(m); ! 1082: return; ! 1083: } ! 1084: IF_ENQUEUE(inq, m); ! 1085: splx(opri); ! 1086: #endif MACH_KERNEL ! 1087: } ! 1088: } ! 1089: } ! 1090: ! 1091: ! 1092: /* ! 1093: * at3c501xmt: ! 1094: * ! 1095: * This routine fills in the appropriate registers and memory ! 1096: * locations on the 3C501 board and starts the board off on ! 1097: * the transmit. ! 1098: * ! 1099: * input : board number of interest, and a pointer to the mbuf ! 1100: * output : board memory and registers are set for xfer and attention ! 1101: * ! 1102: */ ! 1103: at3c501xmt(unit, m) ! 1104: int unit; ! 1105: #ifdef MACH_KERNEL ! 1106: io_req_t m; ! 1107: #else MACH_KERNEL ! 1108: struct mbuf *m; ! 1109: #endif MACH_KERNEL ! 1110: { ! 1111: #ifdef MACH_KERNEL ! 1112: #else MACH_KERNEL ! 1113: register struct mbuf *tm_p; ! 1114: #endif MACH_KERNEL ! 1115: int i; ! 1116: at3c501_softc_t *is = &at3c501_softc[unit]; ! 1117: caddr_t base = is->base; ! 1118: u_short count = 0; ! 1119: u_short bytes_in_msg; ! 1120: ! 1121: is->xmt++; ! 1122: outb(IE_CSR(base), IE_SYSBFR); ! 1123: #ifdef MACH_KERNEL ! 1124: count = m->io_count; ! 1125: #define max(a,b) (((a) > (b)) ? (a) : (b)) ! 1126: bytes_in_msg = max(count, ! 1127: ETHERMIN + sizeof(struct ether_header)); ! 1128: #else MACH_KERNEL ! 1129: bytes_in_msg = max(m_length(m), ETHERMIN + sizeof(struct ether_header)); ! 1130: #endif MACH_KERNEL ! 1131: outw(IE_GP(base), BFRSIZ-bytes_in_msg); ! 1132: #ifdef MACH_KERNEL ! 1133: loutb(IE_BFR(base), m->io_data, count); ! 1134: #else MACH_KERNEL ! 1135: for (tm_p = m; tm_p != (struct mbuf *)0; tm_p = tm_p->m_next) { ! 1136: if (count + tm_p->m_len > ETHERMTU + sizeof(struct ether_header)) ! 1137: break; ! 1138: if (tm_p->m_len == 0) ! 1139: continue; ! 1140: loutb(IE_BFR(base), mtod(tm_p, caddr_t), tm_p->m_len); ! 1141: count += tm_p->m_len; ! 1142: } ! 1143: #endif MACH_KERNEL ! 1144: while (count < bytes_in_msg) { ! 1145: outb(IE_BFR(base), 0); ! 1146: count++; ! 1147: } ! 1148: do { ! 1149: if (!(int)m) { ! 1150: outb(IE_CSR(base), IE_SYSBFR); ! 1151: } ! 1152: outw(IE_GP(base), BFRSIZ-bytes_in_msg); ! 1153: outb(IE_CSR(base), IE_RIDE|IE_XMTEDLC); ! 1154: if (m) { ! 1155: #ifdef MACH_KERNEL ! 1156: iodone(m); ! 1157: m = 0; ! 1158: #else MACH_KERNEL ! 1159: m_freem(m); ! 1160: m = (struct mbuf *) 0; ! 1161: #endif MACH_KERNEL ! 1162: } ! 1163: for (i=0; inb(IE_CSR(base)) & IE_XMTBSY; i++); ! 1164: if ((i=inb(EDLC_XMT(base))) & EDLC_JAM) { ! 1165: is->badxmt++; ! 1166: #ifdef DEBUG ! 1167: printf("at3c501xmt jam\n"); ! 1168: #endif DEBUG ! 1169: } ! 1170: } while ((i & EDLC_JAM) && !(i & EDLC_16)); ! 1171: ! 1172: if (i & EDLC_16) { ! 1173: printf("%"); ! 1174: } ! 1175: return; ! 1176: ! 1177: } ! 1178: ! 1179: /* ! 1180: * at3c501config: ! 1181: * ! 1182: * This routine does a standard config of the at3c501 board. ! 1183: * ! 1184: */ ! 1185: at3c501config(unit) ! 1186: int unit; ! 1187: { ! 1188: caddr_t base = at3c501_softc[unit].base; ! 1189: u_char stat; ! 1190: ! 1191: /* Enable DMA & Interrupts */ ! 1192: ! 1193: outb(IE_CSR(base), IE_RIDE|IE_SYSBFR); ! 1194: ! 1195: /* No Transmit Interrupts */ ! 1196: ! 1197: outb(EDLC_XMT(base), 0); ! 1198: inb(EDLC_XMT(base)); ! 1199: ! 1200: /* Setup Receive Interrupts */ ! 1201: ! 1202: outb(EDLC_RCV(base), EDLC_BROAD|EDLC_SHORT|EDLC_GOOD|EDLC_DRIBBLE|EDLC_OVER); ! 1203: inb(EDLC_RCV(base)); ! 1204: ! 1205: outb(IE_CSR(base), IE_RIDE|IE_SYSBFR); ! 1206: outb(IE_RP(base), 0); ! 1207: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC); ! 1208: return(TRUE); ! 1209: } ! 1210: ! 1211: /* ! 1212: * at3c501intoff: ! 1213: * ! 1214: * This function turns interrupts off for the at3c501 board indicated. ! 1215: * ! 1216: */ ! 1217: at3c501intoff(unit) ! 1218: int unit; ! 1219: { ! 1220: caddr_t base = at3c501_softc[unit].base; ! 1221: outb(IE_CSR(base), 0); ! 1222: } ! 1223: ! 1224: #ifdef MACH_KERNEL ! 1225: #else MACH_KERNEL ! 1226: /* ! 1227: * The length of an mbuf chain ! 1228: */ ! 1229: m_length(m) ! 1230: register struct mbuf *m; ! 1231: { ! 1232: register int len = 0; ! 1233: ! 1234: while (m) { ! 1235: len += m->m_len; ! 1236: m = m->m_next; ! 1237: } ! 1238: return len; ! 1239: } ! 1240: #endif MACH_KERNEL
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.