xref: /csrg-svn/sys/vax/if/if_ex.c (revision 25621)
123292Smckusick /*
223292Smckusick  * Copyright (c) 1982 Regents of the University of California.
323292Smckusick  * All rights reserved.  The Berkeley software License Agreement
423292Smckusick  * specifies the terms and conditions for redistribution.
523292Smckusick  *
6*25621Ssklower  *	@(#)if_ex.c	6.8 (Berkeley) 12/18/85
723292Smckusick  */
819880Skarels 
923292Smckusick 
1019880Skarels #include "ex.h"
1125273Sbloom #if NEX > 0
1219880Skarels 
1319880Skarels /*
1419880Skarels  * Excelan EXOS 204 Interface
1519880Skarels  *
1619880Skarels  *	George Powers
1719880Skarels  *	Excelan Inc.
1819880Skarels  */
1919880Skarels 
2019880Skarels #include "../machine/pte.h"
2119880Skarels 
2221777Skarels #include "param.h"
2321777Skarels #include "systm.h"
2421777Skarels #include "mbuf.h"
2521777Skarels #include "buf.h"
2621777Skarels #include "protosw.h"
2721777Skarels #include "socket.h"
2821777Skarels #include "vmmac.h"
2921777Skarels #include "ioctl.h"
3021777Skarels #include "errno.h"
3119880Skarels 
3219880Skarels #include "../net/if.h"
3319880Skarels #include "../net/netisr.h"
3419880Skarels #include "../net/route.h"
3524539Skarels 
3624539Skarels #ifdef	BBNNET
3724539Skarels #define	INET
3824539Skarels #endif
3924539Skarels #ifdef	INET
4019880Skarels #include "../netinet/in.h"
4119880Skarels #include "../netinet/in_systm.h"
4221777Skarels #include "../netinet/in_var.h"
4319880Skarels #include "../netinet/ip.h"
4419880Skarels #include "../netinet/if_ether.h"
4524539Skarels #endif
4624539Skarels 
4724556Ssklower #ifdef NS
4824556Ssklower #include "../netns/ns.h"
4924556Ssklower #include "../netns/ns_if.h"
5024556Ssklower #endif
5124556Ssklower 
5219880Skarels #include "../vax/cpu.h"
5319880Skarels #include "../vax/mtpr.h"
5421777Skarels #include "if_exreg.h"
5521777Skarels #include "if_uba.h"
5619880Skarels #include "../vaxuba/ubareg.h"
5719880Skarels #include "../vaxuba/ubavar.h"
5819880Skarels 
5919880Skarels #define DEBUG			/* check for "impossible" events */
6019880Skarels 
6119880Skarels #define	NH2X 4			/* a sufficient number is critical */
6219880Skarels #define	NX2H 4			/* this is pretty arbitrary */
6319880Skarels #define	EXWATCHINTVL 10		/* call exwatch() every 10 seconds */
6419880Skarels 
6519880Skarels int	exprobe(), exattach(), excdint();
6619880Skarels struct	uba_device *exinfo[NEX];
6719880Skarels u_short exstd[] = { 0 };
6819880Skarels struct	uba_driver exdriver =
6919880Skarels 	{ exprobe, 0, exattach, 0, exstd, "ex", exinfo };
7019880Skarels int	exinit(),exoutput(),exioctl(),exreset(),exwatch();
7119880Skarels struct ex_msg *exgetcbuf();
7219880Skarels 
7319880Skarels /*
7419880Skarels  * Ethernet software status per interface.
7519880Skarels  *
7619880Skarels  * Each interface is referenced by a network interface structure,
7719880Skarels  * xs_if, which the routing code uses to locate the interface.
7819880Skarels  * This structure contains the output queue for the interface, its address, ...
7919880Skarels  * We also have, for each interface, a UBA interface structure, which
8019880Skarels  * contains information about the UNIBUS resources held by the interface:
8119880Skarels  * map registers, buffered data paths, etc.  Information is cached in this
8219880Skarels  * structure for use by the if_uba.c routines in running the interface
8319880Skarels  * efficiently.
8419880Skarels  */
8519880Skarels struct	ex_softc {
8621777Skarels 	struct	arpcom xs_ac;		/* Ethernet common part */
8721777Skarels #define	xs_if	xs_ac.ac_if		/* network-visible interface */
8821777Skarels #define	xs_addr	xs_ac.ac_enaddr		/* hardware Ethernet address */
8919880Skarels #ifdef DEBUG
9019880Skarels 	int	xs_wait;
9119880Skarels #endif
9219880Skarels 	struct	ifuba xs_ifuba;		/* UNIBUS resources */
9319880Skarels 	int	xs_flags;		/* private flags */
9419880Skarels #define	EX_XPENDING	1		/* xmit rqst pending on EXOS */
9519880Skarels #define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */
9625447Skarels #define	EX_RUNNING	(1<<2)		/* board is running */
97*25621Ssklower #define EX_SETADDR	(1<<3)		/* physaddr has been changed */
9819880Skarels 	struct	ex_msg *xs_h2xnext;	/* host pointer to request queue */
9919880Skarels 	struct	ex_msg *xs_x2hnext;	/* host pointer to reply queue */
10019880Skarels 	u_long	xs_ubaddr;		/* map info for structs below */
10119880Skarels #define	UNIADDR(x)	((u_long)(x)&0x3FFFF)
10219880Skarels #define	P_UNIADDR(x)	((u_long)(x)&0x3FFF0)
10319880Skarels 	/* the following structures are always mapped in */
10419880Skarels 	u_short	xs_h2xhdr;		/* EXOS's request queue header */
10519880Skarels 	u_short	xs_x2hhdr;		/* EXOS's reply queue header */
10619880Skarels 	struct	ex_msg xs_h2xent[NH2X];	/* request msg buffers */
10719880Skarels 	struct	ex_msg xs_x2hent[NX2H];	/* reply msg buffers */
10819880Skarels 	struct	confmsg xs_cm;		/* configuration message */
10919880Skarels 	struct	stat_array xs_xsa;	/* EXOS writes stats here */
11019880Skarels 	/* end mapped area */
11119880Skarels #define	INCORE_BASE(p)	(((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0)
11219880Skarels #define	RVAL_OFF(n)	((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0]))
11319880Skarels #define	LVAL_OFF(n)	((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0]))
11419880Skarels #define	H2XHDR_OFFSET	RVAL_OFF(xs_h2xhdr)
11519880Skarels #define	X2HHDR_OFFSET	RVAL_OFF(xs_x2hhdr)
11619880Skarels #define	H2XENT_OFFSET	LVAL_OFF(xs_h2xent)
11719880Skarels #define	X2HENT_OFFSET	LVAL_OFF(xs_x2hent)
11819880Skarels #define	CM_OFFSET	RVAL_OFF(xs_cm)
11919880Skarels #define	SA_OFFSET	RVAL_OFF(xs_xsa)
12019880Skarels #define	INCORE_SIZE	RVAL_OFF(xs_end)
12119880Skarels 	int	xs_end;			/* place holder */
12219880Skarels } ex_softc[NEX];
12319880Skarels 
12419880Skarels /*
12519880Skarels  * The following structure is a kludge to store a cvec value
12619880Skarels  * between the time exprobe is called, and exconfig.
12719880Skarels  */
12819880Skarels struct	ex_cvecs {
12919880Skarels 	struct	exdevice *xc_csraddr;
13019880Skarels 	int	xc_cvec;
13119880Skarels }ex_cvecs[NEX];
13219880Skarels 
13319880Skarels int	ex_ncall = 0;			/* counts calls to exprobe */
13419880Skarels 
13519880Skarels exprobe(reg)
13619880Skarels 	caddr_t reg;
13719880Skarels {
13819880Skarels 	register int br, cvec;		/* r11, r10 value-result */
13919880Skarels 	register struct exdevice *addr = (struct exdevice *)reg;
14019880Skarels 	register i;
14119880Skarels 
14219880Skarels 	/*
14319880Skarels 	 * We program the EXOS interrupt vector, like dmf device.
14419880Skarels 	 */
14519880Skarels 	br = 0x15;
14619880Skarels 	cvec = (uba_hd[numuba].uh_lastiv -= 4);
14719880Skarels #ifdef DEBUG
14819880Skarels printf("exprobe%d: cvec = %o\n", ex_ncall, cvec);
14919880Skarels #endif
15019880Skarels 	ex_cvecs[ex_ncall].xc_csraddr = addr;
15119880Skarels 	ex_cvecs[ex_ncall++].xc_cvec = cvec;
15219880Skarels 	/*
15319880Skarels 	 * Reset EXOS and run self-test (guaranteed to
15419880Skarels 	 * complete within 2 seconds).
15519880Skarels 	 */
15619880Skarels 	addr->xd_porta = EX_RESET;
15719880Skarels 	i = 1000000;
15819880Skarels 	while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
15919880Skarels 		;
16019880Skarels 	if ((addr->xd_portb & EX_TESTOK) == 0) {
16119880Skarels 		printf("ex: self-test failed\n");
16219880Skarels 		return 0;
16319880Skarels 	}
16424539Skarels #ifdef lint
16524539Skarels 	br = br;
16624539Skarels #endif
16719880Skarels 	return (sizeof(struct exdevice));
16819880Skarels }
16919880Skarels 
17019880Skarels /*
17119880Skarels  * Interface exists: make available by filling in network interface
17219880Skarels  * record.  System will initialize the interface when it is ready
17319880Skarels  * to accept packets.  Board is temporarily configured and issues
17419880Skarels  * a NET_ADDRS command, only to get the Ethernet address.
17519880Skarels  */
17619880Skarels exattach(ui)
17719880Skarels 	struct uba_device *ui;
17819880Skarels {
17919880Skarels 	register struct ex_softc *xs = &ex_softc[ui->ui_unit];
18019880Skarels 	register struct ifnet *ifp = &xs->xs_if;
18119880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
18219880Skarels 	register struct ex_msg *bp;
18319880Skarels 
18419880Skarels 	ifp->if_unit = ui->ui_unit;
18519880Skarels 	ifp->if_name = "ex";
18619880Skarels 	ifp->if_mtu = ETHERMTU;
18719880Skarels 
18819880Skarels 	/*
18919880Skarels 	 * Temporarily map queues in order to configure EXOS
19019880Skarels 	 */
19119880Skarels 	xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE, 0);
19219880Skarels 	exconfig(ui, 0);			/* without interrupts */
19319880Skarels 	if (xs->xs_cm.cm_cc) goto badconf;
19419880Skarels 
19519880Skarels 	bp = exgetcbuf(xs);
19619880Skarels 	bp->mb_rqst = LLNET_ADDRS;
19719880Skarels 	bp->mb_na.na_mask = READ_OBJ;
19819880Skarels 	bp->mb_na.na_slot = PHYSSLOT;
19919880Skarels 	bp->mb_status |= MH_EXOS;
20019880Skarels 	addr->xd_portb = EX_NTRUPT;
20119880Skarels 	bp = xs->xs_x2hnext;
20219880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
20319880Skarels 		;
20419880Skarels 	printf("ex%d: HW %c.%c, NX %c.%c, addr %x.%x.%x.%x.%x.%x\n",
20519880Skarels 		ui->ui_unit,
20619880Skarels 		xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
20719880Skarels 		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
20819880Skarels 		bp->mb_na.na_addrs[0], bp->mb_na.na_addrs[1],
20919880Skarels 		bp->mb_na.na_addrs[2], bp->mb_na.na_addrs[3],
21019880Skarels 		bp->mb_na.na_addrs[4], bp->mb_na.na_addrs[5]);
21119880Skarels 	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
21219880Skarels 	    sizeof (xs->xs_addr));
21319880Skarels 
21419880Skarels 	ifp->if_init = exinit;
21519880Skarels 	ifp->if_output = exoutput;
21619880Skarels 	ifp->if_ioctl = exioctl;
21719880Skarels 	ifp->if_reset = exreset;
21821777Skarels 	ifp->if_flags = IFF_BROADCAST;
21919880Skarels 	xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
22019880Skarels 	if_attach(ifp);
22119880Skarels badconf:
22219880Skarels 	ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
22319880Skarels }
22419880Skarels 
22519880Skarels /*
22619880Skarels  * Reset of interface after UNIBUS reset.
22719880Skarels  * If interface is on specified uba, reset its state.
22819880Skarels  */
22919880Skarels exreset(unit, uban)
23019880Skarels 	int unit, uban;
23119880Skarels {
23219880Skarels 	register struct uba_device *ui;
23319880Skarels 
23419880Skarels 	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
23519880Skarels 	    ui->ui_ubanum != uban)
23619880Skarels 		return;
23719880Skarels 	printf(" ex%d", unit);
23821777Skarels 	ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
23925447Skarels 	ex_softc[unit].xs_flags &= ~EX_RUNNING;
24019880Skarels 	exinit(unit);
24119880Skarels }
24219880Skarels 
24319880Skarels /*
24419880Skarels  * Initialization of interface; clear recorded pending
24519880Skarels  * operations, and reinitialize UNIBUS usage.
24619880Skarels  * Called at boot time (with interrupts disabled?),
24719880Skarels  * and at ifconfig time via exioctl, with interrupts disabled.
24819880Skarels  */
24919880Skarels exinit(unit)
25019880Skarels 	int unit;
25119880Skarels {
25219880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
25319880Skarels 	register struct uba_device *ui = exinfo[unit];
25419880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
25519880Skarels 	register struct ifnet *ifp = &xs->xs_if;
25619880Skarels 	register struct ex_msg *bp;
25719880Skarels 	int s;
25819880Skarels 
25921777Skarels 	/* not yet, if address still unknown */
26021777Skarels 	if (ifp->if_addrlist == (struct ifaddr *)0)
26119880Skarels 		return;
26225447Skarels 	if (xs->xs_flags & EX_RUNNING)
26325447Skarels 		return;
26419880Skarels 
26525447Skarels 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
26625447Skarels 		if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
26725447Skarels 		    sizeof (struct ether_header),
26825447Skarels 		    (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
26925447Skarels 			printf("ex%d: can't initialize\n", unit);
27025447Skarels 			xs->xs_if.if_flags &= ~IFF_UP;
27125447Skarels 			return;
27225447Skarels 		}
27325447Skarels 		xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
27425447Skarels 			INCORE_SIZE, 0);
27519880Skarels 	}
27619880Skarels 	exconfig(ui, 4);		/* with vectored interrupts*/
27719880Skarels 	/*
27819880Skarels 	 * Put EXOS on the Ethernet, using NET_MODE command
27919880Skarels 	 */
28019880Skarels 	bp = exgetcbuf(xs);
28119880Skarels 	bp->mb_rqst = LLNET_MODE;
28219880Skarels 	bp->mb_nm.nm_mask = WRITE_OBJ;
28319880Skarels 	bp->mb_nm.nm_optn = 0;
28419880Skarels 	bp->mb_nm.nm_mode = MODE_PERF;
28519880Skarels 	bp->mb_status |= MH_EXOS;
28619880Skarels 	addr->xd_portb = EX_NTRUPT;
28719880Skarels 	bp = xs->xs_x2hnext;
28819880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
28919880Skarels 		;
29019880Skarels 	bp->mb_length = MBDATALEN;
29119880Skarels 	bp->mb_status |= MH_EXOS;		/* free up buffer */
29219880Skarels 	addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
29319880Skarels 	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
29419880Skarels 
29519880Skarels 	ifp->if_watchdog = exwatch;
29619880Skarels 	ifp->if_timer = EXWATCHINTVL;
29719880Skarels 	s = splimp();	/* are interrupts always disabled here, anyway? */
29819880Skarels 	exhangrcv(unit);			/* hang receive request */
29921777Skarels 	xs->xs_if.if_flags |= IFF_RUNNING;
30025447Skarels 	xs->xs_flags |= EX_RUNNING;
301*25621Ssklower 	if (xs->xs_flags & EX_SETADDR)
302*25621Ssklower 		ex_setaddr(0, unit);
303*25621Ssklower 	exstart(unit);				/* start transmits */
30419880Skarels 	splx(s);
30519880Skarels }
30619880Skarels 
30719880Skarels /*
30819880Skarels  * Reset, test, and configure EXOS.  This routine assumes
30919880Skarels  * that message queues, etc. have already been mapped into
31019880Skarels  * the UBA.  It is called by exinit, and should also be
31119880Skarels  * callable by exattach.
31219880Skarels  */
31319880Skarels exconfig(ui, itype)
31419880Skarels 	struct	uba_device *ui;
31519880Skarels 	int itype;
31619880Skarels {
31719880Skarels 	register int unit = ui->ui_unit;
31819880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
31919880Skarels 	register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
32019880Skarels 	register struct confmsg *cm = &xs->xs_cm;
32119880Skarels 	register struct ex_msg *bp;
32219880Skarels 	int i;
32319880Skarels 	u_long shiftreg;
32419880Skarels 
32519880Skarels 	xs->xs_flags = 0;
32619880Skarels 	/*
32719880Skarels 	 * Reset EXOS, wait for self-test to complete
32819880Skarels 	 */
32919880Skarels 	addr->xd_porta = EX_RESET;
33019880Skarels 	while ((addr->xd_portb & EX_TESTOK) == 0)
33119880Skarels 		;
33219880Skarels 	/*
33319880Skarels 	 * Set up configuration message.
33419880Skarels 	 */
33519880Skarels 	cm->cm_1rsrv = 1;
33619880Skarels 	cm->cm_cc = 0xFF;
33719880Skarels 	cm->cm_opmode = 0;		/* link-level controller mode */
33819880Skarels 	cm->cm_dfo = 0x0101;		/* enable host data order conversion */
33919880Skarels 	cm->cm_dcn1 = 1;
34019880Skarels 	cm->cm_2rsrv[0] =
34119880Skarels 		cm->cm_2rsrv[1] = 0;
34219880Skarels 	cm->cm_ham = 3;			/* absolute address mode */
34319880Skarels 	cm->cm_3rsrv = 0;
34419880Skarels 	cm->cm_mapsiz = 0;
34519880Skarels 	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */
34619880Skarels 	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */
34719880Skarels 	cm->cm_byteptrn[2] = 0x07;
34819880Skarels 	cm->cm_byteptrn[3] = 0x0F;
34919880Skarels 	cm->cm_wordptrn[0] = 0x0103;
35019880Skarels 	cm->cm_wordptrn[1] = 0x070F;
35119880Skarels 	cm->cm_lwordptrn = 0x0103070F;
35219880Skarels 	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
35319880Skarels 	cm->cm_mba = 0xFFFFFFFF;
35419880Skarels 	cm->cm_nproc = 0xFF;
35519880Skarels 	cm->cm_nmbox = 0xFF;
35619880Skarels 	cm->cm_nmcast = 0xFF;
35719880Skarels 	cm->cm_nhost = 1;
35819880Skarels 	cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
35919880Skarels 	cm->cm_h2xhdr = H2XHDR_OFFSET;
36019880Skarels 	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */
36119880Skarels 	cm->cm_x2hba = cm->cm_h2xba;
36219880Skarels 	cm->cm_x2hhdr = X2HHDR_OFFSET;
36319880Skarels 	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */
36419880Skarels 	for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
36519880Skarels #ifdef DEBUG
36619880Skarels 	if (i >= NEX)
36719880Skarels 		panic("ex: matching csr address not found");
36819880Skarels #endif
36919880Skarels 		;
37019880Skarels 	cm->cm_x2haddr = ex_cvecs[i].xc_cvec;	/* stashed here by exprobe */
37119880Skarels 	/*
37219880Skarels 	 * Set up message queues and headers.
37319880Skarels 	 * First the request queue.
37419880Skarels 	 */
37519880Skarels 	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
37619880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
37719880Skarels 		bp->mb_rsrv = 0;
37819880Skarels 		bp->mb_length = MBDATALEN;
37919880Skarels 		bp->mb_status = MH_HOST;
38019880Skarels 		bp->mb_next = bp+1;
38119880Skarels 	}
38219880Skarels 	xs->xs_h2xhdr =
38319880Skarels 		xs->xs_h2xent[NH2X-1].mb_link =
38419880Skarels 		(u_short)H2XENT_OFFSET;
38519880Skarels 	xs->xs_h2xnext =
38619880Skarels 		xs->xs_h2xent[NH2X-1].mb_next =
38719880Skarels 		xs->xs_h2xent;
38819880Skarels 
38919880Skarels 	/* Now the reply queue. */
39019880Skarels 	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
39119880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
39219880Skarels 		bp->mb_rsrv = 0;
39319880Skarels 		bp->mb_length = MBDATALEN;
39419880Skarels 		bp->mb_status = MH_EXOS;
39519880Skarels 		bp->mb_next = bp+1;
39619880Skarels 	}
39719880Skarels 	xs->xs_x2hhdr =
39819880Skarels 		xs->xs_x2hent[NX2H-1].mb_link =
39919880Skarels 		(u_short)X2HENT_OFFSET;
40019880Skarels 	xs->xs_x2hnext =
40119880Skarels 		xs->xs_x2hent[NX2H-1].mb_next =
40219880Skarels 		xs->xs_x2hent;
40319880Skarels 
40419880Skarels 	/*
40519880Skarels 	 * Write config msg address to EXOS and wait for
40619880Skarels 	 * configuration to complete (guaranteed response
40719880Skarels 	 * within 2 seconds).
40819880Skarels 	 */
40919880Skarels 	shiftreg = (u_long)0x0000FFFF;
41019880Skarels 	for (i = 0; i < 8; i++) {
41119880Skarels 		if (i == 4)
41219880Skarels 			shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET;
41319880Skarels 		while (addr->xd_portb & EX_UNREADY)
41419880Skarels 			;
41519880Skarels 		addr->xd_portb = (u_char)(shiftreg & 0xFF);
41619880Skarels 		shiftreg >>= 8;
41719880Skarels 	}
41819880Skarels 	for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
41919880Skarels 	if (cm->cm_cc)
42019880Skarels 		printf("ex%d: configuration failed; cc = %x\n",
42119880Skarels 			unit, cm->cm_cc);
42219880Skarels }
42319880Skarels 
42419880Skarels /*
42519880Skarels  * Start or re-start output on interface.
42619880Skarels  * Get another datagram to send off of the interface queue,
42719880Skarels  * and map it to the interface before starting the output.
42819880Skarels  * This routine is called by exinit(), exoutput(), and excdint().
42919880Skarels  * In all cases, interrupts by EXOS are disabled.
43019880Skarels  */
43119880Skarels exstart(unit)
43219880Skarels 	int unit;
43319880Skarels {
43419880Skarels 	struct uba_device *ui = exinfo[unit];
43519880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
43619880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
43719880Skarels 	register struct ex_msg *bp;
43819880Skarels 	struct mbuf *m;
43919880Skarels         int len;
44019880Skarels 
44119880Skarels #ifdef DEBUG
44219880Skarels 	if (xs->xs_flags & EX_XPENDING)
44319880Skarels 		panic("exstart(): xmit still pending");
44419880Skarels #endif
44519880Skarels 	IF_DEQUEUE(&xs->xs_if.if_snd, m);
44619880Skarels 	if (m == 0)
44719880Skarels 		return;
44819880Skarels 	len = if_wubaput(&xs->xs_ifuba, m);
44919880Skarels 	if (len - sizeof(struct ether_header) < ETHERMIN)
45019880Skarels 		len = ETHERMIN + sizeof(struct ether_header);
45119880Skarels 	/*
45219880Skarels 	 * Place a transmit request.
45319880Skarels 	 */
45419880Skarels 	bp = exgetcbuf(xs);
45519880Skarels 	bp->mb_rqst = LLRTRANSMIT;
45619880Skarels 	bp->mb_et.et_nblock = 1;
45719880Skarels 	bp->mb_et.et_blks[0].bb_len = (u_short)len;
45819880Skarels 	*(u_long *)bp->mb_et.et_blks[0].bb_addr =
45919880Skarels 		UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
46019880Skarels 	xs->xs_flags |= EX_XPENDING;
46119880Skarels 	bp->mb_status |= MH_EXOS;
46219880Skarels 	addr->xd_portb = EX_NTRUPT;
46319880Skarels }
46419880Skarels 
46519880Skarels /*
46619880Skarels  * Command done interrupt.
46719880Skarels  */
46819880Skarels excdint(unit)
46919880Skarels 	int unit;
47019880Skarels {
47119880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
47219880Skarels 	register struct ex_msg *bp = xs->xs_x2hnext;
47319880Skarels 	struct uba_device *ui = exinfo[unit];
47419880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
47519880Skarels 
47619880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_HOST) {
47719880Skarels 		switch (bp->mb_rqst) {
47819880Skarels 		case LLRECEIVE:
47919880Skarels 			exrecv(unit, bp);
48019880Skarels 			exhangrcv(unit);
48119880Skarels 			break;
48219880Skarels 		case LLRTRANSMIT:
48319880Skarels #ifdef DEBUG
48419880Skarels 			if ((xs->xs_flags & EX_XPENDING) == 0)
48519880Skarels 				panic("exxmit: no xmit pending");
48619880Skarels #endif
48719880Skarels 			xs->xs_flags &= ~EX_XPENDING;
48819880Skarels 			xs->xs_if.if_opackets++;
48919880Skarels 			if (bp->mb_rply == LL_OK) {
49019880Skarels 				;
49119880Skarels 			} else if (bp->mb_rply & LLXM_1RTRY) {
49219880Skarels 				xs->xs_if.if_collisions++;
49319880Skarels 			} else if (bp->mb_rply & LLXM_RTRYS) {
49419880Skarels 				xs->xs_if.if_collisions += 2;	/* guess */
49519880Skarels 			} else if (bp->mb_rply & LLXM_ERROR) {
49619880Skarels 				xs->xs_if.if_oerrors++;
49719880Skarels 				printf("ex%d: transmit error=%b\n",
49819880Skarels 					unit, bp->mb_rply, XMIT_BITS);
49919880Skarels 			}
50019880Skarels 			if (xs->xs_ifuba.ifu_xtofree) {
50119880Skarels 				m_freem(xs->xs_ifuba.ifu_xtofree);
50219880Skarels 				xs->xs_ifuba.ifu_xtofree = 0;
50319880Skarels 			}
50419880Skarels 			exstart(unit);
50519880Skarels 			break;
50619880Skarels 		case LLNET_STSTCS:
50719880Skarels 			xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
50819880Skarels 			xs->xs_flags &= ~EX_STATPENDING;
50919880Skarels 			break;
510*25621Ssklower 		case LLNET_ADDRS:
511*25621Ssklower 		case LLNET_RECV:
512*25621Ssklower 			break;
51319880Skarels #ifdef	DEBUG
51419880Skarels 		default:
51519880Skarels 			panic("ex%d: unknown reply");
51619880Skarels #endif
51719880Skarels 		} /* end of switch */
51819880Skarels 		bp->mb_length = MBDATALEN;
51919880Skarels 		bp->mb_status |= MH_EXOS;		/* free up buffer */
52019880Skarels 		addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
52119880Skarels 		bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
52219880Skarels 	}
52319880Skarels }
52419880Skarels 
52519880Skarels /*
52619880Skarels  * Get a request buffer, fill in standard values, advance pointer.
52719880Skarels  */
52819880Skarels struct ex_msg *
52919880Skarels exgetcbuf(xs)
53019880Skarels 	struct ex_softc *xs;
53119880Skarels {
53219880Skarels 	register struct ex_msg *bp = xs->xs_h2xnext;
53319880Skarels 
53419880Skarels #ifdef DEBUG
53519880Skarels 	if ((bp->mb_status & MH_OWNER) == MH_EXOS)
53619880Skarels 		panic("exgetcbuf(): EXOS owns message buffer");
53719880Skarels #endif
53819880Skarels 	bp->mb_1rsrv = 0;
53919880Skarels 	bp->mb_length = MBDATALEN;
54019880Skarels 	xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
54119880Skarels 	return bp;
54219880Skarels }
54319880Skarels 
54419880Skarels /*
54519880Skarels  * Process Ethernet receive completion:
54619880Skarels  *	If input error just drop packet.
54719880Skarels  *	Otherwise purge input buffered data path and examine
54819880Skarels  *	packet to determine type.  If can't determine length
54919880Skarels  *	from type, then have to drop packet.  Otherwise decapsulate
55019880Skarels  *	packet based on type and pass to type-specific higher-level
55119880Skarels  *	input routine.
55219880Skarels  */
55319880Skarels exrecv(unit, bp)
55419880Skarels 	int unit;
55519880Skarels 	register struct ex_msg *bp;
55619880Skarels {
55719880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
55819880Skarels 	register struct ether_header *eh;
55919880Skarels     	struct mbuf *m;
56019880Skarels 	register int len, off, resid;
56119880Skarels 	register struct ifqueue *inq;
56219880Skarels 
56319880Skarels 	xs->xs_if.if_ipackets++;
56419880Skarels 	len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
56519880Skarels 	if (bp->mb_rply != LL_OK) {
56619880Skarels 		xs->xs_if.if_ierrors++;
56719880Skarels 		printf("ex%d: receive error=%b\n",
56819880Skarels 			unit, bp->mb_rply, RECV_BITS);
56919880Skarels 		return;
57019880Skarels 	}
57119880Skarels 	eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
57219880Skarels 
57319880Skarels 	/*
57421777Skarels 	 * Deal with trailer protocol: if type is trailer
57519880Skarels 	 * get true type from first 16-bit word past data.
57619880Skarels 	 * Remember that type was trailer by setting off.
57719880Skarels 	 */
57819880Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
57919880Skarels #define	exdataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
58021777Skarels 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
58121777Skarels 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
58221777Skarels 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
58319880Skarels 		if (off >= ETHERMTU)
58419880Skarels 			return;		/* sanity */
58519880Skarels 		eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
58619880Skarels 		resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
58719880Skarels 		if (off + resid > len)
58819880Skarels 			return;		/* sanity */
58919880Skarels 		len = off + resid;
59019880Skarels 	} else
59119880Skarels 		off = 0;
59219880Skarels 	if (len == 0)
59319880Skarels 		return;
59419880Skarels 
59519880Skarels 	/*
59619880Skarels 	 * Pull packet off interface.  Off is nonzero if packet
59719880Skarels 	 * has trailing header; if_rubaget will then force this header
59819880Skarels 	 * information to be at the front, but we still have to drop
59919880Skarels 	 * the type and length which are at the front of any trailer data.
60019880Skarels 	 */
60124539Skarels 	m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if);
60219880Skarels 	if (m == 0)
60319880Skarels 		return;
60419880Skarels 	if (off) {
60524539Skarels 		struct ifnet *ifp;
60624539Skarels 
60724539Skarels 		ifp = *(mtod(m, struct ifnet **));
60819880Skarels 		m->m_off += 2 * sizeof (u_short);
60919880Skarels 		m->m_len -= 2 * sizeof (u_short);
61024539Skarels 		*(mtod(m, struct ifnet **)) = ifp;
61119880Skarels 	}
61219880Skarels 	switch (eh->ether_type) {
61319880Skarels 
61419880Skarels #ifdef INET
61521777Skarels 	case ETHERTYPE_IP:
61619880Skarels 		schednetisr(NETISR_IP);	/* is this necessary */
61719880Skarels 		inq = &ipintrq;
61819880Skarels 		break;
61919880Skarels 
62021777Skarels 	case ETHERTYPE_ARP:
62119880Skarels 		arpinput(&xs->xs_ac, m);
62219880Skarels 		return;
62319880Skarels #endif
62424556Ssklower #ifdef NS
62524556Ssklower 	case ETHERTYPE_NS:
62624556Ssklower 		schednetisr(NETISR_NS);
62724556Ssklower 		inq = &nsintrq;
62824556Ssklower 		break;
62924556Ssklower 
63024556Ssklower #endif
63119880Skarels 	default:
63219880Skarels 		m_freem(m);
63319880Skarels 		return;
63419880Skarels 	}
63519880Skarels 
63619880Skarels 	if (IF_QFULL(inq)) {
63719880Skarels 		IF_DROP(inq);
63819880Skarels 		m_freem(m);
63919880Skarels 		return;
64019880Skarels 	}
64119880Skarels 	IF_ENQUEUE(inq, m);
64219880Skarels }
64319880Skarels 
64419880Skarels /*
64519880Skarels  * Send receive request to EXOS.
64619880Skarels  * This routine is called by exinit and excdint,
64719880Skarels  * with interrupts disabled in both cases.
64819880Skarels  */
64919880Skarels exhangrcv(unit)
65019880Skarels 	int unit;
65119880Skarels {
65219880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
65319880Skarels 	register struct ex_msg *bp = exgetcbuf(xs);
65419880Skarels 	struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
65519880Skarels 
65619880Skarels 	bp->mb_rqst = LLRECEIVE;
65719880Skarels 	bp->mb_er.er_nblock = 1;
65819880Skarels 	bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
65919880Skarels 	*(u_long *)bp->mb_er.er_blks[0].bb_addr =
66019880Skarels 		UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
66119880Skarels 	bp->mb_status |= MH_EXOS;
66219880Skarels 	addr->xd_portb = EX_NTRUPT;
66319880Skarels }
66419880Skarels 
66519880Skarels /*
66619880Skarels  * Ethernet output routine.
66719880Skarels  * Encapsulate a packet of type family for the local net.
66819880Skarels  * Use trailer local net encapsulation if enough data in first
66919880Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
67019880Skarels  */
67119880Skarels exoutput(ifp, m0, dst)
67219880Skarels 	register struct ifnet *ifp;
67319880Skarels 	register struct mbuf *m0;
67419880Skarels 	struct sockaddr *dst;
67519880Skarels {
67619880Skarels 	int type, s, error;
67719880Skarels 	u_char edst[6];
67819880Skarels 	struct in_addr idst;
67919880Skarels 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
68019880Skarels 	register struct mbuf *m = m0;
68119880Skarels 	register struct ether_header *eh;
68219880Skarels 	register int off;
68319880Skarels 
68425447Skarels 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
68525447Skarels 		error = ENETDOWN;
68625447Skarels 		goto bad;
68725447Skarels 	}
68819880Skarels 	switch (dst->sa_family) {
68919880Skarels 
69019880Skarels #ifdef INET
69119880Skarels 	case AF_INET:
69219880Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
69319880Skarels 		if (!arpresolve(&xs->xs_ac, m, &idst, edst))
69419880Skarels 			return (0);	/* if not yet resolved */
69519880Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
69619880Skarels 		/* need per host negotiation */
69719880Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
69819880Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
69919880Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
70021777Skarels 			type = ETHERTYPE_TRAIL + (off>>9);
70119880Skarels 			m->m_off -= 2 * sizeof (u_short);
70219880Skarels 			m->m_len += 2 * sizeof (u_short);
70321777Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
70419880Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
70519880Skarels 			goto gottrailertype;
70619880Skarels 		}
70721777Skarels 		type = ETHERTYPE_IP;
70819880Skarels 		off = 0;
70919880Skarels 		goto gottype;
71019880Skarels #endif
71124556Ssklower #ifdef NS
71224556Ssklower 	case AF_NS:
71324556Ssklower 		type = ETHERTYPE_NS;
71424556Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
71524556Ssklower 		(caddr_t)edst, sizeof (edst));
71624556Ssklower 		off = 0;
71724556Ssklower 		goto gottype;
71824556Ssklower #endif
71919880Skarels 
72019880Skarels 	case AF_UNSPEC:
72119880Skarels 		eh = (struct ether_header *)dst->sa_data;
72219880Skarels 		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
72319880Skarels 		type = eh->ether_type;
72419880Skarels 		goto gottype;
72519880Skarels 
72619880Skarels 	default:
72719880Skarels 		printf("ex%d: can't handle af%d\n", ifp->if_unit,
72819880Skarels 			dst->sa_family);
72919880Skarels 		error = EAFNOSUPPORT;
73019880Skarels 		goto bad;
73119880Skarels 	}
73219880Skarels 
73319880Skarels gottrailertype:
73419880Skarels 	/*
73519880Skarels 	 * Packet to be sent as trailer: move first packet
73619880Skarels 	 * (control information) to end of chain.
73719880Skarels 	 */
73819880Skarels 	while (m->m_next)
73919880Skarels 		m = m->m_next;
74019880Skarels 	m->m_next = m0;
74119880Skarels 	m = m0->m_next;
74219880Skarels 	m0->m_next = 0;
74319880Skarels 	m0 = m;
74419880Skarels 
74519880Skarels gottype:
74619880Skarels 	/*
74719880Skarels 	 * Add local net header.  If no space in first mbuf,
74819880Skarels 	 * allocate another.
74919880Skarels 	 */
75019880Skarels 	if (m->m_off > MMAXOFF ||
75119880Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
75219880Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
75319880Skarels 		if (m == 0) {
75419880Skarels 			error = ENOBUFS;
75519880Skarels 			goto bad;
75619880Skarels 		}
75719880Skarels 		m->m_next = m0;
75819880Skarels 		m->m_off = MMINOFF;
75919880Skarels 		m->m_len = sizeof (struct ether_header);
76019880Skarels 	} else {
76119880Skarels 		m->m_off -= sizeof (struct ether_header);
76219880Skarels 		m->m_len += sizeof (struct ether_header);
76319880Skarels 	}
76419880Skarels 	eh = mtod(m, struct ether_header *);
76519880Skarels 	eh->ether_type = htons((u_short)type);
76619880Skarels 	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
76719880Skarels 	bcopy((caddr_t)xs->xs_addr, (caddr_t)eh->ether_shost, 6);
76819880Skarels 
76919880Skarels 	/*
77019880Skarels 	 * Queue message on interface, and start output if interface
77119880Skarels 	 * not yet active.
77219880Skarels 	 */
77319880Skarels 	s = splimp();
77419880Skarels 	if (IF_QFULL(&ifp->if_snd)) {
77519880Skarels 		IF_DROP(&ifp->if_snd);
77619880Skarels 		splx(s);
77719880Skarels 		m_freem(m);
77819880Skarels 		return (ENOBUFS);
77919880Skarels 	}
78019880Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
78119880Skarels 	/*
78219880Skarels 	 * If transmit request not already pending, then
78319880Skarels 	 * kick the back end.
78419880Skarels 	 */
78519880Skarels 	if ((xs->xs_flags & EX_XPENDING) == 0) {
78619880Skarels 		exstart(ifp->if_unit);
78719880Skarels 	}
78819880Skarels #ifdef DEBUG
78919880Skarels 	else {
79019880Skarels 		xs->xs_wait++;
79119880Skarels 	}
79219880Skarels #endif
79319880Skarels 	splx(s);
79419880Skarels 	return (0);
79519880Skarels 
79619880Skarels bad:
79719880Skarels 	m_freem(m0);
79819880Skarels 	return (error);
79919880Skarels }
80019880Skarels 
80119880Skarels /*
80219880Skarels  * Watchdog routine - place stats request to EXOS
80319880Skarels  * (This could be dispensed with, if you don't care
80419880Skarels  *  about the if_ierrors count, or are willing to receive
80519880Skarels  *  bad packets in order to derive it.)
80619880Skarels  */
80719880Skarels exwatch(unit)
80819880Skarels 	int unit;
80919880Skarels {
81019880Skarels 	struct uba_device *ui = exinfo[unit];
81119880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
81219880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
81319880Skarels 	register struct ex_msg *bp;
81419880Skarels 	int s = splimp();
81519880Skarels 
81619880Skarels 	if (xs->xs_flags & EX_STATPENDING) goto exspnd;
81719880Skarels 	bp = exgetcbuf(xs);
81819880Skarels 	xs->xs_flags |= EX_STATPENDING;
81919880Skarels 	bp->mb_rqst = LLNET_STSTCS;
82019880Skarels 	bp->mb_ns.ns_mask = READ_OBJ;
82119880Skarels 	bp->mb_ns.ns_rsrv = 0;
82219880Skarels 	bp->mb_ns.ns_nobj = 8;		/* read all 8 stats objects */
82319880Skarels 	bp->mb_ns.ns_xobj = 0;		/* starting with the 1st one */
82419880Skarels 	bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET;
82519880Skarels 	bp->mb_status |= MH_EXOS;
82619880Skarels 	addr->xd_portb = EX_NTRUPT;
82719880Skarels exspnd:
82819880Skarels 	splx(s);
82919880Skarels 	xs->xs_if.if_timer = EXWATCHINTVL;
83019880Skarels }
83119880Skarels 
83219880Skarels /*
83319880Skarels  * Process an ioctl request.
83419880Skarels  */
83519880Skarels exioctl(ifp, cmd, data)
83619880Skarels 	register struct ifnet *ifp;
83719880Skarels 	int cmd;
83819880Skarels 	caddr_t data;
83919880Skarels {
84021777Skarels 	register struct ifaddr *ifa = (struct ifaddr *)data;
84125447Skarels 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
84219880Skarels 	int s = splimp(), error = 0;
84319880Skarels 
84419880Skarels 	switch (cmd) {
84519880Skarels 
84619880Skarels 	case SIOCSIFADDR:
84721777Skarels                 ifp->if_flags |= IFF_UP;
84824539Skarels                 exinit(ifp->if_unit);
84921777Skarels 
85021777Skarels                 switch (ifa->ifa_addr.sa_family) {
85124556Ssklower #ifdef INET
85221777Skarels 		case AF_INET:
85321777Skarels 			((struct arpcom *)ifp)->ac_ipaddr =
85421777Skarels 				IA_SIN(ifa)->sin_addr;
85521777Skarels 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
85621777Skarels 			break;
85724556Ssklower #endif
85824556Ssklower #ifdef NS
85924556Ssklower 		case AF_NS:
860*25621Ssklower 		    {
861*25621Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
862*25621Ssklower 
863*25621Ssklower 			if (ns_nullhost(*ina))
864*25621Ssklower 				ina->x_host = *(union ns_host *)(xs->xs_addr);
865*25621Ssklower 			else
866*25621Ssklower 				ex_setaddr(ina->x_host.c_host,ifp->if_unit);
86724556Ssklower 			break;
868*25621Ssklower 		    }
86924556Ssklower #endif
87021777Skarels 		}
87119880Skarels 		break;
87219880Skarels 
87325447Skarels 	case SIOCSIFFLAGS:
87425447Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
87525447Skarels 		    xs->xs_flags & EX_RUNNING) {
87625447Skarels 			((struct exdevice *)
87725447Skarels 			  (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET;
87825447Skarels 			xs->xs_flags &= ~EX_RUNNING;
87925447Skarels 		} else if (ifp->if_flags & IFF_UP &&
88025447Skarels 		    (xs->xs_flags & EX_RUNNING) == 0)
88125447Skarels 			exinit(ifp->if_unit);
88225447Skarels 		break;
88325447Skarels 
88419880Skarels 	default:
88519880Skarels 		error = EINVAL;
88619880Skarels 	}
88719880Skarels 	splx(s);
88819880Skarels 	return (error);
88919880Skarels }
890*25621Ssklower 
891*25621Ssklower /*
892*25621Ssklower  * set ethernet address for unit
893*25621Ssklower  */
894*25621Ssklower ex_setaddr(physaddr, unit)
895*25621Ssklower 	u_char *physaddr;
896*25621Ssklower 	int unit;
897*25621Ssklower {
898*25621Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
899*25621Ssklower 	struct uba_device *ui = exinfo[unit];
900*25621Ssklower 	register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
901*25621Ssklower 	register struct ifnet *ifp = &xs->xs_if;
902*25621Ssklower 	register struct ex_msg *bp;
903*25621Ssklower 
904*25621Ssklower 	if (physaddr) {
905*25621Ssklower 		xs->xs_flags |= EX_SETADDR;
906*25621Ssklower 		bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
907*25621Ssklower 	}
908*25621Ssklower 	if (! (xs->xs_flags & EX_RUNNING))
909*25621Ssklower 		return;
910*25621Ssklower 	bp = exgetcbuf(xs);
911*25621Ssklower 	bp->mb_rqst = LLNET_ADDRS;
912*25621Ssklower 	bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
913*25621Ssklower 	bp->mb_na.na_slot = PHYSSLOT;
914*25621Ssklower 	bcopy(xs->xs_addr, bp->mb_na.na_addrs, 6);
915*25621Ssklower 	bp->mb_status |= MH_EXOS;
916*25621Ssklower 	addr->xd_portb = EX_NTRUPT;
917*25621Ssklower 	bp = xs->xs_x2hnext;
918*25621Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
919*25621Ssklower 		;
920*25621Ssklower 	printf("ex%d: reset addr %x.%x.%x.%x.%x.%x\n",
921*25621Ssklower 		ui->ui_unit,
922*25621Ssklower 		bp->mb_na.na_addrs[0], bp->mb_na.na_addrs[1],
923*25621Ssklower 		bp->mb_na.na_addrs[2], bp->mb_na.na_addrs[3],
924*25621Ssklower 		bp->mb_na.na_addrs[4], bp->mb_na.na_addrs[5]);
925*25621Ssklower 	/*
926*25621Ssklower 	 * Now, re-enable reception on phys slot.
927*25621Ssklower 	 */
928*25621Ssklower 	bp = exgetcbuf(xs);
929*25621Ssklower 	bp->mb_rqst = LLNET_RECV;
930*25621Ssklower 	bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
931*25621Ssklower 	bp->mb_nr.nr_slot = PHYSSLOT;
932*25621Ssklower 	bp->mb_status |= MH_EXOS;
933*25621Ssklower 	addr->xd_portb = EX_NTRUPT;
934*25621Ssklower 	bp = xs->xs_x2hnext;
935*25621Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
936*25621Ssklower 		;
937*25621Ssklower }
93825273Sbloom #endif
939