xref: /csrg-svn/sys/tahoe/if/if_ace.c (revision 25694)
1*25694Ssam /*	if_ace.c	1.2	86/01/05	*/
224007Ssam 
324007Ssam /*
424007Ssam  * ACC VERSAbus Ethernet controller
524007Ssam  */
624007Ssam #include "ace.h"
724007Ssam #if NACE > 0
824007Ssam 
924007Ssam #include "../machine/pte.h"
1024007Ssam 
11*25694Ssam #include "param.h"
12*25694Ssam #include "systm.h"
13*25694Ssam #include "mbuf.h"
14*25694Ssam #include "buf.h"
15*25694Ssam #include "protosw.h"
16*25694Ssam #include "socket.h"
17*25694Ssam #include "vmmac.h"
18*25694Ssam #include "ioctl.h"
19*25694Ssam #include "errno.h"
20*25694Ssam #include "vmparam.h"
2124007Ssam 
2224007Ssam #include "../net/if.h"
2324007Ssam #include "../net/netisr.h"
2424007Ssam #include "../net/route.h"
2524007Ssam #include "../netinet/in.h"
2624007Ssam #include "../netinet/in_systm.h"
27*25694Ssam #include "../netinet/in_var.h"
2824007Ssam #include "../netinet/ip.h"
2924007Ssam #include "../netinet/ip_var.h"
3024007Ssam #include "../netinet/if_ether.h"
3124007Ssam 
3224007Ssam #include "../tahoe/mtpr.h"
3324007Ssam #include "../tahoeif/if_acereg.h"
34*25694Ssam #include "../tahoevba/vbavar.h"
3524007Ssam 
3624007Ssam #define	LONET	124
3724007Ssam 
3824007Ssam /*
3924007Ssam  * Configuration table, for 2 units (should be defined by config)
4024007Ssam  */
4124007Ssam #define	ACEVECTOR	0x90
4224007Ssam long	acestd[] = { 0x0ff0000, 0xff0100 };		/* controller */
4324007Ssam 
4424007Ssam extern	char ace0utl[], ace1utl[];			/* dpm */
4524007Ssam char	*acemap[]= { ace0utl, ace1utl };
46*25694Ssam extern	struct pte ACE0map[], ACE1map[];
47*25694Ssam struct	pte *ACEmap[] = { ACE0map, ACE1map };
48*25694Ssam caddr_t	ACEmapa[] = { (caddr_t)0xfff80000, (caddr_t)0xfff90000 };
4924007Ssam 
5024007Ssam /* station address */
5124007Ssam char	ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 };
5224007Ssam /* multicast hash table initializer */
5324007Ssam char	ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF };
5424007Ssam /* backoff table masks */
5524007Ssam short random_mask_tbl[16] = {
5624007Ssam 	0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
5724007Ssam 	0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
5824007Ssam };
5924007Ssam 
6024007Ssam int	aceprobe(), aceattach(), acerint(), acecint();
6124007Ssam struct	vba_device *aceinfo[NACE];
6224007Ssam struct	vba_driver acedriver =
6324007Ssam 	{ aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
6424007Ssam 
6524007Ssam #define	ACEUNIT(x)	minor(x)
6624007Ssam 
6724007Ssam int	aceinit(), aceoutput(), aceioctl(), acereset();
6824007Ssam struct	mbuf *aceget();
6924007Ssam 
7024007Ssam /*
7124007Ssam  * Ethernet software status per interface.
7224007Ssam  *
7324007Ssam  * Each interface is referenced by a network interface structure,
7424007Ssam  * is_if, which the routing code uses to locate the interface.
7524007Ssam  * This structure contains the output queue for the interface, its address, ...
7624007Ssam  */
7724007Ssam struct	ace_softc {
7824007Ssam 	struct	arpcom is_ac;		/* Ethernet common part	*/
7924007Ssam #define	is_if	is_ac.ac_if		/* network-visible interface */
8024007Ssam #define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address */
8124007Ssam 	char	*is_dpm;
8224007Ssam 	short	is_flags;
8324007Ssam #define	ACEF_OACTIVE	0x1		/* output is active */
8424007Ssam #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
8524007Ssam 	short	is_promiscuous;		/* true is enabled */
8624007Ssam 	short	is_segboundry;		/* first TX Seg in dpm */
8724007Ssam 	short	is_eictr;		/* Rx segment tracking ctr */
8824007Ssam 	short	is_eoctr;		/* Tx segment tracking ctr */
8924007Ssam 	short	is_txnext;		/* Next available Tx segment */
9024007Ssam 	short	is_currnd;		/* current random backoff */
9124007Ssam 	struct	ace_stats is_stats;	/* holds board statistics */
9224007Ssam 	short	is_xcnt;		/* count xmitted segments to be acked
9324007Ssam 					   by the controller */
9424007Ssam } ace_softc[NACE];
9524007Ssam extern	struct ifnet loif;
9624007Ssam 
9724007Ssam aceprobe(reg)
9824007Ssam 	caddr_t reg;
9924007Ssam {
10024007Ssam 	register struct acedevice *addr = (struct acedevice *)reg;
10124007Ssam 
10224007Ssam #ifdef lint
10324007Ssam 	acerint(0); acecint(0);
10424007Ssam #endif
10524007Ssam 	if (badaddr(reg, 2))
10624007Ssam 		return(0);
107*25694Ssam 	movow(&addr->csr, CSR_RESET);
10824007Ssam 	DELAY(10000);
10924007Ssam 	return (sizeof (struct acedevice));
11024007Ssam }
11124007Ssam 
11224007Ssam /*
11324007Ssam  * Interface exists: make available by filling in network interface
11424007Ssam  * record.  System will initialize the interface when it is ready
11524007Ssam  * to accept packets.
11624007Ssam  */
11724007Ssam aceattach(ui)
11824007Ssam 	struct vba_device *ui;
11924007Ssam {
12024007Ssam 	register short unit = ui->ui_unit;
12124007Ssam 	register struct ace_softc *is = &ace_softc[unit];
12224007Ssam 	register struct ifnet *ifp = &is->is_if;
12324007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
12424007Ssam 	register short *wp, i;
12524007Ssam 
12624007Ssam 	ifp->if_unit = unit;
12724007Ssam 	ifp->if_name = "ace";
12824007Ssam 	ifp->if_mtu = ETHERMTU;
12924007Ssam 	/*
13024007Ssam 	 * Set station's addresses, multicast
13124007Ssam 	 * hash table, and initialize dual ported memory.
13224007Ssam 	 */
13324007Ssam 	ace_station[5] = ~(unit + 1);
13424007Ssam 	acesetetaddr(unit, addr, ace_station);
13524007Ssam 	is->is_promiscuous = 0;
13624007Ssam 	wp = (short *)addr->hash;
13724007Ssam 	for (i =  0; i < 8; i++)
138*25694Ssam 		movow(wp++, ace_hash[i]);
139*25694Ssam 	movow(&addr->bcastena[0], ~0xffff);
140*25694Ssam 	movow(&addr->bcastena[1], ~0xffff);
14124007Ssam 	aceclean(unit);
14224007Ssam 	ifp->if_init = aceinit;
14324007Ssam 	ifp->if_output = aceoutput;
14424007Ssam 	ifp->if_ioctl = aceioctl;
14524007Ssam 	ifp->if_reset = acereset;
146*25694Ssam 	ifp->if_flags = IFF_BROADCAST;
14724007Ssam 	if_attach(ifp);
14824007Ssam }
14924007Ssam 
15024007Ssam acesetetaddr(unit, addr, station_addr)
15124007Ssam 	short unit;
15224007Ssam 	struct acedevice *addr;
15324007Ssam 	char *station_addr;
15424007Ssam {
15524007Ssam 	register short *wp, i;
15624007Ssam 	register char *cp;
15724007Ssam 	struct ace_softc *is = &ace_softc[unit];
15824007Ssam 
15924007Ssam 	wp = (short *)addr->station;
16024007Ssam 	cp = station_addr;
16124007Ssam 	for (i = 0; i < 6; i++)
162*25694Ssam 		movow(wp++, *cp++);
16324007Ssam 	wp = (short *)addr->station;
164*25694Ssam 	cp = (char *)is->is_addr;
16524007Ssam 	for (i = 0; i < 6; i++)
16624007Ssam 		*cp++ = ~(*wp++);
16724007Ssam }
16824007Ssam 
16924007Ssam /*
17024007Ssam  * Reset of interface after "system" reset.
17124007Ssam  */
17224007Ssam acereset(unit, vban)
17324007Ssam 	int unit, vban;
17424007Ssam {
17524007Ssam 	register struct vba_device *ui;
17624007Ssam 
17724007Ssam 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
17824007Ssam 	    ui->ui_vbanum != vban)
17924007Ssam 		return;
18024007Ssam 	printf(" ace%d", unit);
18124007Ssam 	aceinit(unit);
18224007Ssam }
18324007Ssam 
18424007Ssam /*
18524007Ssam  * Initialization of interface; clear recorded pending operations
18624007Ssam  */
18724007Ssam aceinit(unit)
18824007Ssam 	int unit;
18924007Ssam {
19024007Ssam 	register struct ace_softc *is = &ace_softc[unit];
19124007Ssam 	register struct vba_device *ui = aceinfo[unit];
19224007Ssam 	register struct acedevice *addr;
19324007Ssam 	register struct ifnet *ifp = &is->is_if;
19424007Ssam 	register short Csr;
195*25694Ssam 	register int s;
19624007Ssam 
197*25694Ssam 	if (ifp->if_addrlist == (struct ifaddr *)0)
19824007Ssam 		return;
19924007Ssam 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
20024007Ssam 		/*
20124007Ssam 		 * Reset the controller, initialize the recieve buffers,
20224007Ssam 		 * and turn the controller on again and set board online.
20324007Ssam 		 */
20424007Ssam 		addr = (struct acedevice *)ui->ui_addr;
20524007Ssam 		s = splimp();
206*25694Ssam 		movow(&addr->csr, CSR_RESET);
20724007Ssam 		DELAY(10000);
20824007Ssam 
20924007Ssam 		/*
21024007Ssam 		 * clean up dpm since the controller might
21124007Ssam 		 * jumble dpm after reset
21224007Ssam 		 */
21324007Ssam 		aceclean(unit);
214*25694Ssam 		movow(&addr->csr, CSR_GO);
21524007Ssam 		Csr = addr->csr;
21624007Ssam 		if (Csr & CSR_ACTIVE) {
217*25694Ssam 			movow(&addr->ivct, ACEVECTOR + unit*8);
21824007Ssam 			Csr |= CSR_IENA | is->is_promiscuous;
219*25694Ssam #ifdef notdef
22024007Ssam 			if (ifp->if_net == LONET)
22124007Ssam 				Csr |= CSR_LOOP3;
222*25694Ssam #endif
223*25694Ssam 			movow(&addr->csr, Csr);
22424007Ssam 			is->is_flags = 0;
22524007Ssam 			is->is_xcnt = 0;
226*25694Ssam 			is->is_if.if_flags |= IFF_RUNNING;
22724007Ssam 		}
22824007Ssam 		splx(s);
22924007Ssam 	}
230*25694Ssam 	if (is->is_if.if_snd.ifq_head)
23124007Ssam 		aceStart(unit);
23224007Ssam }
23324007Ssam 
23424007Ssam /*
23524007Ssam  * Start output on interface.
23624007Ssam  * Get another datagram to send off of the interface queue,
23724007Ssam  * and map it to the interface before starting the output.
23824007Ssam  *
23924007Ssam  */
24024007Ssam acestart(dev)
24124007Ssam 	dev_t dev;
24224007Ssam {
24324007Ssam 	register struct tx_segment *txs;
244*25694Ssam 	register long len;
245*25694Ssam 	register int s;
24624007Ssam 	int unit = ACEUNIT(dev);
24724007Ssam 	register struct ace_softc *is = &ace_softc[unit];
24824007Ssam 	struct mbuf *m;
249*25694Ssam 	short retries;
25024007Ssam 
25124007Ssam again:
25224007Ssam 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
25324007Ssam 	if (txs->tx_csr & TCS_TBFULL) {
25424007Ssam 		is->is_stats.tx_busy++;
25524007Ssam 		return;
25624007Ssam 	}
257*25694Ssam 	s = splimp();
25824007Ssam 	IF_DEQUEUE(&is->is_if.if_snd, m);
259*25694Ssam 	splx(s);
26024007Ssam 	if (m == 0)
26124007Ssam 		return;
26224007Ssam 	len = aceput(unit, txs->tx_data, m);
26324007Ssam 	retries = txs->tx_csr & TCS_RTC;
26424007Ssam 	if (retries > 0)
26524007Ssam 		acebakoff(is, txs, retries);
26624007Ssam 
26724007Ssam 	/*
26824007Ssam 	 * Ensure minimum packet length.
26924007Ssam 	 * This makes the safe assumtion that there are no virtual holes
27024007Ssam 	 * after the data.
27124007Ssam 	 * For security, it might be wise to zero out the added bytes,
27224007Ssam 	 * but we're mainly interested in speed at the moment.
27324007Ssam 	 */
27424007Ssam #ifdef notdef
27524007Ssam 	if (len - sizeof (struct ether_header) < ETHERMIN)
27624007Ssam 		len = ETHERMIN + sizeof (struct ether_header);
27724007Ssam #else
27824007Ssam 	if (len - 14 < ETHERMIN)
27924007Ssam 		len = ETHERMIN + 14;
28024007Ssam #endif
28124007Ssam 	if (++is->is_txnext > SEG_MAX)
28224007Ssam 		is->is_txnext = is->is_segboundry;
28324007Ssam 	is->is_if.if_opackets++;
28424007Ssam 	is->is_xcnt++;
28524007Ssam 	len = (len & 0x7fff) | TCS_TBFULL;
286*25694Ssam 	movow(txs, len);
28724007Ssam 	goto again;
28824007Ssam }
28924007Ssam 
29024007Ssam /*
29124007Ssam  * Transmit done interrupt.
29224007Ssam  */
29324007Ssam acecint(unit)
29424007Ssam 	int unit;
29524007Ssam {
29624007Ssam 	register struct ace_softc *is = &ace_softc[unit];
29724007Ssam 	register struct tx_segment *txseg;
298*25694Ssam 	short eostat;
29924007Ssam 
30024007Ssam 	if (is->is_xcnt <= 0)  {
30124007Ssam 		printf("ace%d: stray xmit interrupt, xcnt %d\n",
30224007Ssam 		    unit, is->is_xcnt);
30324007Ssam 		is->is_xcnt = 0;
304*25694Ssam 		if (is->is_if.if_snd.ifq_head)
305*25694Ssam 			aceStart(unit);
30624007Ssam 		return;
30724007Ssam 	}
30824007Ssam 	is->is_xcnt--;
30924007Ssam 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
31024007Ssam 	eostat = txseg->tx_csr;
31124007Ssam 	if ((eostat & TCS_TBFULL) == 0) {
31224007Ssam 		is->is_stats.tx_retries += eostat & TCS_RTC;
31324007Ssam 		if (eostat & TCS_RTFAIL)  {
31424007Ssam 			is->is_stats.tx_discarded++;
31524007Ssam 			is->is_if.if_oerrors++;
31624007Ssam 		} else
31724007Ssam 			is->is_stats.tx_datagrams++;
31824007Ssam 		if (++is->is_eoctr >= 16)
31924007Ssam 			is->is_eoctr = is->is_segboundry;
32024007Ssam 	}
321*25694Ssam 	if (is->is_if.if_snd.ifq_head)
322*25694Ssam 		aceStart(unit);
32324007Ssam }
32424007Ssam 
32524007Ssam /*
32624007Ssam  * Ethernet interface receiver interrupt.
32724007Ssam  * If input error just drop packet.
32824007Ssam  * Otherwise purge input buffered data path and examine
32924007Ssam  * packet to determine type.  If can't determine length
33024007Ssam  * from type, then have to drop packet.  Othewise decapsulate
33124007Ssam  * packet based on type and pass to type specific higher-level
33224007Ssam  * input routine.
33324007Ssam  */
33424007Ssam acerint(unit)
33524007Ssam 	int unit;
33624007Ssam {
33724007Ssam 	register struct ace_softc *is = &ace_softc[unit];
33824007Ssam 	register struct ifqueue *inq;
33924007Ssam 	register struct ether_header *ace;
34024007Ssam 	register struct rx_segment *rxseg;
34124007Ssam 	int len, s, off, resid;
34224007Ssam 	struct mbuf *m;
34324007Ssam 	short eistat;
34424007Ssam 
345*25694Ssam 	if ((is->is_if.if_flags&IFF_RUNNING) == 0)
346*25694Ssam 		return;
34724007Ssam again:
34824007Ssam 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
34924007Ssam 	eistat = rxseg->rx_csr;
35024007Ssam 	if ((eistat & RCS_RBFULL) == 0)
35124007Ssam 		return;
35224007Ssam 	is->is_if.if_ipackets++;
35324007Ssam 	if (++is->is_eictr >= is->is_segboundry)
35424007Ssam 		is->is_eictr = 0;
35524007Ssam 	len = eistat & RCS_RBC;
35624007Ssam 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
35724007Ssam 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
35824007Ssam 		if (eistat & RCS_ROVRN)
35924007Ssam 			is->is_stats.rx_overruns++;
36024007Ssam 		if (eistat & RCS_RCRC)
36124007Ssam 			is->is_stats.rx_crc_errors++;
36224007Ssam 		if (eistat & RCS_RODD)
36324007Ssam 			is->is_stats.rx_align_errors++;
36424007Ssam 		if (len < ET_MINLEN)
36524007Ssam 			is->is_stats.rx_underruns++;
36624007Ssam 		if (len > ET_MAXLEN+CRC_SIZE)
36724007Ssam 			is->is_stats.rx_overruns++;
36824007Ssam 		is->is_if.if_ierrors++;
36924007Ssam 		rxseg->rx_csr = 0;
37024007Ssam 		return;
37124007Ssam 	} else
37224007Ssam 		is->is_stats.rx_datagrams++;
37324007Ssam 	ace = (struct ether_header *)rxseg->rx_data;
37424007Ssam #ifdef notdef
37524007Ssam 	len -= sizeof (struct ether_header);
37624007Ssam #else
37724007Ssam 	len -= 14;
37824007Ssam #endif
37924007Ssam 	/*
380*25694Ssam 	 * Deal with trailer protocol: if type is trailer
38124007Ssam 	 * get true type from first 16-bit word past data.
38224007Ssam 	 * Remember that type was trailer by setting off.
38324007Ssam 	 */
38424007Ssam 	ace->ether_type = ntohs((u_short)ace->ether_type);
38524007Ssam #ifdef notdef
38624007Ssam #define	acedataaddr(ace, off, type) \
38724007Ssam     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
38824007Ssam #else
38924007Ssam #define	acedataaddr(ace, off, type) \
39024007Ssam     ((type)(((caddr_t)(((char *)ace)+14)+(off))))
39124007Ssam #endif
392*25694Ssam 	if (ace->ether_type >= ETHERTYPE_TRAIL &&
393*25694Ssam 	    ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
394*25694Ssam 		off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
39524007Ssam 		if (off >= ETHERMTU)
39624007Ssam 			goto setup;		/* sanity */
39724007Ssam 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
39824007Ssam 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
39924007Ssam 		if (off + resid > len)
40024007Ssam 			goto setup;		/* sanity */
40124007Ssam 		len = off + resid;
40224007Ssam 	} else
40324007Ssam 		off = 0;
40424007Ssam 	if (len == 0)
40524007Ssam 		goto setup;
40624007Ssam 
40724007Ssam 	/*
40824007Ssam 	 * Pull packet off interface.  Off is nonzero if packet
40924007Ssam 	 * has trailing header; aceget will then force this header
41024007Ssam 	 * information to be at the front, but we still have to drop
41124007Ssam 	 * the type and length which are at the front of any trailer data.
41224007Ssam 	 */
413*25694Ssam 	m = aceget(unit, (u_char *)rxseg->rx_data, len, off);
41424007Ssam 	if (m == 0)
41524007Ssam 		goto setup;
41624007Ssam 	if (off) {
41724007Ssam 		m->m_off += 2 * sizeof (u_short);
41824007Ssam 		m->m_len -= 2 * sizeof (u_short);
41924007Ssam 	}
42024007Ssam 	switch (ace->ether_type) {
42124007Ssam 
42224007Ssam #ifdef INET
423*25694Ssam 	case ETHERTYPE_IP:
42424007Ssam 		schednetisr(NETISR_IP);
42524007Ssam 		inq = &ipintrq;
42624007Ssam 		break;
42724007Ssam 
428*25694Ssam 	case ETHERTYPE_ARP:
42924007Ssam 		arpinput(&is->is_ac, m);
43024007Ssam 		goto setup;
43124007Ssam #endif
432*25694Ssam #ifdef NS
433*25694Ssam 	case ETHERTYPE_NS:
434*25694Ssam 		schednetisr(NETISR_NS);
435*25694Ssam 		inq = &nsintrq;
436*25694Ssam 		break;
437*25694Ssam 
438*25694Ssam #endif
43924007Ssam 	default:
44024007Ssam 		m_freem(m);
44124007Ssam 		goto setup;
44224007Ssam 	}
44324007Ssam 	if (IF_QFULL(inq)) {
44424007Ssam 		IF_DROP(inq);
44524007Ssam 		m_freem(m);
44624007Ssam 		goto setup;
44724007Ssam 	}
44824007Ssam 	s = splimp();
44924007Ssam 	IF_ENQUEUE(inq, m);
45024007Ssam 	splx(s);
45124007Ssam setup:
45224007Ssam 	rxseg->rx_csr = 0;
45324007Ssam 	goto again;
45424007Ssam }
45524007Ssam 
45624007Ssam /*
45724007Ssam  * Ethernet output routine.
45824007Ssam  * Encapsulate a packet of type family for the local net.
45924007Ssam  * Use trailer local net encapsulation if enough data in first
46024007Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
46124007Ssam  */
46224007Ssam aceoutput(ifp, m0, dst)
46324007Ssam 	struct ifnet *ifp;
46424007Ssam 	struct mbuf *m0;
46524007Ssam 	struct sockaddr *dst;
46624007Ssam {
46724007Ssam 	register struct ace_softc *is = &ace_softc[ifp->if_unit];
46824007Ssam 	register struct mbuf *m = m0;
46924007Ssam 	register struct ether_header *ace;
47024007Ssam 	register int off;
47124007Ssam 	struct mbuf *mcopy = (struct mbuf *)0;
47224007Ssam 	int type, s, error;
473*25694Ssam 	u_char edst[6];
47424007Ssam 	struct in_addr idst;
47524007Ssam 
47624007Ssam 	switch (dst->sa_family) {
47724007Ssam 
47824007Ssam #ifdef INET
47924007Ssam 	case AF_INET:
48024007Ssam 		idst = ((struct sockaddr_in *)dst)->sin_addr;
481*25694Ssam 		if (!arpresolve(&is->is_ac, m, &idst, edst))
48224007Ssam 			return (0);	/* if not yet resolved */
483*25694Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
484*25694Ssam 		    sizeof(edst)))
48524007Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
48624007Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
48724007Ssam 		/* need per host negotiation */
48824007Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 &&
48924007Ssam 		    (off & 0x1ff) == 0 &&
49024007Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
491*25694Ssam 			type = ETHERTYPE_TRAIL + (off>>9);
49224007Ssam 			m->m_off -= 2 * sizeof (u_short);
49324007Ssam 			m->m_len += 2 * sizeof (u_short);
494*25694Ssam 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
49524007Ssam 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
49624007Ssam 			goto gottrailertype;
49724007Ssam 		}
498*25694Ssam 		type = ETHERTYPE_IP;
49924007Ssam 		off = 0;
50024007Ssam 		goto gottype;
50124007Ssam #endif
502*25694Ssam #ifdef NS
503*25694Ssam 	case AF_NS:
504*25694Ssam  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
505*25694Ssam 		    (caddr_t)edst, sizeof (edst));
506*25694Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,sizeof(edst)))
507*25694Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
508*25694Ssam 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
509*25694Ssam 		    sizeof(edst)))
510*25694Ssam 			return(looutput(&loif, m, dst));
511*25694Ssam 		type = ETHERTYPE_NS;
512*25694Ssam 		off = 0;
513*25694Ssam 		goto gottype;
514*25694Ssam #endif
51524007Ssam 
51624007Ssam 	case AF_UNSPEC:
51724007Ssam 		ace = (struct ether_header *)dst->sa_data;
518*25694Ssam 		bcopy((caddr_t)ace->ether_dhost, (caddr_t)edst, sizeof (edst));
51924007Ssam 		type = ace->ether_type;
52024007Ssam 		goto gottype;
52124007Ssam 
52224007Ssam 	default:
52324007Ssam 		printf("ace%d: can't handle af%d\n",
52424007Ssam 		    ifp->if_unit, dst->sa_family);
52524007Ssam 		error = EAFNOSUPPORT;
52624007Ssam 		goto bad;
52724007Ssam 	}
52824007Ssam 
52924007Ssam gottrailertype:
53024007Ssam 	/*
53124007Ssam 	 * Packet to be sent as trailer: move first packet
53224007Ssam 	 * (control information) to end of chain.
53324007Ssam 	 */
53424007Ssam 	while (m->m_next)
53524007Ssam 		m = m->m_next;
53624007Ssam 	m->m_next = m0;
53724007Ssam 	m = m0->m_next;
53824007Ssam 	m0->m_next = 0;
53924007Ssam 	m0 = m;
54024007Ssam 
54124007Ssam gottype:
54224007Ssam 	/*
54324007Ssam 	 * Add local net header.  If no space in first mbuf,
54424007Ssam 	 * allocate another.
54524007Ssam 	 */
54624007Ssam 	if (m->m_off > MMAXOFF ||
54724007Ssam #ifdef notdef
54824007Ssam 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
54924007Ssam #else
55024007Ssam 	    MMINOFF + 14 > m->m_off) {
55124007Ssam #endif
55224007Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
55324007Ssam 		if (m == 0) {
55424007Ssam 			error = ENOBUFS;
55524007Ssam 			goto bad;
55624007Ssam 		}
55724007Ssam 		m->m_next = m0;
55824007Ssam 		m->m_off = MMINOFF;
55924007Ssam #ifdef notdef
56024007Ssam 		m->m_len = sizeof (struct ether_header);
56124007Ssam #else
56224007Ssam 		m->m_len = 14;
56324007Ssam #endif
56424007Ssam 	} else {
56524007Ssam #ifdef notdef
56624007Ssam 		m->m_off -= sizeof (struct ether_header);
56724007Ssam 		m->m_len += sizeof (struct ether_header);
56824007Ssam #else
56924007Ssam 		m->m_off -= 14;
57024007Ssam 		m->m_len += 14;
57124007Ssam #endif
57224007Ssam 	}
57324007Ssam 	ace = mtod(m, struct ether_header *);
574*25694Ssam 	bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst));
575*25694Ssam 	bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost,
576*25694Ssam 	    sizeof (is->is_addr));
57724007Ssam 	ace->ether_type = htons((u_short)type);
57824007Ssam 
57924007Ssam 	/*
58024007Ssam 	 * Queue message on interface, and start output if interface
58124007Ssam 	 * not yet active.
58224007Ssam 	 */
58324007Ssam 	s = splimp();
58424007Ssam 	if (IF_QFULL(&ifp->if_snd)) {
58524007Ssam 		IF_DROP(&ifp->if_snd);
58624007Ssam 		error = ENOBUFS;
58724007Ssam 		goto qfull;
58824007Ssam 	}
58924007Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
59024007Ssam 	splx(s);
59124007Ssam 	aceStart(ifp->if_unit);
59224007Ssam 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
59324007Ssam qfull:
59424007Ssam 	m0 = m;
59524007Ssam 	splx(s);
59624007Ssam bad:
59724007Ssam 	m_freem(m0);
59824007Ssam 	if (mcopy)
59924007Ssam 		m_freem(mcopy);
60024007Ssam 	return (error);
60124007Ssam }
60224007Ssam 
60324007Ssam aceStart(unit)
60424007Ssam 	int unit;
60524007Ssam {
60624007Ssam 	register struct ace_softc *is = &ace_softc[unit];
60724007Ssam 
60824007Ssam 	if (is->is_flags & ACEF_OACTIVE)
60924007Ssam 		return;
61024007Ssam 	is->is_flags |= ACEF_OACTIVE;
61124007Ssam 	acestart((dev_t)unit);
61224007Ssam 	is->is_flags &= ~ACEF_OACTIVE;
61324007Ssam }
61424007Ssam 
61524007Ssam /*
61624007Ssam  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
61724007Ssam  * If packet size is less than the minimum legal size,
61824007Ssam  * the buffer is expanded.  We probably should zero out the extra
61924007Ssam  * bytes for security, but that would slow things down.
62024007Ssam  */
621*25694Ssam /*ARGSUSED*/
62224007Ssam aceput(unit, txbuf, m)
62324007Ssam 	int unit;			/* for statistics collection */
624*25694Ssam 	char *txbuf;
62524007Ssam 	struct mbuf *m;
62624007Ssam {
62724007Ssam 	register u_char *bp, *mcp;	/* known to be r12, r11 */
62824007Ssam 	register short *s1, *s2;	/* known to be r10, r9 */
629*25694Ssam 	register u_int len;
63024007Ssam 	register struct mbuf *mp;
631*25694Ssam 	int total;
63224007Ssam 
63324007Ssam 	total = 0;
634*25694Ssam 	bp = (u_char *)txbuf;
635*25694Ssam 	for (mp = m; (mp); mp = mp->m_next) {
63624007Ssam 		len = mp->m_len;
63724007Ssam 		if (len == 0)
63824007Ssam 			continue;
63924007Ssam 		total += len;
64024007Ssam 		mcp = mtod(mp, u_char *);
64124007Ssam 		if (((int)mcp & 01) && ((int)bp & 01)) {
64224007Ssam 			/* source & destination at odd addresses */
643*25694Ssam 			movob(bp++, *mcp++);
64424007Ssam 			--len;
64524007Ssam 		}
64624007Ssam 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
647*25694Ssam 			register u_int l;
64824007Ssam 
64924007Ssam 			s1 = (short *)bp;
65024007Ssam 			s2 = (short *)mcp;
65124007Ssam 			l = len >> 1;		/* count # of shorts */
652*25694Ssam 			while (l-- != 0)
653*25694Ssam 				movow(s1++, *s2++);
65424007Ssam 			len &= 1;		/* # remaining bytes */
65524007Ssam 			bp = (u_char *)s1;
65624007Ssam 			mcp = (u_char *)s2;
65724007Ssam 		}
658*25694Ssam 		while (len-- != 0)
659*25694Ssam 			movob(bp++, *mcp++);
66024007Ssam 	}
66124007Ssam 	m_freem(m);
66224007Ssam 	return (total);
66324007Ssam }
66424007Ssam 
66524007Ssam /*
66624007Ssam  * Routine to copy from VERSAbus memory into mbufs.
66724007Ssam  *
66824007Ssam  * Warning: This makes the fairly safe assumption that
66924007Ssam  * mbufs have even lengths.
67024007Ssam  */
671*25694Ssam /*ARGSUSED*/
67224007Ssam struct mbuf *
67324007Ssam aceget(unit, rxbuf, totlen, off0)
67424007Ssam 	int unit;			/* for statistics collection */
67524007Ssam 	u_char *rxbuf;
67624007Ssam 	int totlen, off0;
67724007Ssam {
67824007Ssam 	register u_char *cp, *mcp;	/* known to be r12, r11 */
67924007Ssam 	register int tlen;
68024007Ssam 	register struct mbuf *m;
68124007Ssam 	struct mbuf *top = 0, **mp = &top;
68224007Ssam 	int len, off = off0;
68324007Ssam 
68424007Ssam #ifdef notdef
68524007Ssam 	cp = rxbuf + sizeof (struct ether_header);
68624007Ssam #else
68724007Ssam 	cp = rxbuf + 14;
68824007Ssam #endif
68924007Ssam 	while (totlen > 0) {
69024007Ssam 		MGET(m, M_DONTWAIT, MT_DATA);
69124007Ssam 		if (m == 0)
69224007Ssam 			goto bad;
69324007Ssam 		if (off) {
69424007Ssam 			len = totlen - off;
69524007Ssam #ifdef notdef
69624007Ssam 			cp = rxbuf + sizeof (struct ether_header) + off;
69724007Ssam #else
69824007Ssam 			cp = rxbuf + 14 + off;
69924007Ssam #endif
70024007Ssam 		} else
70124007Ssam 			len = totlen;
70224007Ssam 		if (len >= CLBYTES) {
70324007Ssam 			struct mbuf *p;
70424007Ssam 
70524007Ssam 			MCLGET(p, 1);
70624007Ssam 			if (p != 0) {
70724007Ssam 				m->m_len = len = CLBYTES;
70824007Ssam 				m->m_off = (int)p - (int)m;
70924007Ssam 			} else {
71024007Ssam 				m->m_len = len = MIN(MLEN, len);
71124007Ssam 				m->m_off = MMINOFF;
71224007Ssam 			}
71324007Ssam 		} else {
71424007Ssam 			m->m_len = len = MIN(MLEN, len);
71524007Ssam 			m->m_off = MMINOFF;
71624007Ssam 		}
71724007Ssam 		mcp = mtod(m, u_char *);
71824007Ssam 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
71924007Ssam 		/*cp += len; mcp += len;*/
72024007Ssam 		tlen = len;
72124007Ssam 		if (((int)mcp & 01) && ((int)cp & 01)) {
72224007Ssam 			/* source & destination at odd addresses */
72324007Ssam 			*mcp++ = *cp++;
72424007Ssam 			--tlen;
72524007Ssam 		}
72624007Ssam 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
72724007Ssam 			register short *s1, *s2;
72824007Ssam 			register int l;
72924007Ssam 
73024007Ssam 			s1 = (short *)mcp;
73124007Ssam 			s2 = (short *)cp;
73224007Ssam 			l = tlen >> 1;		/* count # of shorts */
73324007Ssam 			while (l-- > 0)		/* copy shorts */
73424007Ssam 				*s1++ = *s2++;
73524007Ssam 			tlen &= 1;		/* # remaining bytes */
73624007Ssam 			mcp = (u_char *)s1;
73724007Ssam 			cp = (u_char *)s2;
73824007Ssam 		}
73924007Ssam 		while (tlen-- > 0)
74024007Ssam 			*mcp++ = *cp++;
74124007Ssam 		*mp = m;
74224007Ssam 		mp = &m->m_next;
74324007Ssam 		if (off == 0) {
74424007Ssam 			totlen -= len;
74524007Ssam 			continue;
74624007Ssam 		}
74724007Ssam 		off += len;
74824007Ssam 		if (off == totlen) {
74924007Ssam #ifdef notdef
75024007Ssam 			cp = rxbuf + sizeof (struct ether_header);
75124007Ssam #else
75224007Ssam 			cp = rxbuf + 14;
75324007Ssam #endif
75424007Ssam 			off = 0;
75524007Ssam 			totlen = off0;
75624007Ssam 		}
75724007Ssam 	}
75824007Ssam 	return (top);
75924007Ssam bad:
76024007Ssam 	m_freem(top);
76124007Ssam 	return (0);
76224007Ssam }
76324007Ssam 
76424007Ssam acebakoff(is, txseg, retries)
76524007Ssam 	struct ace_softc *is;
76624007Ssam 	struct tx_segment *txseg;
76724007Ssam 	register int retries;
76824007Ssam {
76924007Ssam 	register short *pBakNum, random_num;
77024007Ssam 	short *pMask;
77124007Ssam 
77224007Ssam 	pMask = &random_mask_tbl[0];
77324007Ssam 	pBakNum = &txseg->tx_backoff[0];
77424007Ssam 	while (--retries >= 0) {
77524007Ssam 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
77624007Ssam 		random_num &= *pMask++;
77724007Ssam 		*pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC);
77824007Ssam 	}
77924007Ssam }
78024007Ssam 
78124007Ssam /*
78224007Ssam  * Process an ioctl request.
78324007Ssam  */
78424007Ssam aceioctl(ifp, cmd, data)
78524007Ssam 	register struct ifnet *ifp;
78624007Ssam 	int cmd;
78724007Ssam 	caddr_t data;
78824007Ssam {
789*25694Ssam 	register struct ifaddr *ifa = (struct ifaddr *)data;
790*25694Ssam 	int s = splimp(), error = 0;
79124007Ssam 
79224007Ssam 	switch (cmd) {
79324007Ssam 
79424007Ssam 	case SIOCSIFADDR:
795*25694Ssam 		ifp->if_flags |= IFF_UP;
79624007Ssam 		aceinit(ifp->if_unit);
797*25694Ssam 		((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
798*25694Ssam 		arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
79924007Ssam 		break;
80024007Ssam 
80124007Ssam #ifdef notdef
80224007Ssam 	case SIOCSETETADDR: {		/* set Ethernet station address */
80324007Ssam 		struct vba_device *ui;
80424007Ssam 		struct acedevice *addr;
80524007Ssam 		struct sockaddr_in *sin;
80624007Ssam 
80724007Ssam 		ifp->if_flags &= ~IFF_RUNNING | IFF_UP;
80824007Ssam 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
80924007Ssam 		ui = aceinfo[ifp->if_unit];
81024007Ssam 		addr = (struct acedevice *)ui->ui_addr;
811*25694Ssam 		movow(&addr->csr, CSR_RESET);
81224007Ssam 		DELAY(10000);
81324007Ssam 		/* set station address and copy addr to arp struct */
81424007Ssam 		acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]);
81524007Ssam 		aceinit(ifp->if_unit);		/* Re-initialize */
81624007Ssam 		break;
81724007Ssam 	}
81824007Ssam #endif
81924007Ssam 
82024007Ssam 	default:
82124007Ssam 		error = EINVAL;
82224007Ssam 	}
82324007Ssam 	splx(s);
82424007Ssam 	return (error);
82524007Ssam }
82624007Ssam 
82724007Ssam aceclean(unit)
82824007Ssam 	int unit;
82924007Ssam {
83024007Ssam 	register struct ace_softc *is = &ace_softc[unit];
83124007Ssam 	register struct vba_device *ui = aceinfo[unit];
83224007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
833*25694Ssam 	register short i;
83424007Ssam 	register char *pData1;
83524007Ssam 
83624007Ssam 	ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE);
83724007Ssam 	is->is_dpm = acemap[unit];		/* init dpm */
83824007Ssam 	bzero((char *)is->is_dpm, 16384*2);
83924007Ssam 
84024007Ssam 	is->is_currnd = 49123;
84124007Ssam 	is->is_segboundry = (addr->segb >> 11) & 0xf;
84224007Ssam 	pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11));
84324007Ssam 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
84424007Ssam 		acebakoff(is, (struct tx_segment *)pData1, 15);
84524007Ssam 		pData1 += sizeof (struct tx_segment);
84624007Ssam 	}
84724007Ssam 	is->is_eictr = 0;
84824007Ssam 	is->is_eoctr = is->is_txnext = is->is_segboundry;
84924007Ssam 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
85024007Ssam }
85124007Ssam #endif
852