|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that the above copyright notice and this paragraph are ! 7: * duplicated in all such forms and that any documentation, ! 8: * advertising materials, and other materials related to such ! 9: * distribution and use acknowledge that the software was developed ! 10: * by the University of California, Berkeley. The name of the ! 11: * University may not be used to endorse or promote products derived ! 12: * from this software without specific prior written permission. ! 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 16: * ! 17: * @(#)if_ace.c 7.2 (Berkeley) 6/29/88 ! 18: */ ! 19: ! 20: /* ! 21: * ACC VERSAbus Ethernet controller ! 22: */ ! 23: #include "ace.h" ! 24: #if NACE > 0 ! 25: ! 26: #include "param.h" ! 27: #include "systm.h" ! 28: #include "mbuf.h" ! 29: #include "buf.h" ! 30: #include "protosw.h" ! 31: #include "socket.h" ! 32: #include "vmmac.h" ! 33: #include "ioctl.h" ! 34: #include "errno.h" ! 35: #include "vmparam.h" ! 36: #include "syslog.h" ! 37: ! 38: #include "../net/if.h" ! 39: #include "../net/netisr.h" ! 40: #include "../net/route.h" ! 41: #ifdef INET ! 42: #include "../netinet/in.h" ! 43: #include "../netinet/in_systm.h" ! 44: #include "../netinet/in_var.h" ! 45: #include "../netinet/ip.h" ! 46: #include "../netinet/ip_var.h" ! 47: #include "../netinet/if_ether.h" ! 48: #endif ! 49: #ifdef NS ! 50: #include "../netns/ns.h" ! 51: #include "../netns/ns_if.h" ! 52: #endif ! 53: ! 54: #include "../machine/cpu.h" ! 55: #include "../machine/pte.h" ! 56: ! 57: #include "../tahoe/mtpr.h" ! 58: #include "../tahoeif/if_acereg.h" ! 59: #include "../tahoevba/vbavar.h" ! 60: ! 61: int aceprobe(), aceattach(), acerint(), acecint(); ! 62: struct vba_device *aceinfo[NACE]; ! 63: long acestd[] = { 0 }; ! 64: struct vba_driver acedriver = ! 65: { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 }; ! 66: ! 67: int aceinit(), aceoutput(), aceioctl(), acereset(); ! 68: struct mbuf *aceget(); ! 69: ! 70: /* ! 71: * Ethernet software status per interface. ! 72: * ! 73: * Each interface is referenced by a network interface structure, ! 74: * is_if, which the routing code uses to locate the interface. ! 75: * This structure contains the output queue for the interface, its address, ... ! 76: */ ! 77: struct ace_softc { ! 78: struct arpcom is_ac; /* Ethernet common part */ ! 79: #define is_if is_ac.ac_if /* network-visible interface */ ! 80: #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ ! 81: short is_flags; ! 82: #define ACEF_OACTIVE 0x1 /* output is active */ ! 83: #define ACEF_RCVPENDING 0x2 /* start rcv in acecint */ ! 84: short is_promiscuous; /* true is enabled */ ! 85: short is_segboundry; /* first TX Seg in dpm */ ! 86: short is_eictr; /* Rx segment tracking ctr */ ! 87: short is_eoctr; /* Tx segment tracking ctr */ ! 88: short is_txnext; /* Next available Tx segment */ ! 89: short is_currnd; /* current random backoff */ ! 90: struct ace_stats is_stats; /* holds board statistics */ ! 91: short is_xcnt; /* count xmitted segments to be acked ! 92: by the controller */ ! 93: long is_ivec; /* autoconfig interrupt vector base */ ! 94: struct pte *is_map; /* pte map for dual ported memory */ ! 95: caddr_t is_dpm; /* address of mapped memory */ ! 96: } ace_softc[NACE]; ! 97: extern struct ifnet loif; ! 98: ! 99: aceprobe(reg, vi) ! 100: caddr_t reg; ! 101: struct vba_device *vi; ! 102: { ! 103: register br, cvec; /* must be r12, r11 */ ! 104: struct acedevice *ap = (struct acedevice *)reg; ! 105: struct ace_softc *is = &ace_softc[vi->ui_unit]; ! 106: ! 107: #ifdef lint ! 108: br = 0; cvec = br; br = cvec; ! 109: acerint(0); acecint(0); ! 110: #endif ! 111: if (badaddr(reg, 2)) ! 112: return (0); ! 113: movow(&ap->csr, CSR_RESET); ! 114: DELAY(10000); ! 115: #ifdef notdef ! 116: /* ! 117: * Select two spaces for the interrupts aligned to an ! 118: * eight vector boundary and fitting in 8 bits (as ! 119: * required by the controller) -- YECH. The controller ! 120: * will be notified later at initialization time. ! 121: */ ! 122: if ((vi->ui_hd->vh_lastiv -= 2) > 0xff) ! 123: vi->ui_hd->vh_lastiv = 0x200; ! 124: is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7; ! 125: #else ! 126: is->is_ivec = 0x90+vi->ui_unit*8; ! 127: #endif ! 128: br = 0x14, cvec = is->is_ivec; /* XXX */ ! 129: return (sizeof (*ap)); ! 130: } ! 131: ! 132: /* ! 133: * Interface exists: make available by filling in network interface ! 134: * record. System will initialize the interface when it is ready ! 135: * to accept packets. ! 136: */ ! 137: aceattach(ui) ! 138: struct vba_device *ui; ! 139: { ! 140: register short unit = ui->ui_unit; ! 141: register struct ace_softc *is = &ace_softc[unit]; ! 142: register struct ifnet *ifp = &is->is_if; ! 143: register struct acedevice *addr = (struct acedevice *)ui->ui_addr; ! 144: register short *wp, i; ! 145: ! 146: ifp->if_unit = unit; ! 147: ifp->if_name = "ace"; ! 148: ifp->if_mtu = ETHERMTU; ! 149: /* ! 150: * Get station's addresses and set multicast hash table. ! 151: */ ! 152: for (wp = (short *)addr->station, i = 0; i < 6; i++) ! 153: is->is_addr[i] = ~*wp++; ! 154: printf("ace%d: hardware address %s\n", unit, ! 155: ether_sprintf(is->is_addr)); ! 156: is->is_promiscuous = 0; ! 157: for (wp = (short *)addr->hash, i = 0; i < 8; i++) ! 158: movow(wp++, ~0xf); ! 159: movow(&addr->bcastena[0], ~0xffff); ! 160: movow(&addr->bcastena[1], ~0xffff); ! 161: /* ! 162: * Allocate and map dual ported VERSAbus memory. ! 163: */ ! 164: if (vbmemalloc(32, (caddr_t)ui->ui_flags, ! 165: &is->is_map, &is->is_dpm) == 0) { ! 166: printf("ace%d: can't allocate VERSAbus memory map\n", unit); ! 167: return; ! 168: } ! 169: ! 170: ifp->if_init = aceinit; ! 171: ifp->if_output = aceoutput; ! 172: ifp->if_ioctl = aceioctl; ! 173: ifp->if_reset = acereset; ! 174: ifp->if_flags = IFF_BROADCAST; ! 175: if_attach(ifp); ! 176: } ! 177: ! 178: /* ! 179: * Reset of interface after "system" reset. ! 180: */ ! 181: acereset(unit, vban) ! 182: int unit, vban; ! 183: { ! 184: register struct vba_device *ui; ! 185: ! 186: if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 || ! 187: ui->ui_vbanum != vban) ! 188: return; ! 189: printf(" ace%d", unit); ! 190: aceinit(unit); ! 191: } ! 192: ! 193: /* ! 194: * Initialization of interface; clear recorded pending operations ! 195: */ ! 196: aceinit(unit) ! 197: int unit; ! 198: { ! 199: register struct ace_softc *is = &ace_softc[unit]; ! 200: register struct vba_device *ui = aceinfo[unit]; ! 201: register struct acedevice *addr; ! 202: register struct ifnet *ifp = &is->is_if; ! 203: register short Csr; ! 204: register int s; ! 205: ! 206: if (ifp->if_addrlist == (struct ifaddr *)0) ! 207: return; ! 208: if ((ifp->if_flags & IFF_RUNNING) == 0) { ! 209: /* ! 210: * Reset the controller, initialize the recieve buffers, ! 211: * and turn the controller on again and set board online. ! 212: */ ! 213: addr = (struct acedevice *)ui->ui_addr; ! 214: s = splimp(); ! 215: movow(&addr->csr, CSR_RESET); ! 216: DELAY(10000); ! 217: ! 218: /* ! 219: * Clean up dpm since the controller might ! 220: * jumble dpm after reset. ! 221: */ ! 222: acesetup(unit); ! 223: movow(&addr->csr, CSR_GO); ! 224: Csr = addr->csr; ! 225: if (Csr & CSR_ACTIVE) { ! 226: movow(&addr->ivct, is->is_ivec); ! 227: Csr |= CSR_IENA | is->is_promiscuous; ! 228: movow(&addr->csr, Csr); ! 229: is->is_flags = 0; ! 230: is->is_xcnt = 0; ! 231: is->is_if.if_flags |= IFF_RUNNING; ! 232: } ! 233: splx(s); ! 234: } ! 235: if (is->is_if.if_snd.ifq_head) ! 236: acestart(unit); ! 237: } ! 238: ! 239: /* ! 240: * Start output on interface. ! 241: * Get another datagram to send off of the interface queue, ! 242: * and map it to the interface before starting the output. ! 243: */ ! 244: acestart(unit) ! 245: int unit; ! 246: { ! 247: register struct tx_segment *txs; ! 248: register long len; ! 249: register int s; ! 250: register struct ace_softc *is = &ace_softc[unit]; ! 251: struct mbuf *m; ! 252: short retries; ! 253: ! 254: if (is->is_flags & ACEF_OACTIVE) ! 255: return; ! 256: is->is_flags |= ACEF_OACTIVE; ! 257: again: ! 258: txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11)); ! 259: if (txs->tx_csr & TCS_TBFULL) { ! 260: is->is_stats.tx_busy++; ! 261: is->is_flags &= ~ACEF_OACTIVE; ! 262: return; ! 263: } ! 264: s = splimp(); ! 265: IF_DEQUEUE(&is->is_if.if_snd, m); ! 266: splx(s); ! 267: if (m == 0) { ! 268: is->is_flags &= ~ACEF_OACTIVE; ! 269: return; ! 270: } ! 271: len = aceput(unit, txs->tx_data, m); ! 272: retries = txs->tx_csr & TCS_RTC; ! 273: if (retries > 0) ! 274: acebakoff(is, txs, retries); ! 275: ! 276: /* ! 277: * Ensure minimum packet length. ! 278: * This makes the safe assumtion that there are no virtual holes ! 279: * after the data. ! 280: * For security, it might be wise to zero out the added bytes, ! 281: * but we're mainly interested in speed at the moment. ! 282: */ ! 283: if (len - sizeof (struct ether_header) < ETHERMIN) ! 284: len = ETHERMIN + sizeof (struct ether_header); ! 285: if (++is->is_txnext > SEG_MAX) ! 286: is->is_txnext = is->is_segboundry; ! 287: is->is_if.if_opackets++; ! 288: is->is_xcnt++; ! 289: len = (len & 0x7fff) | TCS_TBFULL; ! 290: movow(txs, len); ! 291: goto again; ! 292: } ! 293: ! 294: /* ! 295: * Transmit done interrupt. ! 296: */ ! 297: acecint(unit) ! 298: int unit; ! 299: { ! 300: register struct ace_softc *is = &ace_softc[unit]; ! 301: register struct tx_segment *txseg; ! 302: short eostat; ! 303: ! 304: if (is->is_xcnt <= 0) { ! 305: log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n", ! 306: unit, is->is_xcnt); ! 307: is->is_xcnt = 0; ! 308: if (is->is_if.if_snd.ifq_head) ! 309: acestart(unit); ! 310: return; ! 311: } ! 312: is->is_xcnt--; ! 313: txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm); ! 314: eostat = txseg->tx_csr; ! 315: if ((eostat & TCS_TBFULL) == 0) { ! 316: is->is_stats.tx_retries += eostat & TCS_RTC; ! 317: if (eostat & TCS_RTFAIL) { ! 318: is->is_stats.tx_discarded++; ! 319: is->is_if.if_oerrors++; ! 320: } else ! 321: is->is_stats.tx_datagrams++; ! 322: if (++is->is_eoctr >= 16) ! 323: is->is_eoctr = is->is_segboundry; ! 324: } ! 325: if (is->is_if.if_snd.ifq_head) ! 326: acestart(unit); ! 327: } ! 328: ! 329: /* ! 330: * Ethernet interface receiver interrupt. ! 331: * If input error just drop packet. ! 332: * Otherwise purge input buffered data path and examine ! 333: * packet to determine type. If can't determine length ! 334: * from type, then have to drop packet. Othewise decapsulate ! 335: * packet based on type and pass to type specific higher-level ! 336: * input routine. ! 337: */ ! 338: acerint(unit) ! 339: int unit; ! 340: { ! 341: register struct ace_softc *is = &ace_softc[unit]; ! 342: register struct ifqueue *inq; ! 343: register struct ether_header *ace; ! 344: register struct rx_segment *rxseg; ! 345: int len, s, off, resid; ! 346: struct mbuf *m; ! 347: short eistat; ! 348: ! 349: if ((is->is_if.if_flags&IFF_RUNNING) == 0) ! 350: return; ! 351: again: ! 352: rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm); ! 353: eistat = rxseg->rx_csr; ! 354: if ((eistat & RCS_RBFULL) == 0) ! 355: return; ! 356: is->is_if.if_ipackets++; ! 357: if (++is->is_eictr >= is->is_segboundry) ! 358: is->is_eictr = 0; ! 359: len = eistat & RCS_RBC; ! 360: if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) || ! 361: len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) { ! 362: if (eistat & RCS_ROVRN) ! 363: is->is_stats.rx_overruns++; ! 364: if (eistat & RCS_RCRC) ! 365: is->is_stats.rx_crc_errors++; ! 366: if (eistat & RCS_RODD) ! 367: is->is_stats.rx_align_errors++; ! 368: if (len < ET_MINLEN) ! 369: is->is_stats.rx_underruns++; ! 370: if (len > ET_MAXLEN+CRC_SIZE) ! 371: is->is_stats.rx_overruns++; ! 372: is->is_if.if_ierrors++; ! 373: rxseg->rx_csr = 0; ! 374: return; ! 375: } else ! 376: is->is_stats.rx_datagrams++; ! 377: ace = (struct ether_header *)rxseg->rx_data; ! 378: len -= sizeof (struct ether_header); ! 379: /* ! 380: * Deal with trailer protocol: if type is trailer ! 381: * get true type from first 16-bit word past data. ! 382: * Remember that type was trailer by setting off. ! 383: */ ! 384: ace->ether_type = ntohs((u_short)ace->ether_type); ! 385: #define acedataaddr(ace, off, type) \ ! 386: ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off)))) ! 387: if (ace->ether_type >= ETHERTYPE_TRAIL && ! 388: ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 389: off = (ace->ether_type - ETHERTYPE_TRAIL) * 512; ! 390: if (off >= ETHERMTU) ! 391: goto setup; /* sanity */ ! 392: ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *)); ! 393: resid = ntohs(*(acedataaddr(ace, off+2, u_short *))); ! 394: if (off + resid > len) ! 395: goto setup; /* sanity */ ! 396: len = off + resid; ! 397: } else ! 398: off = 0; ! 399: if (len == 0) ! 400: goto setup; ! 401: ! 402: /* ! 403: * Pull packet off interface. Off is nonzero if packet ! 404: * has trailing header; aceget will then force this header ! 405: * information to be at the front, but we still have to drop ! 406: * the type and length which are at the front of any trailer data. ! 407: */ ! 408: m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if); ! 409: if (m == 0) ! 410: goto setup; ! 411: if (off) { ! 412: struct ifnet *ifp; ! 413: ! 414: ifp = *(mtod(m, struct ifnet **)); ! 415: m->m_off += 2 * sizeof (u_short); ! 416: m->m_len -= 2 * sizeof (u_short); ! 417: *(mtod(m, struct ifnet **)) = ifp; ! 418: } ! 419: switch (ace->ether_type) { ! 420: ! 421: #ifdef INET ! 422: case ETHERTYPE_IP: ! 423: schednetisr(NETISR_IP); ! 424: inq = &ipintrq; ! 425: break; ! 426: #endif ! 427: ! 428: case ETHERTYPE_ARP: ! 429: arpinput(&is->is_ac, m); ! 430: goto setup; ! 431: #ifdef NS ! 432: case ETHERTYPE_NS: ! 433: schednetisr(NETISR_NS); ! 434: inq = &nsintrq; ! 435: break; ! 436: ! 437: #endif ! 438: default: ! 439: m_freem(m); ! 440: goto setup; ! 441: } ! 442: if (IF_QFULL(inq)) { ! 443: IF_DROP(inq); ! 444: m_freem(m); ! 445: goto setup; ! 446: } ! 447: s = splimp(); ! 448: IF_ENQUEUE(inq, m); ! 449: splx(s); ! 450: setup: ! 451: rxseg->rx_csr = 0; ! 452: goto again; ! 453: } ! 454: ! 455: /* ! 456: * Ethernet output routine. ! 457: * Encapsulate a packet of type family for the local net. ! 458: * Use trailer local net encapsulation if enough data in first ! 459: * packet leaves a multiple of 512 bytes of data in remainder. ! 460: */ ! 461: aceoutput(ifp, m0, dst) ! 462: struct ifnet *ifp; ! 463: struct mbuf *m0; ! 464: struct sockaddr *dst; ! 465: { ! 466: register struct ace_softc *is = &ace_softc[ifp->if_unit]; ! 467: register struct mbuf *m = m0; ! 468: register struct ether_header *ace; ! 469: register int off; ! 470: struct mbuf *mcopy = (struct mbuf *)0; ! 471: int type, s, error, usetrailers; ! 472: u_char edst[6]; ! 473: struct in_addr idst; ! 474: ! 475: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 476: error = ENETDOWN; ! 477: goto bad; ! 478: } ! 479: switch (dst->sa_family) { ! 480: ! 481: #ifdef INET ! 482: case AF_INET: ! 483: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 484: if (!arpresolve(&is->is_ac, m, &idst, edst, &usetrailers)) ! 485: return (0); /* if not yet resolved */ ! 486: if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, ! 487: sizeof (edst))) ! 488: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 489: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; ! 490: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 491: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { ! 492: type = ETHERTYPE_TRAIL + (off>>9); ! 493: m->m_off -= 2 * sizeof (u_short); ! 494: m->m_len += 2 * sizeof (u_short); ! 495: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); ! 496: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 497: goto gottrailertype; ! 498: } ! 499: type = ETHERTYPE_IP; ! 500: off = 0; ! 501: goto gottype; ! 502: #endif ! 503: #ifdef NS ! 504: case AF_NS: ! 505: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 506: (caddr_t)edst, sizeof (edst)); ! 507: if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst))) ! 508: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 509: else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, ! 510: sizeof(edst))) ! 511: return(looutput(&loif, m, dst)); ! 512: type = ETHERTYPE_NS; ! 513: off = 0; ! 514: goto gottype; ! 515: #endif ! 516: case AF_UNSPEC: ! 517: ace = (struct ether_header *)dst->sa_data; ! 518: bcopy((caddr_t)ace->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 519: type = ace->ether_type; ! 520: goto gottype; ! 521: ! 522: default: ! 523: log(LOG_ERR, "ace%d: can't handle af%d\n", ! 524: ifp->if_unit, dst->sa_family); ! 525: error = EAFNOSUPPORT; ! 526: goto bad; ! 527: } ! 528: ! 529: gottrailertype: ! 530: /* ! 531: * Packet to be sent as trailer: move first packet ! 532: * (control information) to end of chain. ! 533: */ ! 534: while (m->m_next) ! 535: m = m->m_next; ! 536: m->m_next = m0; ! 537: m = m0->m_next; ! 538: m0->m_next = 0; ! 539: m0 = m; ! 540: ! 541: gottype: ! 542: /* ! 543: * Add local net header. If no space in first mbuf, ! 544: * allocate another. ! 545: */ ! 546: if (m->m_off > MMAXOFF || ! 547: MMINOFF + sizeof (struct ether_header) > m->m_off) { ! 548: m = m_get(M_DONTWAIT, MT_HEADER); ! 549: if (m == 0) { ! 550: error = ENOBUFS; ! 551: goto bad; ! 552: } ! 553: m->m_next = m0; ! 554: m->m_off = MMINOFF; ! 555: m->m_len = sizeof (struct ether_header); ! 556: } else { ! 557: m->m_off -= sizeof (struct ether_header); ! 558: m->m_len += sizeof (struct ether_header); ! 559: } ! 560: ace = mtod(m, struct ether_header *); ! 561: bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst)); ! 562: bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost, ! 563: sizeof (is->is_addr)); ! 564: ace->ether_type = htons((u_short)type); ! 565: ! 566: /* ! 567: * Queue message on interface, and start output if interface ! 568: * not yet active. ! 569: */ ! 570: s = splimp(); ! 571: if (IF_QFULL(&ifp->if_snd)) { ! 572: IF_DROP(&ifp->if_snd); ! 573: error = ENOBUFS; ! 574: goto qfull; ! 575: } ! 576: IF_ENQUEUE(&ifp->if_snd, m); ! 577: splx(s); ! 578: acestart(ifp->if_unit); ! 579: return (mcopy ? looutput(&loif, mcopy, dst) : 0); ! 580: qfull: ! 581: m0 = m; ! 582: splx(s); ! 583: bad: ! 584: m_freem(m0); ! 585: if (mcopy) ! 586: m_freem(mcopy); ! 587: return (error); ! 588: } ! 589: ! 590: /* ! 591: * Routine to copy from mbuf chain to transmit buffer on the VERSAbus ! 592: * If packet size is less than the minimum legal size, ! 593: * the buffer is expanded. We probably should zero out the extra ! 594: * bytes for security, but that would slow things down. ! 595: */ ! 596: /*ARGSUSED*/ ! 597: aceput(unit, txbuf, m) ! 598: int unit; ! 599: char *txbuf; ! 600: struct mbuf *m; ! 601: { ! 602: register u_char *bp, *mcp; ! 603: register short *s1, *s2; ! 604: register u_int len; ! 605: register struct mbuf *mp; ! 606: int total; ! 607: ! 608: total = 0; ! 609: bp = (u_char *)txbuf; ! 610: for (mp = m; (mp); mp = mp->m_next) { ! 611: len = mp->m_len; ! 612: if (len == 0) ! 613: continue; ! 614: total += len; ! 615: mcp = mtod(mp, u_char *); ! 616: if (((int)mcp & 01) && ((int)bp & 01)) { ! 617: /* source & destination at odd addresses */ ! 618: movob(bp++, *mcp++); ! 619: --len; ! 620: } ! 621: if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) { ! 622: register u_int l; ! 623: ! 624: s1 = (short *)bp; ! 625: s2 = (short *)mcp; ! 626: l = len >> 1; /* count # of shorts */ ! 627: while (l-- != 0) ! 628: movow(s1++, *s2++); ! 629: len &= 1; /* # remaining bytes */ ! 630: bp = (u_char *)s1; ! 631: mcp = (u_char *)s2; ! 632: } ! 633: while (len-- != 0) ! 634: movob(bp++, *mcp++); ! 635: } ! 636: m_freem(m); ! 637: return (total); ! 638: } ! 639: ! 640: /* ! 641: * Routine to copy from VERSAbus memory into mbufs. ! 642: * ! 643: * Warning: This makes the fairly safe assumption that ! 644: * mbufs have even lengths. ! 645: */ ! 646: /*ARGSUSED*/ ! 647: struct mbuf * ! 648: aceget(rxbuf, totlen, off0, ifp) ! 649: u_char *rxbuf; ! 650: int totlen, off0; ! 651: struct ifnet *ifp; ! 652: { ! 653: register u_char *cp, *mcp; ! 654: register int tlen; ! 655: register struct mbuf *m; ! 656: struct mbuf *top = 0, **mp = ⊤ ! 657: int len, off = off0; ! 658: ! 659: cp = rxbuf + sizeof (struct ether_header); ! 660: while (totlen > 0) { ! 661: MGET(m, M_DONTWAIT, MT_DATA); ! 662: if (m == 0) ! 663: goto bad; ! 664: if (off) { ! 665: len = totlen - off; ! 666: cp = rxbuf + sizeof (struct ether_header) + off; ! 667: } else ! 668: len = totlen; ! 669: if (ifp) ! 670: len += sizeof(ifp); ! 671: if (len >= NBPG) { ! 672: MCLGET(m); ! 673: if (m->m_len == CLBYTES) ! 674: m->m_len = len = MIN(len, CLBYTES); ! 675: else ! 676: m->m_len = len = MIN(MLEN, len); ! 677: } else { ! 678: m->m_len = len = MIN(MLEN, len); ! 679: m->m_off = MMINOFF; ! 680: } ! 681: mcp = mtod(m, u_char *); ! 682: if (ifp) { ! 683: /* ! 684: * Prepend interface pointer to first mbuf. ! 685: */ ! 686: *(mtod(m, struct ifnet **)) = ifp; ! 687: mcp += sizeof(ifp); ! 688: len -= sizeof(ifp); ! 689: ifp = (struct ifnet *)0; ! 690: } ! 691: /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/ ! 692: /*cp += len; mcp += len;*/ ! 693: tlen = len; ! 694: if (((int)mcp & 01) && ((int)cp & 01)) { ! 695: /* source & destination at odd addresses */ ! 696: *mcp++ = *cp++; ! 697: --tlen; ! 698: } ! 699: if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) { ! 700: register short *s1, *s2; ! 701: register int l; ! 702: ! 703: s1 = (short *)mcp; ! 704: s2 = (short *)cp; ! 705: l = tlen >> 1; /* count # of shorts */ ! 706: while (l-- > 0) /* copy shorts */ ! 707: *s1++ = *s2++; ! 708: tlen &= 1; /* # remaining bytes */ ! 709: mcp = (u_char *)s1; ! 710: cp = (u_char *)s2; ! 711: } ! 712: while (tlen-- > 0) ! 713: *mcp++ = *cp++; ! 714: *mp = m; ! 715: mp = &m->m_next; ! 716: if (off == 0) { ! 717: totlen -= len; ! 718: continue; ! 719: } ! 720: off += len; ! 721: if (off == totlen) { ! 722: cp = rxbuf + sizeof (struct ether_header); ! 723: off = 0; ! 724: totlen = off0; ! 725: } ! 726: } ! 727: return (top); ! 728: bad: ! 729: m_freem(top); ! 730: return (0); ! 731: } ! 732: ! 733: /* backoff table masks */ ! 734: short random_mask_tbl[16] = { ! 735: 0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0, ! 736: 0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0 ! 737: }; ! 738: ! 739: acebakoff(is, txseg, retries) ! 740: struct ace_softc *is; ! 741: struct tx_segment *txseg; ! 742: register int retries; ! 743: { ! 744: register short *pBakNum, random_num; ! 745: short *pMask; ! 746: ! 747: pMask = &random_mask_tbl[0]; ! 748: pBakNum = &txseg->tx_backoff[0]; ! 749: while (--retries >= 0) { ! 750: random_num = (is->is_currnd = (is->is_currnd * 18741)-13849); ! 751: random_num &= *pMask++; ! 752: *pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc); ! 753: } ! 754: } ! 755: ! 756: /* ! 757: * Process an ioctl request. ! 758: */ ! 759: aceioctl(ifp, cmd, data) ! 760: register struct ifnet *ifp; ! 761: int cmd; ! 762: caddr_t data; ! 763: { ! 764: register struct ifaddr *ifa = (struct ifaddr *)data; ! 765: struct acedevice *addr; ! 766: int s = splimp(), error = 0; ! 767: ! 768: switch (cmd) { ! 769: ! 770: case SIOCSIFADDR: ! 771: ifp->if_flags |= IFF_UP; ! 772: switch (ifa->ifa_addr.sa_family) { ! 773: #ifdef INET ! 774: case AF_INET: ! 775: aceinit(ifp->if_unit); /* before arpwhohas */ ! 776: ((struct arpcom *)ifp)->ac_ipaddr = ! 777: IA_SIN(ifa)->sin_addr; ! 778: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 779: break; ! 780: #endif ! 781: #ifdef NS ! 782: case AF_NS: { ! 783: struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; ! 784: struct ace_softc *is = &ace_softc[ifp->if_unit]; ! 785: ! 786: if (!ns_nullhost(*ina)) { ! 787: ifp->if_flags &= ~IFF_RUNNING; ! 788: addr = (struct acedevice *) ! 789: aceinfo[ifp->if_unit]->ui_addr; ! 790: movow(&addr->csr, CSR_RESET); ! 791: DELAY(10000); ! 792: /* set station address & copy addr to arp */ ! 793: acesetaddr(ifp->if_unit, addr, ! 794: ina->x_host.c_host); ! 795: } else ! 796: ina->x_host = *(union ns_host *)is->is_addr; ! 797: aceinit(ifp->if_unit); ! 798: break; ! 799: } ! 800: #endif ! 801: default: ! 802: aceinit(ifp->if_unit); ! 803: break; ! 804: } ! 805: break; ! 806: ! 807: case SIOCSIFFLAGS: ! 808: if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { ! 809: addr = (struct acedevice *) ! 810: (aceinfo[ifp->if_unit]->ui_addr); ! 811: movow(&addr->csr, CSR_RESET); ! 812: ifp->if_flags &= ~IFF_RUNNING; ! 813: } else if (ifp->if_flags&IFF_UP && ! 814: (ifp->if_flags&IFF_RUNNING) == 0) ! 815: aceinit(ifp->if_unit); ! 816: break; ! 817: ! 818: default: ! 819: error = EINVAL; ! 820: } ! 821: splx(s); ! 822: return (error); ! 823: } ! 824: ! 825: /* ! 826: * Set the on-board station address, then read it back ! 827: * to initialize the address used by ARP (among others). ! 828: */ ! 829: acesetaddr(unit, addr, station) ! 830: short unit; ! 831: struct acedevice *addr; ! 832: u_char *station; ! 833: { ! 834: struct ace_softc *is = &ace_softc[unit]; ! 835: register short *wp, i; ! 836: ! 837: for (wp = (short *)addr->station, i = 0; i < 6; i++) ! 838: movow(wp++, ~*station++); ! 839: for (wp = (short *)addr->station, i = 0; i < 6; i++) ! 840: is->is_addr[i] = ~*wp++; ! 841: printf("ace%d: hardware address %s\n", unit, ! 842: ether_sprintf(is->is_addr)); ! 843: } ! 844: ! 845: /* ! 846: * Setup the device for use. Initialize dual-ported memory, ! 847: * backoff parameters, and various other software state. ! 848: */ ! 849: acesetup(unit) ! 850: int unit; ! 851: { ! 852: register struct ace_softc *is = &ace_softc[unit]; ! 853: register char *pData1; ! 854: register short i; ! 855: struct acedevice *addr; ! 856: ! 857: bzero(is->is_dpm, 16384*2); ! 858: is->is_currnd = 49123; ! 859: addr = (struct acedevice *)aceinfo[unit]->ui_addr; ! 860: is->is_segboundry = (addr->segb >> 11) & 0xf; ! 861: pData1 = is->is_dpm + (is->is_segboundry << 11); ! 862: for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) { ! 863: acebakoff(is, (struct tx_segment *)pData1, 15); ! 864: pData1 += sizeof (struct tx_segment); ! 865: } ! 866: is->is_eictr = 0; ! 867: is->is_eoctr = is->is_txnext = is->is_segboundry; ! 868: bzero((char *)&is->is_stats, sizeof (is->is_stats)); ! 869: } ! 870: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.