xref: /csrg-svn/sys/tahoe/if/if_ex.c (revision 43339)
137110Ssklower /*
237110Ssklower  * Copyright (c) 1989 The Regents of the University of California.
337110Ssklower  * All rights reserved.
437110Ssklower  *
537110Ssklower  * This code is derived from software contributed to Berkeley by
637110Ssklower  * Excelan Inc.
737110Ssklower  *
837110Ssklower  * Redistribution and use in source and binary forms are permitted
937110Ssklower  * provided that the above copyright notice and this paragraph are
1037110Ssklower  * duplicated in all such forms and that any documentation,
1137110Ssklower  * advertising materials, and other materials related to such
1237110Ssklower  * distribution and use acknowledge that the software was developed
1337110Ssklower  * by the University of California, Berkeley.  The name of the
1437110Ssklower  * University may not be used to endorse or promote products derived
1537110Ssklower  * from this software without specific prior written permission.
1637110Ssklower  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1737110Ssklower  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1837110Ssklower  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1937110Ssklower  *
20*43339Ssklower  *	@(#)if_ex.c	7.3 (Berkeley) 06/20/90
2137110Ssklower  */
2237110Ssklower 
2337110Ssklower #include "ex.h"
2437110Ssklower 
2537110Ssklower #if	NEX > 0
2637110Ssklower 
2737110Ssklower /*
2837110Ssklower  * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers
2937110Ssklower  */
3037110Ssklower #include "param.h"
3137110Ssklower #include "systm.h"
3237110Ssklower #include "mbuf.h"
3337110Ssklower #include "buf.h"
3437110Ssklower #include "protosw.h"
3537110Ssklower #include "socket.h"
3637110Ssklower #include "vmmac.h"
3737110Ssklower #include "ioctl.h"
3837110Ssklower #include "errno.h"
3937110Ssklower #include "vmparam.h"
4037110Ssklower #include "syslog.h"
4137110Ssklower #include "uio.h"
4237110Ssklower 
4337110Ssklower #include "../net/if.h"
4437110Ssklower #include "../net/netisr.h"
4537110Ssklower #include "../net/route.h"
4637110Ssklower 
4737110Ssklower #ifdef INET
4837110Ssklower #include "../netinet/in.h"
4937110Ssklower #include "../netinet/in_systm.h"
5037110Ssklower #include "../netinet/in_var.h"
5137110Ssklower #include "../netinet/ip.h"
5237110Ssklower #include "../netinet/if_ether.h"
5337110Ssklower #endif
5437110Ssklower 
5537110Ssklower #ifdef NS
5637110Ssklower #include "../netns/ns.h"
5737110Ssklower #include "../netns/ns_if.h"
5837110Ssklower #endif
5937110Ssklower 
6037474Ssklower #ifdef ISO
6137474Ssklower #include "../netiso/iso.h"
6237474Ssklower #include "../netiso/iso_var.h"
63*43339Ssklower extern char all_es_snpa[], all_is_snpa[];
6437474Ssklower #endif
6537474Ssklower 
6637110Ssklower #include "../tahoe/cpu.h"
6737110Ssklower #include "../tahoe/pte.h"
6837110Ssklower #include "../tahoe/mtpr.h"
6937110Ssklower 
7037110Ssklower #include "../tahoevba/vbavar.h"
7137110Ssklower #include "if_exreg.h"
7237110Ssklower #include "if_vba.h"
7337110Ssklower 
7437110Ssklower 
7537110Ssklower #define	NH2X 32			/* Host to eXcelan request buffers */
7637110Ssklower 
7737110Ssklower #define	NX2H 16			/* eXcelan to Host reply buffers */
7837110Ssklower #define	NREC	16		/* Number of RECeive buffers */
7937110Ssklower #define	NTRB	4		/* Number of TRansmit Buffers */
8037110Ssklower #define NVBI	(NREC + NTRB)
8137110Ssklower 
8237110Ssklower #define EXWATCHINTVL	10	/* call exwatch every x secs */
8337110Ssklower 
8437110Ssklower int	exprobe(), exslave(), exattach(), exintr(), exstart();
8537110Ssklower struct	vba_device *exinfo[NEX];
8637110Ssklower 
8737110Ssklower long	exstd[] = { 0 };
8837110Ssklower 
8937110Ssklower 
9037110Ssklower struct	vba_driver exdriver =
9137110Ssklower 	{ exprobe, 0, exattach, exstart, exstd, "ex", exinfo };
9237110Ssklower int	exinit(),ether_output(),exioctl(),exreset(),exwatch();
9337110Ssklower struct	ex_msg *exgetcbuf();
9437110Ssklower int	ex_ncall = 0;			/* counts calls to exprobe */
9537110Ssklower u_long	busoff;
9637110Ssklower 
9737110Ssklower /*
9837110Ssklower  * Ethernet software status per interface.
9937110Ssklower  *
10037110Ssklower  * Each interface is referenced by a network interface structure, xs_if, which
10137110Ssklower  * the routing code uses to locate the interface.  This structure contains the
10237110Ssklower  * output queue for the interface, its address, ... NOTE: To configure multiple
10337110Ssklower  * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr).
10437110Ssklower  */
10537110Ssklower struct	ex_softc {
10637110Ssklower 	struct		arpcom xs_ac;	/* Ethernet common part */
10737110Ssklower #define	xs_if		xs_ac.ac_if	/* network-visible interface */
10837110Ssklower #define	xs_addr		xs_ac.ac_enaddr	/* hardware Ethernet address */
10937110Ssklower 	int		xs_flags;	/* private flags */
11037110Ssklower #define	EX_XPENDING	1		/* xmit rqst pending on EXOS */
11137110Ssklower #define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */
11237110Ssklower #define	EX_RUNNING	(1<<2)		/* board is running */
11337110Ssklower #define EX_SETADDR	(1<<3)		/* physaddr has been changed */
11437110Ssklower 	int		xs_cvec;	/* probe stores cvec here */
11537110Ssklower 	short		xs_enetunit;	/* unit number for enet filtering */
11637110Ssklower 	short		xs_enetinit;	/* enet inetrface is initialized */
11737110Ssklower 	struct	ex_msg	*xs_h2xnext;	/* host pointer to request queue */
11837110Ssklower 	struct	ex_msg 	*xs_x2hnext;	/* host pointer to reply queue */
11937110Ssklower 	u_long		xs_qbaddr;	/* map info for structs below */
12037474Ssklower 	struct	ex_shm	{
12137110Ssklower 	/* the following structures are always mapped in */
12237474Ssklower 	u_short		sm_h2xhdr;	/* EXOS's request queue header */
12337474Ssklower 	u_short		sm_x2hhdr;	/* EXOS's reply queue header */
12437474Ssklower 	struct ex_msg 	sm_h2xent[NH2X];/* request msg buffers */
12537474Ssklower 	struct ex_msg 	sm_x2hent[NX2H];/* reply msg buffers */
12637474Ssklower 	struct ex_conf	sm_cm;		/* configuration message */
12737474Ssklower 	struct ex_stat	sm_xsa;	/* EXOS writes stats here */
12837110Ssklower 	/* end mapped area */
12937474Ssklower 	} 		*xs_shm;	/* host pointer to shared area */
13037474Ssklower #define	xs_h2xhdr	xs_shm->sm_h2xhdr
13137474Ssklower #define	xs_x2hhdr	xs_shm->sm_x2hhdr
13237474Ssklower #define	xs_h2xent	xs_shm->sm_h2xent
13337474Ssklower #define	xs_x2hent	xs_shm->sm_x2hent
13437474Ssklower #define	xs_cm		xs_shm->sm_cm
13537474Ssklower #define	xs_xsa		xs_shm->sm_xsa
13637474Ssklower #define	BUSADDR(x)	(0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF))
13737474Ssklower #define	P_BUSADDR(x)	(0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0))
13837474Ssklower #define	INCORE_BASE(p)	(((u_long)(p)->xs_shm) & 0xFFFFFFF0)
13937474Ssklower /* we will arrange that the shared memory begins on a 16 byte boundary */
14037474Ssklower #define	RVAL_OFF(n)	(((char *)&(((struct ex_shm *)0)->n))-(char *)0)
14137474Ssklower #define	LVAL_OFF(n)	(((char *)(((struct ex_shm *)0)->n))-(char *)0)
14237474Ssklower #define	H2XHDR_OFFSET	RVAL_OFF(sm_h2xhdr)
14337474Ssklower #define	X2HHDR_OFFSET	RVAL_OFF(sm_x2hhdr)
14437474Ssklower #define	H2XENT_OFFSET	LVAL_OFF(sm_h2xent)
14537474Ssklower #define	X2HENT_OFFSET	LVAL_OFF(sm_x2hent)
14637474Ssklower #define	CM_OFFSET	RVAL_OFF(sm_cm)
14737474Ssklower #define	SA_OFFSET	RVAL_OFF(sm_xsa)
14837110Ssklower 	struct		ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */
14937110Ssklower 	struct		ifvba *xs_pkblist; /* free list of above */
15037474Ssklower #define GetPkBuf(b, v)  ((v = (b)->mb_pkb = xs->xs_pkblist),\
15137474Ssklower 		      (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf))
15237474Ssklower #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\
15337474Ssklower 							(xs->xs_pkblist = v))
15437110Ssklower 	char		xs_nrec;	/* number of pending receive buffers */
15537110Ssklower 	char		xs_ntrb;	/* number of pending transmit buffers */
15637110Ssklower } ex_softc[NEX];
15737110Ssklower 
15837110Ssklower int ex_padcheck = sizeof (struct ex_softc);
15937110Ssklower 
16037110Ssklower exprobe(reg, vi)
16137110Ssklower 	caddr_t reg;
16237110Ssklower 	struct vba_device *vi;
16337110Ssklower {
16437110Ssklower 	register br, cvec;		/* r12, r11 value-result */
16537110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)reg;
16637110Ssklower 	int	i;
16737110Ssklower 
16837474Ssklower 	if (badaddr((caddr_t)exaddr, 2))
16937110Ssklower 		return 0;
17037110Ssklower 	/*
17137110Ssklower 	 * Reset EXOS and run self-test (should complete within 2 seconds).
17237110Ssklower 	 */
17337110Ssklower 	movow(&exaddr->ex_porta, EX_RESET);
17437110Ssklower 	for (i = 1000000; i; i--) {
17537110Ssklower 		uncache(&(exaddr->ex_portb));
17637110Ssklower 		if (exaddr->ex_portb & EX_TESTOK)
17737110Ssklower 			break;
17837110Ssklower 	}
17937110Ssklower 	if ((exaddr->ex_portb & EX_TESTOK) == 0)
18037110Ssklower 		return 0;
18137110Ssklower 	br = 0x15;
18237110Ssklower 	cvec = --vi->ui_hd->vh_lastiv;
18337110Ssklower 	ex_softc[vi->ui_unit].xs_cvec = cvec;
18437110Ssklower 	ex_ncall++;
18537110Ssklower 	return (sizeof(struct exdevice));
18637110Ssklower }
18737110Ssklower 
18837110Ssklower /*
18937110Ssklower  * Interface exists: make available by filling in network interface record.
19037110Ssklower  * System will initialize the interface when it is ready to accept packets.
19137110Ssklower  * A NET_ADDRS command is done to get the ethernet address.
19237110Ssklower  */
19337110Ssklower exattach(ui)
19437110Ssklower 	register struct vba_device	*ui;
19537110Ssklower {
19637110Ssklower 	register struct ex_softc *xs = &ex_softc[ui->ui_unit];
19737110Ssklower 	register struct ifnet *ifp = &xs->xs_if;
19837110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
19937110Ssklower 	register struct ex_msg *bp;
20037110Ssklower 
20137110Ssklower 	ifp->if_unit = ui->ui_unit;
20237110Ssklower 	ifp->if_name = "ex";
20337110Ssklower 	ifp->if_mtu = ETHERMTU;
20437110Ssklower 	ifp->if_init = exinit;
20537110Ssklower 	ifp->if_ioctl = exioctl;
20637110Ssklower 	ifp->if_output = ether_output;
20737110Ssklower 	ifp->if_reset = exreset;
20837110Ssklower 	ifp->if_start = exstart;
20937474Ssklower 	ifp->if_flags = IFF_BROADCAST;
21037110Ssklower 
21137474Ssklower 	/*
21237474Ssklower 	 * Note: extra memory gets returned by if_vbareserve()
21337474Ssklower 	 * first, so, being page alligned, it is also 16-byte alligned.
21437474Ssklower 	 */
21537474Ssklower 	if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF,
21637474Ssklower 			(caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0)
21737110Ssklower 		return;
21837110Ssklower 	/*
21937110Ssklower 	 * Temporarily map queues in order to configure EXOS
22037110Ssklower 	 */
22137110Ssklower 	xs->xs_qbaddr = INCORE_BASE(xs);
22237110Ssklower 	exconfig(ui, 0);			/* without interrupts */
22337110Ssklower 	if (xs->xs_cm.cm_cc)
22437110Ssklower 		return;				/* bad conf */
22537110Ssklower 	/*
22637110Ssklower 	 * Get Ethernet address.
22737110Ssklower 	 */
22837110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)
22937110Ssklower 		panic("exattach");
23037110Ssklower 	bp->mb_na.na_mask = READ_OBJ;
23137110Ssklower 	bp->mb_na.na_slot = PHYSSLOT;
23237110Ssklower 	bp->mb_status |= MH_EXOS;
23337110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
23437110Ssklower 	bp = xs->xs_x2hnext;
23537474Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
23637110Ssklower 	printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",
23737110Ssklower 		ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
23837110Ssklower 		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
23937110Ssklower 		ether_sprintf(bp->mb_na.na_addrs));
24037110Ssklower 	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
24137110Ssklower 		sizeof(xs->xs_addr));
24237110Ssklower 	if_attach(ifp);
24337110Ssklower }
24437110Ssklower 
24537110Ssklower /*
24637110Ssklower  * Reset of interface after BUS reset.
24737110Ssklower  * If interface is on specified vba, reset its state.
24837110Ssklower  */
24937110Ssklower exreset(unit)
25037110Ssklower int unit;
25137110Ssklower {
25237110Ssklower 	register struct vba_device *ui;
25337110Ssklower 
25437110Ssklower 	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)
25537110Ssklower 		return;
25637110Ssklower 	printf(" ex%d", unit);
25737110Ssklower 	ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
25837110Ssklower 	ex_softc[unit].xs_flags &= ~EX_RUNNING;
25937110Ssklower 
26037110Ssklower 	exinit(unit);
26137110Ssklower }
26237110Ssklower 
26337110Ssklower /*
26437110Ssklower  * Initialization of interface; clear recorded pending operations, and
26537110Ssklower  * reinitialize BUS usage. Called at boot time, and at ifconfig time via
26637110Ssklower  * exioctl, with interrupts disabled.
26737110Ssklower  */
26837110Ssklower exinit(unit)
26937110Ssklower int unit;
27037110Ssklower {
27137110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
27237110Ssklower 	register struct vba_device *ui = exinfo[unit];
27337110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
27437110Ssklower 	register struct ifnet *ifp = &xs->xs_if;
27537110Ssklower 	register struct sockaddr_in *sin;
27637110Ssklower 	register struct ex_msg 	*bp;
27737110Ssklower 	int s;
27837110Ssklower 
27937110Ssklower 	/* not yet, if address still unknown */
28037110Ssklower 	if (ifp->if_addrlist == (struct ifaddr *)0)
28137110Ssklower 		return;
28237110Ssklower 	if (xs->xs_flags & EX_RUNNING)
28337110Ssklower 		return;
28437110Ssklower 
28537110Ssklower 	xs->xs_qbaddr = INCORE_BASE(xs);
28637110Ssklower 	exconfig(ui, 4);		/* with vectored interrupts*/
28737110Ssklower 
28837110Ssklower 	/*
28937110Ssklower 	 * Put EXOS on the Ethernet, using NET_MODE command
29037110Ssklower 	 */
29137110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)
29237110Ssklower 		panic("exinit");
29337110Ssklower 	bp->mb_nm.nm_mask = WRITE_OBJ;
29437110Ssklower 	bp->mb_nm.nm_optn = 0;
29537110Ssklower 	bp->mb_nm.nm_mode = MODE_PERF;
29637110Ssklower 	bp->mb_status |= MH_EXOS;
29737110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
29837110Ssklower 	bp = xs->xs_x2hnext;
29937474Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
30037474Ssklower 		;
30137110Ssklower 	bp->mb_length = MBDATALEN;
30237110Ssklower 	bp->mb_status |= MH_EXOS;		/* free up buffer */
30337110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
30437110Ssklower 	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
30537110Ssklower 
30637110Ssklower 	ifp->if_watchdog = exwatch;
30737110Ssklower 	ifp->if_timer = EXWATCHINTVL;
30837110Ssklower 	s = splimp();		/* are interrupts disabled here, anyway? */
30937110Ssklower 	exhangrcv(unit);
31037110Ssklower 	xs->xs_if.if_flags |= IFF_RUNNING;
31137110Ssklower 	xs->xs_flags |= EX_RUNNING;
31237110Ssklower 	if (xs->xs_flags & EX_SETADDR)
31337110Ssklower 		ex_setaddr((u_char *)0, unit);
31437474Ssklower #ifdef ISO
315*43339Ssklower 	ex_setmulti(all_es_snpa, unit, 1);
316*43339Ssklower 	ex_setmulti(all_is_snpa, unit, 2);
31737474Ssklower #endif
31837110Ssklower 	exstart(&ex_softc[unit].xs_if);		/* start transmits */
31937110Ssklower 	splx(s);		/* are interrupts disabled here, anyway? */
32037110Ssklower }
32137110Ssklower 
32237110Ssklower /*
32337110Ssklower  * Reset, test, and configure EXOS.  It is called by exinit, and exattach.
32437110Ssklower  * Returns 0 if successful, 1 if self-test failed.
32537110Ssklower  */
32637110Ssklower exconfig(ui, itype)
32737110Ssklower struct	vba_device *ui;
32837110Ssklower int itype;
32937110Ssklower {
33037110Ssklower 	register int unit = ui->ui_unit;
33137110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
33237110Ssklower 	register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;
33337474Ssklower 	register struct ex_conf *cm = &xs->xs_cm;
33437110Ssklower 	register struct ex_msg 	*bp;
33537110Ssklower 	register struct ifvba *pkb;
33637110Ssklower 	int 	i;
33737110Ssklower 	u_long 	shiftreg;
33837110Ssklower 	static	u_char	cmaddr[8] = {0xFF, 0xFF, 0, 0};
33937110Ssklower 
34037110Ssklower 	xs->xs_flags = 0;
34137110Ssklower 	/*
34237110Ssklower 	 * Reset EXOS, wait for self-test to complete
34337110Ssklower 	 */
34437110Ssklower 	movow(&exaddr->ex_porta, EX_RESET);
34537110Ssklower 	do {
34637110Ssklower 		uncache(&exaddr->ex_portb);
34737110Ssklower 	} while ((exaddr->ex_portb & EX_TESTOK) == 0) ;
34837110Ssklower 	/*
34937110Ssklower 	 * Set up configuration message.
35037110Ssklower 	 */
35137110Ssklower 	cm->cm_1rsrv = 1;
35237110Ssklower 	cm->cm_cc = 0xFF;
35337110Ssklower 	cm->cm_opmode = 0;		/* link-level controller mode */
35437110Ssklower 	cm->cm_dfo = 0x0101;		/* enable host data order conversion */
35537110Ssklower 	cm->cm_dcn1 = 1;
35637110Ssklower 	cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
35737110Ssklower 	cm->cm_ham = 3;			/* absolute address mode */
35837110Ssklower 	cm->cm_3rsrv = 0;
35937110Ssklower 	cm->cm_mapsiz = 0;
36037110Ssklower 	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */
36137110Ssklower 	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */
36237110Ssklower 	cm->cm_byteptrn[2] = 0x07;
36337110Ssklower 	cm->cm_byteptrn[3] = 0x0F;
36437110Ssklower 	cm->cm_wordptrn[0] = 0x0103;
36537110Ssklower 	cm->cm_wordptrn[1] = 0x070F;
36637110Ssklower 	cm->cm_lwordptrn = 0x0103070F;
36737110Ssklower 	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
36837110Ssklower 	cm->cm_mba = 0xFFFFFFFF;
36937110Ssklower 	cm->cm_nproc = 0xFF;
37037110Ssklower 	cm->cm_nmbox = 0xFF;
37137110Ssklower 	cm->cm_nmcast = 0xFF;
37237110Ssklower 	cm->cm_nhost = 1;
37337110Ssklower 	cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);
37437110Ssklower 	cm->cm_h2xhdr = H2XHDR_OFFSET;
37537110Ssklower 	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */
37637110Ssklower 	cm->cm_x2hba = cm->cm_h2xba;
37737110Ssklower 	cm->cm_x2hhdr = X2HHDR_OFFSET;
37837110Ssklower 	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */
37937110Ssklower 	cm->cm_x2haddr = xs->xs_cvec;	/* ivec allocated in exprobe */
38037110Ssklower 	/*
38137110Ssklower 	 * Set up message queues and headers.
38237110Ssklower 	 * First the request queue
38337110Ssklower 	 */
38437110Ssklower 	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
38537110Ssklower 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
38637110Ssklower 		bp->mb_rsrv = 0;
38737110Ssklower 		bp->mb_length = MBDATALEN;
38837110Ssklower 		bp->mb_status = MH_HOST;
38937110Ssklower 		bp->mb_next = bp+1;
39037110Ssklower 	}
39137110Ssklower 	xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;
39237110Ssklower 	xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
39337110Ssklower 
39437110Ssklower 	/* Now the reply queue. */
39537110Ssklower 	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
39637110Ssklower 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
39737110Ssklower 		bp->mb_rsrv = 0;
39837110Ssklower 		bp->mb_length = MBDATALEN;
39937110Ssklower 		bp->mb_status = MH_EXOS;
40037110Ssklower 		bp->mb_next = bp+1;
40137110Ssklower 	}
40237110Ssklower 	xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;
40337110Ssklower 	xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
40437110Ssklower 	xs->xs_nrec = 0;
40537110Ssklower 	xs->xs_ntrb = 0;
40637110Ssklower 	xs->xs_pkblist =  xs->xs_vbinfo + NVBI - 1;
40737474Ssklower 	for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--)
40837110Ssklower 		pkb->iff_mbuf = (struct mbuf *)(pkb - 1);
40937110Ssklower 	xs->xs_vbinfo[0].iff_mbuf = 0;
41037110Ssklower 
41137110Ssklower 	/*
41237110Ssklower 	 * Write config msg address to EXOS and wait for configuration to
41337110Ssklower 	 * complete (guaranteed response within 2 seconds).
41437110Ssklower 	 */
41537110Ssklower 	shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;
41637110Ssklower 	for (i = 4; i < 8; i++) {
41737110Ssklower 		cmaddr[i] = (u_char)(shiftreg & 0xFF);
41837110Ssklower 		shiftreg >>= 8;
41937110Ssklower 	}
42037110Ssklower 	for (i = 0; i < 8; i++) {
42137110Ssklower 		do {
42237110Ssklower 			uncache(&exaddr->ex_portb);
42337110Ssklower 		} while (exaddr->ex_portb & EX_UNREADY) ;
42437110Ssklower 		DELAY(500);
42537110Ssklower 		movow(&exaddr->ex_portb, cmaddr[i]);
42637110Ssklower 	}
42737110Ssklower 	for (i = 500000; i; --i) {
42837110Ssklower 		DELAY(10);
42937110Ssklower 		uncache(&cm->cm_cc);
43037110Ssklower 		if (cm->cm_cc != 0xFF)
43137110Ssklower 			break;
43237110Ssklower 	}
43337110Ssklower 	if (cm->cm_cc)
43437110Ssklower 		printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);
43537110Ssklower }
43637110Ssklower 
43737110Ssklower /*
43837110Ssklower  * Start or re-start output on interface. Get another datagram to send off of
43937110Ssklower  * the interface queue, and map it to the interface before starting the output.
44037110Ssklower  * This routine is called by exinit(), exoutput(), and excdint().  In all cases,
44137110Ssklower  * interrupts by EXOS are disabled.
44237110Ssklower  */
44337110Ssklower exstart(ifp)
44437110Ssklower struct ifnet *ifp;
44537110Ssklower {
44637110Ssklower 	int unit = ifp->if_unit;
44737110Ssklower 	struct vba_device *ui = exinfo[unit];
44837110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
44937110Ssklower 	struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
45037110Ssklower 	register struct ex_msg *bp;
45137110Ssklower 	register struct mbuf *m;
45237110Ssklower         int len;
45337110Ssklower 	register struct ifvba *pkb;
45437474Ssklower 	struct mbuf *m0 = 0;
45537474Ssklower 	register int nb = 0, tlen = 0;
45637110Ssklower 	union l_util {
45737110Ssklower 		u_long	l;
45837110Ssklower 		struct	i86_long i;
45937110Ssklower 	} l_util;
46037110Ssklower 
46137110Ssklower 	if (xs->xs_ntrb >= NTRB)
46237110Ssklower 		return;
46337110Ssklower 	if (xs->xs_pkblist == 0) {
46437110Ssklower 		printf("ex%d: vbinfo exhausted, would panic", unit);
46537110Ssklower 		return;
46637110Ssklower 	}
46737110Ssklower 	IF_DEQUEUE(&xs->xs_if.if_snd, m);
46837110Ssklower 	if (m == 0)
46937110Ssklower 		return;
47037110Ssklower 	/*
47137110Ssklower 	 * Get a transmit request.
47237110Ssklower 	 */
47337110Ssklower 	if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) {
47437110Ssklower 		m_freem(m);
47537110Ssklower 		printf("exstart: no command buffers\n");
47637110Ssklower 		return;
47737110Ssklower 	}
47837110Ssklower 	xs->xs_ntrb++;
47937474Ssklower 	GetPkBuf(bp, pkb);
48037110Ssklower 	pkb->iff_mbuf = m;	/* save mbuf pointer to free when done */
48137110Ssklower 	/*
48237110Ssklower 	 * point directly to the first group of mbufs to be transmitted. The
48337110Ssklower 	 * hardware can only support NFRAGMENTS descriptors.
48437110Ssklower 	 */
48537110Ssklower 	while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) {
48637474Ssklower 		l_util.l = BUSADDR(mtod(m, caddr_t));
48737110Ssklower 		bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len;
48837110Ssklower 		bp->mb_et.et_blks[nb].bb_addr = l_util.i;
48937474Ssklower 		if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
49037474Ssklower 			/* Here, the phys memory for the mbuf is out
49137474Ssklower 			   of range for the vmebus to talk to it */
49237474Ssklower 			if (m == pkb->iff_mbuf)
49337474Ssklower 				pkb->iff_mbuf = 0;
49437474Ssklower 			break;
49537474Ssklower 		}
49637110Ssklower 		tlen += m->m_len;
49737110Ssklower 		m0 = m;
49837110Ssklower 		m = m->m_next;
49937110Ssklower 		nb++;
50037110Ssklower 	}
50137110Ssklower 
50237110Ssklower 	/* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */
50337110Ssklower 	if (m0)
50437110Ssklower 		m0->m_next = 0;
50537110Ssklower 
50637110Ssklower 	/*
50737110Ssklower 	 * if not all of the descriptors would fit then merge remaining data
50837110Ssklower 	 * into the transmit buffer, and point to it.  Note: the mbufs are freed
50937110Ssklower 	 * during the merge, they do not have to be freed when we get the
51037110Ssklower 	 * transmit interrupt.
51137110Ssklower 	 */
51237110Ssklower 	if (m) {
51337474Ssklower 		if (m == pkb->iff_mbuf) {
51437474Ssklower 			printf("ex%d: exstart insanity\n", unit);
51537474Ssklower 			pkb->iff_mbuf = 0;
51637474Ssklower 		}
51737474Ssklower 		len = if_vbaput(pkb->iff_buffer, m, 0);
51837110Ssklower 		l_util.l = BUSADDR(pkb->iff_buffer);
51937110Ssklower 		bp->mb_et.et_blks[nb].bb_len = (u_short)len;
52037110Ssklower 		bp->mb_et.et_blks[nb].bb_addr = l_util.i;
52137110Ssklower 		tlen += len;
52237110Ssklower 		nb++;
52337110Ssklower 	}
52437110Ssklower 
52537110Ssklower 	/*
52637474Ssklower 	 * If the total length of the packet is too small,
52737474Ssklower 	 * pad the last fragment.  (May run into very obscure problems)
52837110Ssklower 	 */
52937474Ssklower 	if (tlen < sizeof(struct ether_header) + ETHERMIN) {
53037110Ssklower 		len = (ETHERMIN + sizeof(struct ether_header)) - tlen;
53137110Ssklower 		bp->mb_et.et_blks[nb-1].bb_len += (u_short)len;
53237110Ssklower 		tlen += len;
53337474Ssklower #ifdef notdef
53437474Ssklower                 if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
53537474Ssklower 			must copy last frag into private buffer
53637474Ssklower 		}
53737474Ssklower #endif
53837110Ssklower 	}
53937110Ssklower 
54037110Ssklower 	/* set number of fragments in descriptor */
54137110Ssklower 	bp->mb_et.et_nblock = nb;
54237110Ssklower 	bp->mb_status |= MH_EXOS;
54337110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
54437110Ssklower }
54537110Ssklower 
54637110Ssklower /*
54737110Ssklower  * interrupt service routine.
54837110Ssklower  */
54937110Ssklower exintr(unit)
55037110Ssklower 	int unit;
55137110Ssklower {
55237110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
55337110Ssklower 	register struct ex_msg *bp = xs->xs_x2hnext;
55437110Ssklower 	struct vba_device *ui = exinfo[unit];
55537110Ssklower 	struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
55637474Ssklower 	struct ex_msg *next_bp;
55737110Ssklower 
55837110Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_HOST) {
55937110Ssklower 		switch (bp->mb_rqst) {
56037110Ssklower 		    case LLRECEIVE:
56137474Ssklower 			if (--xs->xs_nrec < 0) {
56237474Ssklower 				printf("ex%d: internal receive check\n", unit);
56337110Ssklower 				xs->xs_nrec = 0;
56437474Ssklower 			}
56537110Ssklower 			exrecv(unit, bp);
56637110Ssklower 			FreePkBuf(bp->mb_pkb);
56737110Ssklower 			bp->mb_pkb = (struct ifvba *)0;
56837110Ssklower 			exhangrcv(unit);
56937110Ssklower 			break;
57037110Ssklower 
57137110Ssklower 		    case LLTRANSMIT:
57237110Ssklower 		    case LLRTRANSMIT:
57337474Ssklower 			if (--xs->xs_ntrb < 0) {
57437474Ssklower 				printf("ex%d: internal transmit check\n", unit);
57537110Ssklower 				xs->xs_ntrb = 0;
57637474Ssklower 			}
57737110Ssklower 			xs->xs_if.if_opackets++;
57837474Ssklower 			if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
57937110Ssklower 				;
58037110Ssklower 			else if (bp->mb_rply & LLXM_1RTRY)
58137110Ssklower 				xs->xs_if.if_collisions++;
58237110Ssklower 			else if (bp->mb_rply & LLXM_RTRYS)
58337110Ssklower 				xs->xs_if.if_collisions += 2;	/* guess */
58437110Ssklower 			else if (bp->mb_rply & LLXM_ERROR)
58537110Ssklower 				if (xs->xs_if.if_oerrors++ % 100 == 0)
58637110Ssklower 					printf("ex%d: 100 transmit errors=%b\n",
58737110Ssklower 						unit, bp->mb_rply, XMIT_BITS);
58837110Ssklower 			if (bp->mb_pkb->iff_mbuf) {
58937110Ssklower 				m_freem(bp->mb_pkb->iff_mbuf);
59037110Ssklower 				bp->mb_pkb->iff_mbuf = (struct mbuf *)0;
59137110Ssklower 			}
59237110Ssklower 			FreePkBuf(bp->mb_pkb);
59337110Ssklower 			bp->mb_pkb = (struct ifvba *)0;
59437474Ssklower 			exstart(&xs->xs_if);
59537110Ssklower 			exhangrcv(unit);
59637110Ssklower 			break;
59737110Ssklower 
59837110Ssklower 		    case LLNET_STSTCS:
59937110Ssklower 			xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc;
60037110Ssklower 			xs->xs_flags &= ~EX_STATPENDING;
60137474Ssklower 		    case LLNET_ADDRS:
60237474Ssklower 		    case LLNET_RECV:
60337474Ssklower 			if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
60437474Ssklower 				;
60537474Ssklower 			else
60637474Ssklower 				printf("ex%d: %s, request 0x%x, reply 0x%x\n",
60737474Ssklower 				  unit, "unsucessful stat or address change",
60837474Ssklower 				  bp->mb_rqst, bp->mb_rply);
60937110Ssklower 			break;
61037110Ssklower 
61137110Ssklower 		    default:
61237110Ssklower 			printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst);
61337110Ssklower 		}
61437110Ssklower 		bp->mb_length = MBDATALEN;
61537474Ssklower 		next_bp = bp->mb_next;
61637110Ssklower 		bp->mb_status |= MH_EXOS;	/* free up buffer */
61737474Ssklower 		bp = next_bp;			/* paranoia about race */
61837110Ssklower 		movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */
61937110Ssklower 	}
62037110Ssklower 	xs->xs_x2hnext = bp;
62137110Ssklower }
62237110Ssklower 
62337110Ssklower /*
62437110Ssklower  * Get a request buffer, fill in standard values, advance pointer.
62537110Ssklower  */
62637110Ssklower struct ex_msg *
62737110Ssklower exgetcbuf(xs, req)
62837110Ssklower struct ex_softc *xs;
62937110Ssklower int req;
63037110Ssklower {
63137110Ssklower 	register struct ex_msg *bp;
63237110Ssklower 	struct ifvba *pkb;
63337110Ssklower 	int s = splimp();
63437110Ssklower 
63537110Ssklower 	bp = xs->xs_h2xnext;
63637110Ssklower 	if ((bp->mb_status & MH_OWNER) == MH_EXOS) {
63737110Ssklower 		splx(s);
63837110Ssklower 		return (struct ex_msg *)0;
63937110Ssklower 	}
64037110Ssklower 	xs->xs_h2xnext = bp->mb_next;
64137110Ssklower 	bp->mb_1rsrv = 0;
64237110Ssklower 	bp->mb_rqst = req;
64337110Ssklower 	bp->mb_length = MBDATALEN;
64437110Ssklower 	bp->mb_pkb = (struct ifvba *)0;
64537110Ssklower 	splx(s);
64637110Ssklower 	return bp;
64737110Ssklower }
64837110Ssklower 
64937110Ssklower /*
65037110Ssklower  * Process Ethernet receive completion:  If input error just drop packet,
65137110Ssklower  * otherwise examine packet to determine type.  If can't determine length from
65237110Ssklower  * type, then have to drop packet, otherwise decapsulate packet based on type
65337110Ssklower  * and pass to type-specific higher-level input routine.
65437110Ssklower  */
65537110Ssklower exrecv(unit, bp)
65637110Ssklower int unit;
65737110Ssklower register struct ex_msg *bp;
65837110Ssklower {
65937110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
66037110Ssklower 	register struct ether_header *eh;
66137110Ssklower     	register struct mbuf *m;
66237110Ssklower 	int len, off, resid;
66337110Ssklower 	register struct ifqueue *inq;
66437110Ssklower 	int s;
66537110Ssklower 
66637110Ssklower 	xs->xs_if.if_ipackets++;
66737110Ssklower 	/*     total length               - header                      - crc */
66837110Ssklower 	len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
66937110Ssklower 	if (bp->mb_rply != LL_OK) {
67037110Ssklower 		if (xs->xs_if.if_ierrors++ % 100 == 0)
67137110Ssklower 			printf("ex%d: 100 receive errors=%b\n",
67237110Ssklower 				unit, bp->mb_rply, RECV_BITS);
67337110Ssklower 		return;
67437110Ssklower 	}
67537110Ssklower 	eh = (struct ether_header *)(bp->mb_pkb->iff_buffer);
67637110Ssklower 
67737110Ssklower 	/*
67837110Ssklower 	 * Deal with trailer protocol: if type is PUP trailer get true type from
67937110Ssklower 	 * first 16-bit word past data.  Remember that type was trailer by
68037110Ssklower 	 * setting off.
68137110Ssklower 	 */
68237110Ssklower 	eh->ether_type = ntohs((u_short)eh->ether_type);
68337110Ssklower #define	exdataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
68437110Ssklower 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
68537110Ssklower 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
68637110Ssklower 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
68737110Ssklower 		if (off >= ETHERMTU)
68837110Ssklower 			return;			/* sanity */
68937110Ssklower 		eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
69037110Ssklower 		resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
69137110Ssklower 		if (off + resid > len)
69237110Ssklower 			return;			/* sanity */
69337110Ssklower 		len = off + resid;
69437110Ssklower 	} else
69537110Ssklower 		off = 0;
69637110Ssklower 	if (len == 0)
69737110Ssklower 		return;
69837110Ssklower 	/*
69937110Ssklower 	 * Pull packet off interface.  Off is nonzero if packet
70037110Ssklower 	 * has trailing header; if_vbaget will then force this header
70137110Ssklower 	 * information to be at the front, but we still have to drop
70237110Ssklower 	 * the type and length which are at the front of any trailer data.
70337110Ssklower 	 */
70437110Ssklower 	m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0);
70537110Ssklower 	if (m == 0)
70637110Ssklower 		return;
70737110Ssklower 	ether_input(&xs->xs_if, eh, m);
70837110Ssklower 	return;
70937110Ssklower }
71037110Ssklower 
71137110Ssklower /*
71237110Ssklower  * Hang a receive request. This routine is called by exinit and excdint,
71337110Ssklower  * with interrupts disabled in both cases.
71437110Ssklower  */
71537110Ssklower exhangrcv(unit)
71637110Ssklower 	int unit;
71737110Ssklower {
71837110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
71937110Ssklower 	register struct ex_msg *bp;
72037110Ssklower 	register struct ifvba *pkb;
72137110Ssklower 	short mustint = 0;
72237110Ssklower 	union l_util {
72337110Ssklower 		u_long	l;
72437110Ssklower 		struct	i86_long i;
72537110Ssklower 	} l_util;
72637110Ssklower 
72737110Ssklower 	while (xs->xs_nrec < NREC) {
72837110Ssklower 		if (xs->xs_pkblist == (struct ifvba *)0)
72937110Ssklower 			break;
73037110Ssklower 		if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) {
73137110Ssklower 			break;
73237110Ssklower 		}
73337474Ssklower 		GetPkBuf(bp, pkb);
73437474Ssklower 		pkb->iff_mbuf = 0;
73537110Ssklower 		xs->xs_nrec += 1;
73637110Ssklower 		bp->mb_er.er_nblock = 1;
73737110Ssklower 		bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
73837110Ssklower 		l_util.l = BUSADDR(pkb->iff_buffer);
73937110Ssklower 		bp->mb_er.er_blks[0].bb_addr = l_util.i;
74037110Ssklower 		bp->mb_status |= MH_EXOS;
74137110Ssklower 		mustint = 1;
74237110Ssklower 	}
74337110Ssklower 	if (mustint == 0)
74437110Ssklower 		return;
74537110Ssklower 	movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);
74637110Ssklower }
74737110Ssklower 
74837110Ssklower /*
74937110Ssklower  * Ethernet output routine is ether_output().
75037110Ssklower  */
75137110Ssklower 
75237110Ssklower /*
75337110Ssklower  * Watchdog routine (currently not used). Might use this to get stats from EXOS.
75437110Ssklower  */
75537110Ssklower exwatch(unit)
75637110Ssklower int unit;
75737110Ssklower {
75837110Ssklower 	struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr;
75937110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
76037110Ssklower 	register struct ex_msg *bp;
76137110Ssklower 	int s = splimp();
76237110Ssklower 
76337110Ssklower 	if (xs->xs_flags & EX_STATPENDING)
76437110Ssklower 		goto exspnd;
76537110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) {
76637110Ssklower 		splx(s);
76737110Ssklower 		return;
76837110Ssklower 	}
76937110Ssklower 	xs->xs_flags |= EX_STATPENDING;
77037110Ssklower 	bp->mb_ns.ns_mask = READ_OBJ;
77137110Ssklower 	bp->mb_ns.ns_rsrv = 0;
77237110Ssklower 	bp->mb_ns.ns_nobj = 8;
77337110Ssklower 	bp->mb_ns.ns_xobj = 0;
77437110Ssklower 	bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET;
77537110Ssklower 	bp->mb_status |= MH_EXOS;
77637110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
77737110Ssklower exspnd:	splx(s);
77837110Ssklower 	xs->xs_if.if_timer = EXWATCHINTVL;
77937110Ssklower }
78037110Ssklower 
78137110Ssklower /*
78237110Ssklower  * Process an ioctl request.
78337110Ssklower  */
78437110Ssklower exioctl(ifp, cmd, data)
78537110Ssklower 	register struct ifnet *ifp;
78637110Ssklower 	int cmd;
78737110Ssklower 	caddr_t data;
78837110Ssklower {
78937110Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
79037110Ssklower 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
79137110Ssklower 	int s = splimp(), error = 0;
79237110Ssklower 
79337110Ssklower 	switch (cmd) {
79437110Ssklower 
79537110Ssklower 	case SIOCSIFADDR:
79637110Ssklower                 ifp->if_flags |= IFF_UP;
79737110Ssklower                 exinit(ifp->if_unit);
79837110Ssklower 
79937110Ssklower                 switch (ifa->ifa_addr->sa_family) {
80037110Ssklower #ifdef INET
80137110Ssklower 		case AF_INET:
80237110Ssklower 			((struct arpcom *)ifp)->ac_ipaddr =
80337110Ssklower 				IA_SIN(ifa)->sin_addr;
80437110Ssklower 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
80537110Ssklower 			break;
80637110Ssklower #endif
80737110Ssklower #ifdef NS
80837110Ssklower 		case AF_NS:
80937110Ssklower 		    {
81037110Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
81137110Ssklower 
81237110Ssklower 			if (ns_nullhost(*ina))
81337110Ssklower 				ina->x_host = *(union ns_host *)(xs->xs_addr);
81437110Ssklower 			else
81537110Ssklower 				ex_setaddr(ina->x_host.c_host,ifp->if_unit);
81637110Ssklower 			break;
81737110Ssklower 		    }
81837110Ssklower #endif
81937110Ssklower 		}
82037110Ssklower 		break;
82137110Ssklower 
82237110Ssklower 	case SIOCSIFFLAGS:
82337110Ssklower 		if ((ifp->if_flags & IFF_UP) == 0 &&
82437110Ssklower 		    xs->xs_flags & EX_RUNNING) {
82537110Ssklower 			movow(&((struct exdevice *)
82637110Ssklower 			  (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET);
82737110Ssklower 			xs->xs_flags &= ~EX_RUNNING;
82837110Ssklower 		} else if (ifp->if_flags & IFF_UP &&
82937110Ssklower 		    (xs->xs_flags & EX_RUNNING) == 0)
83037110Ssklower 			exinit(ifp->if_unit);
83137110Ssklower 		break;
83237110Ssklower 
83337110Ssklower 	default:
83437110Ssklower 		error = EINVAL;
83537110Ssklower 	}
83637110Ssklower 	splx(s);
83737110Ssklower 	return (error);
83837110Ssklower }
83937110Ssklower 
84037110Ssklower /*
84137110Ssklower  * set ethernet address for unit
84237110Ssklower  */
84337110Ssklower ex_setaddr(physaddr, unit)
84437110Ssklower 	u_char *physaddr;
84537110Ssklower 	int unit;
84637110Ssklower {
84737110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
84837110Ssklower 
84937110Ssklower 	if (physaddr) {
85037110Ssklower 		xs->xs_flags |= EX_SETADDR;
85137110Ssklower 		bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
85237110Ssklower 	}
85337474Ssklower 	ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
85437474Ssklower }
85537474Ssklower 
85637474Ssklower /*
85737474Ssklower  * Enable multicast reception for unit.
85837474Ssklower  */
85937474Ssklower ex_setmulti(linkaddr, unit, slot)
86037474Ssklower 	u_char *linkaddr;
86137474Ssklower 	int unit, slot;
86237474Ssklower {
86337474Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
86437474Ssklower 	struct vba_device *ui = exinfo[unit];
86537474Ssklower 	register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
86637474Ssklower 	register struct ex_msg *bp;
86737474Ssklower 
86837474Ssklower 	if (!(xs->xs_flags & EX_RUNNING))
86937110Ssklower 		return;
87037474Ssklower 	bp = exgetcbuf(xs, LLNET_ADDRS);
87137110Ssklower 	bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
87237474Ssklower 	bp->mb_na.na_slot = slot;
87337474Ssklower 	bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
87437110Ssklower 	bp->mb_status |= MH_EXOS;
87537110Ssklower 	movow(&addr->ex_portb, EX_NTRUPT);
87637110Ssklower 	bp = xs->xs_x2hnext;
87737474Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
87837110Ssklower #ifdef	DEBUG
87937474Ssklower 	log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
88037474Ssklower 		(slot == PHYSSLOT ? "reset addr" : "add multicast"
88137474Ssklower 		ether_sprintf(bp->mb_na.na_addrs), slot);
88237110Ssklower #endif
88337110Ssklower 	/*
88437474Ssklower 	 * Now, re-enable reception on slot.
88537110Ssklower 	 */
88637474Ssklower 	bp = exgetcbuf(xs, LLNET_RECV);
88737110Ssklower 	bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
88837474Ssklower 	bp->mb_nr.nr_slot = slot;
88937110Ssklower 	bp->mb_status |= MH_EXOS;
89037110Ssklower 	movow(&addr->ex_portb, EX_NTRUPT);
89137110Ssklower 	bp = xs->xs_x2hnext;
89237474Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
89337110Ssklower 		;
89437110Ssklower }
89537110Ssklower #endif
896