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