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