123292Smckusick /*
229363Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
335320Sbostic * All rights reserved.
423292Smckusick *
535320Sbostic * This code is derived from software contributed to Berkeley by
635320Sbostic * Excelan Inc.
735320Sbostic *
844559Sbostic * %sccs.include.redist.c%
935320Sbostic *
10*45801Sbostic * @(#)if_ex.c 7.9 (Berkeley) 12/16/90
1123292Smckusick */
1219880Skarels
1319880Skarels #include "ex.h"
1425273Sbloom #if NEX > 0
1519880Skarels
1619880Skarels /*
1719880Skarels * Excelan EXOS 204 Interface
1819880Skarels *
1919880Skarels * George Powers
2019880Skarels * Excelan Inc.
2119880Skarels */
2219880Skarels
23*45801Sbostic #include "sys/param.h"
24*45801Sbostic #include "sys/systm.h"
25*45801Sbostic #include "sys/mbuf.h"
26*45801Sbostic #include "sys/buf.h"
27*45801Sbostic #include "sys/protosw.h"
28*45801Sbostic #include "sys/socket.h"
29*45801Sbostic #include "sys/vmmac.h"
30*45801Sbostic #include "sys/ioctl.h"
31*45801Sbostic #include "sys/syslog.h"
32*45801Sbostic #include "sys/errno.h"
3319880Skarels
34*45801Sbostic #include "net/if.h"
35*45801Sbostic #include "net/netisr.h"
36*45801Sbostic #include "net/route.h"
3724539Skarels
3824539Skarels #ifdef INET
39*45801Sbostic #include "netinet/in.h"
40*45801Sbostic #include "netinet/in_systm.h"
41*45801Sbostic #include "netinet/in_var.h"
42*45801Sbostic #include "netinet/ip.h"
43*45801Sbostic #include "netinet/if_ether.h"
4424539Skarels #endif
4524539Skarels
4624556Ssklower #ifdef NS
47*45801Sbostic #include "netns/ns.h"
48*45801Sbostic #include "netns/ns_if.h"
4924556Ssklower #endif
5024556Ssklower
5137476Ssklower #ifdef ISO
52*45801Sbostic #include "netiso/iso.h"
53*45801Sbostic #include "netiso/iso_var.h"
5443338Ssklower extern char all_es_snpa[], all_is_snpa[];
5537476Ssklower #endif
5637476Ssklower
57*45801Sbostic #include "../include/pte.h"
58*45801Sbostic #include "../include/cpu.h"
59*45801Sbostic #include "../include/mtpr.h"
6021777Skarels #include "if_exreg.h"
6121777Skarels #include "if_uba.h"
62*45801Sbostic #include "../uba/ubareg.h"
63*45801Sbostic #include "../uba/ubavar.h"
6419880Skarels
6534531Skarels /* #define DEBUG /* check for "impossible" events */
6619880Skarels
6719880Skarels #define NH2X 4 /* a sufficient number is critical */
6819880Skarels #define NX2H 4 /* this is pretty arbitrary */
6919880Skarels #define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */
7019880Skarels
7119880Skarels int exprobe(), exattach(), excdint();
7219880Skarels struct uba_device *exinfo[NEX];
7319880Skarels u_short exstd[] = { 0 };
7419880Skarels struct uba_driver exdriver =
7519880Skarels { exprobe, 0, exattach, 0, exstd, "ex", exinfo };
7640681Skarels int exinit(),exstart(),ether_output(),exioctl(),exreset(),exwatch();
7719880Skarels struct ex_msg *exgetcbuf();
7819880Skarels
7919880Skarels /*
8019880Skarels * Ethernet software status per interface.
8119880Skarels *
8219880Skarels * Each interface is referenced by a network interface structure,
8319880Skarels * xs_if, which the routing code uses to locate the interface.
8419880Skarels * This structure contains the output queue for the interface, its address, ...
8519880Skarels * We also have, for each interface, a UBA interface structure, which
8619880Skarels * contains information about the UNIBUS resources held by the interface:
8719880Skarels * map registers, buffered data paths, etc. Information is cached in this
8819880Skarels * structure for use by the if_uba.c routines in running the interface
8919880Skarels * efficiently.
9019880Skarels */
9119880Skarels struct ex_softc {
9221777Skarels struct arpcom xs_ac; /* Ethernet common part */
9321777Skarels #define xs_if xs_ac.ac_if /* network-visible interface */
9421777Skarels #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
9519880Skarels #ifdef DEBUG
9619880Skarels int xs_wait;
9719880Skarels #endif
9819880Skarels struct ifuba xs_ifuba; /* UNIBUS resources */
9919880Skarels int xs_flags; /* private flags */
10019880Skarels #define EX_XPENDING 1 /* xmit rqst pending on EXOS */
10119880Skarels #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */
10225447Skarels #define EX_RUNNING (1<<2) /* board is running */
10325621Ssklower #define EX_SETADDR (1<<3) /* physaddr has been changed */
10419880Skarels struct ex_msg *xs_h2xnext; /* host pointer to request queue */
10519880Skarels struct ex_msg *xs_x2hnext; /* host pointer to reply queue */
10626391Skarels int xs_ubaddr; /* map info for structs below */
10719880Skarels #define UNIADDR(x) ((u_long)(x)&0x3FFFF)
10819880Skarels #define P_UNIADDR(x) ((u_long)(x)&0x3FFF0)
10919880Skarels /* the following structures are always mapped in */
11019880Skarels u_short xs_h2xhdr; /* EXOS's request queue header */
11119880Skarels u_short xs_x2hhdr; /* EXOS's reply queue header */
11219880Skarels struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */
11319880Skarels struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */
11419880Skarels struct confmsg xs_cm; /* configuration message */
11519880Skarels struct stat_array xs_xsa; /* EXOS writes stats here */
11619880Skarels /* end mapped area */
11726391Skarels #define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))
11825728Smckusick #define RVAL_OFF(unit, n) \
11926391Skarels ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))
12025728Smckusick #define LVAL_OFF(unit, n) \
12126391Skarels ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))
12225728Smckusick #define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr)
12325728Smckusick #define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr)
12425728Smckusick #define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent)
12525728Smckusick #define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent)
12625728Smckusick #define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm)
12725728Smckusick #define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa)
12825728Smckusick #define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end)
12919880Skarels int xs_end; /* place holder */
13019880Skarels } ex_softc[NEX];
13119880Skarels
13219880Skarels /*
13319880Skarels * The following structure is a kludge to store a cvec value
13419880Skarels * between the time exprobe is called, and exconfig.
13519880Skarels */
13619880Skarels struct ex_cvecs {
13719880Skarels struct exdevice *xc_csraddr;
13819880Skarels int xc_cvec;
13919880Skarels }ex_cvecs[NEX];
14019880Skarels
14119880Skarels int ex_ncall = 0; /* counts calls to exprobe */
14219880Skarels
exprobe(reg)14319880Skarels exprobe(reg)
14419880Skarels caddr_t reg;
14519880Skarels {
14619880Skarels register int br, cvec; /* r11, r10 value-result */
14719880Skarels register struct exdevice *addr = (struct exdevice *)reg;
14819880Skarels register i;
14919880Skarels
15019880Skarels /*
15119880Skarels * We program the EXOS interrupt vector, like dmf device.
15219880Skarels */
15319880Skarels br = 0x15;
15419880Skarels cvec = (uba_hd[numuba].uh_lastiv -= 4);
15519880Skarels ex_cvecs[ex_ncall].xc_csraddr = addr;
15626013Skarels ex_cvecs[ex_ncall].xc_cvec = cvec;
15719880Skarels /*
15819880Skarels * Reset EXOS and run self-test (guaranteed to
15919880Skarels * complete within 2 seconds).
16019880Skarels */
16119880Skarels addr->xd_porta = EX_RESET;
16226013Skarels i = 2000;
16319880Skarels while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
16426013Skarels DELAY(1000);
16519880Skarels if ((addr->xd_portb & EX_TESTOK) == 0) {
16619880Skarels printf("ex: self-test failed\n");
16719880Skarels return 0;
16819880Skarels }
16924539Skarels #ifdef lint
17024539Skarels br = br;
17126391Skarels excdint(0);
17224539Skarels #endif
17326013Skarels ex_ncall++;
17419880Skarels return (sizeof(struct exdevice));
17519880Skarels }
17619880Skarels
17719880Skarels /*
17819880Skarels * Interface exists: make available by filling in network interface
17919880Skarels * record. System will initialize the interface when it is ready
18019880Skarels * to accept packets. Board is temporarily configured and issues
18119880Skarels * a NET_ADDRS command, only to get the Ethernet address.
18219880Skarels */
exattach(ui)18319880Skarels exattach(ui)
18437476Ssklower register struct uba_device *ui;
18519880Skarels {
18619880Skarels register struct ex_softc *xs = &ex_softc[ui->ui_unit];
18719880Skarels register struct ifnet *ifp = &xs->xs_if;
18819880Skarels register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
18919880Skarels register struct ex_msg *bp;
19025728Smckusick int unit = ui->ui_unit;
19119880Skarels ifp->if_unit = ui->ui_unit;
19219880Skarels ifp->if_name = "ex";
19319880Skarels ifp->if_mtu = ETHERMTU;
19419880Skarels
19519880Skarels /*
19619880Skarels * Temporarily map queues in order to configure EXOS
19719880Skarels */
19825728Smckusick xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
19925728Smckusick INCORE_SIZE(unit), 0);
20019880Skarels exconfig(ui, 0); /* without interrupts */
20119880Skarels if (xs->xs_cm.cm_cc) goto badconf;
20219880Skarels
20319880Skarels bp = exgetcbuf(xs);
20419880Skarels bp->mb_rqst = LLNET_ADDRS;
20519880Skarels bp->mb_na.na_mask = READ_OBJ;
20619880Skarels bp->mb_na.na_slot = PHYSSLOT;
20719880Skarels bp->mb_status |= MH_EXOS;
20819880Skarels addr->xd_portb = EX_NTRUPT;
20919880Skarels bp = xs->xs_x2hnext;
21019880Skarels while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
21119880Skarels ;
21225975Skarels printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n",
21326013Skarels ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
21426013Skarels xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
21526013Skarels ether_sprintf(bp->mb_na.na_addrs));
21619880Skarels bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
21719880Skarels sizeof (xs->xs_addr));
21819880Skarels
21919880Skarels ifp->if_init = exinit;
22037476Ssklower ifp->if_output = ether_output;
22140681Skarels ifp->if_start = exstart;
22219880Skarels ifp->if_ioctl = exioctl;
22319880Skarels ifp->if_reset = exreset;
22421777Skarels ifp->if_flags = IFF_BROADCAST;
22519880Skarels xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
22619880Skarels if_attach(ifp);
22719880Skarels badconf:
22819880Skarels ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
22919880Skarels }
23019880Skarels
23119880Skarels /*
23219880Skarels * Reset of interface after UNIBUS reset.
23319880Skarels * If interface is on specified uba, reset its state.
23419880Skarels */
exreset(unit,uban)23519880Skarels exreset(unit, uban)
23619880Skarels int unit, uban;
23719880Skarels {
23819880Skarels register struct uba_device *ui;
23919880Skarels
24019880Skarels if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
24119880Skarels ui->ui_ubanum != uban)
24219880Skarels return;
24319880Skarels printf(" ex%d", unit);
24421777Skarels ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
24525447Skarels ex_softc[unit].xs_flags &= ~EX_RUNNING;
24619880Skarels exinit(unit);
24719880Skarels }
24819880Skarels
24919880Skarels /*
25019880Skarels * Initialization of interface; clear recorded pending
25119880Skarels * operations, and reinitialize UNIBUS usage.
25219880Skarels * Called at boot time (with interrupts disabled?),
25319880Skarels * and at ifconfig time via exioctl, with interrupts disabled.
25419880Skarels */
exinit(unit)25519880Skarels exinit(unit)
25619880Skarels int unit;
25719880Skarels {
25819880Skarels register struct ex_softc *xs = &ex_softc[unit];
25919880Skarels register struct uba_device *ui = exinfo[unit];
26019880Skarels register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
26119880Skarels register struct ifnet *ifp = &xs->xs_if;
26219880Skarels register struct ex_msg *bp;
26319880Skarels int s;
26419880Skarels
26521777Skarels /* not yet, if address still unknown */
26621777Skarels if (ifp->if_addrlist == (struct ifaddr *)0)
26719880Skarels return;
26825447Skarels if (xs->xs_flags & EX_RUNNING)
26925447Skarels return;
27019880Skarels
27125447Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) {
27225447Skarels if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
27325447Skarels sizeof (struct ether_header),
27425447Skarels (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
27525447Skarels printf("ex%d: can't initialize\n", unit);
27625447Skarels xs->xs_if.if_flags &= ~IFF_UP;
27725447Skarels return;
27825447Skarels }
27925447Skarels xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
28025728Smckusick INCORE_SIZE(unit), 0);
28119880Skarels }
28219880Skarels exconfig(ui, 4); /* with vectored interrupts*/
28319880Skarels /*
28419880Skarels * Put EXOS on the Ethernet, using NET_MODE command
28519880Skarels */
28619880Skarels bp = exgetcbuf(xs);
28719880Skarels bp->mb_rqst = LLNET_MODE;
28819880Skarels bp->mb_nm.nm_mask = WRITE_OBJ;
28919880Skarels bp->mb_nm.nm_optn = 0;
29019880Skarels bp->mb_nm.nm_mode = MODE_PERF;
29119880Skarels bp->mb_status |= MH_EXOS;
29219880Skarels addr->xd_portb = EX_NTRUPT;
29319880Skarels bp = xs->xs_x2hnext;
29419880Skarels while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
29519880Skarels ;
29619880Skarels bp->mb_length = MBDATALEN;
29719880Skarels bp->mb_status |= MH_EXOS; /* free up buffer */
29819880Skarels addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
29919880Skarels xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
30019880Skarels
30119880Skarels ifp->if_watchdog = exwatch;
30219880Skarels ifp->if_timer = EXWATCHINTVL;
30319880Skarels s = splimp(); /* are interrupts always disabled here, anyway? */
30419880Skarels exhangrcv(unit); /* hang receive request */
30521777Skarels xs->xs_if.if_flags |= IFF_RUNNING;
30625447Skarels xs->xs_flags |= EX_RUNNING;
30725621Ssklower if (xs->xs_flags & EX_SETADDR)
30826391Skarels ex_setaddr((u_char *)0, unit);
30937476Ssklower #ifdef ISO
31043338Ssklower ex_setmulti(all_es_snpa, unit, 1);
31143338Ssklower ex_setmulti(all_is_snpa, unit, 2);
31237476Ssklower #endif
31337476Ssklower (void) exstart(&xs->xs_if); /* start transmits */
31419880Skarels splx(s);
31519880Skarels }
31619880Skarels
31719880Skarels /*
31819880Skarels * Reset, test, and configure EXOS. This routine assumes
31919880Skarels * that message queues, etc. have already been mapped into
32019880Skarels * the UBA. It is called by exinit, and should also be
32119880Skarels * callable by exattach.
32219880Skarels */
32319880Skarels exconfig(ui, itype)
32419880Skarels struct uba_device *ui;
32519880Skarels int itype;
32619880Skarels {
32719880Skarels register int unit = ui->ui_unit;
32819880Skarels register struct ex_softc *xs = &ex_softc[unit];
32919880Skarels register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
33019880Skarels register struct confmsg *cm = &xs->xs_cm;
33119880Skarels register struct ex_msg *bp;
33219880Skarels int i;
33319880Skarels u_long shiftreg;
33419880Skarels
33519880Skarels xs->xs_flags = 0;
33619880Skarels /*
33719880Skarels * Reset EXOS, wait for self-test to complete
33819880Skarels */
33919880Skarels addr->xd_porta = EX_RESET;
34019880Skarels while ((addr->xd_portb & EX_TESTOK) == 0)
34119880Skarels ;
34219880Skarels /*
34319880Skarels * Set up configuration message.
34419880Skarels */
34519880Skarels cm->cm_1rsrv = 1;
34619880Skarels cm->cm_cc = 0xFF;
34719880Skarels cm->cm_opmode = 0; /* link-level controller mode */
34819880Skarels cm->cm_dfo = 0x0101; /* enable host data order conversion */
34919880Skarels cm->cm_dcn1 = 1;
35037476Ssklower cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
35119880Skarels cm->cm_ham = 3; /* absolute address mode */
35219880Skarels cm->cm_3rsrv = 0;
35319880Skarels cm->cm_mapsiz = 0;
35419880Skarels cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */
35519880Skarels cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */
35619880Skarels cm->cm_byteptrn[2] = 0x07;
35719880Skarels cm->cm_byteptrn[3] = 0x0F;
35819880Skarels cm->cm_wordptrn[0] = 0x0103;
35919880Skarels cm->cm_wordptrn[1] = 0x070F;
36019880Skarels cm->cm_lwordptrn = 0x0103070F;
36119880Skarels for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
36219880Skarels cm->cm_mba = 0xFFFFFFFF;
36319880Skarels cm->cm_nproc = 0xFF;
36419880Skarels cm->cm_nmbox = 0xFF;
36519880Skarels cm->cm_nmcast = 0xFF;
36619880Skarels cm->cm_nhost = 1;
36719880Skarels cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
36825728Smckusick cm->cm_h2xhdr = H2XHDR_OFFSET(unit);
36919880Skarels cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */
37019880Skarels cm->cm_x2hba = cm->cm_h2xba;
37125728Smckusick cm->cm_x2hhdr = X2HHDR_OFFSET(unit);
37219880Skarels cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */
37319880Skarels for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
37419880Skarels #ifdef DEBUG
37519880Skarels if (i >= NEX)
37619880Skarels panic("ex: matching csr address not found");
37719880Skarels #endif
37819880Skarels ;
37919880Skarels cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */
38019880Skarels /*
38119880Skarels * Set up message queues and headers.
38219880Skarels * First the request queue.
38319880Skarels */
38419880Skarels for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
38519880Skarels bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
38619880Skarels bp->mb_rsrv = 0;
38719880Skarels bp->mb_length = MBDATALEN;
38819880Skarels bp->mb_status = MH_HOST;
38919880Skarels bp->mb_next = bp+1;
39019880Skarels }
39119880Skarels xs->xs_h2xhdr =
39237476Ssklower xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit);
39337476Ssklower xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
39419880Skarels
39519880Skarels /* Now the reply queue. */
39619880Skarels for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
39719880Skarels bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
39819880Skarels bp->mb_rsrv = 0;
39919880Skarels bp->mb_length = MBDATALEN;
40019880Skarels bp->mb_status = MH_EXOS;
40119880Skarels bp->mb_next = bp+1;
40219880Skarels }
40319880Skarels xs->xs_x2hhdr =
40437476Ssklower xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit);
40537476Ssklower xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
40619880Skarels
40719880Skarels /*
40819880Skarels * Write config msg address to EXOS and wait for
40919880Skarels * configuration to complete (guaranteed response
41019880Skarels * within 2 seconds).
41119880Skarels */
41219880Skarels shiftreg = (u_long)0x0000FFFF;
41319880Skarels for (i = 0; i < 8; i++) {
41419880Skarels if (i == 4)
41525728Smckusick shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit);
41619880Skarels while (addr->xd_portb & EX_UNREADY)
41719880Skarels ;
41819880Skarels addr->xd_portb = (u_char)(shiftreg & 0xFF);
41919880Skarels shiftreg >>= 8;
42019880Skarels }
42119880Skarels for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
42219880Skarels if (cm->cm_cc)
42319880Skarels printf("ex%d: configuration failed; cc = %x\n",
42419880Skarels unit, cm->cm_cc);
42519880Skarels }
42619880Skarels
42719880Skarels /*
42819880Skarels * Start or re-start output on interface.
42919880Skarels * Get another datagram to send off of the interface queue,
43019880Skarels * and map it to the interface before starting the output.
43137476Ssklower * This routine is called by exinit(), ether_output(), and excdint().
43219880Skarels * In all cases, interrupts by EXOS are disabled.
43319880Skarels */
43437476Ssklower exstart(ifp)
43537476Ssklower struct ifnet *ifp;
43619880Skarels {
43737476Ssklower int unit = ifp->if_unit;
43819880Skarels struct uba_device *ui = exinfo[unit];
43919880Skarels register struct ex_softc *xs = &ex_softc[unit];
44019880Skarels register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
44119880Skarels register struct ex_msg *bp;
44219880Skarels struct mbuf *m;
44319880Skarels int len;
44419880Skarels
44519880Skarels #ifdef DEBUG
44637476Ssklower if (xs->xs_if.if_flags & IFF_OACTIVE)
44719880Skarels panic("exstart(): xmit still pending");
44819880Skarels #endif
44919880Skarels IF_DEQUEUE(&xs->xs_if.if_snd, m);
45019880Skarels if (m == 0)
45137476Ssklower return (0);
45219880Skarels len = if_wubaput(&xs->xs_ifuba, m);
45319880Skarels if (len - sizeof(struct ether_header) < ETHERMIN)
45419880Skarels len = ETHERMIN + sizeof(struct ether_header);
45519880Skarels /*
45619880Skarels * Place a transmit request.
45719880Skarels */
45819880Skarels bp = exgetcbuf(xs);
45919880Skarels bp->mb_rqst = LLRTRANSMIT;
46019880Skarels bp->mb_et.et_nblock = 1;
46119880Skarels bp->mb_et.et_blks[0].bb_len = (u_short)len;
46219880Skarels *(u_long *)bp->mb_et.et_blks[0].bb_addr =
46319880Skarels UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
46437476Ssklower xs->xs_if.if_flags |= IFF_OACTIVE;
46519880Skarels bp->mb_status |= MH_EXOS;
46619880Skarels addr->xd_portb = EX_NTRUPT;
46737476Ssklower return (0);
46819880Skarels }
46919880Skarels
47019880Skarels /*
47119880Skarels * Command done interrupt.
47219880Skarels */
excdint(unit)47319880Skarels excdint(unit)
47419880Skarels int unit;
47519880Skarels {
47619880Skarels register struct ex_softc *xs = &ex_softc[unit];
47719880Skarels register struct ex_msg *bp = xs->xs_x2hnext;
47819880Skarels struct uba_device *ui = exinfo[unit];
47919880Skarels struct exdevice *addr = (struct exdevice *)ui->ui_addr;
48019880Skarels
48119880Skarels while ((bp->mb_status & MH_OWNER) == MH_HOST) {
48219880Skarels switch (bp->mb_rqst) {
48319880Skarels case LLRECEIVE:
48419880Skarels exrecv(unit, bp);
48519880Skarels exhangrcv(unit);
48619880Skarels break;
48719880Skarels case LLRTRANSMIT:
48819880Skarels #ifdef DEBUG
48937476Ssklower if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0)
49019880Skarels panic("exxmit: no xmit pending");
49119880Skarels #endif
49237476Ssklower xs->xs_if.if_flags &= ~IFF_OACTIVE;
49319880Skarels xs->xs_if.if_opackets++;
49419880Skarels if (bp->mb_rply == LL_OK) {
49519880Skarels ;
49619880Skarels } else if (bp->mb_rply & LLXM_1RTRY) {
49719880Skarels xs->xs_if.if_collisions++;
49819880Skarels } else if (bp->mb_rply & LLXM_RTRYS) {
49919880Skarels xs->xs_if.if_collisions += 2; /* guess */
50019880Skarels } else if (bp->mb_rply & LLXM_ERROR) {
50119880Skarels xs->xs_if.if_oerrors++;
50229849Skarels log(LOG_ERR, "ex%d: transmit error=%b\n",
50319880Skarels unit, bp->mb_rply, XMIT_BITS);
50419880Skarels }
50519880Skarels if (xs->xs_ifuba.ifu_xtofree) {
50619880Skarels m_freem(xs->xs_ifuba.ifu_xtofree);
50719880Skarels xs->xs_ifuba.ifu_xtofree = 0;
50819880Skarels }
50937476Ssklower (void) exstart(&xs->xs_if);
51019880Skarels break;
51119880Skarels case LLNET_STSTCS:
51219880Skarels xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
51319880Skarels xs->xs_flags &= ~EX_STATPENDING;
51419880Skarels break;
51525621Ssklower case LLNET_ADDRS:
51625621Ssklower case LLNET_RECV:
51725621Ssklower break;
51819880Skarels #ifdef DEBUG
51919880Skarels default:
52019880Skarels panic("ex%d: unknown reply");
52119880Skarels #endif
52219880Skarels } /* end of switch */
52319880Skarels bp->mb_length = MBDATALEN;
52419880Skarels bp->mb_status |= MH_EXOS; /* free up buffer */
52519880Skarels addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
52619880Skarels bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
52719880Skarels }
52819880Skarels }
52919880Skarels
53019880Skarels /*
53119880Skarels * Get a request buffer, fill in standard values, advance pointer.
53219880Skarels */
53319880Skarels struct ex_msg *
exgetcbuf(xs)53419880Skarels exgetcbuf(xs)
53519880Skarels struct ex_softc *xs;
53619880Skarels {
53719880Skarels register struct ex_msg *bp = xs->xs_h2xnext;
53819880Skarels
53919880Skarels #ifdef DEBUG
54019880Skarels if ((bp->mb_status & MH_OWNER) == MH_EXOS)
54119880Skarels panic("exgetcbuf(): EXOS owns message buffer");
54219880Skarels #endif
54319880Skarels bp->mb_1rsrv = 0;
54419880Skarels bp->mb_length = MBDATALEN;
54519880Skarels xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
54619880Skarels return bp;
54719880Skarels }
54819880Skarels
54919880Skarels /*
55019880Skarels * Process Ethernet receive completion:
55119880Skarels * If input error just drop packet.
55219880Skarels * Otherwise purge input buffered data path and examine
55319880Skarels * packet to determine type. If can't determine length
55419880Skarels * from type, then have to drop packet. Otherwise decapsulate
55519880Skarels * packet based on type and pass to type-specific higher-level
55619880Skarels * input routine.
55719880Skarels */
exrecv(unit,bp)55819880Skarels exrecv(unit, bp)
55919880Skarels int unit;
56019880Skarels register struct ex_msg *bp;
56119880Skarels {
56219880Skarels register struct ex_softc *xs = &ex_softc[unit];
56319880Skarels register struct ether_header *eh;
56419880Skarels struct mbuf *m;
56519880Skarels register int len, off, resid;
56619880Skarels register struct ifqueue *inq;
56729849Skarels int s;
56819880Skarels
56919880Skarels xs->xs_if.if_ipackets++;
57019880Skarels len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
57119880Skarels if (bp->mb_rply != LL_OK) {
57219880Skarels xs->xs_if.if_ierrors++;
57329849Skarels log(LOG_ERR, "ex%d: receive error=%b\n",
57419880Skarels unit, bp->mb_rply, RECV_BITS);
57519880Skarels return;
57619880Skarels }
57719880Skarels eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
57819880Skarels
57919880Skarels /*
58021777Skarels * Deal with trailer protocol: if type is trailer
58119880Skarels * get true type from first 16-bit word past data.
58219880Skarels * Remember that type was trailer by setting off.
58319880Skarels */
58419880Skarels eh->ether_type = ntohs((u_short)eh->ether_type);
58519880Skarels #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
58621777Skarels if (eh->ether_type >= ETHERTYPE_TRAIL &&
58721777Skarels eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
58821777Skarels off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
58919880Skarels if (off >= ETHERMTU)
59019880Skarels return; /* sanity */
59119880Skarels eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
59219880Skarels resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
59319880Skarels if (off + resid > len)
59419880Skarels return; /* sanity */
59519880Skarels len = off + resid;
59619880Skarels } else
59719880Skarels off = 0;
59819880Skarels if (len == 0)
59919880Skarels return;
60019880Skarels
60119880Skarels /*
60219880Skarels * Pull packet off interface. Off is nonzero if packet
60319880Skarels * has trailing header; if_rubaget will then force this header
60419880Skarels * information to be at the front, but we still have to drop
60519880Skarels * the type and length which are at the front of any trailer data.
60619880Skarels */
60724539Skarels m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if);
60819880Skarels if (m == 0)
60919880Skarels return;
61037476Ssklower ether_input(&xs->xs_if, eh, m);
61119880Skarels }
61219880Skarels
61319880Skarels /*
61419880Skarels * Send receive request to EXOS.
61519880Skarels * This routine is called by exinit and excdint,
61619880Skarels * with interrupts disabled in both cases.
61719880Skarels */
exhangrcv(unit)61819880Skarels exhangrcv(unit)
61919880Skarels int unit;
62019880Skarels {
62119880Skarels register struct ex_softc *xs = &ex_softc[unit];
62219880Skarels register struct ex_msg *bp = exgetcbuf(xs);
62319880Skarels struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
62419880Skarels
62519880Skarels bp->mb_rqst = LLRECEIVE;
62619880Skarels bp->mb_er.er_nblock = 1;
62719880Skarels bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
62819880Skarels *(u_long *)bp->mb_er.er_blks[0].bb_addr =
62919880Skarels UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
63019880Skarels bp->mb_status |= MH_EXOS;
63119880Skarels addr->xd_portb = EX_NTRUPT;
63219880Skarels }
63319880Skarels
63419880Skarels /*
63519880Skarels * Watchdog routine - place stats request to EXOS
63619880Skarels * (This could be dispensed with, if you don't care
63719880Skarels * about the if_ierrors count, or are willing to receive
63819880Skarels * bad packets in order to derive it.)
63919880Skarels */
exwatch(unit)64019880Skarels exwatch(unit)
64119880Skarels int unit;
64219880Skarels {
64319880Skarels struct uba_device *ui = exinfo[unit];
64419880Skarels struct exdevice *addr = (struct exdevice *)ui->ui_addr;
64519880Skarels register struct ex_softc *xs = &ex_softc[unit];
64619880Skarels register struct ex_msg *bp;
64719880Skarels int s = splimp();
64819880Skarels
64919880Skarels if (xs->xs_flags & EX_STATPENDING) goto exspnd;
65019880Skarels bp = exgetcbuf(xs);
65119880Skarels xs->xs_flags |= EX_STATPENDING;
65219880Skarels bp->mb_rqst = LLNET_STSTCS;
65319880Skarels bp->mb_ns.ns_mask = READ_OBJ;
65419880Skarels bp->mb_ns.ns_rsrv = 0;
65519880Skarels bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */
65619880Skarels bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */
65725728Smckusick bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit);
65819880Skarels bp->mb_status |= MH_EXOS;
65919880Skarels addr->xd_portb = EX_NTRUPT;
66019880Skarels exspnd:
66119880Skarels splx(s);
66219880Skarels xs->xs_if.if_timer = EXWATCHINTVL;
66319880Skarels }
66419880Skarels
66519880Skarels /*
66619880Skarels * Process an ioctl request.
66719880Skarels */
exioctl(ifp,cmd,data)66819880Skarels exioctl(ifp, cmd, data)
66919880Skarels register struct ifnet *ifp;
67019880Skarels int cmd;
67119880Skarels caddr_t data;
67219880Skarels {
67321777Skarels register struct ifaddr *ifa = (struct ifaddr *)data;
67425447Skarels register struct ex_softc *xs = &ex_softc[ifp->if_unit];
67519880Skarels int s = splimp(), error = 0;
67619880Skarels
67719880Skarels switch (cmd) {
67819880Skarels
67919880Skarels case SIOCSIFADDR:
68021777Skarels ifp->if_flags |= IFF_UP;
68124539Skarels exinit(ifp->if_unit);
68221777Skarels
68337476Ssklower switch (ifa->ifa_addr->sa_family) {
68424556Ssklower #ifdef INET
68521777Skarels case AF_INET:
68621777Skarels ((struct arpcom *)ifp)->ac_ipaddr =
68721777Skarels IA_SIN(ifa)->sin_addr;
68821777Skarels arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
68921777Skarels break;
69024556Ssklower #endif
69124556Ssklower #ifdef NS
69224556Ssklower case AF_NS:
69325621Ssklower {
69425621Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
69525621Ssklower
69625621Ssklower if (ns_nullhost(*ina))
69725621Ssklower ina->x_host = *(union ns_host *)(xs->xs_addr);
69825621Ssklower else
69925621Ssklower ex_setaddr(ina->x_host.c_host,ifp->if_unit);
70024556Ssklower break;
70125621Ssklower }
70224556Ssklower #endif
70321777Skarels }
70419880Skarels break;
70519880Skarels
70625447Skarels case SIOCSIFFLAGS:
70725447Skarels if ((ifp->if_flags & IFF_UP) == 0 &&
70825447Skarels xs->xs_flags & EX_RUNNING) {
70925447Skarels ((struct exdevice *)
71025447Skarels (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET;
71125447Skarels xs->xs_flags &= ~EX_RUNNING;
71225447Skarels } else if (ifp->if_flags & IFF_UP &&
71325447Skarels (xs->xs_flags & EX_RUNNING) == 0)
71425447Skarels exinit(ifp->if_unit);
71525447Skarels break;
71625447Skarels
71719880Skarels default:
71819880Skarels error = EINVAL;
71919880Skarels }
72019880Skarels splx(s);
72119880Skarels return (error);
72219880Skarels }
72325621Ssklower
72425621Ssklower /*
72525621Ssklower * set ethernet address for unit
72625621Ssklower */
ex_setaddr(physaddr,unit)72725621Ssklower ex_setaddr(physaddr, unit)
72825621Ssklower u_char *physaddr;
72925621Ssklower int unit;
73025621Ssklower {
73125621Ssklower register struct ex_softc *xs = &ex_softc[unit];
73225621Ssklower
73325621Ssklower if (physaddr) {
73425621Ssklower xs->xs_flags |= EX_SETADDR;
73525621Ssklower bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
73625621Ssklower }
73737476Ssklower ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
73837476Ssklower }
73937476Ssklower /*
74037476Ssklower * enable multicast reception on a particular address.
74137476Ssklower */
ex_setmulti(linkaddr,unit,slot)74237476Ssklower ex_setmulti(linkaddr, unit, slot)
74337476Ssklower u_char *linkaddr;
74437476Ssklower int unit;
74537476Ssklower {
74637476Ssklower register struct ex_softc *xs = &ex_softc[unit];
74737476Ssklower struct uba_device *ui = exinfo[unit];
74837476Ssklower register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
74937476Ssklower register struct ex_msg *bp;
75037476Ssklower
75125621Ssklower if (! (xs->xs_flags & EX_RUNNING))
75225621Ssklower return;
75325621Ssklower bp = exgetcbuf(xs);
75425621Ssklower bp->mb_rqst = LLNET_ADDRS;
75525621Ssklower bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
75637476Ssklower bp->mb_na.na_slot = slot;
75737476Ssklower bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
75825621Ssklower bp->mb_status |= MH_EXOS;
75925621Ssklower addr->xd_portb = EX_NTRUPT;
76025621Ssklower bp = xs->xs_x2hnext;
76125621Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
76225621Ssklower ;
76325975Skarels #ifdef DEBUG
76437476Ssklower log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
76537476Ssklower (slot == PHYSSLOT ? "reset addr" : "add multicast"
76637476Ssklower ether_sprintf(bp->mb_na.na_addrs), slot);
76725975Skarels #endif
76825621Ssklower /*
76937476Ssklower * Now, re-enable reception on slot.
77025621Ssklower */
77125621Ssklower bp = exgetcbuf(xs);
77225621Ssklower bp->mb_rqst = LLNET_RECV;
77325621Ssklower bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
77437476Ssklower bp->mb_nr.nr_slot = slot;
77525621Ssklower bp->mb_status |= MH_EXOS;
77625621Ssklower addr->xd_portb = EX_NTRUPT;
77725621Ssklower bp = xs->xs_x2hnext;
77825621Ssklower while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
77925621Ssklower ;
78025621Ssklower }
78125273Sbloom #endif
782