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