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