xref: /csrg-svn/sys/vax/if/if_ex.c (revision 37476)
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  *
835320Sbostic  * Redistribution and use in source and binary forms are permitted
935320Sbostic  * provided that the above copyright notice and this paragraph are
1035320Sbostic  * duplicated in all such forms and that any documentation,
1135320Sbostic  * advertising materials, and other materials related to such
1235320Sbostic  * distribution and use acknowledge that the software was developed
1335320Sbostic  * by the University of California, Berkeley.  The name of the
1435320Sbostic  * University may not be used to endorse or promote products derived
1535320Sbostic  * from this software without specific prior written permission.
1635320Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1735320Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1835320Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1935320Sbostic  *
20*37476Ssklower  *	@(#)if_ex.c	7.5 (Berkeley) 04/22/89
2123292Smckusick  */
2219880Skarels 
2319880Skarels #include "ex.h"
2425273Sbloom #if NEX > 0
2519880Skarels 
2619880Skarels /*
2719880Skarels  * Excelan EXOS 204 Interface
2819880Skarels  *
2919880Skarels  *	George Powers
3019880Skarels  *	Excelan Inc.
3119880Skarels  */
3219880Skarels 
3321777Skarels #include "param.h"
3421777Skarels #include "systm.h"
3521777Skarels #include "mbuf.h"
3621777Skarels #include "buf.h"
3721777Skarels #include "protosw.h"
3821777Skarels #include "socket.h"
3921777Skarels #include "vmmac.h"
4021777Skarels #include "ioctl.h"
4129849Skarels #include "syslog.h"
4221777Skarels #include "errno.h"
4319880Skarels 
4419880Skarels #include "../net/if.h"
4519880Skarels #include "../net/netisr.h"
4619880Skarels #include "../net/route.h"
4724539Skarels 
4824539Skarels #ifdef	INET
4919880Skarels #include "../netinet/in.h"
5019880Skarels #include "../netinet/in_systm.h"
5121777Skarels #include "../netinet/in_var.h"
5219880Skarels #include "../netinet/ip.h"
5319880Skarels #include "../netinet/if_ether.h"
5424539Skarels #endif
5524539Skarels 
5624556Ssklower #ifdef NS
5724556Ssklower #include "../netns/ns.h"
5824556Ssklower #include "../netns/ns_if.h"
5924556Ssklower #endif
6024556Ssklower 
61*37476Ssklower #ifdef ISO
62*37476Ssklower #include "../netiso/iso.h"
63*37476Ssklower #include "../netiso/iso_var.h"
64*37476Ssklower #include "../netiso/iso_snpac.h"
65*37476Ssklower extern struct snpa_cache all_es, all_is;
66*37476Ssklower #endif
67*37476Ssklower 
6834531Skarels #include "../vax/pte.h"
6919880Skarels #include "../vax/cpu.h"
7019880Skarels #include "../vax/mtpr.h"
7121777Skarels #include "if_exreg.h"
7221777Skarels #include "if_uba.h"
7319880Skarels #include "../vaxuba/ubareg.h"
7419880Skarels #include "../vaxuba/ubavar.h"
7519880Skarels 
7634531Skarels /* #define DEBUG			/* check for "impossible" events */
7719880Skarels 
7819880Skarels #define	NH2X 4			/* a sufficient number is critical */
7919880Skarels #define	NX2H 4			/* this is pretty arbitrary */
8019880Skarels #define	EXWATCHINTVL 10		/* call exwatch() every 10 seconds */
8119880Skarels 
8219880Skarels int	exprobe(), exattach(), excdint();
8319880Skarels struct	uba_device *exinfo[NEX];
8419880Skarels u_short exstd[] = { 0 };
8519880Skarels struct	uba_driver exdriver =
8619880Skarels 	{ exprobe, 0, exattach, 0, exstd, "ex", exinfo };
87*37476Ssklower int	exinit(),ether_output(),exioctl(),exreset(),exwatch();
8819880Skarels struct ex_msg *exgetcbuf();
8919880Skarels 
9019880Skarels /*
9119880Skarels  * Ethernet software status per interface.
9219880Skarels  *
9319880Skarels  * Each interface is referenced by a network interface structure,
9419880Skarels  * xs_if, which the routing code uses to locate the interface.
9519880Skarels  * This structure contains the output queue for the interface, its address, ...
9619880Skarels  * We also have, for each interface, a UBA interface structure, which
9719880Skarels  * contains information about the UNIBUS resources held by the interface:
9819880Skarels  * map registers, buffered data paths, etc.  Information is cached in this
9919880Skarels  * structure for use by the if_uba.c routines in running the interface
10019880Skarels  * efficiently.
10119880Skarels  */
10219880Skarels struct	ex_softc {
10321777Skarels 	struct	arpcom xs_ac;		/* Ethernet common part */
10421777Skarels #define	xs_if	xs_ac.ac_if		/* network-visible interface */
10521777Skarels #define	xs_addr	xs_ac.ac_enaddr		/* hardware Ethernet address */
10619880Skarels #ifdef DEBUG
10719880Skarels 	int	xs_wait;
10819880Skarels #endif
10919880Skarels 	struct	ifuba xs_ifuba;		/* UNIBUS resources */
11019880Skarels 	int	xs_flags;		/* private flags */
11119880Skarels #define	EX_XPENDING	1		/* xmit rqst pending on EXOS */
11219880Skarels #define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */
11325447Skarels #define	EX_RUNNING	(1<<2)		/* board is running */
11425621Ssklower #define EX_SETADDR	(1<<3)		/* physaddr has been changed */
11519880Skarels 	struct	ex_msg *xs_h2xnext;	/* host pointer to request queue */
11619880Skarels 	struct	ex_msg *xs_x2hnext;	/* host pointer to reply queue */
11726391Skarels 	int	xs_ubaddr;		/* map info for structs below */
11819880Skarels #define	UNIADDR(x)	((u_long)(x)&0x3FFFF)
11919880Skarels #define	P_UNIADDR(x)	((u_long)(x)&0x3FFF0)
12019880Skarels 	/* the following structures are always mapped in */
12119880Skarels 	u_short	xs_h2xhdr;		/* EXOS's request queue header */
12219880Skarels 	u_short	xs_x2hhdr;		/* EXOS's reply queue header */
12319880Skarels 	struct	ex_msg xs_h2xent[NH2X];	/* request msg buffers */
12419880Skarels 	struct	ex_msg xs_x2hent[NX2H];	/* reply msg buffers */
12519880Skarels 	struct	confmsg xs_cm;		/* configuration message */
12619880Skarels 	struct	stat_array xs_xsa;	/* EXOS writes stats here */
12719880Skarels 	/* end mapped area */
12826391Skarels #define	INCORE_BASE(p)	((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))
12925728Smckusick #define	RVAL_OFF(unit, n) \
13026391Skarels 	((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))
13125728Smckusick #define	LVAL_OFF(unit, n) \
13226391Skarels 	((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))
13325728Smckusick #define	H2XHDR_OFFSET(unit)	RVAL_OFF(unit, xs_h2xhdr)
13425728Smckusick #define	X2HHDR_OFFSET(unit)	RVAL_OFF(unit, xs_x2hhdr)
13525728Smckusick #define	H2XENT_OFFSET(unit)	LVAL_OFF(unit, xs_h2xent)
13625728Smckusick #define	X2HENT_OFFSET(unit)	LVAL_OFF(unit, xs_x2hent)
13725728Smckusick #define	CM_OFFSET(unit)		RVAL_OFF(unit, xs_cm)
13825728Smckusick #define	SA_OFFSET(unit)		RVAL_OFF(unit, xs_xsa)
13925728Smckusick #define	INCORE_SIZE(unit)	RVAL_OFF(unit, xs_end)
14019880Skarels 	int	xs_end;			/* place holder */
14119880Skarels } ex_softc[NEX];
14219880Skarels 
14319880Skarels /*
14419880Skarels  * The following structure is a kludge to store a cvec value
14519880Skarels  * between the time exprobe is called, and exconfig.
14619880Skarels  */
14719880Skarels struct	ex_cvecs {
14819880Skarels 	struct	exdevice *xc_csraddr;
14919880Skarels 	int	xc_cvec;
15019880Skarels }ex_cvecs[NEX];
15119880Skarels 
15219880Skarels int	ex_ncall = 0;			/* counts calls to exprobe */
15319880Skarels 
15419880Skarels exprobe(reg)
15519880Skarels 	caddr_t reg;
15619880Skarels {
15719880Skarels 	register int br, cvec;		/* r11, r10 value-result */
15819880Skarels 	register struct exdevice *addr = (struct exdevice *)reg;
15919880Skarels 	register i;
16019880Skarels 
16119880Skarels 	/*
16219880Skarels 	 * We program the EXOS interrupt vector, like dmf device.
16319880Skarels 	 */
16419880Skarels 	br = 0x15;
16519880Skarels 	cvec = (uba_hd[numuba].uh_lastiv -= 4);
16619880Skarels 	ex_cvecs[ex_ncall].xc_csraddr = addr;
16726013Skarels 	ex_cvecs[ex_ncall].xc_cvec = cvec;
16819880Skarels 	/*
16919880Skarels 	 * Reset EXOS and run self-test (guaranteed to
17019880Skarels 	 * complete within 2 seconds).
17119880Skarels 	 */
17219880Skarels 	addr->xd_porta = EX_RESET;
17326013Skarels 	i = 2000;
17419880Skarels 	while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
17526013Skarels 		DELAY(1000);
17619880Skarels 	if ((addr->xd_portb & EX_TESTOK) == 0) {
17719880Skarels 		printf("ex: self-test failed\n");
17819880Skarels 		return 0;
17919880Skarels 	}
18024539Skarels #ifdef lint
18124539Skarels 	br = br;
18226391Skarels 	excdint(0);
18324539Skarels #endif
18426013Skarels 	ex_ncall++;
18519880Skarels 	return (sizeof(struct exdevice));
18619880Skarels }
18719880Skarels 
18819880Skarels /*
18919880Skarels  * Interface exists: make available by filling in network interface
19019880Skarels  * record.  System will initialize the interface when it is ready
19119880Skarels  * to accept packets.  Board is temporarily configured and issues
19219880Skarels  * a NET_ADDRS command, only to get the Ethernet address.
19319880Skarels  */
19419880Skarels exattach(ui)
195*37476Ssklower 	register struct uba_device *ui;
19619880Skarels {
19719880Skarels 	register struct ex_softc *xs = &ex_softc[ui->ui_unit];
19819880Skarels 	register struct ifnet *ifp = &xs->xs_if;
19919880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
20019880Skarels 	register struct ex_msg *bp;
20125728Smckusick 	int unit = ui->ui_unit;
20219880Skarels 	ifp->if_unit = ui->ui_unit;
20319880Skarels 	ifp->if_name = "ex";
20419880Skarels 	ifp->if_mtu = ETHERMTU;
20519880Skarels 
20619880Skarels 	/*
20719880Skarels 	 * Temporarily map queues in order to configure EXOS
20819880Skarels 	 */
20925728Smckusick 	xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
21025728Smckusick 		INCORE_SIZE(unit), 0);
21119880Skarels 	exconfig(ui, 0);			/* without interrupts */
21219880Skarels 	if (xs->xs_cm.cm_cc) goto badconf;
21319880Skarels 
21419880Skarels 	bp = exgetcbuf(xs);
21519880Skarels 	bp->mb_rqst = LLNET_ADDRS;
21619880Skarels 	bp->mb_na.na_mask = READ_OBJ;
21719880Skarels 	bp->mb_na.na_slot = PHYSSLOT;
21819880Skarels 	bp->mb_status |= MH_EXOS;
21919880Skarels 	addr->xd_portb = EX_NTRUPT;
22019880Skarels 	bp = xs->xs_x2hnext;
22119880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
22219880Skarels 		;
22325975Skarels 	printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n",
22426013Skarels 		ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
22526013Skarels 		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
22626013Skarels 		ether_sprintf(bp->mb_na.na_addrs));
22719880Skarels 	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
22819880Skarels 	    sizeof (xs->xs_addr));
22919880Skarels 
23019880Skarels 	ifp->if_init = exinit;
231*37476Ssklower 	ifp->if_output = ether_output;
23219880Skarels 	ifp->if_ioctl = exioctl;
23319880Skarels 	ifp->if_reset = exreset;
23421777Skarels 	ifp->if_flags = IFF_BROADCAST;
23519880Skarels 	xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
23619880Skarels 	if_attach(ifp);
23719880Skarels badconf:
23819880Skarels 	ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
23919880Skarels }
24019880Skarels 
24119880Skarels /*
24219880Skarels  * Reset of interface after UNIBUS reset.
24319880Skarels  * If interface is on specified uba, reset its state.
24419880Skarels  */
24519880Skarels exreset(unit, uban)
24619880Skarels 	int unit, uban;
24719880Skarels {
24819880Skarels 	register struct uba_device *ui;
24919880Skarels 
25019880Skarels 	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
25119880Skarels 	    ui->ui_ubanum != uban)
25219880Skarels 		return;
25319880Skarels 	printf(" ex%d", unit);
25421777Skarels 	ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
25525447Skarels 	ex_softc[unit].xs_flags &= ~EX_RUNNING;
25619880Skarels 	exinit(unit);
25719880Skarels }
25819880Skarels 
25919880Skarels /*
26019880Skarels  * Initialization of interface; clear recorded pending
26119880Skarels  * operations, and reinitialize UNIBUS usage.
26219880Skarels  * Called at boot time (with interrupts disabled?),
26319880Skarels  * and at ifconfig time via exioctl, with interrupts disabled.
26419880Skarels  */
26519880Skarels exinit(unit)
26619880Skarels 	int unit;
26719880Skarels {
26819880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
26919880Skarels 	register struct uba_device *ui = exinfo[unit];
27019880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
27119880Skarels 	register struct ifnet *ifp = &xs->xs_if;
27219880Skarels 	register struct ex_msg *bp;
27319880Skarels 	int s;
27419880Skarels 
27521777Skarels 	/* not yet, if address still unknown */
27621777Skarels 	if (ifp->if_addrlist == (struct ifaddr *)0)
27719880Skarels 		return;
27825447Skarels 	if (xs->xs_flags & EX_RUNNING)
27925447Skarels 		return;
28019880Skarels 
28125447Skarels 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
28225447Skarels 		if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
28325447Skarels 		    sizeof (struct ether_header),
28425447Skarels 		    (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
28525447Skarels 			printf("ex%d: can't initialize\n", unit);
28625447Skarels 			xs->xs_if.if_flags &= ~IFF_UP;
28725447Skarels 			return;
28825447Skarels 		}
28925447Skarels 		xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
29025728Smckusick 			INCORE_SIZE(unit), 0);
29119880Skarels 	}
29219880Skarels 	exconfig(ui, 4);		/* with vectored interrupts*/
29319880Skarels 	/*
29419880Skarels 	 * Put EXOS on the Ethernet, using NET_MODE command
29519880Skarels 	 */
29619880Skarels 	bp = exgetcbuf(xs);
29719880Skarels 	bp->mb_rqst = LLNET_MODE;
29819880Skarels 	bp->mb_nm.nm_mask = WRITE_OBJ;
29919880Skarels 	bp->mb_nm.nm_optn = 0;
30019880Skarels 	bp->mb_nm.nm_mode = MODE_PERF;
30119880Skarels 	bp->mb_status |= MH_EXOS;
30219880Skarels 	addr->xd_portb = EX_NTRUPT;
30319880Skarels 	bp = xs->xs_x2hnext;
30419880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
30519880Skarels 		;
30619880Skarels 	bp->mb_length = MBDATALEN;
30719880Skarels 	bp->mb_status |= MH_EXOS;		/* free up buffer */
30819880Skarels 	addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
30919880Skarels 	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
31019880Skarels 
31119880Skarels 	ifp->if_watchdog = exwatch;
31219880Skarels 	ifp->if_timer = EXWATCHINTVL;
31319880Skarels 	s = splimp();	/* are interrupts always disabled here, anyway? */
31419880Skarels 	exhangrcv(unit);			/* hang receive request */
31521777Skarels 	xs->xs_if.if_flags |= IFF_RUNNING;
31625447Skarels 	xs->xs_flags |= EX_RUNNING;
31725621Ssklower 	if (xs->xs_flags & EX_SETADDR)
31826391Skarels 		ex_setaddr((u_char *)0, unit);
319*37476Ssklower #ifdef ISO
320*37476Ssklower 	ex_setmulti(all_es.sc_snpa, unit, 1);
321*37476Ssklower 	ex_setmulti(all_is.sc_snpa, unit, 2);
322*37476Ssklower #endif
323*37476Ssklower 	(void) exstart(&xs->xs_if);			/* start transmits */
32419880Skarels 	splx(s);
32519880Skarels }
32619880Skarels 
32719880Skarels /*
32819880Skarels  * Reset, test, and configure EXOS.  This routine assumes
32919880Skarels  * that message queues, etc. have already been mapped into
33019880Skarels  * the UBA.  It is called by exinit, and should also be
33119880Skarels  * callable by exattach.
33219880Skarels  */
33319880Skarels exconfig(ui, itype)
33419880Skarels 	struct	uba_device *ui;
33519880Skarels 	int itype;
33619880Skarels {
33719880Skarels 	register int unit = ui->ui_unit;
33819880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
33919880Skarels 	register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
34019880Skarels 	register struct confmsg *cm = &xs->xs_cm;
34119880Skarels 	register struct ex_msg *bp;
34219880Skarels 	int i;
34319880Skarels 	u_long shiftreg;
34419880Skarels 
34519880Skarels 	xs->xs_flags = 0;
34619880Skarels 	/*
34719880Skarels 	 * Reset EXOS, wait for self-test to complete
34819880Skarels 	 */
34919880Skarels 	addr->xd_porta = EX_RESET;
35019880Skarels 	while ((addr->xd_portb & EX_TESTOK) == 0)
35119880Skarels 		;
35219880Skarels 	/*
35319880Skarels 	 * Set up configuration message.
35419880Skarels 	 */
35519880Skarels 	cm->cm_1rsrv = 1;
35619880Skarels 	cm->cm_cc = 0xFF;
35719880Skarels 	cm->cm_opmode = 0;		/* link-level controller mode */
35819880Skarels 	cm->cm_dfo = 0x0101;		/* enable host data order conversion */
35919880Skarels 	cm->cm_dcn1 = 1;
360*37476Ssklower 	cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
36119880Skarels 	cm->cm_ham = 3;			/* absolute address mode */
36219880Skarels 	cm->cm_3rsrv = 0;
36319880Skarels 	cm->cm_mapsiz = 0;
36419880Skarels 	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */
36519880Skarels 	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */
36619880Skarels 	cm->cm_byteptrn[2] = 0x07;
36719880Skarels 	cm->cm_byteptrn[3] = 0x0F;
36819880Skarels 	cm->cm_wordptrn[0] = 0x0103;
36919880Skarels 	cm->cm_wordptrn[1] = 0x070F;
37019880Skarels 	cm->cm_lwordptrn = 0x0103070F;
37119880Skarels 	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
37219880Skarels 	cm->cm_mba = 0xFFFFFFFF;
37319880Skarels 	cm->cm_nproc = 0xFF;
37419880Skarels 	cm->cm_nmbox = 0xFF;
37519880Skarels 	cm->cm_nmcast = 0xFF;
37619880Skarels 	cm->cm_nhost = 1;
37719880Skarels 	cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
37825728Smckusick 	cm->cm_h2xhdr = H2XHDR_OFFSET(unit);
37919880Skarels 	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */
38019880Skarels 	cm->cm_x2hba = cm->cm_h2xba;
38125728Smckusick 	cm->cm_x2hhdr = X2HHDR_OFFSET(unit);
38219880Skarels 	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */
38319880Skarels 	for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
38419880Skarels #ifdef DEBUG
38519880Skarels 	if (i >= NEX)
38619880Skarels 		panic("ex: matching csr address not found");
38719880Skarels #endif
38819880Skarels 		;
38919880Skarels 	cm->cm_x2haddr = ex_cvecs[i].xc_cvec;	/* stashed here by exprobe */
39019880Skarels 	/*
39119880Skarels 	 * Set up message queues and headers.
39219880Skarels 	 * First the request queue.
39319880Skarels 	 */
39419880Skarels 	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
39519880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
39619880Skarels 		bp->mb_rsrv = 0;
39719880Skarels 		bp->mb_length = MBDATALEN;
39819880Skarels 		bp->mb_status = MH_HOST;
39919880Skarels 		bp->mb_next = bp+1;
40019880Skarels 	}
40119880Skarels 	xs->xs_h2xhdr =
402*37476Ssklower 		xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit);
403*37476Ssklower 	xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
40419880Skarels 
40519880Skarels 	/* Now the reply queue. */
40619880Skarels 	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
40719880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
40819880Skarels 		bp->mb_rsrv = 0;
40919880Skarels 		bp->mb_length = MBDATALEN;
41019880Skarels 		bp->mb_status = MH_EXOS;
41119880Skarels 		bp->mb_next = bp+1;
41219880Skarels 	}
41319880Skarels 	xs->xs_x2hhdr =
414*37476Ssklower 		xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit);
415*37476Ssklower 	xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
41619880Skarels 
41719880Skarels 	/*
41819880Skarels 	 * Write config msg address to EXOS and wait for
41919880Skarels 	 * configuration to complete (guaranteed response
42019880Skarels 	 * within 2 seconds).
42119880Skarels 	 */
42219880Skarels 	shiftreg = (u_long)0x0000FFFF;
42319880Skarels 	for (i = 0; i < 8; i++) {
42419880Skarels 		if (i == 4)
42525728Smckusick 			shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit);
42619880Skarels 		while (addr->xd_portb & EX_UNREADY)
42719880Skarels 			;
42819880Skarels 		addr->xd_portb = (u_char)(shiftreg & 0xFF);
42919880Skarels 		shiftreg >>= 8;
43019880Skarels 	}
43119880Skarels 	for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
43219880Skarels 	if (cm->cm_cc)
43319880Skarels 		printf("ex%d: configuration failed; cc = %x\n",
43419880Skarels 			unit, cm->cm_cc);
43519880Skarels }
43619880Skarels 
43719880Skarels /*
43819880Skarels  * Start or re-start output on interface.
43919880Skarels  * Get another datagram to send off of the interface queue,
44019880Skarels  * and map it to the interface before starting the output.
441*37476Ssklower  * This routine is called by exinit(), ether_output(), and excdint().
44219880Skarels  * In all cases, interrupts by EXOS are disabled.
44319880Skarels  */
444*37476Ssklower exstart(ifp)
445*37476Ssklower struct ifnet *ifp;
44619880Skarels {
447*37476Ssklower 	int unit = ifp->if_unit;
44819880Skarels 	struct uba_device *ui = exinfo[unit];
44919880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
45019880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
45119880Skarels 	register struct ex_msg *bp;
45219880Skarels 	struct mbuf *m;
45319880Skarels         int len;
45419880Skarels 
45519880Skarels #ifdef DEBUG
456*37476Ssklower 	if (xs->xs_if.if_flags & IFF_OACTIVE)
45719880Skarels 		panic("exstart(): xmit still pending");
45819880Skarels #endif
45919880Skarels 	IF_DEQUEUE(&xs->xs_if.if_snd, m);
46019880Skarels 	if (m == 0)
461*37476Ssklower 		return (0);
46219880Skarels 	len = if_wubaput(&xs->xs_ifuba, m);
46319880Skarels 	if (len - sizeof(struct ether_header) < ETHERMIN)
46419880Skarels 		len = ETHERMIN + sizeof(struct ether_header);
46519880Skarels 	/*
46619880Skarels 	 * Place a transmit request.
46719880Skarels 	 */
46819880Skarels 	bp = exgetcbuf(xs);
46919880Skarels 	bp->mb_rqst = LLRTRANSMIT;
47019880Skarels 	bp->mb_et.et_nblock = 1;
47119880Skarels 	bp->mb_et.et_blks[0].bb_len = (u_short)len;
47219880Skarels 	*(u_long *)bp->mb_et.et_blks[0].bb_addr =
47319880Skarels 		UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
474*37476Ssklower 	xs->xs_if.if_flags |= IFF_OACTIVE;
47519880Skarels 	bp->mb_status |= MH_EXOS;
47619880Skarels 	addr->xd_portb = EX_NTRUPT;
477*37476Ssklower 	return (0);
47819880Skarels }
47919880Skarels 
48019880Skarels /*
48119880Skarels  * Command done interrupt.
48219880Skarels  */
48319880Skarels excdint(unit)
48419880Skarels 	int unit;
48519880Skarels {
48619880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
48719880Skarels 	register struct ex_msg *bp = xs->xs_x2hnext;
48819880Skarels 	struct uba_device *ui = exinfo[unit];
48919880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
49019880Skarels 
49119880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_HOST) {
49219880Skarels 		switch (bp->mb_rqst) {
49319880Skarels 		case LLRECEIVE:
49419880Skarels 			exrecv(unit, bp);
49519880Skarels 			exhangrcv(unit);
49619880Skarels 			break;
49719880Skarels 		case LLRTRANSMIT:
49819880Skarels #ifdef DEBUG
499*37476Ssklower 			if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0)
50019880Skarels 				panic("exxmit: no xmit pending");
50119880Skarels #endif
502*37476Ssklower 			xs->xs_if.if_flags &= ~IFF_OACTIVE;
50319880Skarels 			xs->xs_if.if_opackets++;
50419880Skarels 			if (bp->mb_rply == LL_OK) {
50519880Skarels 				;
50619880Skarels 			} else if (bp->mb_rply & LLXM_1RTRY) {
50719880Skarels 				xs->xs_if.if_collisions++;
50819880Skarels 			} else if (bp->mb_rply & LLXM_RTRYS) {
50919880Skarels 				xs->xs_if.if_collisions += 2;	/* guess */
51019880Skarels 			} else if (bp->mb_rply & LLXM_ERROR) {
51119880Skarels 				xs->xs_if.if_oerrors++;
51229849Skarels 				log(LOG_ERR, "ex%d: transmit error=%b\n",
51319880Skarels 					unit, bp->mb_rply, XMIT_BITS);
51419880Skarels 			}
51519880Skarels 			if (xs->xs_ifuba.ifu_xtofree) {
51619880Skarels 				m_freem(xs->xs_ifuba.ifu_xtofree);
51719880Skarels 				xs->xs_ifuba.ifu_xtofree = 0;
51819880Skarels 			}
519*37476Ssklower 			(void) exstart(&xs->xs_if);
52019880Skarels 			break;
52119880Skarels 		case LLNET_STSTCS:
52219880Skarels 			xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
52319880Skarels 			xs->xs_flags &= ~EX_STATPENDING;
52419880Skarels 			break;
52525621Ssklower 		case LLNET_ADDRS:
52625621Ssklower 		case LLNET_RECV:
52725621Ssklower 			break;
52819880Skarels #ifdef	DEBUG
52919880Skarels 		default:
53019880Skarels 			panic("ex%d: unknown reply");
53119880Skarels #endif
53219880Skarels 		} /* end of switch */
53319880Skarels 		bp->mb_length = MBDATALEN;
53419880Skarels 		bp->mb_status |= MH_EXOS;		/* free up buffer */
53519880Skarels 		addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
53619880Skarels 		bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
53719880Skarels 	}
53819880Skarels }
53919880Skarels 
54019880Skarels /*
54119880Skarels  * Get a request buffer, fill in standard values, advance pointer.
54219880Skarels  */
54319880Skarels struct ex_msg *
54419880Skarels exgetcbuf(xs)
54519880Skarels 	struct ex_softc *xs;
54619880Skarels {
54719880Skarels 	register struct ex_msg *bp = xs->xs_h2xnext;
54819880Skarels 
54919880Skarels #ifdef DEBUG
55019880Skarels 	if ((bp->mb_status & MH_OWNER) == MH_EXOS)
55119880Skarels 		panic("exgetcbuf(): EXOS owns message buffer");
55219880Skarels #endif
55319880Skarels 	bp->mb_1rsrv = 0;
55419880Skarels 	bp->mb_length = MBDATALEN;
55519880Skarels 	xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
55619880Skarels 	return bp;
55719880Skarels }
55819880Skarels 
55919880Skarels /*
56019880Skarels  * Process Ethernet receive completion:
56119880Skarels  *	If input error just drop packet.
56219880Skarels  *	Otherwise purge input buffered data path and examine
56319880Skarels  *	packet to determine type.  If can't determine length
56419880Skarels  *	from type, then have to drop packet.  Otherwise decapsulate
56519880Skarels  *	packet based on type and pass to type-specific higher-level
56619880Skarels  *	input routine.
56719880Skarels  */
56819880Skarels exrecv(unit, bp)
56919880Skarels 	int unit;
57019880Skarels 	register struct ex_msg *bp;
57119880Skarels {
57219880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
57319880Skarels 	register struct ether_header *eh;
57419880Skarels     	struct mbuf *m;
57519880Skarels 	register int len, off, resid;
57619880Skarels 	register struct ifqueue *inq;
57729849Skarels 	int s;
57819880Skarels 
57919880Skarels 	xs->xs_if.if_ipackets++;
58019880Skarels 	len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
58119880Skarels 	if (bp->mb_rply != LL_OK) {
58219880Skarels 		xs->xs_if.if_ierrors++;
58329849Skarels 		log(LOG_ERR, "ex%d: receive error=%b\n",
58419880Skarels 			unit, bp->mb_rply, RECV_BITS);
58519880Skarels 		return;
58619880Skarels 	}
58719880Skarels 	eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
58819880Skarels 
58919880Skarels 	/*
59021777Skarels 	 * Deal with trailer protocol: if type is trailer
59119880Skarels 	 * get true type from first 16-bit word past data.
59219880Skarels 	 * Remember that type was trailer by setting off.
59319880Skarels 	 */
59419880Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
59519880Skarels #define	exdataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
59621777Skarels 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
59721777Skarels 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
59821777Skarels 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
59919880Skarels 		if (off >= ETHERMTU)
60019880Skarels 			return;		/* sanity */
60119880Skarels 		eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
60219880Skarels 		resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
60319880Skarels 		if (off + resid > len)
60419880Skarels 			return;		/* sanity */
60519880Skarels 		len = off + resid;
60619880Skarels 	} else
60719880Skarels 		off = 0;
60819880Skarels 	if (len == 0)
60919880Skarels 		return;
61019880Skarels 
61119880Skarels 	/*
61219880Skarels 	 * Pull packet off interface.  Off is nonzero if packet
61319880Skarels 	 * has trailing header; if_rubaget will then force this header
61419880Skarels 	 * information to be at the front, but we still have to drop
61519880Skarels 	 * the type and length which are at the front of any trailer data.
61619880Skarels 	 */
61724539Skarels 	m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if);
61819880Skarels 	if (m == 0)
61919880Skarels 		return;
620*37476Ssklower 	ether_input(&xs->xs_if, eh, m);
62119880Skarels }
62219880Skarels 
62319880Skarels /*
62419880Skarels  * Send receive request to EXOS.
62519880Skarels  * This routine is called by exinit and excdint,
62619880Skarels  * with interrupts disabled in both cases.
62719880Skarels  */
62819880Skarels exhangrcv(unit)
62919880Skarels 	int unit;
63019880Skarels {
63119880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
63219880Skarels 	register struct ex_msg *bp = exgetcbuf(xs);
63319880Skarels 	struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
63419880Skarels 
63519880Skarels 	bp->mb_rqst = LLRECEIVE;
63619880Skarels 	bp->mb_er.er_nblock = 1;
63719880Skarels 	bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
63819880Skarels 	*(u_long *)bp->mb_er.er_blks[0].bb_addr =
63919880Skarels 		UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
64019880Skarels 	bp->mb_status |= MH_EXOS;
64119880Skarels 	addr->xd_portb = EX_NTRUPT;
64219880Skarels }
64319880Skarels 
64419880Skarels /*
64519880Skarels  * Watchdog routine - place stats request to EXOS
64619880Skarels  * (This could be dispensed with, if you don't care
64719880Skarels  *  about the if_ierrors count, or are willing to receive
64819880Skarels  *  bad packets in order to derive it.)
64919880Skarels  */
65019880Skarels exwatch(unit)
65119880Skarels 	int unit;
65219880Skarels {
65319880Skarels 	struct uba_device *ui = exinfo[unit];
65419880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
65519880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
65619880Skarels 	register struct ex_msg *bp;
65719880Skarels 	int s = splimp();
65819880Skarels 
65919880Skarels 	if (xs->xs_flags & EX_STATPENDING) goto exspnd;
66019880Skarels 	bp = exgetcbuf(xs);
66119880Skarels 	xs->xs_flags |= EX_STATPENDING;
66219880Skarels 	bp->mb_rqst = LLNET_STSTCS;
66319880Skarels 	bp->mb_ns.ns_mask = READ_OBJ;
66419880Skarels 	bp->mb_ns.ns_rsrv = 0;
66519880Skarels 	bp->mb_ns.ns_nobj = 8;		/* read all 8 stats objects */
66619880Skarels 	bp->mb_ns.ns_xobj = 0;		/* starting with the 1st one */
66725728Smckusick 	bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit);
66819880Skarels 	bp->mb_status |= MH_EXOS;
66919880Skarels 	addr->xd_portb = EX_NTRUPT;
67019880Skarels exspnd:
67119880Skarels 	splx(s);
67219880Skarels 	xs->xs_if.if_timer = EXWATCHINTVL;
67319880Skarels }
67419880Skarels 
67519880Skarels /*
67619880Skarels  * Process an ioctl request.
67719880Skarels  */
67819880Skarels exioctl(ifp, cmd, data)
67919880Skarels 	register struct ifnet *ifp;
68019880Skarels 	int cmd;
68119880Skarels 	caddr_t data;
68219880Skarels {
68321777Skarels 	register struct ifaddr *ifa = (struct ifaddr *)data;
68425447Skarels 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
68519880Skarels 	int s = splimp(), error = 0;
68619880Skarels 
68719880Skarels 	switch (cmd) {
68819880Skarels 
68919880Skarels 	case SIOCSIFADDR:
69021777Skarels                 ifp->if_flags |= IFF_UP;
69124539Skarels                 exinit(ifp->if_unit);
69221777Skarels 
693*37476Ssklower                 switch (ifa->ifa_addr->sa_family) {
69424556Ssklower #ifdef INET
69521777Skarels 		case AF_INET:
69621777Skarels 			((struct arpcom *)ifp)->ac_ipaddr =
69721777Skarels 				IA_SIN(ifa)->sin_addr;
69821777Skarels 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
69921777Skarels 			break;
70024556Ssklower #endif
70124556Ssklower #ifdef NS
70224556Ssklower 		case AF_NS:
70325621Ssklower 		    {
70425621Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
70525621Ssklower 
70625621Ssklower 			if (ns_nullhost(*ina))
70725621Ssklower 				ina->x_host = *(union ns_host *)(xs->xs_addr);
70825621Ssklower 			else
70925621Ssklower 				ex_setaddr(ina->x_host.c_host,ifp->if_unit);
71024556Ssklower 			break;
71125621Ssklower 		    }
71224556Ssklower #endif
71321777Skarels 		}
71419880Skarels 		break;
71519880Skarels 
71625447Skarels 	case SIOCSIFFLAGS:
71725447Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
71825447Skarels 		    xs->xs_flags & EX_RUNNING) {
71925447Skarels 			((struct exdevice *)
72025447Skarels 			  (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET;
72125447Skarels 			xs->xs_flags &= ~EX_RUNNING;
72225447Skarels 		} else if (ifp->if_flags & IFF_UP &&
72325447Skarels 		    (xs->xs_flags & EX_RUNNING) == 0)
72425447Skarels 			exinit(ifp->if_unit);
72525447Skarels 		break;
72625447Skarels 
72719880Skarels 	default:
72819880Skarels 		error = EINVAL;
72919880Skarels 	}
73019880Skarels 	splx(s);
73119880Skarels 	return (error);
73219880Skarels }
73325621Ssklower 
73425621Ssklower /*
73525621Ssklower  * set ethernet address for unit
73625621Ssklower  */
73725621Ssklower ex_setaddr(physaddr, unit)
73825621Ssklower 	u_char *physaddr;
73925621Ssklower 	int unit;
74025621Ssklower {
74125621Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
74225621Ssklower 
74325621Ssklower 	if (physaddr) {
74425621Ssklower 		xs->xs_flags |= EX_SETADDR;
74525621Ssklower 		bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
74625621Ssklower 	}
747*37476Ssklower 	ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
748*37476Ssklower }
749*37476Ssklower /*
750*37476Ssklower  * enable multicast reception on a particular address.
751*37476Ssklower  */
752*37476Ssklower ex_setmulti(linkaddr, unit, slot)
753*37476Ssklower 	u_char *linkaddr;
754*37476Ssklower 	int unit;
755*37476Ssklower {
756*37476Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
757*37476Ssklower 	struct uba_device *ui = exinfo[unit];
758*37476Ssklower 	register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
759*37476Ssklower 	register struct ex_msg *bp;
760*37476Ssklower 
76125621Ssklower 	if (! (xs->xs_flags & EX_RUNNING))
76225621Ssklower 		return;
76325621Ssklower 	bp = exgetcbuf(xs);
76425621Ssklower 	bp->mb_rqst = LLNET_ADDRS;
76525621Ssklower 	bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
766*37476Ssklower 	bp->mb_na.na_slot = slot;
767*37476Ssklower 	bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
76825621Ssklower 	bp->mb_status |= MH_EXOS;
76925621Ssklower 	addr->xd_portb = EX_NTRUPT;
77025621Ssklower 	bp = xs->xs_x2hnext;
77125621Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
77225621Ssklower 		;
77325975Skarels #ifdef	DEBUG
774*37476Ssklower 	log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
775*37476Ssklower 		(slot == PHYSSLOT ? "reset addr" : "add multicast"
776*37476Ssklower 		ether_sprintf(bp->mb_na.na_addrs), slot);
77725975Skarels #endif
77825621Ssklower 	/*
779*37476Ssklower 	 * Now, re-enable reception on slot.
78025621Ssklower 	 */
78125621Ssklower 	bp = exgetcbuf(xs);
78225621Ssklower 	bp->mb_rqst = LLNET_RECV;
78325621Ssklower 	bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
784*37476Ssklower 	bp->mb_nr.nr_slot = slot;
78525621Ssklower 	bp->mb_status |= MH_EXOS;
78625621Ssklower 	addr->xd_portb = EX_NTRUPT;
78725621Ssklower 	bp = xs->xs_x2hnext;
78825621Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
78925621Ssklower 		;
79025621Ssklower }
79125273Sbloom #endif
792