xref: /csrg-svn/sys/tahoe/if/if_ace.c (revision 25694)
1 /*	if_ace.c	1.2	86/01/05	*/
2 
3 /*
4  * ACC VERSAbus Ethernet controller
5  */
6 #include "ace.h"
7 #if NACE > 0
8 
9 #include "../machine/pte.h"
10 
11 #include "param.h"
12 #include "systm.h"
13 #include "mbuf.h"
14 #include "buf.h"
15 #include "protosw.h"
16 #include "socket.h"
17 #include "vmmac.h"
18 #include "ioctl.h"
19 #include "errno.h"
20 #include "vmparam.h"
21 
22 #include "../net/if.h"
23 #include "../net/netisr.h"
24 #include "../net/route.h"
25 #include "../netinet/in.h"
26 #include "../netinet/in_systm.h"
27 #include "../netinet/in_var.h"
28 #include "../netinet/ip.h"
29 #include "../netinet/ip_var.h"
30 #include "../netinet/if_ether.h"
31 
32 #include "../tahoe/mtpr.h"
33 #include "../tahoeif/if_acereg.h"
34 #include "../tahoevba/vbavar.h"
35 
36 #define	LONET	124
37 
38 /*
39  * Configuration table, for 2 units (should be defined by config)
40  */
41 #define	ACEVECTOR	0x90
42 long	acestd[] = { 0x0ff0000, 0xff0100 };		/* controller */
43 
44 extern	char ace0utl[], ace1utl[];			/* dpm */
45 char	*acemap[]= { ace0utl, ace1utl };
46 extern	struct pte ACE0map[], ACE1map[];
47 struct	pte *ACEmap[] = { ACE0map, ACE1map };
48 caddr_t	ACEmapa[] = { (caddr_t)0xfff80000, (caddr_t)0xfff90000 };
49 
50 /* station address */
51 char	ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 };
52 /* multicast hash table initializer */
53 char	ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF };
54 /* backoff table masks */
55 short random_mask_tbl[16] = {
56 	0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
57 	0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
58 };
59 
60 int	aceprobe(), aceattach(), acerint(), acecint();
61 struct	vba_device *aceinfo[NACE];
62 struct	vba_driver acedriver =
63 	{ aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
64 
65 #define	ACEUNIT(x)	minor(x)
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 	char	*is_dpm;
82 	short	is_flags;
83 #define	ACEF_OACTIVE	0x1		/* output is active */
84 #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
85 	short	is_promiscuous;		/* true is enabled */
86 	short	is_segboundry;		/* first TX Seg in dpm */
87 	short	is_eictr;		/* Rx segment tracking ctr */
88 	short	is_eoctr;		/* Tx segment tracking ctr */
89 	short	is_txnext;		/* Next available Tx segment */
90 	short	is_currnd;		/* current random backoff */
91 	struct	ace_stats is_stats;	/* holds board statistics */
92 	short	is_xcnt;		/* count xmitted segments to be acked
93 					   by the controller */
94 } ace_softc[NACE];
95 extern	struct ifnet loif;
96 
97 aceprobe(reg)
98 	caddr_t reg;
99 {
100 	register struct acedevice *addr = (struct acedevice *)reg;
101 
102 #ifdef lint
103 	acerint(0); acecint(0);
104 #endif
105 	if (badaddr(reg, 2))
106 		return(0);
107 	movow(&addr->csr, CSR_RESET);
108 	DELAY(10000);
109 	return (sizeof (struct acedevice));
110 }
111 
112 /*
113  * Interface exists: make available by filling in network interface
114  * record.  System will initialize the interface when it is ready
115  * to accept packets.
116  */
117 aceattach(ui)
118 	struct vba_device *ui;
119 {
120 	register short unit = ui->ui_unit;
121 	register struct ace_softc *is = &ace_softc[unit];
122 	register struct ifnet *ifp = &is->is_if;
123 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
124 	register short *wp, i;
125 
126 	ifp->if_unit = unit;
127 	ifp->if_name = "ace";
128 	ifp->if_mtu = ETHERMTU;
129 	/*
130 	 * Set station's addresses, multicast
131 	 * hash table, and initialize dual ported memory.
132 	 */
133 	ace_station[5] = ~(unit + 1);
134 	acesetetaddr(unit, addr, ace_station);
135 	is->is_promiscuous = 0;
136 	wp = (short *)addr->hash;
137 	for (i =  0; i < 8; i++)
138 		movow(wp++, ace_hash[i]);
139 	movow(&addr->bcastena[0], ~0xffff);
140 	movow(&addr->bcastena[1], ~0xffff);
141 	aceclean(unit);
142 	ifp->if_init = aceinit;
143 	ifp->if_output = aceoutput;
144 	ifp->if_ioctl = aceioctl;
145 	ifp->if_reset = acereset;
146 	ifp->if_flags = IFF_BROADCAST;
147 	if_attach(ifp);
148 }
149 
150 acesetetaddr(unit, addr, station_addr)
151 	short unit;
152 	struct acedevice *addr;
153 	char *station_addr;
154 {
155 	register short *wp, i;
156 	register char *cp;
157 	struct ace_softc *is = &ace_softc[unit];
158 
159 	wp = (short *)addr->station;
160 	cp = station_addr;
161 	for (i = 0; i < 6; i++)
162 		movow(wp++, *cp++);
163 	wp = (short *)addr->station;
164 	cp = (char *)is->is_addr;
165 	for (i = 0; i < 6; i++)
166 		*cp++ = ~(*wp++);
167 }
168 
169 /*
170  * Reset of interface after "system" reset.
171  */
172 acereset(unit, vban)
173 	int unit, vban;
174 {
175 	register struct vba_device *ui;
176 
177 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
178 	    ui->ui_vbanum != vban)
179 		return;
180 	printf(" ace%d", unit);
181 	aceinit(unit);
182 }
183 
184 /*
185  * Initialization of interface; clear recorded pending operations
186  */
187 aceinit(unit)
188 	int unit;
189 {
190 	register struct ace_softc *is = &ace_softc[unit];
191 	register struct vba_device *ui = aceinfo[unit];
192 	register struct acedevice *addr;
193 	register struct ifnet *ifp = &is->is_if;
194 	register short Csr;
195 	register int s;
196 
197 	if (ifp->if_addrlist == (struct ifaddr *)0)
198 		return;
199 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
200 		/*
201 		 * Reset the controller, initialize the recieve buffers,
202 		 * and turn the controller on again and set board online.
203 		 */
204 		addr = (struct acedevice *)ui->ui_addr;
205 		s = splimp();
206 		movow(&addr->csr, CSR_RESET);
207 		DELAY(10000);
208 
209 		/*
210 		 * clean up dpm since the controller might
211 		 * jumble dpm after reset
212 		 */
213 		aceclean(unit);
214 		movow(&addr->csr, CSR_GO);
215 		Csr = addr->csr;
216 		if (Csr & CSR_ACTIVE) {
217 			movow(&addr->ivct, ACEVECTOR + unit*8);
218 			Csr |= CSR_IENA | is->is_promiscuous;
219 #ifdef notdef
220 			if (ifp->if_net == LONET)
221 				Csr |= CSR_LOOP3;
222 #endif
223 			movow(&addr->csr, Csr);
224 			is->is_flags = 0;
225 			is->is_xcnt = 0;
226 			is->is_if.if_flags |= IFF_RUNNING;
227 		}
228 		splx(s);
229 	}
230 	if (is->is_if.if_snd.ifq_head)
231 		aceStart(unit);
232 }
233 
234 /*
235  * Start output on interface.
236  * Get another datagram to send off of the interface queue,
237  * and map it to the interface before starting the output.
238  *
239  */
240 acestart(dev)
241 	dev_t dev;
242 {
243 	register struct tx_segment *txs;
244 	register long len;
245 	register int s;
246 	int unit = ACEUNIT(dev);
247 	register struct ace_softc *is = &ace_softc[unit];
248 	struct mbuf *m;
249 	short retries;
250 
251 again:
252 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
253 	if (txs->tx_csr & TCS_TBFULL) {
254 		is->is_stats.tx_busy++;
255 		return;
256 	}
257 	s = splimp();
258 	IF_DEQUEUE(&is->is_if.if_snd, m);
259 	splx(s);
260 	if (m == 0)
261 		return;
262 	len = aceput(unit, 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 #ifdef notdef
275 	if (len - sizeof (struct ether_header) < ETHERMIN)
276 		len = ETHERMIN + sizeof (struct ether_header);
277 #else
278 	if (len - 14 < ETHERMIN)
279 		len = ETHERMIN + 14;
280 #endif
281 	if (++is->is_txnext > SEG_MAX)
282 		is->is_txnext = is->is_segboundry;
283 	is->is_if.if_opackets++;
284 	is->is_xcnt++;
285 	len = (len & 0x7fff) | TCS_TBFULL;
286 	movow(txs, len);
287 	goto again;
288 }
289 
290 /*
291  * Transmit done interrupt.
292  */
293 acecint(unit)
294 	int unit;
295 {
296 	register struct ace_softc *is = &ace_softc[unit];
297 	register struct tx_segment *txseg;
298 	short eostat;
299 
300 	if (is->is_xcnt <= 0)  {
301 		printf("ace%d: stray xmit interrupt, xcnt %d\n",
302 		    unit, is->is_xcnt);
303 		is->is_xcnt = 0;
304 		if (is->is_if.if_snd.ifq_head)
305 			aceStart(unit);
306 		return;
307 	}
308 	is->is_xcnt--;
309 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
310 	eostat = txseg->tx_csr;
311 	if ((eostat & TCS_TBFULL) == 0) {
312 		is->is_stats.tx_retries += eostat & TCS_RTC;
313 		if (eostat & TCS_RTFAIL)  {
314 			is->is_stats.tx_discarded++;
315 			is->is_if.if_oerrors++;
316 		} else
317 			is->is_stats.tx_datagrams++;
318 		if (++is->is_eoctr >= 16)
319 			is->is_eoctr = is->is_segboundry;
320 	}
321 	if (is->is_if.if_snd.ifq_head)
322 		aceStart(unit);
323 }
324 
325 /*
326  * Ethernet interface receiver interrupt.
327  * If input error just drop packet.
328  * Otherwise purge input buffered data path and examine
329  * packet to determine type.  If can't determine length
330  * from type, then have to drop packet.  Othewise decapsulate
331  * packet based on type and pass to type specific higher-level
332  * input routine.
333  */
334 acerint(unit)
335 	int unit;
336 {
337 	register struct ace_softc *is = &ace_softc[unit];
338 	register struct ifqueue *inq;
339 	register struct ether_header *ace;
340 	register struct rx_segment *rxseg;
341 	int len, s, off, resid;
342 	struct mbuf *m;
343 	short eistat;
344 
345 	if ((is->is_if.if_flags&IFF_RUNNING) == 0)
346 		return;
347 again:
348 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
349 	eistat = rxseg->rx_csr;
350 	if ((eistat & RCS_RBFULL) == 0)
351 		return;
352 	is->is_if.if_ipackets++;
353 	if (++is->is_eictr >= is->is_segboundry)
354 		is->is_eictr = 0;
355 	len = eistat & RCS_RBC;
356 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
357 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
358 		if (eistat & RCS_ROVRN)
359 			is->is_stats.rx_overruns++;
360 		if (eistat & RCS_RCRC)
361 			is->is_stats.rx_crc_errors++;
362 		if (eistat & RCS_RODD)
363 			is->is_stats.rx_align_errors++;
364 		if (len < ET_MINLEN)
365 			is->is_stats.rx_underruns++;
366 		if (len > ET_MAXLEN+CRC_SIZE)
367 			is->is_stats.rx_overruns++;
368 		is->is_if.if_ierrors++;
369 		rxseg->rx_csr = 0;
370 		return;
371 	} else
372 		is->is_stats.rx_datagrams++;
373 	ace = (struct ether_header *)rxseg->rx_data;
374 #ifdef notdef
375 	len -= sizeof (struct ether_header);
376 #else
377 	len -= 14;
378 #endif
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 #ifdef notdef
386 #define	acedataaddr(ace, off, type) \
387     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
388 #else
389 #define	acedataaddr(ace, off, type) \
390     ((type)(((caddr_t)(((char *)ace)+14)+(off))))
391 #endif
392 	if (ace->ether_type >= ETHERTYPE_TRAIL &&
393 	    ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
394 		off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
395 		if (off >= ETHERMTU)
396 			goto setup;		/* sanity */
397 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
398 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
399 		if (off + resid > len)
400 			goto setup;		/* sanity */
401 		len = off + resid;
402 	} else
403 		off = 0;
404 	if (len == 0)
405 		goto setup;
406 
407 	/*
408 	 * Pull packet off interface.  Off is nonzero if packet
409 	 * has trailing header; aceget will then force this header
410 	 * information to be at the front, but we still have to drop
411 	 * the type and length which are at the front of any trailer data.
412 	 */
413 	m = aceget(unit, (u_char *)rxseg->rx_data, len, off);
414 	if (m == 0)
415 		goto setup;
416 	if (off) {
417 		m->m_off += 2 * sizeof (u_short);
418 		m->m_len -= 2 * sizeof (u_short);
419 	}
420 	switch (ace->ether_type) {
421 
422 #ifdef INET
423 	case ETHERTYPE_IP:
424 		schednetisr(NETISR_IP);
425 		inq = &ipintrq;
426 		break;
427 
428 	case ETHERTYPE_ARP:
429 		arpinput(&is->is_ac, m);
430 		goto setup;
431 #endif
432 #ifdef NS
433 	case ETHERTYPE_NS:
434 		schednetisr(NETISR_NS);
435 		inq = &nsintrq;
436 		break;
437 
438 #endif
439 	default:
440 		m_freem(m);
441 		goto setup;
442 	}
443 	if (IF_QFULL(inq)) {
444 		IF_DROP(inq);
445 		m_freem(m);
446 		goto setup;
447 	}
448 	s = splimp();
449 	IF_ENQUEUE(inq, m);
450 	splx(s);
451 setup:
452 	rxseg->rx_csr = 0;
453 	goto again;
454 }
455 
456 /*
457  * Ethernet output routine.
458  * Encapsulate a packet of type family for the local net.
459  * Use trailer local net encapsulation if enough data in first
460  * packet leaves a multiple of 512 bytes of data in remainder.
461  */
462 aceoutput(ifp, m0, dst)
463 	struct ifnet *ifp;
464 	struct mbuf *m0;
465 	struct sockaddr *dst;
466 {
467 	register struct ace_softc *is = &ace_softc[ifp->if_unit];
468 	register struct mbuf *m = m0;
469 	register struct ether_header *ace;
470 	register int off;
471 	struct mbuf *mcopy = (struct mbuf *)0;
472 	int type, s, error;
473 	u_char edst[6];
474 	struct in_addr idst;
475 
476 	switch (dst->sa_family) {
477 
478 #ifdef INET
479 	case AF_INET:
480 		idst = ((struct sockaddr_in *)dst)->sin_addr;
481 		if (!arpresolve(&is->is_ac, m, &idst, edst))
482 			return (0);	/* if not yet resolved */
483 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
484 		    sizeof(edst)))
485 			mcopy = m_copy(m, 0, (int)M_COPYALL);
486 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
487 		/* need per host negotiation */
488 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 &&
489 		    (off & 0x1ff) == 0 &&
490 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
491 			type = ETHERTYPE_TRAIL + (off>>9);
492 			m->m_off -= 2 * sizeof (u_short);
493 			m->m_len += 2 * sizeof (u_short);
494 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
495 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
496 			goto gottrailertype;
497 		}
498 		type = ETHERTYPE_IP;
499 		off = 0;
500 		goto gottype;
501 #endif
502 #ifdef NS
503 	case AF_NS:
504  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
505 		    (caddr_t)edst, sizeof (edst));
506 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst)))
507 			mcopy = m_copy(m, 0, (int)M_COPYALL);
508 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
509 		    sizeof(edst)))
510 			return(looutput(&loif, m, dst));
511 		type = ETHERTYPE_NS;
512 		off = 0;
513 		goto gottype;
514 #endif
515 
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 		printf("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 #ifdef notdef
548 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
549 #else
550 	    MMINOFF + 14 > m->m_off) {
551 #endif
552 		m = m_get(M_DONTWAIT, MT_HEADER);
553 		if (m == 0) {
554 			error = ENOBUFS;
555 			goto bad;
556 		}
557 		m->m_next = m0;
558 		m->m_off = MMINOFF;
559 #ifdef notdef
560 		m->m_len = sizeof (struct ether_header);
561 #else
562 		m->m_len = 14;
563 #endif
564 	} else {
565 #ifdef notdef
566 		m->m_off -= sizeof (struct ether_header);
567 		m->m_len += sizeof (struct ether_header);
568 #else
569 		m->m_off -= 14;
570 		m->m_len += 14;
571 #endif
572 	}
573 	ace = mtod(m, struct ether_header *);
574 	bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst));
575 	bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost,
576 	    sizeof (is->is_addr));
577 	ace->ether_type = htons((u_short)type);
578 
579 	/*
580 	 * Queue message on interface, and start output if interface
581 	 * not yet active.
582 	 */
583 	s = splimp();
584 	if (IF_QFULL(&ifp->if_snd)) {
585 		IF_DROP(&ifp->if_snd);
586 		error = ENOBUFS;
587 		goto qfull;
588 	}
589 	IF_ENQUEUE(&ifp->if_snd, m);
590 	splx(s);
591 	aceStart(ifp->if_unit);
592 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
593 qfull:
594 	m0 = m;
595 	splx(s);
596 bad:
597 	m_freem(m0);
598 	if (mcopy)
599 		m_freem(mcopy);
600 	return (error);
601 }
602 
603 aceStart(unit)
604 	int unit;
605 {
606 	register struct ace_softc *is = &ace_softc[unit];
607 
608 	if (is->is_flags & ACEF_OACTIVE)
609 		return;
610 	is->is_flags |= ACEF_OACTIVE;
611 	acestart((dev_t)unit);
612 	is->is_flags &= ~ACEF_OACTIVE;
613 }
614 
615 /*
616  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
617  * If packet size is less than the minimum legal size,
618  * the buffer is expanded.  We probably should zero out the extra
619  * bytes for security, but that would slow things down.
620  */
621 /*ARGSUSED*/
622 aceput(unit, txbuf, m)
623 	int unit;			/* for statistics collection */
624 	char *txbuf;
625 	struct mbuf *m;
626 {
627 	register u_char *bp, *mcp;	/* known to be r12, r11 */
628 	register short *s1, *s2;	/* known to be r10, r9 */
629 	register u_int len;
630 	register struct mbuf *mp;
631 	int total;
632 
633 	total = 0;
634 	bp = (u_char *)txbuf;
635 	for (mp = m; (mp); mp = mp->m_next) {
636 		len = mp->m_len;
637 		if (len == 0)
638 			continue;
639 		total += len;
640 		mcp = mtod(mp, u_char *);
641 		if (((int)mcp & 01) && ((int)bp & 01)) {
642 			/* source & destination at odd addresses */
643 			movob(bp++, *mcp++);
644 			--len;
645 		}
646 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
647 			register u_int l;
648 
649 			s1 = (short *)bp;
650 			s2 = (short *)mcp;
651 			l = len >> 1;		/* count # of shorts */
652 			while (l-- != 0)
653 				movow(s1++, *s2++);
654 			len &= 1;		/* # remaining bytes */
655 			bp = (u_char *)s1;
656 			mcp = (u_char *)s2;
657 		}
658 		while (len-- != 0)
659 			movob(bp++, *mcp++);
660 	}
661 	m_freem(m);
662 	return (total);
663 }
664 
665 /*
666  * Routine to copy from VERSAbus memory into mbufs.
667  *
668  * Warning: This makes the fairly safe assumption that
669  * mbufs have even lengths.
670  */
671 /*ARGSUSED*/
672 struct mbuf *
673 aceget(unit, rxbuf, totlen, off0)
674 	int unit;			/* for statistics collection */
675 	u_char *rxbuf;
676 	int totlen, off0;
677 {
678 	register u_char *cp, *mcp;	/* known to be r12, r11 */
679 	register int tlen;
680 	register struct mbuf *m;
681 	struct mbuf *top = 0, **mp = &top;
682 	int len, off = off0;
683 
684 #ifdef notdef
685 	cp = rxbuf + sizeof (struct ether_header);
686 #else
687 	cp = rxbuf + 14;
688 #endif
689 	while (totlen > 0) {
690 		MGET(m, M_DONTWAIT, MT_DATA);
691 		if (m == 0)
692 			goto bad;
693 		if (off) {
694 			len = totlen - off;
695 #ifdef notdef
696 			cp = rxbuf + sizeof (struct ether_header) + off;
697 #else
698 			cp = rxbuf + 14 + off;
699 #endif
700 		} else
701 			len = totlen;
702 		if (len >= CLBYTES) {
703 			struct mbuf *p;
704 
705 			MCLGET(p, 1);
706 			if (p != 0) {
707 				m->m_len = len = CLBYTES;
708 				m->m_off = (int)p - (int)m;
709 			} else {
710 				m->m_len = len = MIN(MLEN, len);
711 				m->m_off = MMINOFF;
712 			}
713 		} else {
714 			m->m_len = len = MIN(MLEN, len);
715 			m->m_off = MMINOFF;
716 		}
717 		mcp = mtod(m, u_char *);
718 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
719 		/*cp += len; mcp += len;*/
720 		tlen = len;
721 		if (((int)mcp & 01) && ((int)cp & 01)) {
722 			/* source & destination at odd addresses */
723 			*mcp++ = *cp++;
724 			--tlen;
725 		}
726 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
727 			register short *s1, *s2;
728 			register int l;
729 
730 			s1 = (short *)mcp;
731 			s2 = (short *)cp;
732 			l = tlen >> 1;		/* count # of shorts */
733 			while (l-- > 0)		/* copy shorts */
734 				*s1++ = *s2++;
735 			tlen &= 1;		/* # remaining bytes */
736 			mcp = (u_char *)s1;
737 			cp = (u_char *)s2;
738 		}
739 		while (tlen-- > 0)
740 			*mcp++ = *cp++;
741 		*mp = m;
742 		mp = &m->m_next;
743 		if (off == 0) {
744 			totlen -= len;
745 			continue;
746 		}
747 		off += len;
748 		if (off == totlen) {
749 #ifdef notdef
750 			cp = rxbuf + sizeof (struct ether_header);
751 #else
752 			cp = rxbuf + 14;
753 #endif
754 			off = 0;
755 			totlen = off0;
756 		}
757 	}
758 	return (top);
759 bad:
760 	m_freem(top);
761 	return (0);
762 }
763 
764 acebakoff(is, txseg, retries)
765 	struct ace_softc *is;
766 	struct tx_segment *txseg;
767 	register int retries;
768 {
769 	register short *pBakNum, random_num;
770 	short *pMask;
771 
772 	pMask = &random_mask_tbl[0];
773 	pBakNum = &txseg->tx_backoff[0];
774 	while (--retries >= 0) {
775 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
776 		random_num &= *pMask++;
777 		*pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC);
778 	}
779 }
780 
781 /*
782  * Process an ioctl request.
783  */
784 aceioctl(ifp, cmd, data)
785 	register struct ifnet *ifp;
786 	int cmd;
787 	caddr_t data;
788 {
789 	register struct ifaddr *ifa = (struct ifaddr *)data;
790 	int s = splimp(), error = 0;
791 
792 	switch (cmd) {
793 
794 	case SIOCSIFADDR:
795 		ifp->if_flags |= IFF_UP;
796 		aceinit(ifp->if_unit);
797 		((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
798 		arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
799 		break;
800 
801 #ifdef notdef
802 	case SIOCSETETADDR: {		/* set Ethernet station address */
803 		struct vba_device *ui;
804 		struct acedevice *addr;
805 		struct sockaddr_in *sin;
806 
807 		ifp->if_flags &= ~IFF_RUNNING | IFF_UP;
808 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
809 		ui = aceinfo[ifp->if_unit];
810 		addr = (struct acedevice *)ui->ui_addr;
811 		movow(&addr->csr, CSR_RESET);
812 		DELAY(10000);
813 		/* set station address and copy addr to arp struct */
814 		acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]);
815 		aceinit(ifp->if_unit);		/* Re-initialize */
816 		break;
817 	}
818 #endif
819 
820 	default:
821 		error = EINVAL;
822 	}
823 	splx(s);
824 	return (error);
825 }
826 
827 aceclean(unit)
828 	int unit;
829 {
830 	register struct ace_softc *is = &ace_softc[unit];
831 	register struct vba_device *ui = aceinfo[unit];
832 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
833 	register short i;
834 	register char *pData1;
835 
836 	ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE);
837 	is->is_dpm = acemap[unit];		/* init dpm */
838 	bzero((char *)is->is_dpm, 16384*2);
839 
840 	is->is_currnd = 49123;
841 	is->is_segboundry = (addr->segb >> 11) & 0xf;
842 	pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11));
843 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
844 		acebakoff(is, (struct tx_segment *)pData1, 15);
845 		pData1 += sizeof (struct tx_segment);
846 	}
847 	is->is_eictr = 0;
848 	is->is_eoctr = is->is_txnext = is->is_segboundry;
849 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
850 }
851 #endif
852