xref: /csrg-svn/sys/tahoe/if/if_ace.c (revision 37503)
134405Skarels /*
234405Skarels  * Copyright (c) 1988 Regents of the University of California.
334405Skarels  * All rights reserved.
434405Skarels  *
535411Skarels  * This code is derived from software contributed to Berkeley by
635411Skarels  * Computer Consoles Inc.
735411Skarels  *
834405Skarels  * Redistribution and use in source and binary forms are permitted
934864Sbostic  * provided that the above copyright notice and this paragraph are
1034864Sbostic  * duplicated in all such forms and that any documentation,
1134864Sbostic  * advertising materials, and other materials related to such
1234864Sbostic  * distribution and use acknowledge that the software was developed
1334864Sbostic  * by the University of California, Berkeley.  The name of the
1434864Sbostic  * University may not be used to endorse or promote products derived
1534864Sbostic  * from this software without specific prior written permission.
1634864Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1734864Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1834864Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1934405Skarels  *
20*37503Smckusick  *	@(#)if_ace.c	7.5 (Berkeley) 04/25/89
2134405Skarels  */
2224007Ssam 
2324007Ssam /*
2424007Ssam  * ACC VERSAbus Ethernet controller
2524007Ssam  */
2624007Ssam #include "ace.h"
2724007Ssam #if NACE > 0
2824007Ssam 
2925694Ssam #include "param.h"
3025694Ssam #include "systm.h"
3135411Skarels #include "malloc.h"
3225694Ssam #include "mbuf.h"
3325694Ssam #include "buf.h"
3425694Ssam #include "protosw.h"
3525694Ssam #include "socket.h"
3625694Ssam #include "vmmac.h"
3725694Ssam #include "ioctl.h"
3825694Ssam #include "errno.h"
3925694Ssam #include "vmparam.h"
4025855Ssam #include "syslog.h"
4124007Ssam 
4224007Ssam #include "../net/if.h"
4324007Ssam #include "../net/netisr.h"
4424007Ssam #include "../net/route.h"
4525855Ssam #ifdef INET
4624007Ssam #include "../netinet/in.h"
4724007Ssam #include "../netinet/in_systm.h"
4825694Ssam #include "../netinet/in_var.h"
4924007Ssam #include "../netinet/ip.h"
5024007Ssam #include "../netinet/ip_var.h"
5124007Ssam #include "../netinet/if_ether.h"
5225855Ssam #endif
5325855Ssam #ifdef NS
5425855Ssam #include "../netns/ns.h"
5525855Ssam #include "../netns/ns_if.h"
5625855Ssam #endif
5724007Ssam 
58*37503Smckusick #include "machine/cpu.h"
59*37503Smckusick #include "machine/pte.h"
6030229Ssam 
6124007Ssam #include "../tahoe/mtpr.h"
6224007Ssam #include "../tahoeif/if_acereg.h"
6325694Ssam #include "../tahoevba/vbavar.h"
6424007Ssam 
6535411Skarels int	aceprobe(), aceattach(), acerint(), acecint(), acestart();
6624007Ssam struct	vba_device *aceinfo[NACE];
6725983Ssam long	acestd[] = { 0 };
6824007Ssam struct	vba_driver acedriver =
6925927Ssam     { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 };
7024007Ssam 
7124007Ssam int	aceinit(), aceoutput(), aceioctl(), acereset();
7224007Ssam struct	mbuf *aceget();
7324007Ssam 
7424007Ssam /*
7524007Ssam  * Ethernet software status per interface.
7624007Ssam  *
7724007Ssam  * Each interface is referenced by a network interface structure,
7824007Ssam  * is_if, which the routing code uses to locate the interface.
7924007Ssam  * This structure contains the output queue for the interface, its address, ...
8024007Ssam  */
8124007Ssam struct	ace_softc {
8224007Ssam 	struct	arpcom is_ac;		/* Ethernet common part	*/
8324007Ssam #define	is_if	is_ac.ac_if		/* network-visible interface */
8424007Ssam #define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address */
8524007Ssam 	short	is_flags;
8624007Ssam #define	ACEF_OACTIVE	0x1		/* output is active */
8724007Ssam #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
8824007Ssam 	short	is_promiscuous;		/* true is enabled */
8924007Ssam 	short	is_segboundry;		/* first TX Seg in dpm */
9024007Ssam 	short	is_eictr;		/* Rx segment tracking ctr */
9124007Ssam 	short	is_eoctr;		/* Tx segment tracking ctr */
9224007Ssam 	short	is_txnext;		/* Next available Tx segment */
9324007Ssam 	short	is_currnd;		/* current random backoff */
9424007Ssam 	struct	ace_stats is_stats;	/* holds board statistics */
9524007Ssam 	short	is_xcnt;		/* count xmitted segments to be acked
9624007Ssam 					   by the controller */
9725855Ssam 	long	is_ivec;		/* autoconfig interrupt vector base */
9825927Ssam 	struct	pte *is_map;		/* pte map for dual ported memory */
9925927Ssam 	caddr_t	is_dpm;			/* address of mapped memory */
10024007Ssam } ace_softc[NACE];
10124007Ssam extern	struct ifnet loif;
10224007Ssam 
10325855Ssam aceprobe(reg, vi)
10424007Ssam 	caddr_t reg;
10525855Ssam 	struct vba_device *vi;
10624007Ssam {
10725855Ssam 	register br, cvec;		/* must be r12, r11 */
10825855Ssam 	struct acedevice *ap = (struct acedevice *)reg;
10925855Ssam 	struct ace_softc *is = &ace_softc[vi->ui_unit];
11024007Ssam 
11124007Ssam #ifdef lint
11230295Ssam 	br = 0; cvec = br; br = cvec;
11324007Ssam 	acerint(0); acecint(0);
11424007Ssam #endif
11524007Ssam 	if (badaddr(reg, 2))
11625855Ssam 		return (0);
11725855Ssam 	movow(&ap->csr, CSR_RESET);
11824007Ssam 	DELAY(10000);
11925855Ssam #ifdef notdef
12025855Ssam 	/*
12125855Ssam 	 * Select two spaces for the interrupts aligned to an
12225855Ssam 	 * eight vector boundary and fitting in 8 bits (as
12325855Ssam 	 * required by the controller) -- YECH.  The controller
12425855Ssam 	 * will be notified later at initialization time.
12525855Ssam 	 */
12625855Ssam 	if ((vi->ui_hd->vh_lastiv -= 2) > 0xff)
12725855Ssam 		vi->ui_hd->vh_lastiv  = 0x200;
12825855Ssam 	is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7;
12925855Ssam #else
13025855Ssam 	is->is_ivec = 0x90+vi->ui_unit*8;
13125855Ssam #endif
13225855Ssam 	br = 0x14, cvec = is->is_ivec;		/* XXX */
13325855Ssam 	return (sizeof (*ap));
13424007Ssam }
13524007Ssam 
13624007Ssam /*
13724007Ssam  * Interface exists: make available by filling in network interface
13824007Ssam  * record.  System will initialize the interface when it is ready
13924007Ssam  * to accept packets.
14024007Ssam  */
14124007Ssam aceattach(ui)
14224007Ssam 	struct vba_device *ui;
14324007Ssam {
14424007Ssam 	register short unit = ui->ui_unit;
14524007Ssam 	register struct ace_softc *is = &ace_softc[unit];
14624007Ssam 	register struct ifnet *ifp = &is->is_if;
14724007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
14824007Ssam 	register short *wp, i;
14924007Ssam 
15024007Ssam 	ifp->if_unit = unit;
15124007Ssam 	ifp->if_name = "ace";
15224007Ssam 	ifp->if_mtu = ETHERMTU;
15324007Ssam 	/*
15429408Ssam 	 * Get station's addresses and set multicast hash table.
15524007Ssam 	 */
15629408Ssam 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
15729408Ssam 		is->is_addr[i] = ~*wp++;
15829408Ssam 	printf("ace%d: hardware address %s\n", unit,
15929408Ssam 	    ether_sprintf(is->is_addr));
16024007Ssam 	is->is_promiscuous = 0;
16129408Ssam 	for (wp = (short *)addr->hash, i =  0; i < 8; i++)
16229408Ssam 		movow(wp++, ~0xf);
16325694Ssam 	movow(&addr->bcastena[0], ~0xffff);
16425694Ssam 	movow(&addr->bcastena[1], ~0xffff);
16525927Ssam 	/*
16625927Ssam 	 * Allocate and map dual ported VERSAbus memory.
16725927Ssam 	 */
16831735Skarels 	if (vbmemalloc(32, (caddr_t)ui->ui_flags,
16931735Skarels 	    &is->is_map, &is->is_dpm) == 0) {
17031735Skarels 		printf("ace%d: can't allocate VERSAbus memory map\n", unit);
17131735Skarels 		return;
17231735Skarels 	}
17325927Ssam 
17424007Ssam 	ifp->if_init = aceinit;
17537474Ssklower 	ifp->if_output = ether_output;
17635411Skarels 	ifp->if_start = acestart;
17724007Ssam 	ifp->if_ioctl = aceioctl;
17824007Ssam 	ifp->if_reset = acereset;
17935411Skarels 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
18024007Ssam 	if_attach(ifp);
18124007Ssam }
18224007Ssam 
18324007Ssam /*
18424007Ssam  * Reset of interface after "system" reset.
18524007Ssam  */
18624007Ssam acereset(unit, vban)
18724007Ssam 	int unit, vban;
18824007Ssam {
18924007Ssam 	register struct vba_device *ui;
19024007Ssam 
19124007Ssam 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
19224007Ssam 	    ui->ui_vbanum != vban)
19324007Ssam 		return;
19424007Ssam 	printf(" ace%d", unit);
19524007Ssam 	aceinit(unit);
19624007Ssam }
19724007Ssam 
19824007Ssam /*
19924007Ssam  * Initialization of interface; clear recorded pending operations
20024007Ssam  */
20124007Ssam aceinit(unit)
20224007Ssam 	int unit;
20324007Ssam {
20424007Ssam 	register struct ace_softc *is = &ace_softc[unit];
20524007Ssam 	register struct vba_device *ui = aceinfo[unit];
20624007Ssam 	register struct acedevice *addr;
20724007Ssam 	register short Csr;
20825694Ssam 	register int s;
20924007Ssam 
21035411Skarels 	if (is->is_if.if_addrlist == (struct ifaddr *)0)
21124007Ssam 		return;
21235411Skarels 	if ((is->is_if.if_flags & IFF_RUNNING) == 0) {
21324007Ssam 		/*
21424007Ssam 		 * Reset the controller, initialize the recieve buffers,
21524007Ssam 		 * and turn the controller on again and set board online.
21624007Ssam 		 */
21724007Ssam 		addr = (struct acedevice *)ui->ui_addr;
21824007Ssam 		s = splimp();
21925694Ssam 		movow(&addr->csr, CSR_RESET);
22024007Ssam 		DELAY(10000);
22124007Ssam 
22224007Ssam 		/*
22325927Ssam 		 * Clean up dpm since the controller might
22425927Ssam 		 * jumble dpm after reset.
22524007Ssam 		 */
22625927Ssam 		acesetup(unit);
22725694Ssam 		movow(&addr->csr, CSR_GO);
22824007Ssam 		Csr = addr->csr;
22924007Ssam 		if (Csr & CSR_ACTIVE) {
23025855Ssam 			movow(&addr->ivct, is->is_ivec);
23124007Ssam 			Csr |= CSR_IENA | is->is_promiscuous;
23225694Ssam 			movow(&addr->csr, Csr);
23324007Ssam 			is->is_flags = 0;
23424007Ssam 			is->is_xcnt = 0;
23525694Ssam 			is->is_if.if_flags |= IFF_RUNNING;
23624007Ssam 		}
23724007Ssam 		splx(s);
23824007Ssam 	}
23925694Ssam 	if (is->is_if.if_snd.ifq_head)
24035411Skarels 		acestart(&is->is_if);
24124007Ssam }
24224007Ssam 
24324007Ssam /*
24424007Ssam  * Start output on interface.
24524007Ssam  * Get another datagram to send off of the interface queue,
24624007Ssam  * and map it to the interface before starting the output.
24724007Ssam  */
24835411Skarels acestart(ifp)
24935411Skarels 	register struct ifnet *ifp;
25024007Ssam {
25124007Ssam 	register struct tx_segment *txs;
25225694Ssam 	register long len;
25325694Ssam 	register int s;
25424007Ssam 	struct mbuf *m;
25525694Ssam 	short retries;
25635411Skarels #define	is ((struct ace_softc *)ifp)
25724007Ssam 
25824007Ssam again:
25924007Ssam 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
26024007Ssam 	if (txs->tx_csr & TCS_TBFULL) {
26124007Ssam 		is->is_stats.tx_busy++;
26235411Skarels 		ifp->if_flags |= IFF_OACTIVE;
26335411Skarels 		return (0);
26424007Ssam 	}
26525694Ssam 	s = splimp();
26635411Skarels 	IF_DEQUEUE(&ifp->if_snd, m);
26725694Ssam 	splx(s);
26825927Ssam 	if (m == 0) {
26935411Skarels 		ifp->if_flags &= ~IFF_OACTIVE;
27035411Skarels 		return (0);
27125927Ssam 	}
27235411Skarels 	len = aceput(txs->tx_data, m);
27324007Ssam 	retries = txs->tx_csr & TCS_RTC;
27424007Ssam 	if (retries > 0)
27524007Ssam 		acebakoff(is, txs, retries);
27624007Ssam 
27724007Ssam 	/*
27824007Ssam 	 * Ensure minimum packet length.
27924007Ssam 	 * This makes the safe assumtion that there are no virtual holes
28024007Ssam 	 * after the data.
28124007Ssam 	 * For security, it might be wise to zero out the added bytes,
28224007Ssam 	 * but we're mainly interested in speed at the moment.
28324007Ssam 	 */
28424007Ssam 	if (len - sizeof (struct ether_header) < ETHERMIN)
28524007Ssam 		len = ETHERMIN + sizeof (struct ether_header);
28624007Ssam 	if (++is->is_txnext > SEG_MAX)
28724007Ssam 		is->is_txnext = is->is_segboundry;
28835411Skarels 	ifp->if_opackets++;
28924007Ssam 	is->is_xcnt++;
29024007Ssam 	len = (len & 0x7fff) | TCS_TBFULL;
29125694Ssam 	movow(txs, len);
29224007Ssam 	goto again;
29335411Skarels #undef is
29424007Ssam }
29524007Ssam 
29624007Ssam /*
29724007Ssam  * Transmit done interrupt.
29824007Ssam  */
29924007Ssam acecint(unit)
30024007Ssam 	int unit;
30124007Ssam {
30224007Ssam 	register struct ace_softc *is = &ace_softc[unit];
30324007Ssam 	register struct tx_segment *txseg;
30425694Ssam 	short eostat;
30524007Ssam 
30624007Ssam 	if (is->is_xcnt <= 0)  {
30725855Ssam 		log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n",
30824007Ssam 		    unit, is->is_xcnt);
30924007Ssam 		is->is_xcnt = 0;
31025694Ssam 		if (is->is_if.if_snd.ifq_head)
31135411Skarels 			acestart(&is->is_if);
31224007Ssam 		return;
31324007Ssam 	}
31424007Ssam 	is->is_xcnt--;
31524007Ssam 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
31624007Ssam 	eostat = txseg->tx_csr;
31724007Ssam 	if ((eostat & TCS_TBFULL) == 0) {
31824007Ssam 		is->is_stats.tx_retries += eostat & TCS_RTC;
31924007Ssam 		if (eostat & TCS_RTFAIL)  {
32024007Ssam 			is->is_stats.tx_discarded++;
32124007Ssam 			is->is_if.if_oerrors++;
32224007Ssam 		} else
32324007Ssam 			is->is_stats.tx_datagrams++;
32424007Ssam 		if (++is->is_eoctr >= 16)
32524007Ssam 			is->is_eoctr = is->is_segboundry;
32624007Ssam 	}
32725694Ssam 	if (is->is_if.if_snd.ifq_head)
32835411Skarels 		acestart(&is->is_if);
32924007Ssam }
33024007Ssam 
33124007Ssam /*
33224007Ssam  * Ethernet interface receiver interrupt.
33324007Ssam  * If input error just drop packet.
33424007Ssam  * Otherwise purge input buffered data path and examine
33524007Ssam  * packet to determine type.  If can't determine length
33624007Ssam  * from type, then have to drop packet.  Othewise decapsulate
33724007Ssam  * packet based on type and pass to type specific higher-level
33824007Ssam  * input routine.
33924007Ssam  */
34024007Ssam acerint(unit)
34124007Ssam 	int unit;
34224007Ssam {
34324007Ssam 	register struct ace_softc *is = &ace_softc[unit];
34424007Ssam 	register struct ifqueue *inq;
34524007Ssam 	register struct ether_header *ace;
34624007Ssam 	register struct rx_segment *rxseg;
34724007Ssam 	int len, s, off, resid;
34824007Ssam 	struct mbuf *m;
34924007Ssam 	short eistat;
35024007Ssam 
35125694Ssam 	if ((is->is_if.if_flags&IFF_RUNNING) == 0)
35225694Ssam 		return;
35324007Ssam again:
35424007Ssam 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
35524007Ssam 	eistat = rxseg->rx_csr;
35624007Ssam 	if ((eistat & RCS_RBFULL) == 0)
35724007Ssam 		return;
35824007Ssam 	is->is_if.if_ipackets++;
35924007Ssam 	if (++is->is_eictr >= is->is_segboundry)
36024007Ssam 		is->is_eictr = 0;
36124007Ssam 	len = eistat & RCS_RBC;
36224007Ssam 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
36324007Ssam 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
36424007Ssam 		if (eistat & RCS_ROVRN)
36524007Ssam 			is->is_stats.rx_overruns++;
36624007Ssam 		if (eistat & RCS_RCRC)
36724007Ssam 			is->is_stats.rx_crc_errors++;
36824007Ssam 		if (eistat & RCS_RODD)
36924007Ssam 			is->is_stats.rx_align_errors++;
37024007Ssam 		if (len < ET_MINLEN)
37124007Ssam 			is->is_stats.rx_underruns++;
37224007Ssam 		if (len > ET_MAXLEN+CRC_SIZE)
37324007Ssam 			is->is_stats.rx_overruns++;
37424007Ssam 		is->is_if.if_ierrors++;
37524007Ssam 		rxseg->rx_csr = 0;
37624007Ssam 		return;
37724007Ssam 	} else
37824007Ssam 		is->is_stats.rx_datagrams++;
37924007Ssam 	ace = (struct ether_header *)rxseg->rx_data;
38024007Ssam 	len -= sizeof (struct ether_header);
38124007Ssam 	/*
38225694Ssam 	 * Deal with trailer protocol: if type is trailer
38324007Ssam 	 * get true type from first 16-bit word past data.
38424007Ssam 	 * Remember that type was trailer by setting off.
38524007Ssam 	 */
38624007Ssam 	ace->ether_type = ntohs((u_short)ace->ether_type);
38724007Ssam #define	acedataaddr(ace, off, type) \
38824007Ssam     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
38925694Ssam 	if (ace->ether_type >= ETHERTYPE_TRAIL &&
39025694Ssam 	    ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
39125694Ssam 		off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
39224007Ssam 		if (off >= ETHERMTU)
39324007Ssam 			goto setup;		/* sanity */
39424007Ssam 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
39524007Ssam 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
39624007Ssam 		if (off + resid > len)
39724007Ssam 			goto setup;		/* sanity */
39824007Ssam 		len = off + resid;
39924007Ssam 	} else
40024007Ssam 		off = 0;
40124007Ssam 	if (len == 0)
40224007Ssam 		goto setup;
40324007Ssam 
40424007Ssam 	/*
40524007Ssam 	 * Pull packet off interface.  Off is nonzero if packet
40624007Ssam 	 * has trailing header; aceget will then force this header
40735411Skarels 	 * information to be at the front.
40824007Ssam 	 */
40925855Ssam 	m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if);
41024007Ssam 	if (m == 0)
41124007Ssam 		goto setup;
41224007Ssam 	switch (ace->ether_type) {
41324007Ssam 
41424007Ssam #ifdef INET
41525694Ssam 	case ETHERTYPE_IP:
41624007Ssam 		schednetisr(NETISR_IP);
41724007Ssam 		inq = &ipintrq;
41824007Ssam 		break;
41925855Ssam #endif
42024007Ssam 
42125694Ssam 	case ETHERTYPE_ARP:
42224007Ssam 		arpinput(&is->is_ac, m);
42324007Ssam 		goto setup;
42425694Ssam #ifdef NS
42525694Ssam 	case ETHERTYPE_NS:
42625694Ssam 		schednetisr(NETISR_NS);
42725694Ssam 		inq = &nsintrq;
42825694Ssam 		break;
42925694Ssam 
43025694Ssam #endif
43124007Ssam 	default:
43224007Ssam 		m_freem(m);
43324007Ssam 		goto setup;
43424007Ssam 	}
43524007Ssam 	if (IF_QFULL(inq)) {
43624007Ssam 		IF_DROP(inq);
43724007Ssam 		m_freem(m);
43824007Ssam 		goto setup;
43924007Ssam 	}
44024007Ssam 	s = splimp();
44124007Ssam 	IF_ENQUEUE(inq, m);
44224007Ssam 	splx(s);
44324007Ssam setup:
44424007Ssam 	rxseg->rx_csr = 0;
44524007Ssam 	goto again;
44624007Ssam }
44724007Ssam 
44824007Ssam /*
44924007Ssam  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
45024007Ssam  * If packet size is less than the minimum legal size,
45124007Ssam  * the buffer is expanded.  We probably should zero out the extra
45224007Ssam  * bytes for security, but that would slow things down.
45324007Ssam  */
45435411Skarels aceput(txbuf, m)
45525694Ssam 	char *txbuf;
45624007Ssam 	struct mbuf *m;
45737474Ssklower #ifdef notdef
45824007Ssam {
45925855Ssam 	register u_char *bp, *mcp;
46025855Ssam 	register short *s1, *s2;
46125694Ssam 	register u_int len;
46224007Ssam 	register struct mbuf *mp;
46325694Ssam 	int total;
46424007Ssam 
46535411Skarels 	total = mp->m_pkthdr.len;
46625694Ssam 	bp = (u_char *)txbuf;
46737474Ssklower 	for (mp = m; mp; mp = mp->m_next) {
46824007Ssam 		len = mp->m_len;
46924007Ssam 		if (len == 0)
47024007Ssam 			continue;
47124007Ssam 		mcp = mtod(mp, u_char *);
47224007Ssam 		if (((int)mcp & 01) && ((int)bp & 01)) {
47324007Ssam 			/* source & destination at odd addresses */
47425694Ssam 			movob(bp++, *mcp++);
47524007Ssam 			--len;
47624007Ssam 		}
47724007Ssam 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
47837474Ssklower 			int l = len & 1;
47924007Ssam 
48024007Ssam 			s1 = (short *)bp;
48124007Ssam 			s2 = (short *)mcp;
48235411Skarels 			len >>= 1;		/* count # of shorts */
48335411Skarels 			while (len-- != 0)
48425694Ssam 				movow(s1++, *s2++);
48537474Ssklower 			len = l;		/* # remaining bytes */
48624007Ssam 			bp = (u_char *)s1;
48724007Ssam 			mcp = (u_char *)s2;
48824007Ssam 		}
48925694Ssam 		while (len-- != 0)
49025694Ssam 			movob(bp++, *mcp++);
49124007Ssam 	}
49224007Ssam 	m_freem(m);
49324007Ssam 	return (total);
49424007Ssam }
49537474Ssklower #else
49637474Ssklower {
49737474Ssklower 	register u_char *bp, *mcp;
49837474Ssklower 	register short *s1, *s2;
49937474Ssklower 	register u_int len;
50037474Ssklower 	register struct mbuf *mp;
50137474Ssklower 	int total;
50224007Ssam 
50337474Ssklower 	total = 0;
50437474Ssklower 	bp = (u_char *)txbuf;
50537474Ssklower 	for (mp = m; (mp); mp = mp->m_next) {
50637474Ssklower 		len = mp->m_len;
50737474Ssklower 		if (len == 0)
50837474Ssklower 			continue;
50937474Ssklower 		total += len;
51037474Ssklower 		mcp = mtod(mp, u_char *);
51137474Ssklower 		if (((int)mcp & 01) && ((int)bp & 01)) {
51237474Ssklower 			/* source & destination at odd addresses */
51337474Ssklower 			movob(bp++, *mcp++);
51437474Ssklower 			--len;
51537474Ssklower 		}
51637474Ssklower 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
51737474Ssklower 			register u_int l;
51837474Ssklower 
51937474Ssklower 			s1 = (short *)bp;
52037474Ssklower 			s2 = (short *)mcp;
52137474Ssklower 			l = len >> 1;		/* count # of shorts */
52237474Ssklower 			while (l-- != 0)
52337474Ssklower 				movow(s1++, *s2++);
52437474Ssklower 			len &= 1;		/* # remaining bytes */
52537474Ssklower 			bp = (u_char *)s1;
52637474Ssklower 			mcp = (u_char *)s2;
52737474Ssklower 		}
52837474Ssklower 		while (len-- != 0)
52937474Ssklower 			movob(bp++, *mcp++);
53037474Ssklower 	}
53137474Ssklower 	m_freem(m);
53237474Ssklower 	return (total);
53337474Ssklower }
53437474Ssklower #endif
53537474Ssklower 
53624007Ssam /*
53724007Ssam  * Routine to copy from VERSAbus memory into mbufs.
53824007Ssam  *
53924007Ssam  * Warning: This makes the fairly safe assumption that
54024007Ssam  * mbufs have even lengths.
54124007Ssam  */
54224007Ssam struct mbuf *
54335411Skarels aceget(rxbuf, totlen, off, ifp)
54424007Ssam 	u_char *rxbuf;
54535411Skarels 	int totlen, off;
54625855Ssam 	struct ifnet *ifp;
54724007Ssam {
54825855Ssam 	register u_char *cp, *mcp;
54935411Skarels 	register struct mbuf *m;
55024007Ssam 	register int tlen;
55124007Ssam 	struct mbuf *top = 0, **mp = &top;
55235411Skarels 	int len;
55335411Skarels 	u_char *packet_end;
55424007Ssam 
55535411Skarels 	rxbuf += sizeof (struct ether_header);
55635411Skarels 	cp = rxbuf;
55735411Skarels 	packet_end = cp + totlen;
55835411Skarels 	if (off) {
55935411Skarels 		off += 2 * sizeof(u_short);
56035411Skarels 		totlen -= 2 *sizeof(u_short);
56135411Skarels 		cp = rxbuf + off;
56235411Skarels 	}
56335411Skarels 
56435411Skarels 	MGETHDR(m, M_DONTWAIT, MT_DATA);
56535411Skarels 	if (m == 0)
56635411Skarels 		return (0);
56735411Skarels 	m->m_pkthdr.rcvif = ifp;
56835411Skarels 	m->m_pkthdr.len = totlen;
56935411Skarels 	m->m_len = MHLEN;
57035411Skarels 
57124007Ssam 	while (totlen > 0) {
57235411Skarels 		if (top) {
57335411Skarels 			MGET(m, M_DONTWAIT, MT_DATA);
57435411Skarels 			if (m == 0) {
57535411Skarels 				m_freem(top);
57635411Skarels 				return (0);
57735411Skarels 			}
57835411Skarels 			m->m_len = MLEN;
57935411Skarels 		}
58035411Skarels 		len = min(totlen, (packet_end - cp));
58135411Skarels 		if (len >= MINCLSIZE) {
58235411Skarels 			MCLGET(m, M_DONTWAIT);
58335411Skarels 			if (m->m_flags & M_EXT)
58435411Skarels 				m->m_len = len = min(len, MCLBYTES);
58529563Ssam 			else
58635411Skarels 				len = m->m_len;
58724007Ssam 		} else {
58825855Ssam 			/*
58935411Skarels 			 * Place initial small packet/header at end of mbuf.
59025855Ssam 			 */
59135411Skarels 			if (len < m->m_len) {
59235411Skarels 				if (top == 0 && len + max_linkhdr <= m->m_len)
59335411Skarels 					m->m_data += max_linkhdr;
59435411Skarels 				m->m_len = len;
59535411Skarels 			} else
59635411Skarels 				len = m->m_len;
59725855Ssam 		}
59835411Skarels 		mcp = mtod(m, u_char *);
59924007Ssam 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
60024007Ssam 		/*cp += len; mcp += len;*/
60124007Ssam 		tlen = len;
60224007Ssam 		if (((int)mcp & 01) && ((int)cp & 01)) {
60324007Ssam 			/* source & destination at odd addresses */
60424007Ssam 			*mcp++ = *cp++;
60524007Ssam 			--tlen;
60624007Ssam 		}
60724007Ssam 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
60824007Ssam 			register short *s1, *s2;
60924007Ssam 			register int l;
61024007Ssam 
61124007Ssam 			s1 = (short *)mcp;
61224007Ssam 			s2 = (short *)cp;
61324007Ssam 			l = tlen >> 1;		/* count # of shorts */
61424007Ssam 			while (l-- > 0)		/* copy shorts */
61524007Ssam 				*s1++ = *s2++;
61624007Ssam 			tlen &= 1;		/* # remaining bytes */
61724007Ssam 			mcp = (u_char *)s1;
61824007Ssam 			cp = (u_char *)s2;
61924007Ssam 		}
62024007Ssam 		while (tlen-- > 0)
62124007Ssam 			*mcp++ = *cp++;
62224007Ssam 		*mp = m;
62324007Ssam 		mp = &m->m_next;
62435411Skarels 		totlen -= len;
62535411Skarels 		if (cp == packet_end)
62635411Skarels 			cp = rxbuf;
62724007Ssam 	}
62824007Ssam 	return (top);
62924007Ssam }
63024007Ssam 
63129408Ssam /* backoff table masks */
63229408Ssam short	random_mask_tbl[16] = {
63329563Ssam 	0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0,
63429563Ssam 	0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0
63529408Ssam };
63629408Ssam 
63724007Ssam acebakoff(is, txseg, retries)
63824007Ssam 	struct ace_softc *is;
63924007Ssam 	struct tx_segment *txseg;
64024007Ssam 	register int retries;
64124007Ssam {
64224007Ssam 	register short *pBakNum, random_num;
64324007Ssam 	short *pMask;
64424007Ssam 
64524007Ssam 	pMask = &random_mask_tbl[0];
64624007Ssam 	pBakNum = &txseg->tx_backoff[0];
64724007Ssam 	while (--retries >= 0) {
64824007Ssam 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
64924007Ssam 		random_num &= *pMask++;
65029563Ssam 		*pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc);
65124007Ssam 	}
65224007Ssam }
65324007Ssam 
65424007Ssam /*
65524007Ssam  * Process an ioctl request.
65624007Ssam  */
65724007Ssam aceioctl(ifp, cmd, data)
65824007Ssam 	register struct ifnet *ifp;
65924007Ssam 	int cmd;
66024007Ssam 	caddr_t data;
66124007Ssam {
66225694Ssam 	register struct ifaddr *ifa = (struct ifaddr *)data;
66325855Ssam 	struct acedevice *addr;
66425694Ssam 	int s = splimp(), error = 0;
66524007Ssam 
66624007Ssam 	switch (cmd) {
66724007Ssam 
66824007Ssam 	case SIOCSIFADDR:
66925694Ssam 		ifp->if_flags |= IFF_UP;
67037474Ssklower 		switch (ifa->ifa_addr->sa_family) {
67125855Ssam #ifdef INET
67225855Ssam 		case AF_INET:
67325855Ssam 			aceinit(ifp->if_unit);	/* before arpwhohas */
67425855Ssam 			((struct arpcom *)ifp)->ac_ipaddr =
67525855Ssam 				IA_SIN(ifa)->sin_addr;
67625855Ssam 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
67725855Ssam 			break;
67825855Ssam #endif
67925855Ssam #ifdef NS
68025855Ssam 		case AF_NS: {
68125937Ssam 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
68225937Ssam 			struct ace_softc *is = &ace_softc[ifp->if_unit];
68325855Ssam 
68425855Ssam 			if (!ns_nullhost(*ina)) {
68525855Ssam 				ifp->if_flags &= ~IFF_RUNNING;
68625855Ssam 				addr = (struct acedevice *)
68725937Ssam 				    aceinfo[ifp->if_unit]->ui_addr;
68825855Ssam 				movow(&addr->csr, CSR_RESET);
68925855Ssam 				DELAY(10000);
69025855Ssam 				/* set station address & copy addr to arp */
69129408Ssam 				acesetaddr(ifp->if_unit, addr,
69225855Ssam 				    ina->x_host.c_host);
69325855Ssam 			} else
69425937Ssam 				ina->x_host = *(union ns_host *)is->is_addr;
69525855Ssam 			aceinit(ifp->if_unit);
69625855Ssam 			break;
69725855Ssam 		}
69825855Ssam #endif
69925855Ssam 		default:
70025855Ssam 			aceinit(ifp->if_unit);
70125855Ssam 			break;
70225855Ssam 		}
70324007Ssam 		break;
70424007Ssam 
70525855Ssam 	case SIOCSIFFLAGS:
70625855Ssam 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
70725855Ssam 			addr = (struct acedevice *)
70825855Ssam 			    (aceinfo[ifp->if_unit]->ui_addr);
70925855Ssam 			movow(&addr->csr, CSR_RESET);
71025855Ssam 			ifp->if_flags &= ~IFF_RUNNING;
71125855Ssam 		} else if (ifp->if_flags&IFF_UP &&
71225855Ssam 		    (ifp->if_flags&IFF_RUNNING) == 0)
71325855Ssam 			aceinit(ifp->if_unit);
71424007Ssam 		break;
71524007Ssam 
71624007Ssam 	default:
71724007Ssam 		error = EINVAL;
71824007Ssam 	}
71924007Ssam 	splx(s);
72024007Ssam 	return (error);
72124007Ssam }
72224007Ssam 
72329408Ssam /*
72429408Ssam  * Set the on-board station address, then read it back
72529408Ssam  * to initialize the address used by ARP (among others).
72629408Ssam  */
72729408Ssam acesetaddr(unit, addr, station)
72829408Ssam 	short unit;
72929408Ssam 	struct acedevice *addr;
73030295Ssam 	u_char *station;
73129408Ssam {
73229408Ssam 	struct ace_softc *is = &ace_softc[unit];
73329408Ssam 	register short *wp, i;
73429408Ssam 
73529408Ssam 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
73629408Ssam 		movow(wp++, ~*station++);
73729408Ssam 	for (wp = (short *)addr->station, i = 0; i < 6; i++)
73829408Ssam 		is->is_addr[i] = ~*wp++;
73929408Ssam 	printf("ace%d: hardware address %s\n", unit,
74029408Ssam 	    ether_sprintf(is->is_addr));
74129408Ssam }
74229408Ssam 
74329408Ssam /*
74429408Ssam  * Setup the device for use.  Initialize dual-ported memory,
74529408Ssam  * backoff parameters, and various other software state.
74629408Ssam  */
74725927Ssam acesetup(unit)
74824007Ssam 	int unit;
74924007Ssam {
75024007Ssam 	register struct ace_softc *is = &ace_softc[unit];
75125927Ssam 	register char *pData1;
75225694Ssam 	register short i;
75325927Ssam 	struct acedevice *addr;
75424007Ssam 
75525927Ssam 	bzero(is->is_dpm, 16384*2);
75624007Ssam 	is->is_currnd = 49123;
75725927Ssam 	addr = (struct acedevice *)aceinfo[unit]->ui_addr;
75824007Ssam 	is->is_segboundry = (addr->segb >> 11) & 0xf;
75925927Ssam 	pData1 = is->is_dpm + (is->is_segboundry << 11);
76024007Ssam 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
76124007Ssam 		acebakoff(is, (struct tx_segment *)pData1, 15);
76224007Ssam 		pData1 += sizeof (struct tx_segment);
76324007Ssam 	}
76424007Ssam 	is->is_eictr = 0;
76524007Ssam 	is->is_eoctr = is->is_txnext = is->is_segboundry;
76624007Ssam 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
76724007Ssam }
76824007Ssam #endif
769