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.8 (Berkeley) 12/16/90
11 */
12
13 /*
14 * ACC VERSAbus Ethernet controller
15 */
16 #include "ace.h"
17 #if NACE > 0
18
19 #include "sys/param.h"
20 #include "sys/systm.h"
21 #include "sys/malloc.h"
22 #include "sys/mbuf.h"
23 #include "sys/buf.h"
24 #include "sys/protosw.h"
25 #include "sys/socket.h"
26 #include "sys/vmmac.h"
27 #include "sys/ioctl.h"
28 #include "sys/errno.h"
29 #include "sys/vmparam.h"
30 #include "sys/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 "../include/cpu.h"
49 #include "../include/pte.h"
50
51 #include "../include/mtpr.h"
52 #include "../if/if_acereg.h"
53 #include "../vba/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
aceprobe(reg,vi)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 */
acereset(unit,vban)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 */
aceinit(unit)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 */
acestart(ifp)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 */
acecint(unit)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 */
acerint(unit)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 */
aceput(txbuf,m)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 *
aceget(rxbuf,totlen,off,ifp)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 */
aceioctl(ifp,cmd,data)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 */
acesetaddr(unit,addr,station)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 */
acesetup(unit)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