xref: /csrg-svn/sys/i386/isa/if_ec.c (revision 63364)
151135Ssklower /*
2*63364Sbostic  * Copyright (c) 1992, 1993
3*63364Sbostic  *	The Regents of the University of California.  All rights reserved.
451135Ssklower  *
551135Ssklower  * %sccs.include.redist.c%
651135Ssklower  *
7*63364Sbostic  *	@(#)if_ec.c	8.1 (Berkeley) 06/11/93
851135Ssklower  */
951135Ssklower 
1055602Ssklower 
1155602Ssklower /* WARNING -- THIS DRIVER DOES NOT WORK YET -- It is merely a sketch */
1255602Ssklower 
1351135Ssklower #include "ec.h"
1451135Ssklower #if NEC > 0
1551135Ssklower 
1651135Ssklower /*
1751135Ssklower  * Intel 82586/3com Etherlink II controller.
1851135Ssklower  */
1956513Sbostic #include <sys/param.h>
2056513Sbostic #include <sys/systm.h>
2156513Sbostic #include <sys/mbuf.h>
2256513Sbostic #include <sys/buf.h>
2356513Sbostic #include <sys/protosw.h>
2456513Sbostic #include <sys/socket.h>
2556513Sbostic #include <sys/syslog.h>
2656513Sbostic #include <sys/ioctl.h>
2756513Sbostic #include <sys/errno.h>
2851135Ssklower 
2956513Sbostic #include <net/if.h>
3056513Sbostic #include <net/netisr.h>
3156513Sbostic #include <net/route.h>
3251135Ssklower 
3351135Ssklower #ifdef INET
3456513Sbostic #include <netinet/in.h>
3556513Sbostic #include <netinet/in_systm.h>
3656513Sbostic #include <netinet/in_var.h>
3756513Sbostic #include <netinet/ip.h>
3856513Sbostic #include <netinet/if_ether.h>
3951135Ssklower #endif
4051135Ssklower 
4151135Ssklower #ifdef NS
4256513Sbostic #include <netns/ns.h>
4356513Sbostic #include <netns/ns_if.h>
4451135Ssklower #endif
4551135Ssklower 
4651135Ssklower #ifdef ISO
4751135Ssklower extern	char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
4851135Ssklower #endif
4951135Ssklower 
5056513Sbostic #include <i386/isa/if_ecreg.h>
5151135Ssklower 
5251135Ssklower #if NBPFILTER > 0
5356513Sbostic #include <net/bpf.h>
5456513Sbostic #include <net/bpfdesc.h>
5551135Ssklower #endif
5651135Ssklower 
5755602Ssklower int	ecdebug = 1;		/* console error messages */
5851135Ssklower 
5951135Ssklower int	ecintr(), ecinit(), ecioctl(), ecstart(), ether_output();
6051135Ssklower int	ecattach(), ecprobe(), ecreset(), ecwatchdog();
6151135Ssklower void	ec_idpattern(), ec_reset_all(), ec_getnmdata(), ecread();
6251135Ssklower 
6351135Ssklower struct	mbuf *m_devget();
6451135Ssklower extern	struct ifnet loif;
6551135Ssklower struct	ec_82586params ec_82586defaults =
6651135Ssklower     { 11, 0xc8, ECMINSIZE, 0x2e, 0, 0x60, 0, 2, 0, 0, 0x40};
6751135Ssklower     /* 2e == no source insert */
6851135Ssklower 
6951135Ssklower /*
7051135Ssklower  * Ethernet software status per interface.
7151135Ssklower  *
7251135Ssklower  * Each interface is referenced by a network interface structure,
7351135Ssklower  * sc_if, which the routing code uses to locate the interface.
7451135Ssklower  * This structure contains the output queue for the interface, its address, ...
7551135Ssklower  */
7651135Ssklower struct	ec_softc {
7751135Ssklower 	struct	arpcom sc_ac;	/* common Ethernet structures */
7851135Ssklower #define	sc_if	sc_ac.ac_if	/* network-visible interface */
7951135Ssklower #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
8051135Ssklower 	caddr_t	sc_device;		/* e.g. isa_device */
8151135Ssklower 	caddr_t	sc_bpf;			/* for packet filter */
8251135Ssklower 	struct	ec_ports *sc_ports;	/* control ports for this unit */
8351135Ssklower 	struct	ec_mem *sc_hmem;	/* Host addr for shared memory */
8451135Ssklower 	struct	ec_mem *sc_dmem;	/* Device (chip) addr for shared mem */
8551135Ssklower 	int	sc_msize;		/* How much memory is mapped? */
8651135Ssklower 	int	sc_iflags;		/* copy of sc_if.if_flags for state */
8751135Ssklower 	int	sc_rxnum;		/* Last receiver dx we looked at */
8851135Ssklower 	int	sc_txnum;		/* Last tranmistter dx we stomped on */
8951135Ssklower 	int	sc_txcnt;		/* Number of packets queued for tx*/
9051135Ssklower 	int	sc_xint;
9151135Ssklower 	/* errors */
9251135Ssklower 	int	sc_txbusy;		/* we're confused */
9351135Ssklower 	int	sc_uflo;		/* DMA Late */
9451135Ssklower 	int	sc_runt;		/* too short */
9551135Ssklower 	int	sc_txbad;
9651135Ssklower 	int	sc_rxlen;
9751135Ssklower } ec_softc[NEC];
9851135Ssklower 
9956513Sbostic #include <i386/isa/isa_device.h>
10051135Ssklower 
10151135Ssklower struct	isa_driver ecdriver = {
10251135Ssklower 	ecprobe, ecattach, "ec",
10351135Ssklower };
10451135Ssklower 
10551135Ssklower 
10651135Ssklower #define TIMO 10000 /* used in ec_uprim */
10751135Ssklower 
ecprobe(id)10851135Ssklower ecprobe(id)
10951135Ssklower 	register struct	isa_device *id;
11051135Ssklower {
11151135Ssklower 	int	unit = id->id_unit, msize = id->id_msize;
11251135Ssklower 	struct	ec_ports *reg = (struct ec_ports *)id->id_iobase;
11351135Ssklower 	register struct	ec_softc *ec = ec_softc + unit;
11451135Ssklower 	u_char	data[6];
11551135Ssklower 
11651135Ssklower 	ec_reset_all();
11751135Ssklower 	bzero((caddr_t)data, sizeof(data));
11851135Ssklower 	ec_getnmdata(reg, R_ECID, data);
11955602Ssklower 	if (bcmp((caddr_t)data, "*3COM*", sizeof(data)) != 0) {
12055602Ssklower 		if (ecdebug) {
12155602Ssklower 			printf("ecprobe: ec%d not matched: %s\n",
12255602Ssklower 				unit, ether_sprintf(data));
12355602Ssklower 		}
12451135Ssklower 		return 0;
12551135Ssklower 	}
12651135Ssklower 	ec_getnmdata(reg, R_ETHER, ec->sc_addr);
12751135Ssklower 	ec_getnmdata(reg, R_REV, data);
12851135Ssklower 	ec->sc_hmem	= (struct ec_mem *) (id->id_maddr);
12951135Ssklower 	ec->sc_dmem	= (struct ec_mem *) (0x10000 - msize);
13051135Ssklower 	ec->sc_msize	= msize;
13151135Ssklower 	ec->sc_device	= (caddr_t) id;
13251135Ssklower 	ec->sc_ports	= reg;
13355602Ssklower 	printf("ec%d: hardware address %s, rev info %s\n",
13455602Ssklower 		unit, ether_sprintf(ec->sc_addr), ether_sprintf(data));
13551135Ssklower 	return 1;
13651135Ssklower }
13751135Ssklower 
13851135Ssklower void
ec_idpattern()13951135Ssklower ec_idpattern()
14051135Ssklower {
14151135Ssklower 	int i = 255, n;
14251135Ssklower 	register caddr_t p = (caddr_t)0x100;
14351135Ssklower 	for (n = 255;  n > 0; n--) {
14451135Ssklower 		outb(p, i);
14551135Ssklower 		if ((i <<= 1) & 0x100)
14651135Ssklower 			i ^= 0xe7;
14751135Ssklower 	}
14851135Ssklower }
14951135Ssklower 
15051135Ssklower void
ec_reset_all()15151135Ssklower ec_reset_all()
15251135Ssklower {
15351135Ssklower 	register caddr_t p = (caddr_t)0x100;
15451135Ssklower 	outb(p, 0);
15551135Ssklower 	ec_idpattern();
15651135Ssklower 	outb(p, 0);
15751135Ssklower }
15851135Ssklower extern int cpuspeed;
15951135Ssklower #define ECWR(p, e, d)	outb(&(p->e), d)
16051135Ssklower #define ECRD(p, e)	inb(&(p->e))
16151135Ssklower #define SET_CA		ECWR(ec->sc_ports, port_ca, 0)
16251135Ssklower #define UNLATCH_INT	ECWR(ec->sc_ports, port_ic, 0);
16351135Ssklower 
16451135Ssklower void
ec_getnmdata(p,which,data)16551135Ssklower ec_getnmdata(p, which, data)
16651135Ssklower register struct ec_ports *p;
16751135Ssklower int which;
16851135Ssklower register u_char *data;
16951135Ssklower {
17051135Ssklower 	register int i;
17151135Ssklower 
17251135Ssklower 	ECWR(p, creg, which);
17351135Ssklower 	DELAY(2);
17451135Ssklower 	for (i = 0; i < 6; i++) {
17551135Ssklower 		DELAY(2);
17651135Ssklower 		data[i] = ECRD(p, data[i]);
17751135Ssklower 	}
17851135Ssklower }
17951135Ssklower 
ecreset(unit)18051135Ssklower ecreset(unit)
18151135Ssklower 	register int unit;
18251135Ssklower {
18351135Ssklower 	register struct ec_softc *ec = &ec_softc[unit];
18451135Ssklower 	struct ec_ports *p	 = ec->sc_ports;
18551135Ssklower 	struct ec_mem	*hmem	 = ec->sc_hmem;
18651135Ssklower 	int timo;
18751135Ssklower 
18851135Ssklower 	ECWR(p, creg, R_LPB);	DELAY(10);
18951135Ssklower 	if ((ec->sc_if.if_flags & IFF_RUNNING) == 0)
19051135Ssklower 		return 0;
19155602Ssklower 	if (ecdebug)
19255602Ssklower 		printf("ec%dreset\n", unit);
19351135Ssklower 	ec_meminit(ec);
19451135Ssklower 	ECWR(p, creg, R_NORST);	DELAY(10);
19555602Ssklower 	hmem->iscp.busy = 1;
19651135Ssklower 	ECWR(p, port_ca, 0);	DELAY(10);
19751135Ssklower 	for (timo = TIMO; hmem->iscp.busy; )
19851135Ssklower 		timo--;
19951135Ssklower 	if (timo == 0) {
20051135Ssklower 		printf("ec(%d)reset: iscp failed\n", unit);
20151135Ssklower 		return 0;
20251135Ssklower 	}
20351135Ssklower 	hmem->scb.command = CU_START;
20451135Ssklower 	ECWR(p, port_ca, 0);	DELAY(10);
20551135Ssklower 	for (timo = TIMO; (hmem->scb.status & CU_STATE) == CUS_ACTIVE;)
20651135Ssklower 		timo--;
20755602Ssklower 	if (timo == 0 || (hmem->scb.status & CU_STATE) != CUS_IDLE) {
20855602Ssklower 		printf("ec(%d)reset: setup failed\n", unit);
20951135Ssklower 		return 0;
21051135Ssklower 	}
21151135Ssklower 	ECWR(p, port_ic, 0);	DELAY(10);
21251135Ssklower 	ECWR(p, creg, R_NORST|R_IEN);
21355602Ssklower 	hmem->scb.command = RU_START | (hmem->scb.status & 0xf000);
21451135Ssklower 	ECWR(p, port_ca, 0);	DELAY(10);
21551135Ssklower 	ec->sc_if.if_timer = 5;
21651135Ssklower 	return 0;			/* Keep GCC Happy! */
21751135Ssklower }
21851135Ssklower 
21951135Ssklower /*
22051135Ssklower  * Interface exists: make available by filling in network interface
22151135Ssklower  * record.  System will initialize the interface when it is ready
22251135Ssklower  * to accept packets.
22351135Ssklower  */
22451135Ssklower 
ecattach(id)22551135Ssklower ecattach(id)
22651135Ssklower 	register struct isa_device *id;
22751135Ssklower {
22851135Ssklower 	int	unit = id->id_unit;
22951135Ssklower 	struct ec_softc *ec = &ec_softc[unit];
23051135Ssklower 	struct ifnet *ifp = &ec->sc_if;
23151135Ssklower 
23251135Ssklower 	ifp->if_unit = unit;
23351135Ssklower 	ifp->if_name = "ec";
23451135Ssklower 	ifp->if_mtu = ETHERMTU;
23551135Ssklower 	ifp->if_init = ecinit;
23651135Ssklower 	ifp->if_init = ecreset;
23751135Ssklower 	ifp->if_ioctl = ecioctl;
23851135Ssklower 	ifp->if_watchdog = ecwatchdog;
23951135Ssklower 	ifp->if_output = ether_output;
24051135Ssklower 	ifp->if_start = ecstart;
24151135Ssklower 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
24251135Ssklower #if NBPFILTER > 0
24351135Ssklower 	bpfattach(&ec->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
24451135Ssklower #endif
24551135Ssklower 	if_attach(ifp);
24651135Ssklower 	return (1);
24751135Ssklower }
24851135Ssklower #define OFF(e) ((u_short)&(((struct ec_mem *)0)->e))
24951135Ssklower 
ec_meminit(ec)25051135Ssklower ec_meminit(ec)
25151135Ssklower 	register struct ec_softc *ec;
25251135Ssklower {
25351135Ssklower 	register struct ec_mem *hmem = ec->sc_hmem;
25451135Ssklower 	register int i;
25551135Ssklower 	struct ec_rfd *rc = hmem->rcom;
25651135Ssklower 	struct ec_transmit *tc = hmem->tcom;
25751135Ssklower 	caddr_t cp;
25851135Ssklower 
25951135Ssklower 	bzero((caddr_t)hmem, ec->sc_msize);
26051135Ssklower 	*(struct ec_mem **)
26151135Ssklower 		(ec->sc_msize - 4 + (caddr_t)ec->sc_hmem) = ec->sc_dmem;
26251135Ssklower 
26351135Ssklower 	hmem->iscp.scb_off	= OFF(scb);
26451135Ssklower 	hmem->iscp.scb_base	= (caddr_t)ec->sc_dmem;
26551135Ssklower 
26651135Ssklower 	hmem->scb.rfa_off	= OFF(rcom[0]);
26751135Ssklower 	hmem->scb.cbl_off	= OFF(config);
26851135Ssklower 
26951135Ssklower 	hmem->config.com1	= COM1_CONFIGURE;
27051135Ssklower 	bcopy((caddr_t)&ec_82586defaults, (caddr_t)&hmem->config.modes,
27151135Ssklower 		sizeof(hmem->config.modes));
27251135Ssklower #if NBPFILTER > 0
27351135Ssklower 	if (ec->sc_if.if_flags & IFF_PROMISC)
27451135Ssklower 		hmem->config.modes.promisc |= M_PROMISC;
27551135Ssklower #endif
27651135Ssklower 	hmem->config.next_off	= OFF(iasetup);
27751135Ssklower 
27851135Ssklower 	bcopy((caddr_t)ec->sc_addr, (caddr_t)hmem->iasetup.srcaddr, 6);
27951135Ssklower #ifndef ISO
28051135Ssklower 	hmem->iasetup.com1	= COM1_IASETUP | COM1_S | COM1_EL;
28151135Ssklower #else
28251135Ssklower 	hmem->iasetup.com1	= COM1_IASETUP;
28351135Ssklower 	hmem->iasetup.next_off	= OFF(mcsetup);
28451135Ssklower 
28551135Ssklower 	hmem->mcsetup.com1	= COM1_MCSETUP | COM1_S | COM1_EL;
28651135Ssklower 	hmem->mcsetup.count	= 24;
28751135Ssklower 	cp = (caddr_t)hmem->txbuf[0];
28851135Ssklower 	bcopy((caddr_t)all_es_snpa, cp, 6);	cp += 6;
28951135Ssklower 	bcopy((caddr_t)all_is_snpa, cp, 6);	cp += 6;
29051135Ssklower 	bcopy((caddr_t)all_l1is_snpa, cp, 6);	cp += 6;
29151135Ssklower 	bcopy((caddr_t)all_l2is_snpa, cp, 6);	cp += 6;
29251135Ssklower #endif
29351135Ssklower 	for (i = 0; i < NTXBUF; i++) {
29451135Ssklower 		tc->tbd_off	= OFF(tcom[i].count);
29551135Ssklower 		tc->buffer	= ec->sc_dmem->txbuf[i];
29651135Ssklower 		(tc++)->com1	= COM1_TRANSMIT | COM1_S | COM1_EL | COM1_I;
29751135Ssklower 	}
29851135Ssklower 	for (i = 0; i < NRXBUF; i++) {
29951135Ssklower 		rc->next_off	= OFF(rcom[i + 1]);
30051135Ssklower 		rc->rbd_off	= OFF(rcom[i].count);
30151135Ssklower 		rc->buffer	= ec->sc_dmem->rxbuf[i];
30251135Ssklower 		(rc++)->size	= ECMTU | COM1_EL;
30351135Ssklower 	}
30451135Ssklower 	(--rc)->next_off = OFF(rcom[0]);
30551135Ssklower }
30651135Ssklower /*
30751135Ssklower  * Initialization of interface
30851135Ssklower  */
ecinit(unit)30951135Ssklower ecinit(unit)
31051135Ssklower 	int unit;
31151135Ssklower {
31251135Ssklower 	register struct ifnet *ifp = &ec_softc[unit].sc_if;
31351135Ssklower 	register struct ifaddr *ifa;
31451135Ssklower 	int s;
31551135Ssklower 
31651135Ssklower 	/* not yet, if address still unknown */
31751135Ssklower 	for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next)
31851135Ssklower 		if (ifa == 0)
31951135Ssklower 			return 0;
32051135Ssklower 		else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
32151135Ssklower 			break;
32251135Ssklower 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
32351135Ssklower 		s = splimp();
32451135Ssklower 		ifp->if_flags |= IFF_RUNNING;
32551135Ssklower 		ecreset(unit);
32651135Ssklower 	        (void) ecstart(ifp);
32751135Ssklower 		splx(s);
32851135Ssklower 	}
32951135Ssklower 	return 0;
33051135Ssklower }
33151135Ssklower 
33251135Ssklower /*
33351135Ssklower  * Timeout: for now check for a transmit command taking more than 10 seconds.
33451135Ssklower  */
ecwatchdog(unit)33551135Ssklower ecwatchdog(unit)
33651135Ssklower 	int unit;
33751135Ssklower {
33851135Ssklower 	register struct ec_softc *ec = ec_softc + unit;
33951135Ssklower 	if (ec->sc_iflags & IFF_OACTIVE) {
34051135Ssklower 		ec->sc_if.if_flags &= ~IFF_RUNNING;
34151135Ssklower 		ecinit(unit);
34251135Ssklower 	} else if (ec->sc_txcnt > 0)
34351135Ssklower 		ec->sc_iflags |= IFF_OACTIVE;
34451135Ssklower 	ec->sc_if.if_timer = 5;
34551135Ssklower }
34651135Ssklower 
34751135Ssklower 
34851135Ssklower 
ec_txstart(ec)34951135Ssklower ec_txstart(ec)
35051135Ssklower register struct ec_softc *ec;
35151135Ssklower {
35251135Ssklower 	struct	ec_mem *hmem = ec->sc_hmem;
35351135Ssklower 	int i;
35451135Ssklower 
35551135Ssklower 	if ((i = ec->sc_txnum - ec->sc_txcnt) < 0) i += NTXBUF;
35651135Ssklower 	hmem->scb.cbl_off = OFF(tcom[i]);
35751135Ssklower 	hmem->scb.command = CU_START;
35851135Ssklower 	hmem->scb.status = 0;
35951135Ssklower 	SET_CA;
36051135Ssklower }
36151135Ssklower /*
36251135Ssklower  * Start output on interface.  Get another datagram to send
36351135Ssklower  * off of the interface queue, and copy it to the interface
36451135Ssklower  * before starting the output.
36551135Ssklower  */
36651135Ssklower ecstart(ifp)
36751135Ssklower 	struct ifnet *ifp;
36851135Ssklower {
36951135Ssklower 	register struct ec_softc *ec = &ec_softc[ifp->if_unit];
37051135Ssklower 	register struct ec_transmit *tmd;
37151135Ssklower 	register struct mbuf *m;
37251135Ssklower 	int len;
37351135Ssklower 
37451135Ssklower again:
37551135Ssklower 	if ((ec->sc_if.if_flags & IFF_RUNNING) == 0 || ec->sc_txcnt >= NTXBUF)
37651135Ssklower 		return (0);
37751135Ssklower 	tmd = ec->sc_hmem->tcom + ec->sc_txnum;
37851135Ssklower 	if (tmd->com0 & (COM0_B | COM0_C))
37951135Ssklower 		return (ec->sc_txbusy++, 0);
38051135Ssklower 	IF_DEQUEUE(&ec->sc_if.if_snd, m);
38151135Ssklower 	if (m == 0)
38251135Ssklower 		return (0);
38351135Ssklower 	len = ecput(ec->sc_hmem->txbuf[ec->sc_txnum], m);
38451135Ssklower #if NBPFILTER > 0
38551135Ssklower 	/*
38651135Ssklower 	 * If bpf is listening on this interface, let it
38751135Ssklower 	 * see the packet before we commit it to the wire.
38851135Ssklower 	 */
38951135Ssklower 	if (ec->sc_bpf)
39051135Ssklower                 bpf_tap(ec->sc_bpf, ec->sc_hmem->txbuf[ec->sc_txnum], len);
39151135Ssklower #endif
39251135Ssklower 	tmd->com0 = 0;
39351135Ssklower 	tmd->count = len | COM1_EL;
39451135Ssklower 	if (ec->sc_txcnt == 0)
39551135Ssklower 		ec_txstart(ec);
39651135Ssklower 	if (++ec->sc_txnum >= NTXBUF)
39751135Ssklower 		ec->sc_txnum = 0;
39851135Ssklower 	if (++ec->sc_txcnt >= NTXBUF) {
39951135Ssklower 		ec->sc_txcnt = NTXBUF;
40051135Ssklower 		ec->sc_if.if_flags |= IFF_OACTIVE;
40151135Ssklower 	}
40251135Ssklower 	goto again;
40351135Ssklower }
40455602Ssklower int ECC_intr, ECC_rint, ECC_xint, ECC_unready;
40551135Ssklower 
ecintr(unit)40651135Ssklower ecintr(unit)
40751135Ssklower 	register int unit;
40851135Ssklower {
40951135Ssklower 	struct ec_softc *ec = &ec_softc[unit];
41051135Ssklower 	struct ec_mem *hmem = ec->sc_hmem;
41151135Ssklower 	register int stat = hmem->scb.status;
41251135Ssklower 
41351135Ssklower 	hmem->scb.command = stat & 0xf000; /* Ack interrupt cause */
41451135Ssklower 	SET_CA;
41551135Ssklower 	if (stat & FR)
41651135Ssklower 		ecrint(unit);
41751135Ssklower 	if (stat & CX)
41851135Ssklower 		ecxint(unit);
41955602Ssklower 	ECC_intr++;
42055602Ssklower 	if ((stat & RU_STATE) != RUS_READY)
42155602Ssklower 		ECC_unready++;
42251135Ssklower 	UNLATCH_INT;
42351135Ssklower }
42451135Ssklower 
42551135Ssklower /*
42651135Ssklower  * Ethernet interface transmitter interrupt.
42751135Ssklower  * Start another output if more data to send.
42851135Ssklower  */
ecxint(unit)42951135Ssklower ecxint(unit)
43051135Ssklower 	register int unit;
43151135Ssklower {
43251135Ssklower 	register struct ec_softc *ec = &ec_softc[unit];
43351135Ssklower 	register struct ec_transmit *tmd;
43451135Ssklower 	int i;
43551135Ssklower 
43655602Ssklower 	ECC_rint++;
43751135Ssklower 	if (ec->sc_txcnt == 0) {
43851135Ssklower 		ec->sc_xint++;	/* unexpected transmit interrupt */
43951135Ssklower 		return;
44051135Ssklower 	}
44151135Ssklower 	ec->sc_iflags &= ~IFF_OACTIVE; /* clear deadman indication */
44251135Ssklower 	if ((i = ec->sc_txnum - ec->sc_txcnt) < 0) i += NTXBUF;
44351135Ssklower 	tmd = ec->sc_hmem->tcom + i;
44451135Ssklower 	if (tmd->com0 & COM0_B)
44551135Ssklower 		return;
44651135Ssklower 	ec->sc_if.if_collisions += tmd->com0 & 0xf;
44751135Ssklower 	if ((tmd->com0 & EXCOL) && (tmd->com0 & 0xf) == 0)
44851135Ssklower 		ec->sc_if.if_collisions += 16;
44951135Ssklower 	if ((tmd->com0 & COM0_OK) == 0) {
45051135Ssklower 		ecxerror(unit);
45151135Ssklower 		ec->sc_if.if_oerrors++;
45251135Ssklower 		if (tmd->com0 & DMALATE) {
45351135Ssklower 			ec->sc_uflo++;
45451135Ssklower 			(void) ecreset(unit);
45551135Ssklower 			return;
45651135Ssklower 		}
45751135Ssklower 	} else
45851135Ssklower 		ec->sc_if.if_opackets++;
45951135Ssklower 	tmd->com0 = 0;
46051135Ssklower 	if (--ec->sc_txcnt > 0)
46151135Ssklower 		ec_txstart(ec);
46251135Ssklower 	if (ec->sc_txcnt < 0) {
46351135Ssklower 		ec->sc_txbad++;
46451135Ssklower 		ec->sc_txcnt = 0;
46551135Ssklower 	}
46651135Ssklower 	ec->sc_if.if_flags &= ~IFF_OACTIVE;
46751135Ssklower 	(void) ecstart(&ec->sc_if);
46851135Ssklower }
46951135Ssklower 
47051135Ssklower #define	ECNEXTRCOM \
47151135Ssklower 	if (++bix == NRXBUF) bix = 0, rmd = ec->sc_hmem->rcom; else ++rmd
47251135Ssklower 
47351135Ssklower /*
47451135Ssklower  * Ethernet interface receiver interrupt.
47551135Ssklower  * If input error just drop packet.
47651135Ssklower  * Decapsulate packet based on type and pass to type specific
47751135Ssklower  * higher-level input routine.
47851135Ssklower  */
ecrint(unit)47951135Ssklower ecrint(unit)
48051135Ssklower 	int unit;
48151135Ssklower {
48251135Ssklower 	register struct ec_softc *ec = &ec_softc[unit];
48351135Ssklower 	register int bix = ec->sc_rxnum;
48451135Ssklower 	register struct ec_rfd *rmd = ec->sc_hmem->rcom + bix;
48551135Ssklower 
48651135Ssklower 	/*
48751135Ssklower 	 * Out of sync with hardware, should never happen?
48851135Ssklower 	 */
48955602Ssklower 	ECC_xint++;
49051795Ssklower 	if ((rmd->rfd0 & COM0_C) == 0 || (rmd->count & RBD_F) == 0) {
49151795Ssklower 		ecrerror(unit, "out of sync, resetting");
49251795Ssklower 		return ecreset(unit);
49351795Ssklower 	}
49451135Ssklower 	/*
49551135Ssklower 	 * Process all buffers with valid data
49651135Ssklower 	 */
49751135Ssklower 	while ((rmd->rfd0 & COM0_C) && (rmd->count & RBD_F)) {
49851135Ssklower 		if (rmd->rfd0 & (COM0_C|COM0_B|COM0_OK) != (COM0_C|COM0_OK)) {
49951135Ssklower 			ec->sc_rxnum = bix;
50051135Ssklower 			ecrerror(unit, "bad packet");
50151135Ssklower 			ec->sc_if.if_ierrors++;
50251135Ssklower 		}
50351135Ssklower 		if ((rmd->count & (RBD_F|RBD_EOF)) != (RBD_F|RBD_EOF)) {
50451135Ssklower 			ecrerror(unit, "chained buffer");
50551135Ssklower 			ec->sc_rxlen++;
50651135Ssklower 			ec->sc_if.if_ierrors++;
50751135Ssklower 		} else
50851135Ssklower 			ecread(ec, ec->sc_hmem->txbuf[bix], rmd->count & 0x2f);
50951135Ssklower 		rmd->count = 0;
51051135Ssklower 		rmd->rfd0 = 0;
51151135Ssklower 		ECNEXTRCOM;
51251135Ssklower 		ec->sc_rxnum = bix;
51351135Ssklower 	}
51451135Ssklower }
51551135Ssklower 
51651135Ssklower void
ecread(ec,buf,len)51751135Ssklower ecread(ec, buf, len)
51851135Ssklower 	register struct ec_softc *ec;
51951135Ssklower 	char *buf;
52051135Ssklower 	int len;
52151135Ssklower {
52251135Ssklower 	struct ether_header *et, eh;
52351135Ssklower     	struct mbuf *m;
52451135Ssklower 	int off, resid, unit = ec->sc_if.if_unit;
52551135Ssklower 
52651135Ssklower 	ec->sc_if.if_ipackets++;
52751135Ssklower 	et = (struct ether_header *)buf;
52851135Ssklower 	et->ether_type = ntohs((u_short)et->ether_type);
52951135Ssklower 	bcopy((caddr_t)et, &eh, sizeof(eh));
53051135Ssklower 	/* adjust input length to account for header */
53151135Ssklower 	len = len - sizeof(struct ether_header);
53251135Ssklower 
53351135Ssklower #define	ecdataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
53451135Ssklower 	if (et->ether_type >= ETHERTYPE_TRAIL &&
53551135Ssklower 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
53651135Ssklower 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
53751135Ssklower 		if (off >= ETHERMTU)
53851135Ssklower 			return;		/* sanity */
53951135Ssklower 		et->ether_type = ntohs(*ecdataaddr(et, off, u_short *));
54051135Ssklower 		resid = ntohs(*(ecdataaddr(et, off+2, u_short *)));
54151135Ssklower 		if (off + resid > len)
54251135Ssklower 			return;		/* sanity */
54351135Ssklower 		len = off + resid;
54451135Ssklower 	} else
54551135Ssklower 		off = 0;
54651135Ssklower 
54751135Ssklower 	if (len <= 0) {
54851135Ssklower 		if (ecdebug)
54951135Ssklower 			log(LOG_WARNING,
55051135Ssklower 			    "ec%d: ierror(runt packet): from %s: len=%d\n",
55151135Ssklower 			    unit, ether_sprintf(et->ether_shost), len);
55251135Ssklower 		ec->sc_runt++;
55351135Ssklower 		ec->sc_if.if_ierrors++;
55451135Ssklower 		return;
55551135Ssklower 	}
55651135Ssklower #if NBPFILTER > 0
55751135Ssklower 	/*
55851135Ssklower 	 * Check if there's a bpf filter listening on this interface.
55951135Ssklower 	 * If so, hand off the raw packet to bpf, which must deal with
56051135Ssklower 	 * trailers in its own way.
56151135Ssklower 	 */
56251135Ssklower 	if (ec->sc_bpf)
56351135Ssklower 		bpf_tap(ec->sc_bpf, buf, len + sizeof(struct ether_header));
56451135Ssklower #endif
56551135Ssklower #if defined(ISO) || NBPFILTER > 0
56651135Ssklower 	/*
56751135Ssklower 	 * Note that the interface cannot be in promiscuous mode if
56851135Ssklower 	 * there are no bpf listeners.  If we are in promiscuous
56951135Ssklower 	 * mode, we have to check if this packet is really ours.
57051135Ssklower 	 * However, there may be appropriate multicate addresses involved
57151135Ssklower 	 */
57251135Ssklower #define NOT_TO(p) (bcmp(et->ether_dhost, p, sizeof(et->ether_dhost)) != 0)
57351135Ssklower 	if (et->ether_dhost[0] & 1) {
57451135Ssklower 		if (NOT_TO(etherbroadcastaddr)
57551135Ssklower #ifdef ISO
57651135Ssklower 		    && NOT_TO(all_es_snpa) && NOT_TO(all_is_snpa)
57751135Ssklower 		    && NOT_TO(all_l1is_snpa) && NOT_TO(all_l2is_snpa)
57851135Ssklower #endif
57951135Ssklower 		     ) return;
58051135Ssklower 	} else if ((ec->sc_if.if_flags & IFF_PROMISC) && NOT_TO(ec->sc_addr))
58151135Ssklower 		return;
58251135Ssklower #endif
58351135Ssklower 	/*
58451135Ssklower 	 * Pull packet off interface.  Off is nonzero if packet
58551135Ssklower 	 * has trailing header; m_devget will then force this header
58651135Ssklower 	 * information to be at the front, but we still have to drop
58751135Ssklower 	 * the type and length which are at the front of any trailer data.
58851135Ssklower 	 */
58951135Ssklower 	m = m_devget((char *)(et + 1), len, off, &ec->sc_if, 0);
59051135Ssklower 	if (m == 0)
59151135Ssklower 		return;
59251135Ssklower 	ether_input(&ec->sc_if, &eh, m);
59351135Ssklower }
59451135Ssklower 
59551135Ssklower /*
59651135Ssklower  * Routine to copy from mbuf chain to transmit
59751135Ssklower  * buffer in board local memory.
59851135Ssklower  */
ecput(ecbuf,m)59951135Ssklower ecput(ecbuf, m)
60051135Ssklower 	register char *ecbuf;
60151135Ssklower 	register struct mbuf *m;
60251135Ssklower {
60351135Ssklower 	register struct mbuf *mp;
60451135Ssklower 	register int len, tlen = 0;
60551135Ssklower 
60651135Ssklower 	for (mp = m; mp; mp = mp->m_next) {
60751135Ssklower 		len = mp->m_len;
60851135Ssklower 		if (len == 0)
60951135Ssklower 			continue;
61051135Ssklower 		tlen += len;
61151135Ssklower 		bcopy(mtod(mp, char *), ecbuf, len);
61251135Ssklower 		ecbuf += len;
61351135Ssklower 	}
61451135Ssklower 	m_freem(m);
61551135Ssklower 	if (tlen < ECMINSIZE) {
61651135Ssklower 		bzero(ecbuf, ECMINSIZE - tlen);
61751135Ssklower 		tlen = ECMINSIZE;
61851135Ssklower 	}
61951135Ssklower 	return(tlen);
62051135Ssklower }
62151135Ssklower 
62251135Ssklower /*
62351135Ssklower  * Process an ioctl request.
62451135Ssklower  */
ecioctl(ifp,cmd,data)62551135Ssklower ecioctl(ifp, cmd, data)
62651135Ssklower 	register struct ifnet *ifp;
62751135Ssklower 	int cmd;
62851135Ssklower 	caddr_t data;
62951135Ssklower {
63051135Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
63151135Ssklower 	struct ec_softc *ec = &ec_softc[ifp->if_unit];
63251135Ssklower 	int s = splimp(), error = 0;
63351135Ssklower 
63451135Ssklower 	switch (cmd) {
63551135Ssklower 
63651135Ssklower 	case SIOCSIFADDR:
63751135Ssklower 		ifp->if_flags |= IFF_UP;
63851135Ssklower 		switch (ifa->ifa_addr->sa_family) {
63951135Ssklower #ifdef INET
64051135Ssklower 		case AF_INET:
64151135Ssklower 			ecinit(ifp->if_unit);	/* before arpwhohas */
64251135Ssklower 			((struct arpcom *)ifp)->ac_ipaddr =
64351135Ssklower 				IA_SIN(ifa)->sin_addr;
64451135Ssklower 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
64551135Ssklower 			break;
64651135Ssklower #endif
64751135Ssklower #ifdef NS
64851135Ssklower 		case AF_NS:
64951135Ssklower 		    {
65051135Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
65151135Ssklower 
65251135Ssklower 			if (ns_nullhost(*ina))
65351135Ssklower 				ina->x_host = *(union ns_host *)(ec->sc_addr);
65451135Ssklower 			else {
65551135Ssklower 				ifp->if_flags &= ~IFF_RUNNING;
65651135Ssklower 				bcopy((caddr_t)ina->x_host.c_host,
65751135Ssklower 				    (caddr_t)ec->sc_addr, sizeof(ec->sc_addr));
65851135Ssklower 			}
65951135Ssklower 			ecinit(ifp->if_unit);
66051135Ssklower 			break;
66151135Ssklower 		    }
66251135Ssklower #endif
66351135Ssklower 		default:
66451135Ssklower 			ecinit(ifp->if_unit);
66551135Ssklower 			break;
66651135Ssklower 		}
66751135Ssklower 		break;
66851135Ssklower 
66951135Ssklower 	case SIOCSIFFLAGS:
67051135Ssklower 		if ((ifp->if_flags & IFF_UP) == 0 &&
67151135Ssklower 		    ifp->if_flags & IFF_RUNNING) {
67251135Ssklower 			ifp->if_flags &= ~IFF_RUNNING;
67351135Ssklower 			ecreset(ifp->if_unit);
67451135Ssklower 		} else if (ifp->if_flags & IFF_UP &&
67551135Ssklower 		    (ifp->if_flags & IFF_RUNNING) == 0)
67651135Ssklower 			ecinit(ifp->if_unit);
67751135Ssklower 		/*
67851135Ssklower 		 * If the state of the promiscuous bit changes, the interface
67951135Ssklower 		 * must be reset to effect the change.
68051135Ssklower 		 */
68151135Ssklower 		if (((ifp->if_flags ^ ec->sc_iflags) & IFF_PROMISC) &&
68251135Ssklower 		    (ifp->if_flags & IFF_RUNNING)) {
68351135Ssklower 			ec->sc_iflags = ifp->if_flags & ~IFF_OACTIVE;
68451135Ssklower 			ecreset(ifp->if_unit);
68551135Ssklower 			ecstart(ifp);
68651135Ssklower 		}
68751135Ssklower 		break;
68851135Ssklower 
68951135Ssklower 	default:
69051135Ssklower 		error = EINVAL;
69151135Ssklower 	}
69251135Ssklower 	splx(s);
69351135Ssklower 	return (error);
69451135Ssklower }
69551135Ssklower 
ecrerror(unit,msg)69651135Ssklower ecrerror(unit, msg)
69751135Ssklower 	int unit;
69851135Ssklower 	char *msg;
69951135Ssklower {
70051135Ssklower 	register struct ec_softc *ec = &ec_softc[unit];
70151135Ssklower 	register struct ec_rfd *rmd;
70251135Ssklower 	int len;
70351135Ssklower 
70451135Ssklower 	if (!ecdebug)
70551135Ssklower 		return;
70651135Ssklower 
70751135Ssklower 	rmd = &ec->sc_hmem->rcom[ec->sc_rxnum];
70851135Ssklower 	len = rmd->count;
70951135Ssklower 	log(LOG_WARNING,
71051135Ssklower 	    "ec%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
71151135Ssklower 	    unit, msg,
71251135Ssklower 	    len > 11 ? ether_sprintf(&ec->sc_hmem->rxbuf[ec->sc_rxnum][6]) : "unknown",
71351135Ssklower 	    ec->sc_rxnum, len,
71451135Ssklower 	    rmd->rfd0, "\14\14LEN\13CRC\12ALGN\11NBUF\10DMAL\07SHRT");
71551135Ssklower }
71651135Ssklower 
ecxerror(unit)71751135Ssklower ecxerror(unit)
71851135Ssklower 	int unit;
71951135Ssklower {
72051135Ssklower 	register struct ec_softc *ec = &ec_softc[unit];
72151135Ssklower 	register struct ec_transmit *tmd;
72251135Ssklower 	int len;
72351135Ssklower 
72451135Ssklower 	if (!ecdebug)
72551135Ssklower 		return;
72651135Ssklower 
72751135Ssklower 	tmd = &ec->sc_hmem->tcom[ec->sc_txnum];
72851135Ssklower 	len = tmd->count;
72951135Ssklower 	log(LOG_WARNING,
73051135Ssklower 	    "ec%d: oerror: to %s: buf=%d, len=%d, com0=%b\n",
73151135Ssklower 	    unit,
73251135Ssklower 	    len > 5 ? ether_sprintf(ec->sc_hmem->txbuf[ec->sc_txnum]) : "unknown",
73351135Ssklower 	    ec->sc_txnum, len,
73451135Ssklower 	    tmd->com0,
73551135Ssklower 	    "\14\14ABRT\13LCOLL\12NCAR\11NCTS\10DMAL\07TDEF\06HRBT\05XCOL");
73651135Ssklower }
73751135Ssklower #endif
738