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) 06/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 871