1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)if_ec.c 7.1 (Berkeley) 6/5/86 7: * 1.0 (2.10BSD EATON IMSD sms@etn-wlv.eaton.com 12/28/87) 8: */ 9: 10: #include "ec.h" 11: #if NEC > 0 12: 13: /* 14: * 3Com Ethernet Controller interface 15: * 16: * Adapted from the 4.3BSD version to run on 2.10BSD. Major differences: 17: * 18: * 1) static instead of autoconfiguration, 'autoconfig' has problems with 19: * our triple vector. 20: * 2) reduction of the number of buffers from 16 to 12, this is because 21: * the unibus memory for this device is 'enabled' by clipping resistors 22: * on the cpu board and must start on a mod 4 UMR boundary and we only 23: * have UMRs 28, 29 and 30. The number of UMRs available has to be 24: * reduced in ubinit() (/sys/pdp/machdep2.c) if this driver is to 25: * be used. 26: * 3) Buffers are mapped thru APR5, copyv() is used to go to/from mbufs. 27: * 4) Exponential backup redone to use a count instead of a mask. 28: * 5) The ec_softc structure reduced in size to remove unused fields. 29: * 6) Modified to run in supervisor mode, about all this required was 30: * changing the macros in seg.h to use supervisor registers if 31: * SUPERVISOR is defined (from the makefiles) AND changing where 32: * SEG5 is mapped in/out. Use mbcopyin/out instead of copyv. 33: * 7) Broken ethernet cable showed up a problem in collision handling, 34: * the backoff being done via a DELAY loop effectively hangs the system. 35: * Changed to use a timeout with the number of ticks being the number 36: * of collisions (up to 16 max). 37: * 38: * Who knows if trailers and NS work, i don't. Coding style changed to reflect 39: * personal preferences, conditional vax code removed to improve readability. 40: * 41: * Oh, one more thing. The 3Com board is hardwired to interrupt at spl6 for 42: * the receiver, spl5 for the collision detect, and spl4 for the transmitter. 43: * References to splimp() have been replaced in this driver with splhigh(). 44: * you'll have to change splimp() to be spl6 and recompile the whole kernel 45: * in order to avoid recursive interrupts caused by the receiver using splimp 46: * anywhere in its path. TRUST ME, you crash if you don't do this. Better 47: * to lose a few clock ticks than the system! 48: */ 49: 50: #include "param.h" 51: #include "../machine/seg.h" 52: #include "mbuf.h" 53: #include "buf.h" 54: #include "domain.h" 55: #include "protosw.h" 56: #include "socket.h" 57: #include "ioctl.h" 58: #include "errno.h" 59: 60: #include "../net/if.h" 61: #include "../net/netisr.h" 62: #include "../net/route.h" 63: 64: #ifdef INET 65: #include "../netinet/in.h" 66: #include "../netinet/in_systm.h" 67: #include "../netinet/in_var.h" 68: #include "../netinet/ip.h" 69: #include "../netinet/if_ether.h" 70: #endif 71: 72: #ifdef NS 73: #include "../netns/ns.h" 74: #include "../netns/ns_if.h" 75: #endif 76: 77: #include "if_ecreg.h" 78: #include "if_uba.h" 79: #include "../pdpuba/ubavar.h" 80: 81: #define MAPBUFDESC (((btoc(2048) - 1) << 8 ) | RW) 82: #define BUFP ((caddr_t)0120000) 83: #undef ECRHBF 84: #define ECRHBF 11 85: #define ECNUMBUFS (ECRHBF + 1) 86: 87: extern struct ifnet loif; 88: int ecattach(), ecinit(), ecioctl(), ecoutput(), ecunjam(); 89: struct uba_device *ecinfo[NEC]; 90: u_short ecstd[] = { 0 }; 91: struct uba_driver ecdriver = 92: { 0, 0, ecattach, 0, ecstd, "ec", ecinfo }; 93: struct mbuf *ecget(); 94: 95: /* 96: * Ethernet software status per interface. 97: * 98: * Each interface is referenced by a network interface structure, 99: * es_if, which the routing code uses to locate the interface. 100: * This structure contains the output queue for the interface, its address, ... 101: */ 102: struct ec_softc { 103: struct arpcom es_ac; /* common Ethernet structures */ 104: #define es_if es_ac.ac_if /* network-visible interface */ 105: #define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ 106: u_char es_mask; /* mask for current output delay */ 107: u_char es_oactive; /* is output active? */ 108: memaddr es_buf[ECNUMBUFS]; /* virtual click buffer addresses */ 109: } ec_softc[NEC]; 110: 111: /* 112: * Interface exists: make available by filling in network interface 113: * record. System will initialize the interface when it is ready 114: * to accept packets. 115: */ 116: ecattach(ui) 117: struct uba_device *ui; 118: { 119: struct ec_softc *es = &ec_softc[ui->ui_unit]; 120: register struct ifnet *ifp = &es->es_if; 121: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 122: int i, j; 123: u_char *cp; 124: 125: ifp->if_unit = ui->ui_unit; 126: ifp->if_name = "ec"; 127: ifp->if_mtu = ETHERMTU; 128: 129: /* Read the ethernet address off the board, one nibble at a time. */ 130: 131: addr->ec_xcr = EC_UECLR; /* zero address pointer */ 132: addr->ec_rcr = EC_AROM; 133: cp = es->es_addr; 134: #define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM 135: for (i=0; i < sizeof (es->es_addr); i++) 136: { 137: *cp = 0; 138: for (j=0; j<=4; j+=4) 139: { 140: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 141: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 142: } 143: cp++; 144: } 145: printf("ec%d: addr %s\n", ui->ui_unit, ether_sprintf(es->es_addr)); 146: ifp->if_init = ecinit; 147: ifp->if_ioctl = ecioctl; 148: ifp->if_output = ecoutput; 149: ifp->if_reset = 0; 150: ifp->if_flags = IFF_BROADCAST; 151: /* 152: * the (memaddr)(0177000) below is UMR28 translated into clicks. 153: */ 154: for (i = 0; i < ECNUMBUFS; i++) 155: es->es_buf[i] = (memaddr)(0177000) + (memaddr)(btoc(2048) * i); 156: if_attach(ifp); 157: } 158: 159: /* 160: * Initialization of interface; clear recorded pending operations. 161: */ 162: ecinit(unit) 163: int unit; 164: { 165: struct ec_softc *es = &ec_softc[unit]; 166: struct ecdevice *addr; 167: register struct ifnet *ifp = &es->es_if; 168: int i, s; 169: 170: /* not yet, if address still unknown */ 171: if (ifp->if_addrlist == (struct ifaddr *)0) 172: return; 173: 174: /* 175: * Hang receive buffers and start any pending writes. 176: * Writing into the rcr also makes sure the memory 177: * is turned on. 178: */ 179: if ((ifp->if_flags & IFF_RUNNING) == 0) 180: { 181: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 182: s = splhigh(); 183: /* 184: * write our ethernet address into the address recognition ROM 185: * so we can always use the same EC_READ bits (referencing ROM), 186: * in case we change the address sometime. 187: * Note that this is safe here as the receiver is NOT armed. 188: */ 189: ec_setaddr(es->es_addr, unit); 190: /* 191: * Arm the receiver 192: */ 193: for (i = ECRHBF; i >= ECRLBF; i--) 194: addr->ec_rcr = EC_READ | i; 195: es->es_oactive = 0; 196: es->es_mask = 1; 197: es->es_if.if_flags |= IFF_RUNNING; 198: if (es->es_if.if_snd.ifq_head) 199: ecstart(unit); 200: splx(s); 201: } 202: } 203: 204: /* 205: * Start output on interface. Get another datagram to send 206: * off of the interface queue, and copy it to the interface 207: * before starting the output. 208: */ 209: ecstart(unit) 210: int unit; 211: { 212: register struct ec_softc *es = &ec_softc[unit]; 213: struct ecdevice *addr; 214: struct mbuf *m; 215: 216: if ((es->es_if.if_flags & IFF_RUNNING) == 0) 217: return; 218: IF_DEQUEUE(&es->es_if.if_snd, m); 219: if (m == 0) 220: return; 221: ecput(es->es_buf[ECTBF], m); 222: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 223: addr->ec_xcr = EC_WRITE|ECTBF; 224: es->es_oactive = 1; 225: } 226: 227: /* 228: * Ethernet interface transmitter interrupt. 229: * Start another output if more data to send. 230: */ 231: ecxint(unit) 232: int unit; 233: { 234: register struct ec_softc *es = &ec_softc[unit]; 235: register struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 236: register int s; 237: 238: if (es->es_oactive == 0) 239: return; 240: if (!(addr->ec_xcr&EC_XDONE) || (addr->ec_xcr&EC_XBN) != ECTBF) 241: { 242: printf("ec%d: stray xint, xcr=%b\n",unit,addr->ec_xcr,EC_XBITS); 243: es->es_oactive = 0; 244: addr->ec_xcr = EC_XCLR; 245: return; 246: } 247: es->es_if.if_opackets++; 248: es->es_oactive = 0; 249: es->es_mask = 1; 250: addr->ec_xcr = EC_XCLR; 251: s = splimp(); 252: if (es->es_if.if_snd.ifq_head) 253: ecstart(unit); 254: splx(s); 255: } 256: 257: /* 258: * Collision on ethernet interface. Do exponential 259: * backoff, and retransmit. If have backed off all 260: * the way print warning diagnostic, and drop packet. 261: */ 262: eccollide(unit) 263: int unit; 264: { 265: register struct ec_softc *es = &ec_softc[unit]; 266: register struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 267: register int i; 268: long delay; 269: 270: es->es_if.if_collisions++; 271: if (es->es_oactive == 0) 272: return; 273: if (es->es_mask++ >= 16) 274: { 275: es->es_if.if_oerrors++; 276: printf("ec%d: send err\n", unit); 277: /* 278: * Reset interface, then requeue rcv buffers. 279: * Some incoming packets may be lost, but that 280: * can't be helped. 281: */ 282: addr->ec_xcr = EC_UECLR; 283: for (i=ECRHBF; i>=ECRLBF; i--) 284: addr->ec_rcr = EC_READ|i; 285: /* 286: * Reset and transmit next packet (if any). 287: */ 288: es->es_oactive = 0; 289: es->es_mask = 1; 290: if (es->es_if.if_snd.ifq_head) 291: ecstart(unit); 292: return; 293: } 294: /* 295: * use a timeout instead of a delay loop - the loop hung the system 296: * when someone unscrewed a terminator on the net. 297: * 298: * this isn't exponential, but it sure beats a hung up system in the 299: * face of a broken cable. 300: */ 301: TIMEOUT(ecunjam, addr, es->es_mask); 302: } 303: 304: ecunjam(addr) 305: struct ecdevice *addr; 306: { 307: 308: /* 309: * Clear the controller's collision flag, thus enabling retransmit. 310: */ 311: addr->ec_xcr = EC_CLEAR; 312: } 313: 314: /* 315: * Ethernet interface receiver interrupt. 316: * If input error just drop packet. 317: * Otherwise examine packet to determine type. If can't determine length 318: * from type, then have to drop packet. Othewise decapsulate 319: * packet based on type and pass to type specific higher-level 320: * input routine. 321: */ 322: 323: ecrint(unit) 324: int unit; 325: { 326: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 327: 328: while (addr->ec_rcr & EC_RDONE) 329: ecread(unit); 330: } 331: 332: ecread(unit) 333: int unit; 334: { 335: register struct ec_softc *es = &ec_softc[unit]; 336: register struct ether_header *ec; 337: register struct ifqueue *inq; 338: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; 339: struct mbuf *m; 340: int len, off = 0, resid, ecoff, rbuf, type; 341: u_char *ecbuf; 342: segm sav5; 343: 344: es->es_if.if_ipackets++; 345: rbuf = addr->ec_rcr & EC_RBN; 346: if (rbuf < ECRLBF || rbuf > ECRHBF) 347: panic("ecrint"); /* sanity */ 348: /* 349: * we change SDSA5 only while NOT looking at mbufs (there might be some on SEG5) 350: * and carefully restore it before calling 'ecget' who uses mbcopyin(). 351: * the save/restore seg routines are ifdef'd on SUPERVISOR (which had better 352: * be set when compiling the network stuff!!). 353: */ 354: saveseg5(sav5); 355: mapseg5(es->es_buf[rbuf], MAPBUFDESC); 356: ecbuf = (u_char *)SEG5; 357: ecoff = *(short *)SEG5; 358: if (ecoff <= ECRDOFF || ecoff > 2046) 359: { 360: es->es_if.if_ierrors++; 361: #ifdef notyet 362: printf("ec%d ecoff=0%o rbuf=0%o\n", unit, ecoff, rbuf); 363: #endif 364: goto setup; 365: } 366: 367: /* 368: * Get input data length. 369: * Get pointer to ethernet header (in input buffer). 370: * Deal with trailer protocol: if type is trailer type 371: * get true type from first 16-bit word past data. 372: * Remember that type was trailer by setting off. 373: */ 374: len = ecoff - ECRDOFF - sizeof (struct ether_header); 375: ec = (struct ether_header *)(ecbuf + ECRDOFF); 376: ec->ether_type = ntohs((u_short)ec->ether_type); 377: #ifdef weliketrailers 378: #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) 379: if (ec->ether_type >= ETHERTYPE_TRAIL && 380: ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) 381: { 382: off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; 383: if (off >= ETHERMTU) 384: goto setup; /* sanity */ 385: ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); 386: resid = ntohs(*(ecdataaddr(ec, off+2, u_short *))); 387: if (off + resid > len) 388: goto setup; /* sanity */ 389: len = off + resid; 390: } 391: else 392: off = 0; 393: if (!len) 394: goto setup; 395: #else 396: if (!len || (ec->ether_type >= ETHERTYPE_TRAIL && 397: ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER)) 398: { 399: printf("ec%d type=%x len=%d\n", unit, ec->ether_type,len); 400: es->es_if.if_ierrors++; 401: goto setup; 402: } 403: #endif 404: /* 405: * Pull packet off interface. Off is nonzero if packet 406: * has trailing header; ecget will then force this header 407: * information to be at the front, but we still have to drop 408: * the type and length which are at the front of any trailer data. 409: */ 410: type = ec->ether_type; /* save before restoring mapping */ 411: restorseg5(sav5); /* put it back now! */ 412: m = ecget(es->es_buf[rbuf], len, off, &es->es_if); 413: if (m == 0) 414: goto setup; 415: #ifdef weliketrailers 416: if (off) 417: { 418: struct ifnet *ifp; 419: 420: ifp = *(mtod(m, struct ifnet **)); 421: m->m_off += 2 * sizeof (u_short); 422: m->m_len -= 2 * sizeof (u_short); 423: *(mtod(m, struct ifnet **)) = ifp; 424: } 425: #endif 426: switch (type) 427: { 428: #ifdef INET 429: case ETHERTYPE_IP: 430: schednetisr(NETISR_IP); 431: inq = &ipintrq; 432: break; 433: case ETHERTYPE_ARP: 434: arpinput(&es->es_ac, m); 435: goto setup; 436: #endif 437: #ifdef NS 438: case ETHERTYPE_NS: 439: schednetisr(NETISR_NS); 440: inq = &nsintrq; 441: break; 442: #endif 443: default: 444: m_freem(m); 445: goto setup; 446: } 447: if (IF_QFULL(inq)) 448: { 449: IF_DROP(inq); 450: m_freem(m); 451: goto setup; 452: } 453: IF_ENQUEUE(inq, m); 454: setup: 455: /* Reset for next packet. */ 456: restorseg5(sav5); /* put it back before leaving */ 457: addr->ec_rcr = EC_READ|EC_RCLR|rbuf; 458: } 459: 460: /* 461: * Ethernet output routine. 462: * Encapsulate a packet of type family for the local net. 463: * Use trailer local net encapsulation if enough data in first 464: * packet leaves a multiple of 512 bytes of data in remainder and trailers 465: * are allowed (which we should NEVER do). 466: * If destination is this address or broadcast, send packet to 467: * loop device to kludge around the fact that 3com interfaces can't 468: * talk to themselves. 469: */ 470: ecoutput(ifp, m0, dst) 471: struct ifnet *ifp; 472: struct mbuf *m0; 473: struct sockaddr *dst; 474: { 475: int type, s, error, usetrailers; 476: u_char edst[6]; 477: struct in_addr idst; 478: struct ec_softc *es = &ec_softc[ifp->if_unit]; 479: register struct mbuf *m = m0; 480: register struct ether_header *ec; 481: register int off; 482: u_short *p; 483: struct mbuf *mcopy = (struct mbuf *)0; 484: 485: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 486: { 487: error = ENETDOWN; 488: goto bad; 489: } 490: switch (dst->sa_family) 491: { 492: #ifdef INET 493: case AF_INET: 494: idst = ((struct sockaddr_in *)dst)->sin_addr; 495: if (!arpresolve(&es->es_ac, m, &idst, edst, 496: &usetrailers)) 497: return(0); /* if not yet resolved */ 498: if (!bcmp(edst, etherbroadcastaddr, sizeof(edst))) 499: mcopy = m_copy(m, 0, (int)M_COPYALL); 500: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) 501: - m->m_len; 502: /* need per host negotiation */ 503: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 504: m->m_off >= MMINOFF + 2 * sizeof (u_short)) 505: { 506: type = ETHERTYPE_TRAIL + (off>>9); 507: m->m_off -= 2 * sizeof (u_short); 508: m->m_len += 2 * sizeof (u_short); 509: p = mtod(m, u_short *); 510: *p++ =ntohs((u_short)ETHERTYPE_IP); 511: *p = ntohs((u_short)m->m_len); 512: goto gottrailertype; 513: } 514: type = ETHERTYPE_IP; 515: off = 0; 516: goto gottype; 517: #endif 518: #ifdef NS 519: case AF_NS: 520: bcopy(&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 521: edst, sizeof (edst)); 522: if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, 523: sizeof(edst))) 524: mcopy = m_copy(m, 0, (int)M_COPYALL); 525: else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 526: sizeof(edst))) 527: return(looutput(&loif, m, dst)); 528: type = ETHERTYPE_NS; 529: off = 0; 530: goto gottype; 531: #endif 532: case AF_UNSPEC: 533: ec = (struct ether_header *)dst->sa_data; 534: bcopy(ec->ether_dhost, (caddr_t)edst, sizeof (edst)); 535: type = ec->ether_type; 536: goto gottype; 537: default: 538: printf("ec%d: af%d\n", ifp->if_unit, dst->sa_family); 539: error = EAFNOSUPPORT; 540: goto bad; 541: } 542: gottrailertype: 543: /* 544: * Packet to be sent as trailer: move first packet 545: * (control information) to end of chain. 546: */ 547: while (m->m_next) 548: m = m->m_next; 549: m->m_next = m0; 550: m = m0->m_next; 551: m0->m_next = 0; 552: m0 = m; 553: gottype: 554: /* 555: * Add local net header. If no space in first mbuf, 556: * allocate another. 557: */ 558: if (m->m_off > MMAXOFF || 559: MMINOFF + sizeof (struct ether_header) > m->m_off) 560: { 561: m = m_get(M_DONTWAIT, MT_HEADER); 562: if (m == 0) 563: { 564: error = ENOBUFS; 565: goto bad; 566: } 567: m->m_next = m0; 568: m->m_off = MMINOFF; 569: m->m_len = sizeof (struct ether_header); 570: } 571: else 572: { 573: m->m_off -= sizeof (struct ether_header); 574: m->m_len += sizeof (struct ether_header); 575: } 576: ec = mtod(m, struct ether_header *); 577: bcopy((caddr_t)edst, (caddr_t)ec->ether_dhost, sizeof (edst)); 578: bcopy(es->es_addr, (caddr_t)ec->ether_shost, sizeof(ec->ether_shost)); 579: ec->ether_type = htons((u_short)type); 580: 581: /* 582: * Queue message on interface, and start output if interface 583: * not yet active. 584: */ 585: s = splhigh(); 586: if (IF_QFULL(&ifp->if_snd)) 587: { 588: IF_DROP(&ifp->if_snd); 589: error = ENOBUFS; 590: goto qfull; 591: } 592: IF_ENQUEUE(&ifp->if_snd, m); 593: if (es->es_oactive == 0) 594: ecstart(ifp->if_unit); 595: splx(s); 596: error = mcopy ? looutput(&loif, mcopy, dst) : 0; 597: return(error); 598: qfull: 599: m0 = m; 600: splx(s); 601: bad: 602: m_freem(m0); 603: if (mcopy) 604: m_freem(mcopy); 605: return(error); 606: } 607: 608: /* 609: * Routine to copy from mbuf chain to transmit 610: * buffer in UNIBUS memory. 611: * If packet size is less than the minimum legal size, 612: * the buffer is expanded. We probably should zero out the extra 613: * bytes for security, but that would slow things down. 614: */ 615: ecput(ecbuf, m) 616: memaddr ecbuf; 617: struct mbuf *m; 618: { 619: register struct mbuf *mp; 620: register u_short off; 621: segm sav5; 622: 623: for (off = 2048, mp = m; mp; mp = mp->m_next) 624: off -= mp->m_len; 625: if (2048 - off < ETHERMIN + sizeof (struct ether_header)) 626: off = 2048 - ETHERMIN - sizeof (struct ether_header); 627: saveseg5(sav5); 628: mapseg5(ecbuf, MAPBUFDESC); 629: *(u_short *)SEG5 = off; 630: restorseg5(sav5); 631: for (mp = m; mp; mp = mp->m_next) 632: { 633: register unsigned len = mp->m_len; 634: 635: if (len == 0) 636: continue; 637: mbcopyout(mtod(mp, caddr_t), ecbuf, off, len); 638: off += len; 639: } 640: m_freem(m); 641: } 642: 643: /* 644: * Routine to copy from UNIBUS memory into mbufs. 645: */ 646: struct mbuf * 647: ecget(ecbuf, totlen, off0, ifp) 648: memaddr ecbuf; 649: int totlen, off0; 650: struct ifnet *ifp; 651: { 652: register struct mbuf *m; 653: register int off = off0, len; 654: struct mbuf *top = 0, **mp = ⊤ 655: u_short distance; 656: 657: distance = ECRDOFF + sizeof (struct ether_header); 658: while (totlen > 0) 659: { 660: MGET(m, M_DONTWAIT, MT_DATA); 661: if (m == 0) 662: goto bad; 663: if (off) 664: { 665: len = totlen - off; 666: distance = ECRDOFF + off + sizeof (struct ether_header); 667: } 668: else 669: len = totlen; 670: if (ifp) 671: len += sizeof(ifp); 672: if (len >= NBPG) 673: { 674: MCLGET(m); 675: if (m->m_len == CLBYTES) 676: m->m_len = len = MIN(len, CLBYTES); 677: else 678: m->m_len = len = MIN(MLEN, len); 679: } 680: else 681: m->m_len = len = MIN(MLEN, len); 682: if (ifp) 683: { 684: /* Prepend interface pointer to first mbuf. */ 685: *(mtod(m, struct ifnet **)) = ifp; 686: len -= sizeof(ifp); 687: } 688: mbcopyin(ecbuf, distance, 689: ifp ? mtod(m,caddr_t)+sizeof(ifp) : mtod(m,caddr_t), len); 690: ifp = (struct ifnet *)0; 691: distance += len; 692: *mp = m; 693: mp = &m->m_next; 694: if (off == 0) 695: { 696: totlen -= len; 697: continue; 698: } 699: off += len; 700: if (off == totlen) 701: { 702: distance = ECRDOFF + sizeof (struct ether_header); 703: off = 0; 704: totlen = off0; 705: } 706: } 707: return(top); 708: bad: 709: m_freem(top); 710: return(0); 711: } 712: 713: /* 714: * Process an ioctl request. 715: */ 716: ecioctl(ifp, cmd, data) 717: register struct ifnet *ifp; 718: int cmd; 719: caddr_t data; 720: { 721: register struct ifaddr *ifa = (struct ifaddr *)data; 722: struct ec_softc *es = &ec_softc[ifp->if_unit]; 723: struct ecdevice *addr; 724: int s = splhigh(), error = 0; 725: 726: addr = (struct ecdevice *)ecinfo[ifp->if_unit]->ui_addr; 727: switch (cmd) 728: { 729: case SIOCSIFADDR: 730: ifp->if_flags |= IFF_UP; 731: switch (ifa->ifa_addr.sa_family) 732: { 733: #ifdef INET 734: case AF_INET: 735: ecinit(ifp->if_unit); 736: ((struct arpcom *)ifp)->ac_ipaddr = 737: IA_SIN(ifa)->sin_addr; 738: arpwhohas((struct arpcom *)ifp, 739: &IA_SIN(ifa)->sin_addr); 740: break; 741: #endif 742: #ifdef NS 743: case AF_NS: 744: { 745: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 746: 747: if (ns_nullhost(*ina)) 748: ina->x_host = *(union ns_host *) 749: (es->es_addr); 750: else 751: { 752: /* 753: * The manual says we can't change the address 754: * while the receiver is armed, 755: * so reset everything 756: */ 757: ifp->if_flags &= ~IFF_RUNNING; 758: bcopy(ina->x_host.c_host, 759: es->es_addr, 760: sizeof(es->es_addr)); 761: } 762: ecinit(ifp->if_unit); /* do ec_setaddr*/ 763: break; 764: } 765: #endif 766: default: 767: ecinit(ifp->if_unit); 768: break; 769: } 770: break; 771: case SIOCSIFFLAGS: 772: if ((ifp->if_flags & IFF_UP) == 0 && 773: ifp->if_flags & IFF_RUNNING) 774: { 775: addr->ec_xcr = EC_UECLR; 776: ifp->if_flags &= ~IFF_RUNNING; 777: } 778: else if (ifp->if_flags & IFF_UP && 779: (ifp->if_flags & IFF_RUNNING) == 0) 780: ecinit(ifp->if_unit); 781: break; 782: default: 783: error = EINVAL; 784: } 785: splx(s); 786: return(error); 787: } 788: 789: ec_setaddr(physaddr,unit) 790: u_char *physaddr; 791: int unit; 792: { 793: struct ec_softc *es = &ec_softc[unit]; 794: struct uba_device *ui = ecinfo[unit]; 795: struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; 796: register char nibble; 797: register int i, j; 798: 799: /* 800: * Use the ethernet address supplied 801: * Note that we do a UECLR here, so the receive buffers 802: * must be requeued. 803: */ 804: 805: #ifdef DEBUG 806: printf("ec_setaddr: setting address for unit %d = %s", 807: unit, ether_sprintf(physaddr)); 808: #endif 809: addr->ec_xcr = EC_UECLR; 810: addr->ec_rcr = 0; 811: /* load requested address */ 812: for (i = 0; i < 6; i++) 813: { /* 6 bytes of address */ 814: es->es_addr[i] = physaddr[i]; 815: nibble = physaddr[i] & 0xf; /* lower nibble */ 816: addr->ec_rcr = (nibble << 8); 817: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 818: addr->ec_rcr = (nibble << 8); 819: for (j=0; j < 4; j++) 820: { 821: addr->ec_rcr = 0; 822: addr->ec_rcr = EC_ASTEP; /* step counter */ 823: addr->ec_rcr = 0; 824: } 825: nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ 826: addr->ec_rcr = (nibble << 8); 827: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ 828: addr->ec_rcr = (nibble << 8); 829: for (j=0; j < 4; j++) 830: { 831: addr->ec_rcr = 0; 832: addr->ec_rcr = EC_ASTEP; /* step counter */ 833: addr->ec_rcr = 0; 834: } 835: } 836: #ifdef DEBUG 837: /* 838: * Read the ethernet address off the board, one nibble at a time. 839: */ 840: addr->ec_xcr = EC_UECLR; 841: addr->ec_rcr = 0; /* read RAM */ 842: cp = es->es_addr; 843: #undef NEXTBIT 844: #define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 845: for (i=0; i < sizeof (es->es_addr); i++) 846: { 847: *cp = 0; 848: for (j=0; j<=4; j+=4) 849: { 850: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; 851: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; 852: } 853: cp++; 854: } 855: printf("ec_setaddr: RAM address for unit %d = %s", 856: unit, ether_sprintf(physaddr)); 857: #endif 858: } 859: #endif