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