|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)if_ec.c 7.7 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "ec.h" ! 24: #if NEC > 0 ! 25: ! 26: /* ! 27: * 3Com Ethernet Controller interface ! 28: */ ! 29: #include "machine/pte.h" ! 30: ! 31: #include "param.h" ! 32: #include "systm.h" ! 33: #include "mbuf.h" ! 34: #include "buf.h" ! 35: #include "protosw.h" ! 36: #include "socket.h" ! 37: #include "syslog.h" ! 38: #include "vmmac.h" ! 39: #include "ioctl.h" ! 40: #include "errno.h" ! 41: ! 42: #include "../net/if.h" ! 43: #include "../net/netisr.h" ! 44: #include "../net/route.h" ! 45: ! 46: #ifdef INET ! 47: #include "../netinet/in.h" ! 48: #include "../netinet/in_systm.h" ! 49: #include "../netinet/in_var.h" ! 50: #include "../netinet/ip.h" ! 51: #include "../netinet/if_ether.h" ! 52: #endif ! 53: ! 54: #ifdef NS ! 55: #include "../netns/ns.h" ! 56: #include "../netns/ns_if.h" ! 57: #endif ! 58: ! 59: #include "../vax/cpu.h" ! 60: #include "../vax/mtpr.h" ! 61: #include "if_ecreg.h" ! 62: #include "if_uba.h" ! 63: #include "../vaxuba/ubareg.h" ! 64: #include "../vaxuba/ubavar.h" ! 65: ! 66: #if CLSIZE == 2 ! 67: #define ECBUFSIZE 32 /* on-board memory, clusters */ ! 68: #endif ! 69: ! 70: int ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide(); ! 71: struct uba_device *ecinfo[NEC]; ! 72: u_short ecstd[] = { 0 }; ! 73: struct uba_driver ecdriver = ! 74: { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, 0, ecubamem }; ! 75: ! 76: int ecinit(),ecioctl(),ecstart(),ecreset(),ether_output(); ! 77: struct mbuf *ecget(); ! 78: ! 79: extern struct ifnet loif; ! 80: ! 81: /* ! 82: * Ethernet software status per interface. ! 83: * ! 84: * Each interface is referenced by a network interface structure, ! 85: * es_if, which the routing code uses to locate the interface. ! 86: * This structure contains the output queue for the interface, its address, ... ! 87: * We also have, for each interface, a UBA interface structure, which ! 88: * contains information about the UNIBUS resources held by the interface: ! 89: * map registers, buffered data paths, etc. Information is cached in this ! 90: * structure for use by the if_uba.c routines in running the interface ! 91: * efficiently. ! 92: */ ! 93: struct ec_softc { ! 94: struct arpcom es_ac; /* common Ethernet structures */ ! 95: #define es_if es_ac.ac_if /* network-visible interface */ ! 96: #define es_addr es_ac.ac_enaddr /* hardware Ethernet address */ ! 97: struct ifuba es_ifuba; /* UNIBUS resources */ ! 98: short es_mask; /* mask for current output delay */ ! 99: u_char *es_buf[16]; /* virtual addresses of buffers */ ! 100: } ec_softc[NEC]; ! 101: ! 102: /* ! 103: * Configure on-board memory for an interface. ! 104: * Called from autoconfig and after a uba reset. ! 105: * The address of the memory on the uba is supplied in the device flags. ! 106: */ ! 107: ecubamem(ui, uban) ! 108: register struct uba_device *ui; ! 109: { ! 110: register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags]; ! 111: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 112: ! 113: /* ! 114: * Make sure csr is there (we run before ecprobe). ! 115: */ ! 116: if (badaddr((caddr_t)addr, 2)) ! 117: return (-1); ! 118: #if VAX780 ! 119: if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { ! 120: uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; ! 121: return (-1); ! 122: } ! 123: #endif ! 124: /* ! 125: * Make sure memory is turned on ! 126: */ ! 127: addr->ec_rcr = EC_AROM; ! 128: /* ! 129: * Tell the system that the board has memory here, so it won't ! 130: * attempt to allocate the addresses later. ! 131: */ ! 132: if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) { ! 133: printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit); ! 134: addr->ec_rcr = EC_MDISAB; /* disable memory */ ! 135: return (-1); ! 136: } ! 137: /* ! 138: * Check for existence of buffers on Unibus. ! 139: */ ! 140: if (badaddr((caddr_t)ecbuf, 2)) { ! 141: bad: ! 142: printf("ec%d: buffer mem not found\n", ui->ui_unit); ! 143: (void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0); ! 144: addr->ec_rcr = EC_MDISAB; /* disable memory */ ! 145: return (-1); ! 146: } ! 147: #if VAX780 ! 148: if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) { ! 149: uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr; ! 150: goto bad; ! 151: } ! 152: #endif ! 153: if (ui->ui_alive == 0) /* Only printf from autoconfig */ ! 154: printf("ec%d: mem %x-%x\n", ui->ui_unit, ! 155: ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1); ! 156: ui->ui_type = 1; /* Memory on, allocated */ ! 157: return (0); ! 158: } ! 159: ! 160: /* ! 161: * Do output DMA to determine interface presence and ! 162: * interrupt vector. DMA is too short to disturb other hosts. ! 163: */ ! 164: ecprobe(reg, ui) ! 165: caddr_t reg; ! 166: struct uba_device *ui; ! 167: { ! 168: register int br, cvec; /* r11, r10 value-result */ ! 169: register struct ecdevice *addr = (struct ecdevice *)reg; ! 170: register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags]; ! 171: ! 172: #ifdef lint ! 173: br = 0; cvec = br; br = cvec; ! 174: ecrint(0); ecxint(0); eccollide(0); ! 175: #endif ! 176: ! 177: /* ! 178: * Check that buffer memory was found and enabled. ! 179: */ ! 180: if (ui->ui_type == 0) ! 181: return(0); ! 182: /* ! 183: * Make a one byte packet in what should be buffer #0. ! 184: * Submit it for sending. This should cause an xmit interrupt. ! 185: * The xmit interrupt vector is 8 bytes after the receive vector, ! 186: * so adjust for this before returning. ! 187: */ ! 188: *(u_short *)ecbuf = (u_short) 03777; ! 189: ecbuf[03777] = '\0'; ! 190: addr->ec_xcr = EC_XINTEN|EC_XWBN; ! 191: DELAY(100000); ! 192: addr->ec_xcr = EC_XCLR; ! 193: if (cvec > 0 && cvec != 0x200) { ! 194: if (cvec & 04) { /* collision interrupt */ ! 195: cvec -= 04; ! 196: br += 1; /* rcv is collision + 1 */ ! 197: } else { /* xmit interrupt */ ! 198: cvec -= 010; ! 199: br += 2; /* rcv is xmit + 2 */ ! 200: } ! 201: } ! 202: return (1); ! 203: } ! 204: ! 205: /* ! 206: * Interface exists: make available by filling in network interface ! 207: * record. System will initialize the interface when it is ready ! 208: * to accept packets. ! 209: */ ! 210: ecattach(ui) ! 211: struct uba_device *ui; ! 212: { ! 213: struct ec_softc *es = &ec_softc[ui->ui_unit]; ! 214: register struct ifnet *ifp = &es->es_if; ! 215: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 216: int i, j; ! 217: u_char *cp; ! 218: ! 219: ifp->if_unit = ui->ui_unit; ! 220: ifp->if_name = "ec"; ! 221: ifp->if_mtu = ETHERMTU; ! 222: ! 223: /* ! 224: * Read the ethernet address off the board, one nibble at a time. ! 225: */ ! 226: addr->ec_xcr = EC_UECLR; /* zero address pointer */ ! 227: addr->ec_rcr = EC_AROM; ! 228: cp = es->es_addr; ! 229: #define NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM ! 230: for (i=0; i < sizeof (es->es_addr); i++) { ! 231: *cp = 0; ! 232: for (j=0; j<=4; j+=4) { ! 233: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; ! 234: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; ! 235: } ! 236: cp++; ! 237: } ! 238: printf("ec%d: hardware address %s\n", ui->ui_unit, ! 239: ether_sprintf(es->es_addr)); ! 240: ifp->if_init = ecinit; ! 241: ifp->if_ioctl = ecioctl; ! 242: ifp->if_output = ether_output; ! 243: ifp->if_start = ecstart; ! 244: ifp->if_reset = ecreset; ! 245: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; ! 246: for (i=0; i<16; i++) ! 247: es->es_buf[i] ! 248: = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i]; ! 249: if_attach(ifp); ! 250: } ! 251: ! 252: /* ! 253: * Reset of interface after UNIBUS reset. ! 254: * If interface is on specified uba, reset its state. ! 255: */ ! 256: ecreset(unit, uban) ! 257: int unit, uban; ! 258: { ! 259: register struct uba_device *ui; ! 260: ! 261: if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 || ! 262: ui->ui_ubanum != uban) ! 263: return; ! 264: printf(" ec%d", unit); ! 265: ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING; ! 266: ecinit(unit); ! 267: } ! 268: ! 269: /* ! 270: * Initialization of interface; clear recorded pending ! 271: * operations, and reinitialize UNIBUS usage. ! 272: */ ! 273: ecinit(unit) ! 274: int unit; ! 275: { ! 276: struct ec_softc *es = &ec_softc[unit]; ! 277: struct ecdevice *addr; ! 278: register struct ifnet *ifp = &es->es_if; ! 279: int i, s; ! 280: ! 281: /* not yet, if address still unknown */ ! 282: if (ifp->if_addrlist == (struct ifaddr *)0) ! 283: return; ! 284: ! 285: /* ! 286: * Hang receive buffers and start any pending writes. ! 287: * Writing into the rcr also makes sure the memory ! 288: * is turned on. ! 289: */ ! 290: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 291: u_short start_read; ! 292: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 293: s = splimp(); ! 294: /* ! 295: * write our ethernet address into the address recognition ROM ! 296: * so we can always use the same EC_READ bits (referencing ROM), ! 297: * in case we change the address sometime. ! 298: * Note that this is safe here as the receiver is NOT armed. ! 299: */ ! 300: ec_setaddr(es->es_addr, unit); ! 301: /* ! 302: * Arm the receiver ! 303: #ifdef MULTI ! 304: if (es->es_if.if_flags & IFF_PROMISC) ! 305: start_read = EC_PROMISC; ! 306: else if (es->es_if.if_flags & IFF_MULTI) ! 307: start_read = EC_MULTI; ! 308: else ! 309: #endif MULTI ! 310: start_read = EC_READ; ! 311: */ ! 312: for (i = ECRHBF; i >= ECRLBF; i--) ! 313: addr->ec_rcr = EC_READ | i; ! 314: es->es_if.if_flags &= ~IFF_OACTIVE; ! 315: es->es_mask = ~0; ! 316: es->es_if.if_flags |= IFF_RUNNING; ! 317: if (es->es_if.if_snd.ifq_head) ! 318: (void) ecstart(&es->es_if); ! 319: splx(s); ! 320: } ! 321: } ! 322: ! 323: /* ! 324: * Start output on interface. Get another datagram to send ! 325: * off of the interface queue, and copy it to the interface ! 326: * before starting the output. ! 327: */ ! 328: ecstart(ifp) ! 329: struct ifnet *ifp; ! 330: { ! 331: int unit = ifp->if_unit; ! 332: register struct ec_softc *es = &ec_softc[unit]; ! 333: struct ecdevice *addr; ! 334: struct mbuf *m; ! 335: ! 336: if ((es->es_if.if_flags & IFF_RUNNING) == 0) ! 337: return (0); ! 338: IF_DEQUEUE(&es->es_if.if_snd, m); ! 339: if (m == 0) ! 340: return (0); ! 341: ecput(es->es_buf[ECTBF], m); ! 342: addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 343: addr->ec_xcr = EC_WRITE|ECTBF; ! 344: es->es_if.if_flags |= IFF_OACTIVE; ! 345: return (0); ! 346: } ! 347: ! 348: /* ! 349: * Ethernet interface transmitter interrupt. ! 350: * Start another output if more data to send. ! 351: */ ! 352: ecxint(unit) ! 353: int unit; ! 354: { ! 355: register struct ec_softc *es = &ec_softc[unit]; ! 356: register struct ecdevice *addr = ! 357: (struct ecdevice *)ecinfo[unit]->ui_addr; ! 358: ! 359: if ((es->es_if.if_flags & IFF_OACTIVE) == 0) ! 360: return; ! 361: if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) { ! 362: printf("ec%d: stray xmit interrupt, xcr=%b\n", unit, ! 363: addr->ec_xcr, EC_XBITS); ! 364: es->es_if.if_flags &= ~IFF_OACTIVE; ! 365: addr->ec_xcr = EC_XCLR; ! 366: return; ! 367: } ! 368: es->es_if.if_opackets++; ! 369: es->es_if.if_flags &= ~IFF_OACTIVE; ! 370: es->es_mask = ~0; ! 371: addr->ec_xcr = EC_XCLR; ! 372: if (es->es_if.if_snd.ifq_head) ! 373: (void) ecstart(&es->es_if); ! 374: } ! 375: ! 376: /* ! 377: * Collision on ethernet interface. Do exponential ! 378: * backoff, and retransmit. If have backed off all ! 379: * the way print warning diagnostic, and drop packet. ! 380: */ ! 381: eccollide(unit) ! 382: int unit; ! 383: { ! 384: register struct ec_softc *es = &ec_softc[unit]; ! 385: register struct ecdevice *addr = ! 386: (struct ecdevice *)ecinfo[unit]->ui_addr; ! 387: register i; ! 388: int delay; ! 389: ! 390: es->es_if.if_collisions++; ! 391: if ((es->es_if.if_flags & IFF_OACTIVE) == 0) ! 392: return; ! 393: ! 394: /* ! 395: * Es_mask is a 16 bit number with n low zero bits, with ! 396: * n the number of backoffs. When es_mask is 0 we have ! 397: * backed off 16 times, and give up. ! 398: */ ! 399: if (es->es_mask == 0) { ! 400: u_short start_read; ! 401: es->es_if.if_oerrors++; ! 402: log(LOG_ERR, "ec%d: send error\n", unit); ! 403: /* ! 404: * Reset interface, then requeue rcv buffers. ! 405: * Some incoming packets may be lost, but that ! 406: * can't be helped. ! 407: */ ! 408: addr->ec_xcr = EC_UECLR; ! 409: #ifdef MULTI ! 410: if (es->es_if.if_flags & IFF_PROMISC) ! 411: start_read = EC_PROMISC; ! 412: else if (es->es_if.if_flags & IFF_MULTI) ! 413: start_read = EC_MULTI; ! 414: else ! 415: #endif MULTI ! 416: start_read = EC_READ; ! 417: for (i=ECRHBF; i>=ECRLBF; i--) ! 418: addr->ec_rcr = start_read|i; ! 419: /* ! 420: * Reset and transmit next packet (if any). ! 421: */ ! 422: es->es_if.if_flags &= ~IFF_OACTIVE; ! 423: es->es_mask = ~0; ! 424: if (es->es_if.if_snd.ifq_head) ! 425: (void) ecstart(&es->es_if); ! 426: return; ! 427: } ! 428: /* ! 429: * Do exponential backoff. Compute delay based on low bits ! 430: * of the interval timer (1 bit for each transmission attempt, ! 431: * but at most 5 bits). Then delay for that number of ! 432: * slot times. A slot time is 51.2 microseconds (rounded to 51). ! 433: * This does not take into account the time already used to ! 434: * process the interrupt. ! 435: */ ! 436: es->es_mask <<= 1; ! 437: delay = mfpr(ICR) & 0x1f &~ es->es_mask; ! 438: DELAY(delay * 51); ! 439: /* ! 440: * Clear the controller's collision flag, thus enabling retransmit. ! 441: */ ! 442: addr->ec_xcr = EC_CLEAR; ! 443: } ! 444: ! 445: /* ! 446: * Ethernet interface receiver interrupt. ! 447: * If input error just drop packet. ! 448: * Otherwise examine ! 449: * packet to determine type. If can't determine length ! 450: * from type, then have to drop packet. Othewise decapsulate ! 451: * packet based on type and pass to type specific higher-level ! 452: * input routine. ! 453: */ ! 454: ecrint(unit) ! 455: int unit; ! 456: { ! 457: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 458: ! 459: while (addr->ec_rcr & EC_RDONE) ! 460: ecread(unit); ! 461: } ! 462: ! 463: ecread(unit) ! 464: int unit; ! 465: { ! 466: register struct ec_softc *es = &ec_softc[unit]; ! 467: struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr; ! 468: register struct ether_header *ec; ! 469: struct mbuf *m; ! 470: int len, off, resid, ecoff, rbuf; ! 471: register struct ifqueue *inq; ! 472: u_short start_read; ! 473: u_char *ecbuf; ! 474: ! 475: es->es_if.if_ipackets++; ! 476: rbuf = addr->ec_rcr & EC_RBN; ! 477: if (rbuf < ECRLBF || rbuf > ECRHBF) ! 478: panic("ecrint"); ! 479: ecbuf = es->es_buf[rbuf]; ! 480: ecoff = *(short *)ecbuf; ! 481: if (ecoff <= ECRDOFF || ecoff > 2046) { ! 482: es->es_if.if_ierrors++; ! 483: #ifdef notdef ! 484: if (es->es_if.if_ierrors % 100 == 0) ! 485: printf("ec%d: += 100 input errors\n", unit); ! 486: #endif ! 487: goto setup; ! 488: } ! 489: ! 490: /* ! 491: * Get input data length. ! 492: * Get pointer to ethernet header (in input buffer). ! 493: * Deal with trailer protocol: if type is trailer type ! 494: * get true type from first 16-bit word past data. ! 495: * Remember that type was trailer by setting off. ! 496: */ ! 497: len = ecoff - ECRDOFF - sizeof (struct ether_header); ! 498: ec = (struct ether_header *)(ecbuf + ECRDOFF); ! 499: ec->ether_type = ntohs((u_short)ec->ether_type); ! 500: #define ecdataaddr(ec, off, type) ((type)(((caddr_t)((ec)+1)+(off)))) ! 501: if (ec->ether_type >= ETHERTYPE_TRAIL && ! 502: ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 503: off = (ec->ether_type - ETHERTYPE_TRAIL) * 512; ! 504: if (off >= ETHERMTU) ! 505: goto setup; /* sanity */ ! 506: ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *)); ! 507: resid = ntohs(*(ecdataaddr(ec, off+2, u_short *))); ! 508: if (off + resid > len) ! 509: goto setup; /* sanity */ ! 510: len = off + resid; ! 511: } else ! 512: off = 0; ! 513: if (len == 0) ! 514: goto setup; ! 515: ! 516: /* ! 517: * Pull packet off interface. Off is nonzero if packet ! 518: * has trailing header; ecget will then force this header ! 519: * information to be at the front, but we still have to drop ! 520: * the type and length which are at the front of any trailer data. ! 521: */ ! 522: m = ecget(ecbuf, len, off, &es->es_if); ! 523: if (m) ! 524: ether_input(&es->es_if, ec, m); ! 525: /* ! 526: * Reset for next packet. ! 527: */ ! 528: setup: ! 529: #ifdef MULTI ! 530: if (es->es_if.if_flags & IFF_PROMISC) ! 531: start_read = EC_PROMISC; ! 532: else if (es->es_if.if_flags & IFF_MULTI) ! 533: start_read = EC_MULTI; ! 534: else ! 535: #endif MULTI ! 536: start_read = EC_READ; ! 537: addr->ec_rcr = start_read|EC_RCLR|rbuf; ! 538: } ! 539: ! 540: /* ! 541: * Routine to copy from mbuf chain to transmit ! 542: * buffer in UNIBUS memory. ! 543: * If packet size is less than the minimum legal size, ! 544: * the buffer is expanded. We probably should zero out the extra ! 545: * bytes for security, but that would slow things down. ! 546: */ ! 547: ecput(ecbuf, m) ! 548: u_char *ecbuf; ! 549: struct mbuf *m; ! 550: { ! 551: register struct mbuf *mp; ! 552: register int off; ! 553: u_char *bp; ! 554: ! 555: for (off = 2048, mp = m; mp; mp = mp->m_next) ! 556: off -= mp->m_len; ! 557: if (2048 - off < ETHERMIN + sizeof (struct ether_header)) ! 558: off = 2048 - ETHERMIN - sizeof (struct ether_header); ! 559: *(u_short *)ecbuf = off; ! 560: bp = (u_char *)(ecbuf + off); ! 561: for (mp = m; mp; mp = mp->m_next) { ! 562: register unsigned len = mp->m_len; ! 563: u_char *mcp; ! 564: ! 565: if (len == 0) ! 566: continue; ! 567: mcp = mtod(mp, u_char *); ! 568: if ((unsigned)bp & 01) { ! 569: *bp++ = *mcp++; ! 570: len--; ! 571: } ! 572: if (off = (len >> 1)) { ! 573: register u_short *to, *from; ! 574: ! 575: to = (u_short *)bp; ! 576: from = (u_short *)mcp; ! 577: do ! 578: *to++ = *from++; ! 579: while (--off > 0); ! 580: bp = (u_char *)to, ! 581: mcp = (u_char *)from; ! 582: } ! 583: if (len & 01) ! 584: *bp++ = *mcp++; ! 585: } ! 586: m_freem(m); ! 587: } ! 588: ! 589: /* ! 590: * Routine to copy from UNIBUS memory into mbufs. ! 591: * Similar in spirit to if_rubaget. ! 592: * ! 593: * Warning: This makes the fairly safe assumption that ! 594: * mbufs have even lengths. ! 595: */ ! 596: struct mbuf * ! 597: ecget(ecbuf, totlen, off0, ifp) ! 598: u_char *ecbuf; ! 599: int totlen, off0; ! 600: struct ifnet *ifp; ! 601: { ! 602: register struct mbuf *m; ! 603: struct mbuf *top = 0, **mp = ⊤ ! 604: register int off = off0, len; ! 605: u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header)); ! 606: u_char *packet_end = cp + totlen; ! 607: ! 608: if (off) { ! 609: off += 2 * sizeof(u_short); ! 610: totlen -= 2 *sizeof(u_short); ! 611: cp += off; ! 612: } ! 613: ! 614: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 615: if (m == 0) ! 616: return (0); ! 617: m->m_pkthdr.rcvif = ifp; ! 618: m->m_pkthdr.len = totlen; ! 619: m->m_len = MHLEN; ! 620: ! 621: while (totlen > 0) { ! 622: register int words; ! 623: u_char *mcp; ! 624: ! 625: if (top) { ! 626: MGET(m, M_DONTWAIT, MT_DATA); ! 627: if (m == 0) { ! 628: m_freem(top); ! 629: return (0); ! 630: } ! 631: m->m_len = MLEN; ! 632: } ! 633: len = min(totlen, (packet_end - cp)); ! 634: if (len >= MINCLSIZE) { ! 635: MCLGET(m, M_DONTWAIT); ! 636: if (m->m_flags & M_EXT) ! 637: m->m_len = len = min(len, MCLBYTES); ! 638: else ! 639: len = m->m_len; ! 640: } else { ! 641: /* ! 642: * Place initial small packet/header at end of mbuf. ! 643: */ ! 644: if (len < m->m_len) { ! 645: if (top == 0 && len + max_linkhdr <= m->m_len) ! 646: m->m_data += max_linkhdr; ! 647: m->m_len = len; ! 648: } else ! 649: len = m->m_len; ! 650: } ! 651: mcp = mtod(m, u_char *); ! 652: if (words = (len >> 1)) { ! 653: register u_short *to, *from; ! 654: ! 655: to = (u_short *)mcp; ! 656: from = (u_short *)cp; ! 657: do ! 658: *to++ = *from++; ! 659: while (--words > 0); ! 660: mcp = (u_char *)to; ! 661: cp = (u_char *)from; ! 662: } ! 663: if (len & 01) ! 664: *mcp++ = *cp++; ! 665: *mp = m; ! 666: mp = &m->m_next; ! 667: totlen -= len; ! 668: if (cp == packet_end) ! 669: cp = ecbuf; ! 670: } ! 671: return (top); ! 672: bad: ! 673: m_freem(top); ! 674: return (0); ! 675: } ! 676: ! 677: /* ! 678: * Process an ioctl request. ! 679: */ ! 680: ecioctl(ifp, cmd, data) ! 681: register struct ifnet *ifp; ! 682: int cmd; ! 683: caddr_t data; ! 684: { ! 685: register struct ifaddr *ifa = (struct ifaddr *)data; ! 686: struct ec_softc *es = &ec_softc[ifp->if_unit]; ! 687: struct ecdevice *addr; ! 688: int s = splimp(), error = 0; ! 689: ! 690: addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr); ! 691: ! 692: switch (cmd) { ! 693: ! 694: case SIOCSIFADDR: ! 695: ifp->if_flags |= IFF_UP; ! 696: ! 697: switch (ifa->ifa_addr->sa_family) { ! 698: #ifdef INET ! 699: case AF_INET: ! 700: ecinit(ifp->if_unit); /* before arpwhohas */ ! 701: ((struct arpcom *)ifp)->ac_ipaddr = ! 702: IA_SIN(ifa)->sin_addr; ! 703: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 704: break; ! 705: #endif ! 706: #ifdef NS ! 707: case AF_NS: ! 708: { ! 709: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 710: ! 711: if (ns_nullhost(*ina)) ! 712: ina->x_host = *(union ns_host *)(es->es_addr); ! 713: else { ! 714: /* ! 715: * The manual says we can't change the address ! 716: * while the receiver is armed, ! 717: * so reset everything ! 718: */ ! 719: ifp->if_flags &= ~IFF_RUNNING; ! 720: bcopy((caddr_t)ina->x_host.c_host, ! 721: (caddr_t)es->es_addr, sizeof(es->es_addr)); ! 722: } ! 723: ecinit(ifp->if_unit); /* does ec_setaddr() */ ! 724: break; ! 725: } ! 726: #endif ! 727: default: ! 728: ecinit(ifp->if_unit); ! 729: break; ! 730: } ! 731: break; ! 732: ! 733: case SIOCSIFFLAGS: ! 734: if ((ifp->if_flags & IFF_UP) == 0 && ! 735: ifp->if_flags & IFF_RUNNING) { ! 736: addr->ec_xcr = EC_UECLR; ! 737: ifp->if_flags &= ~IFF_RUNNING; ! 738: } else if (ifp->if_flags & IFF_UP && ! 739: (ifp->if_flags & IFF_RUNNING) == 0) ! 740: ecinit(ifp->if_unit); ! 741: break; ! 742: ! 743: default: ! 744: error = EINVAL; ! 745: } ! 746: splx(s); ! 747: return (error); ! 748: } ! 749: ! 750: ec_setaddr(physaddr,unit) ! 751: u_char *physaddr; ! 752: int unit; ! 753: { ! 754: struct ec_softc *es = &ec_softc[unit]; ! 755: struct uba_device *ui = ecinfo[unit]; ! 756: register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr; ! 757: register char nibble; ! 758: register int i, j; ! 759: ! 760: /* ! 761: * Use the ethernet address supplied ! 762: * Note that we do a UECLR here, so the receive buffers ! 763: * must be requeued. ! 764: */ ! 765: ! 766: #ifdef DEBUG ! 767: printf("ec_setaddr: setting address for unit %d = %s", ! 768: unit, ether_sprintf(physaddr)); ! 769: #endif ! 770: addr->ec_xcr = EC_UECLR; ! 771: addr->ec_rcr = 0; ! 772: /* load requested address */ ! 773: for (i = 0; i < 6; i++) { /* 6 bytes of address */ ! 774: es->es_addr[i] = physaddr[i]; ! 775: nibble = physaddr[i] & 0xf; /* lower nibble */ ! 776: addr->ec_rcr = (nibble << 8); ! 777: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ ! 778: addr->ec_rcr = (nibble << 8); ! 779: for (j=0; j < 4; j++) { ! 780: addr->ec_rcr = 0; ! 781: addr->ec_rcr = EC_ASTEP; /* step counter */ ! 782: addr->ec_rcr = 0; ! 783: } ! 784: nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */ ! 785: addr->ec_rcr = (nibble << 8); ! 786: addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */ ! 787: addr->ec_rcr = (nibble << 8); ! 788: for (j=0; j < 4; j++) { ! 789: addr->ec_rcr = 0; ! 790: addr->ec_rcr = EC_ASTEP; /* step counter */ ! 791: addr->ec_rcr = 0; ! 792: } ! 793: } ! 794: #ifdef DEBUG ! 795: /* ! 796: * Read the ethernet address off the board, one nibble at a time. ! 797: */ ! 798: addr->ec_xcr = EC_UECLR; ! 799: addr->ec_rcr = 0; /* read RAM */ ! 800: cp = es->es_addr; ! 801: #undef NEXTBIT ! 802: #define NEXTBIT addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0 ! 803: for (i=0; i < sizeof (es->es_addr); i++) { ! 804: *cp = 0; ! 805: for (j=0; j<=4; j+=4) { ! 806: *cp |= ((addr->ec_rcr >> 8) & 0xf) << j; ! 807: NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT; ! 808: } ! 809: cp++; ! 810: } ! 811: printf("ec_setaddr: RAM address for unit %d = %s", ! 812: unit, ether_sprintf(physaddr)); ! 813: #endif ! 814: } ! 815: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.