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