xref: /csrg-svn/sys/tahoe/if/if_ex.c (revision 37110)
1*37110Ssklower /*
2*37110Ssklower  * Copyright (c) 1989 The Regents of the University of California.
3*37110Ssklower  * All rights reserved.
4*37110Ssklower  *
5*37110Ssklower  * This code is derived from software contributed to Berkeley by
6*37110Ssklower  * Excelan Inc.
7*37110Ssklower  *
8*37110Ssklower  * Redistribution and use in source and binary forms are permitted
9*37110Ssklower  * provided that the above copyright notice and this paragraph are
10*37110Ssklower  * duplicated in all such forms and that any documentation,
11*37110Ssklower  * advertising materials, and other materials related to such
12*37110Ssklower  * distribution and use acknowledge that the software was developed
13*37110Ssklower  * by the University of California, Berkeley.  The name of the
14*37110Ssklower  * University may not be used to endorse or promote products derived
15*37110Ssklower  * from this software without specific prior written permission.
16*37110Ssklower  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*37110Ssklower  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*37110Ssklower  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*37110Ssklower  *
20*37110Ssklower  *	@(#)if_ex.c	7.1 (Berkeley) 03/09/89
21*37110Ssklower  */
22*37110Ssklower 
23*37110Ssklower #include "ex.h"
24*37110Ssklower 
25*37110Ssklower #if	NEX > 0
26*37110Ssklower 
27*37110Ssklower /*
28*37110Ssklower  * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers
29*37110Ssklower  */
30*37110Ssklower #include "param.h"
31*37110Ssklower #include "systm.h"
32*37110Ssklower #include "mbuf.h"
33*37110Ssklower #include "buf.h"
34*37110Ssklower #include "protosw.h"
35*37110Ssklower #include "socket.h"
36*37110Ssklower #include "vmmac.h"
37*37110Ssklower #include "ioctl.h"
38*37110Ssklower #include "errno.h"
39*37110Ssklower #include "vmparam.h"
40*37110Ssklower #include "syslog.h"
41*37110Ssklower #include "uio.h"
42*37110Ssklower 
43*37110Ssklower #include "../net/if.h"
44*37110Ssklower #include "../net/netisr.h"
45*37110Ssklower #include "../net/route.h"
46*37110Ssklower 
47*37110Ssklower #ifdef INET
48*37110Ssklower #include "../netinet/in.h"
49*37110Ssklower #include "../netinet/in_systm.h"
50*37110Ssklower #include "../netinet/in_var.h"
51*37110Ssklower #include "../netinet/ip.h"
52*37110Ssklower #include "../netinet/if_ether.h"
53*37110Ssklower #endif
54*37110Ssklower 
55*37110Ssklower #ifdef NS
56*37110Ssklower #include "../netns/ns.h"
57*37110Ssklower #include "../netns/ns_if.h"
58*37110Ssklower #endif
59*37110Ssklower 
60*37110Ssklower #include "../tahoe/cpu.h"
61*37110Ssklower #include "../tahoe/pte.h"
62*37110Ssklower #include "../tahoe/mtpr.h"
63*37110Ssklower 
64*37110Ssklower #include "../tahoevba/vbavar.h"
65*37110Ssklower #include "if_exreg.h"
66*37110Ssklower #include "if_vba.h"
67*37110Ssklower 
68*37110Ssklower 
69*37110Ssklower #define	NH2X 32			/* Host to eXcelan request buffers */
70*37110Ssklower 
71*37110Ssklower #define	NX2H 16			/* eXcelan to Host reply buffers */
72*37110Ssklower #define	NREC	16		/* Number of RECeive buffers */
73*37110Ssklower #define	NTRB	4		/* Number of TRansmit Buffers */
74*37110Ssklower #define NVBI	(NREC + NTRB)
75*37110Ssklower 
76*37110Ssklower #define EXWATCHINTVL	10	/* call exwatch every x secs */
77*37110Ssklower 
78*37110Ssklower int	exprobe(), exslave(), exattach(), exintr(), exstart();
79*37110Ssklower struct	vba_device *exinfo[NEX];
80*37110Ssklower 
81*37110Ssklower long	exstd[] = { 0 };
82*37110Ssklower 
83*37110Ssklower 
84*37110Ssklower struct	vba_driver exdriver =
85*37110Ssklower 	{ exprobe, 0, exattach, exstart, exstd, "ex", exinfo };
86*37110Ssklower int	exinit(),ether_output(),exioctl(),exreset(),exwatch();
87*37110Ssklower struct	ex_msg *exgetcbuf();
88*37110Ssklower int	ex_ncall = 0;			/* counts calls to exprobe */
89*37110Ssklower u_long	busoff;
90*37110Ssklower 
91*37110Ssklower /*
92*37110Ssklower  * Ethernet software status per interface.
93*37110Ssklower  *
94*37110Ssklower  * Each interface is referenced by a network interface structure, xs_if, which
95*37110Ssklower  * the routing code uses to locate the interface.  This structure contains the
96*37110Ssklower  * output queue for the interface, its address, ... NOTE: To configure multiple
97*37110Ssklower  * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr).
98*37110Ssklower  */
99*37110Ssklower struct	ex_softc {
100*37110Ssklower 	struct		arpcom xs_ac;	/* Ethernet common part */
101*37110Ssklower #define	xs_if		xs_ac.ac_if	/* network-visible interface */
102*37110Ssklower #define	xs_addr		xs_ac.ac_enaddr	/* hardware Ethernet address */
103*37110Ssklower 	int		xs_flags;	/* private flags */
104*37110Ssklower #define	EX_XPENDING	1		/* xmit rqst pending on EXOS */
105*37110Ssklower #define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */
106*37110Ssklower #define	EX_RUNNING	(1<<2)		/* board is running */
107*37110Ssklower #define EX_SETADDR	(1<<3)		/* physaddr has been changed */
108*37110Ssklower 	int		xs_cvec;	/* probe stores cvec here */
109*37110Ssklower 	short		xs_enetunit;	/* unit number for enet filtering */
110*37110Ssklower 	short		xs_enetinit;	/* enet inetrface is initialized */
111*37110Ssklower 	struct	ex_msg	*xs_h2xnext;	/* host pointer to request queue */
112*37110Ssklower 	struct	ex_msg 	*xs_x2hnext;	/* host pointer to reply queue */
113*37110Ssklower 	u_long		xs_qbaddr;	/* map info for structs below */
114*37110Ssklower 	/* the following structures are always mapped in */
115*37110Ssklower 	u_short		xs_h2xhdr;	/* EXOS's request queue header */
116*37110Ssklower 	u_short		xs_x2hhdr;	/* EXOS's reply queue header */
117*37110Ssklower 	struct ex_msg 	xs_h2xent[NH2X];/* request msg buffers */
118*37110Ssklower 	struct ex_msg 	xs_x2hent[NX2H];/* reply msg buffers */
119*37110Ssklower 	struct confmsg	xs_cm;		/* configuration message */
120*37110Ssklower 	struct stat_array xs_xsa;	/* EXOS writes stats here */
121*37110Ssklower 	/* end mapped area */
122*37110Ssklower #define	BUSADDR(x)	((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFFF)) + busoff)
123*37110Ssklower #define	P_BUSADDR(x)	((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFF0)) + busoff)
124*37110Ssklower #define	INCORE_BASE(p)	(((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0)
125*37110Ssklower #define	RVAL_OFF(n)	((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0]))
126*37110Ssklower #define	LVAL_OFF(n)	((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0]))
127*37110Ssklower #define	H2XHDR_OFFSET	RVAL_OFF(xs_h2xhdr)
128*37110Ssklower #define	X2HHDR_OFFSET	RVAL_OFF(xs_x2hhdr)
129*37110Ssklower #define	H2XENT_OFFSET	LVAL_OFF(xs_h2xent)
130*37110Ssklower #define	X2HENT_OFFSET	LVAL_OFF(xs_x2hent)
131*37110Ssklower #define	CM_OFFSET	RVAL_OFF(xs_cm)
132*37110Ssklower #define	SA_OFFSET	RVAL_OFF(xs_xsa)
133*37110Ssklower #define FreePkBuf(b) (((b)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\
134*37110Ssklower 							(xs->xs_pkblist = b))
135*37110Ssklower 	struct		ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */
136*37110Ssklower 	struct		ifvba *xs_pkblist; /* free list of above */
137*37110Ssklower 	char		xs_nrec;	/* number of pending receive buffers */
138*37110Ssklower 	char		xs_ntrb;	/* number of pending transmit buffers */
139*37110Ssklower 	char		pad[6];		/* make BUSADDR macros */
140*37110Ssklower } ex_softc[NEX];
141*37110Ssklower 
142*37110Ssklower int ex_padcheck = sizeof (struct ex_softc);
143*37110Ssklower 
144*37110Ssklower exprobe(reg, vi)
145*37110Ssklower 	caddr_t reg;
146*37110Ssklower 	struct vba_device *vi;
147*37110Ssklower {
148*37110Ssklower 	register br, cvec;		/* r12, r11 value-result */
149*37110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)reg;
150*37110Ssklower 	int	i;
151*37110Ssklower 
152*37110Ssklower 	if (badaddr(exaddr, 2))
153*37110Ssklower 		return 0;
154*37110Ssklower 	/*
155*37110Ssklower 	 * Reset EXOS and run self-test (should complete within 2 seconds).
156*37110Ssklower 	 */
157*37110Ssklower 	movow(&exaddr->ex_porta, EX_RESET);
158*37110Ssklower 	for (i = 1000000; i; i--) {
159*37110Ssklower 		uncache(&(exaddr->ex_portb));
160*37110Ssklower 		if (exaddr->ex_portb & EX_TESTOK)
161*37110Ssklower 			break;
162*37110Ssklower 	}
163*37110Ssklower 	if ((exaddr->ex_portb & EX_TESTOK) == 0)
164*37110Ssklower 		return 0;
165*37110Ssklower 	br = 0x15;
166*37110Ssklower 	cvec = --vi->ui_hd->vh_lastiv;
167*37110Ssklower 	ex_softc[vi->ui_unit].xs_cvec = cvec;
168*37110Ssklower 	ex_ncall++;
169*37110Ssklower 	return (sizeof(struct exdevice));
170*37110Ssklower }
171*37110Ssklower 
172*37110Ssklower /*
173*37110Ssklower  * Interface exists: make available by filling in network interface record.
174*37110Ssklower  * System will initialize the interface when it is ready to accept packets.
175*37110Ssklower  * A NET_ADDRS command is done to get the ethernet address.
176*37110Ssklower  */
177*37110Ssklower exattach(ui)
178*37110Ssklower 	register struct vba_device	*ui;
179*37110Ssklower {
180*37110Ssklower 	register struct ex_softc *xs = &ex_softc[ui->ui_unit];
181*37110Ssklower 	register struct ifnet *ifp = &xs->xs_if;
182*37110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
183*37110Ssklower 	register struct ex_msg *bp;
184*37110Ssklower 
185*37110Ssklower 	ifp->if_unit = ui->ui_unit;
186*37110Ssklower 	ifp->if_name = "ex";
187*37110Ssklower 	ifp->if_mtu = ETHERMTU;
188*37110Ssklower 	ifp->if_init = exinit;
189*37110Ssklower 	ifp->if_ioctl = exioctl;
190*37110Ssklower 	ifp->if_output = ether_output;
191*37110Ssklower 	ifp->if_reset = exreset;
192*37110Ssklower 	ifp->if_start = exstart;
193*37110Ssklower 
194*37110Ssklower 	if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF) == 0)
195*37110Ssklower 		return;
196*37110Ssklower 	/*
197*37110Ssklower 	 * Temporarily map queues in order to configure EXOS
198*37110Ssklower 	 */
199*37110Ssklower 	xs->xs_qbaddr = INCORE_BASE(xs);
200*37110Ssklower 	exconfig(ui, 0);			/* without interrupts */
201*37110Ssklower 	if (xs->xs_cm.cm_cc)
202*37110Ssklower 		return;				/* bad conf */
203*37110Ssklower 	/*
204*37110Ssklower 	 * Get Ethernet address.
205*37110Ssklower 	 */
206*37110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)
207*37110Ssklower 		panic("exattach");
208*37110Ssklower 	bp->mb_na.na_mask = READ_OBJ;
209*37110Ssklower 	bp->mb_na.na_slot = PHYSSLOT;
210*37110Ssklower 	bp->mb_status |= MH_EXOS;
211*37110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
212*37110Ssklower 	bp = xs->xs_x2hnext;
213*37110Ssklower 	do {
214*37110Ssklower 		uncache(&bp->mb_status);
215*37110Ssklower 	} while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
216*37110Ssklower 	printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",
217*37110Ssklower 		ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
218*37110Ssklower 		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
219*37110Ssklower 		ether_sprintf(bp->mb_na.na_addrs));
220*37110Ssklower 	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
221*37110Ssklower 		sizeof(xs->xs_addr));
222*37110Ssklower 	if_attach(ifp);
223*37110Ssklower }
224*37110Ssklower 
225*37110Ssklower /*
226*37110Ssklower  * Reset of interface after BUS reset.
227*37110Ssklower  * If interface is on specified vba, reset its state.
228*37110Ssklower  */
229*37110Ssklower exreset(unit)
230*37110Ssklower int unit;
231*37110Ssklower {
232*37110Ssklower 	register struct vba_device *ui;
233*37110Ssklower 
234*37110Ssklower 	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)
235*37110Ssklower 		return;
236*37110Ssklower 	printf(" ex%d", unit);
237*37110Ssklower 	ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
238*37110Ssklower 	ex_softc[unit].xs_flags &= ~EX_RUNNING;
239*37110Ssklower 
240*37110Ssklower 	exinit(unit);
241*37110Ssklower }
242*37110Ssklower 
243*37110Ssklower /*
244*37110Ssklower  * Initialization of interface; clear recorded pending operations, and
245*37110Ssklower  * reinitialize BUS usage. Called at boot time, and at ifconfig time via
246*37110Ssklower  * exioctl, with interrupts disabled.
247*37110Ssklower  */
248*37110Ssklower exinit(unit)
249*37110Ssklower int unit;
250*37110Ssklower {
251*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
252*37110Ssklower 	register struct vba_device *ui = exinfo[unit];
253*37110Ssklower 	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
254*37110Ssklower 	register struct ifnet *ifp = &xs->xs_if;
255*37110Ssklower 	register struct sockaddr_in *sin;
256*37110Ssklower 	register struct ex_msg 	*bp;
257*37110Ssklower 	int s;
258*37110Ssklower 
259*37110Ssklower 	/* not yet, if address still unknown */
260*37110Ssklower 	if (ifp->if_addrlist == (struct ifaddr *)0)
261*37110Ssklower 		return;
262*37110Ssklower 	if (xs->xs_flags & EX_RUNNING)
263*37110Ssklower 		return;
264*37110Ssklower 
265*37110Ssklower 	xs->xs_qbaddr = INCORE_BASE(xs);
266*37110Ssklower 	exconfig(ui, 4);		/* with vectored interrupts*/
267*37110Ssklower 
268*37110Ssklower 	/*
269*37110Ssklower 	 * Put EXOS on the Ethernet, using NET_MODE command
270*37110Ssklower 	 */
271*37110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)
272*37110Ssklower 		panic("exinit");
273*37110Ssklower 	bp->mb_nm.nm_mask = WRITE_OBJ;
274*37110Ssklower 	bp->mb_nm.nm_optn = 0;
275*37110Ssklower 	bp->mb_nm.nm_mode = MODE_PERF;
276*37110Ssklower 	bp->mb_status |= MH_EXOS;
277*37110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
278*37110Ssklower 	bp = xs->xs_x2hnext;
279*37110Ssklower 	do {
280*37110Ssklower 		uncache(&bp->mb_status);
281*37110Ssklower 	} while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
282*37110Ssklower 	bp->mb_length = MBDATALEN;
283*37110Ssklower 	bp->mb_status |= MH_EXOS;		/* free up buffer */
284*37110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
285*37110Ssklower 	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
286*37110Ssklower 
287*37110Ssklower 	ifp->if_watchdog = exwatch;
288*37110Ssklower 	ifp->if_timer = EXWATCHINTVL;
289*37110Ssklower 	s = splimp();		/* are interrupts disabled here, anyway? */
290*37110Ssklower 	exhangrcv(unit);
291*37110Ssklower 	xs->xs_if.if_flags |= IFF_RUNNING;
292*37110Ssklower 	xs->xs_flags |= EX_RUNNING;
293*37110Ssklower 	if (xs->xs_flags & EX_SETADDR)
294*37110Ssklower 		ex_setaddr((u_char *)0, unit);
295*37110Ssklower 	exstart(&ex_softc[unit].xs_if);		/* start transmits */
296*37110Ssklower 	splx(s);		/* are interrupts disabled here, anyway? */
297*37110Ssklower }
298*37110Ssklower 
299*37110Ssklower /*
300*37110Ssklower  * Reset, test, and configure EXOS.  It is called by exinit, and exattach.
301*37110Ssklower  * Returns 0 if successful, 1 if self-test failed.
302*37110Ssklower  */
303*37110Ssklower exconfig(ui, itype)
304*37110Ssklower struct	vba_device *ui;
305*37110Ssklower int itype;
306*37110Ssklower {
307*37110Ssklower 	register int unit = ui->ui_unit;
308*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
309*37110Ssklower 	register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;
310*37110Ssklower 	register struct confmsg *cm = &xs->xs_cm;
311*37110Ssklower 	register struct ex_msg 	*bp;
312*37110Ssklower 	register struct ifvba *pkb;
313*37110Ssklower 	int 	i;
314*37110Ssklower 	u_long 	shiftreg;
315*37110Ssklower 	static	u_char	cmaddr[8] = {0xFF, 0xFF, 0, 0};
316*37110Ssklower 
317*37110Ssklower 	xs->xs_flags = 0;
318*37110Ssklower 	/*
319*37110Ssklower 	 * Reset EXOS, wait for self-test to complete
320*37110Ssklower 	 */
321*37110Ssklower 	movow(&exaddr->ex_porta, EX_RESET);
322*37110Ssklower 	do {
323*37110Ssklower 		uncache(&exaddr->ex_portb);
324*37110Ssklower 	} while ((exaddr->ex_portb & EX_TESTOK) == 0) ;
325*37110Ssklower 	/*
326*37110Ssklower 	 * Set up configuration message.
327*37110Ssklower 	 */
328*37110Ssklower 	cm->cm_1rsrv = 1;
329*37110Ssklower 	cm->cm_cc = 0xFF;
330*37110Ssklower 	cm->cm_opmode = 0;		/* link-level controller mode */
331*37110Ssklower 	cm->cm_dfo = 0x0101;		/* enable host data order conversion */
332*37110Ssklower 	cm->cm_dcn1 = 1;
333*37110Ssklower 	cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
334*37110Ssklower 	cm->cm_ham = 3;			/* absolute address mode */
335*37110Ssklower 	cm->cm_3rsrv = 0;
336*37110Ssklower 	cm->cm_mapsiz = 0;
337*37110Ssklower 	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */
338*37110Ssklower 	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */
339*37110Ssklower 	cm->cm_byteptrn[2] = 0x07;
340*37110Ssklower 	cm->cm_byteptrn[3] = 0x0F;
341*37110Ssklower 	cm->cm_wordptrn[0] = 0x0103;
342*37110Ssklower 	cm->cm_wordptrn[1] = 0x070F;
343*37110Ssklower 	cm->cm_lwordptrn = 0x0103070F;
344*37110Ssklower 	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
345*37110Ssklower 	cm->cm_mba = 0xFFFFFFFF;
346*37110Ssklower 	cm->cm_nproc = 0xFF;
347*37110Ssklower 	cm->cm_nmbox = 0xFF;
348*37110Ssklower 	cm->cm_nmcast = 0xFF;
349*37110Ssklower 	cm->cm_nhost = 1;
350*37110Ssklower 	cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);
351*37110Ssklower 	cm->cm_h2xhdr = H2XHDR_OFFSET;
352*37110Ssklower 	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */
353*37110Ssklower 	cm->cm_x2hba = cm->cm_h2xba;
354*37110Ssklower 	cm->cm_x2hhdr = X2HHDR_OFFSET;
355*37110Ssklower 	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */
356*37110Ssklower 	cm->cm_x2haddr = xs->xs_cvec;	/* ivec allocated in exprobe */
357*37110Ssklower 	/*
358*37110Ssklower 	 * Set up message queues and headers.
359*37110Ssklower 	 * First the request queue
360*37110Ssklower 	 */
361*37110Ssklower 	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
362*37110Ssklower 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
363*37110Ssklower 		bp->mb_rsrv = 0;
364*37110Ssklower 		bp->mb_length = MBDATALEN;
365*37110Ssklower 		bp->mb_status = MH_HOST;
366*37110Ssklower 		bp->mb_next = bp+1;
367*37110Ssklower 	}
368*37110Ssklower 	xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;
369*37110Ssklower 	xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
370*37110Ssklower 
371*37110Ssklower 	/* Now the reply queue. */
372*37110Ssklower 	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
373*37110Ssklower 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
374*37110Ssklower 		bp->mb_rsrv = 0;
375*37110Ssklower 		bp->mb_length = MBDATALEN;
376*37110Ssklower 		bp->mb_status = MH_EXOS;
377*37110Ssklower 		bp->mb_next = bp+1;
378*37110Ssklower 	}
379*37110Ssklower 	xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;
380*37110Ssklower 	xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
381*37110Ssklower 	xs->xs_nrec = 0;
382*37110Ssklower 	xs->xs_ntrb = 0;
383*37110Ssklower 	xs->xs_pkblist =  xs->xs_vbinfo + NVBI - 1;
384*37110Ssklower 	for (pkb = xs->xs_pkblist; pkb >= xs->xs_vbinfo; pkb--)
385*37110Ssklower 		pkb->iff_mbuf = (struct mbuf *)(pkb - 1);
386*37110Ssklower 	xs->xs_vbinfo[0].iff_mbuf = 0;
387*37110Ssklower 
388*37110Ssklower 	/*
389*37110Ssklower 	 * Write config msg address to EXOS and wait for configuration to
390*37110Ssklower 	 * complete (guaranteed response within 2 seconds).
391*37110Ssklower 	 */
392*37110Ssklower 	shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;
393*37110Ssklower 	for (i = 4; i < 8; i++) {
394*37110Ssklower 		cmaddr[i] = (u_char)(shiftreg & 0xFF);
395*37110Ssklower 		shiftreg >>= 8;
396*37110Ssklower 	}
397*37110Ssklower 	for (i = 0; i < 8; i++) {
398*37110Ssklower 		do {
399*37110Ssklower 			uncache(&exaddr->ex_portb);
400*37110Ssklower 		} while (exaddr->ex_portb & EX_UNREADY) ;
401*37110Ssklower 		DELAY(500);
402*37110Ssklower 		movow(&exaddr->ex_portb, cmaddr[i]);
403*37110Ssklower 	}
404*37110Ssklower 	for (i = 500000; i; --i) {
405*37110Ssklower 		DELAY(10);
406*37110Ssklower 		uncache(&cm->cm_cc);
407*37110Ssklower 		if (cm->cm_cc != 0xFF)
408*37110Ssklower 			break;
409*37110Ssklower 	}
410*37110Ssklower 	if (cm->cm_cc)
411*37110Ssklower 		printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);
412*37110Ssklower }
413*37110Ssklower 
414*37110Ssklower /*
415*37110Ssklower  * Start or re-start output on interface. Get another datagram to send off of
416*37110Ssklower  * the interface queue, and map it to the interface before starting the output.
417*37110Ssklower  * This routine is called by exinit(), exoutput(), and excdint().  In all cases,
418*37110Ssklower  * interrupts by EXOS are disabled.
419*37110Ssklower  */
420*37110Ssklower exstart(ifp)
421*37110Ssklower struct ifnet *ifp;
422*37110Ssklower {
423*37110Ssklower 	int unit = ifp->if_unit;
424*37110Ssklower 	struct vba_device *ui = exinfo[unit];
425*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
426*37110Ssklower 	struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
427*37110Ssklower 	register struct ex_msg *bp;
428*37110Ssklower 	register struct mbuf *m;
429*37110Ssklower         int len;
430*37110Ssklower 	register struct ifvba *pkb;
431*37110Ssklower 	struct mbuf *m0;
432*37110Ssklower 	register int nb, tlen;
433*37110Ssklower 	union l_util {
434*37110Ssklower 		u_long	l;
435*37110Ssklower 		struct	i86_long i;
436*37110Ssklower 	} l_util;
437*37110Ssklower 
438*37110Ssklower 	if (xs->xs_ntrb >= NTRB)
439*37110Ssklower 		return;
440*37110Ssklower 	if (xs->xs_pkblist == 0) {
441*37110Ssklower 		printf("ex%d: vbinfo exhausted, would panic", unit);
442*37110Ssklower 		return;
443*37110Ssklower 	}
444*37110Ssklower 	IF_DEQUEUE(&xs->xs_if.if_snd, m);
445*37110Ssklower 	if (m == 0)
446*37110Ssklower 		return;
447*37110Ssklower 	/*
448*37110Ssklower 	 * Get a transmit request.
449*37110Ssklower 	 */
450*37110Ssklower 	if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) {
451*37110Ssklower 		m_freem(m);
452*37110Ssklower 		printf("exstart: no command buffers\n");
453*37110Ssklower 		return;
454*37110Ssklower 	}
455*37110Ssklower 	xs->xs_ntrb++;
456*37110Ssklower 	bp->mb_pkb = pkb = xs->xs_pkblist;
457*37110Ssklower 	xs->xs_pkblist = (struct ifvba *)pkb->iff_mbuf;
458*37110Ssklower 	nb = 0; tlen = 0; m0 = 0;
459*37110Ssklower 	pkb->iff_mbuf = m;	/* save mbuf pointer to free when done */
460*37110Ssklower 	/*
461*37110Ssklower 	 * point directly to the first group of mbufs to be transmitted. The
462*37110Ssklower 	 * hardware can only support NFRAGMENTS descriptors.
463*37110Ssklower 	 */
464*37110Ssklower 	while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) {
465*37110Ssklower 		l_util.l = BUSADDR(mtod(m, char *));
466*37110Ssklower 		bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len;
467*37110Ssklower 		bp->mb_et.et_blks[nb].bb_addr = l_util.i;
468*37110Ssklower 		tlen += m->m_len;
469*37110Ssklower 		m0 = m;
470*37110Ssklower 		m = m->m_next;
471*37110Ssklower 		nb++;
472*37110Ssklower 	}
473*37110Ssklower 
474*37110Ssklower 	/* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */
475*37110Ssklower 	if (m0)
476*37110Ssklower 		m0->m_next = 0;
477*37110Ssklower 
478*37110Ssklower 	/*
479*37110Ssklower 	 * if not all of the descriptors would fit then merge remaining data
480*37110Ssklower 	 * into the transmit buffer, and point to it.  Note: the mbufs are freed
481*37110Ssklower 	 * during the merge, they do not have to be freed when we get the
482*37110Ssklower 	 * transmit interrupt.
483*37110Ssklower 	 */
484*37110Ssklower 	if (m) {
485*37110Ssklower 		len = if_vbaput(pkb->iff_buffer, m);
486*37110Ssklower 		l_util.l = BUSADDR(pkb->iff_buffer);
487*37110Ssklower 		bp->mb_et.et_blks[nb].bb_len = (u_short)len;
488*37110Ssklower 		bp->mb_et.et_blks[nb].bb_addr = l_util.i;
489*37110Ssklower 		tlen += len;
490*37110Ssklower 		nb++;
491*37110Ssklower 	}
492*37110Ssklower 
493*37110Ssklower 	/*
494*37110Ssklower 	 * If the total length of the packet is too small, pad the last frag
495*37110Ssklower 	 */
496*37110Ssklower 	if (tlen - sizeof(struct ether_header) < ETHERMIN) {
497*37110Ssklower 		len = (ETHERMIN + sizeof(struct ether_header)) - tlen;
498*37110Ssklower 		bp->mb_et.et_blks[nb-1].bb_len += (u_short)len;
499*37110Ssklower 		tlen += len;
500*37110Ssklower 	}
501*37110Ssklower 
502*37110Ssklower 	/* set number of fragments in descriptor */
503*37110Ssklower 	bp->mb_et.et_nblock = nb;
504*37110Ssklower 	bp->mb_status |= MH_EXOS;
505*37110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
506*37110Ssklower }
507*37110Ssklower 
508*37110Ssklower /*
509*37110Ssklower  * interrupt service routine.
510*37110Ssklower  */
511*37110Ssklower exintr(unit)
512*37110Ssklower 	int unit;
513*37110Ssklower {
514*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
515*37110Ssklower 	register struct ex_msg *bp = xs->xs_x2hnext;
516*37110Ssklower 	struct vba_device *ui = exinfo[unit];
517*37110Ssklower 	struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
518*37110Ssklower 
519*37110Ssklower 	uncache(&bp->mb_status);
520*37110Ssklower 	while ((bp->mb_status & MH_OWNER) == MH_HOST) {
521*37110Ssklower 		switch (bp->mb_rqst) {
522*37110Ssklower 		    case LLRECEIVE:
523*37110Ssklower 			if (--xs->xs_nrec < 0)
524*37110Ssklower 				xs->xs_nrec = 0;
525*37110Ssklower 			exrecv(unit, bp);
526*37110Ssklower 			FreePkBuf(bp->mb_pkb);
527*37110Ssklower 			bp->mb_pkb = (struct ifvba *)0;
528*37110Ssklower 			exhangrcv(unit);
529*37110Ssklower 			break;
530*37110Ssklower 
531*37110Ssklower 		    case LLTRANSMIT:
532*37110Ssklower 		    case LLRTRANSMIT:
533*37110Ssklower 			if (--xs->xs_ntrb < 0)
534*37110Ssklower 				xs->xs_ntrb = 0;
535*37110Ssklower 			xs->xs_if.if_opackets++;
536*37110Ssklower 			if (bp->mb_rply == LL_OK)
537*37110Ssklower 				;
538*37110Ssklower 			else if (bp->mb_rply & LLXM_1RTRY)
539*37110Ssklower 				xs->xs_if.if_collisions++;
540*37110Ssklower 			else if (bp->mb_rply & LLXM_RTRYS)
541*37110Ssklower 				xs->xs_if.if_collisions += 2;	/* guess */
542*37110Ssklower 			else if (bp->mb_rply & LLXM_ERROR)
543*37110Ssklower 				if (xs->xs_if.if_oerrors++ % 100 == 0)
544*37110Ssklower 					printf("ex%d: 100 transmit errors=%b\n",
545*37110Ssklower 						unit, bp->mb_rply, XMIT_BITS);
546*37110Ssklower 			if (bp->mb_pkb->iff_mbuf) {
547*37110Ssklower 				m_freem(bp->mb_pkb->iff_mbuf);
548*37110Ssklower 				bp->mb_pkb->iff_mbuf = (struct mbuf *)0;
549*37110Ssklower 			}
550*37110Ssklower 			FreePkBuf(bp->mb_pkb);
551*37110Ssklower 			bp->mb_pkb = (struct ifvba *)0;
552*37110Ssklower 			exstart(&ex_softc[unit].xs_if);
553*37110Ssklower 			exhangrcv(unit);
554*37110Ssklower 			break;
555*37110Ssklower 
556*37110Ssklower 		    case LLNET_STSTCS:
557*37110Ssklower 			xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc;
558*37110Ssklower 			xs->xs_flags &= ~EX_STATPENDING;
559*37110Ssklower 			break;
560*37110Ssklower 
561*37110Ssklower 		    default:
562*37110Ssklower 			printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst);
563*37110Ssklower 		}
564*37110Ssklower 		bp->mb_length = MBDATALEN;
565*37110Ssklower 		bp->mb_status |= MH_EXOS;	/* free up buffer */
566*37110Ssklower 		movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */
567*37110Ssklower 		bp = bp->mb_next;
568*37110Ssklower 		uncache(&bp->mb_status);
569*37110Ssklower 	}
570*37110Ssklower 	xs->xs_x2hnext = bp;
571*37110Ssklower }
572*37110Ssklower 
573*37110Ssklower /*
574*37110Ssklower  * Get a request buffer, fill in standard values, advance pointer.
575*37110Ssklower  */
576*37110Ssklower struct ex_msg *
577*37110Ssklower exgetcbuf(xs, req)
578*37110Ssklower struct ex_softc *xs;
579*37110Ssklower int req;
580*37110Ssklower {
581*37110Ssklower 	register struct ex_msg *bp;
582*37110Ssklower 	struct ifvba *pkb;
583*37110Ssklower 	int s = splimp();
584*37110Ssklower 
585*37110Ssklower 	bp = xs->xs_h2xnext;
586*37110Ssklower 	uncache(&bp->mb_status);
587*37110Ssklower 	if ((bp->mb_status & MH_OWNER) == MH_EXOS) {
588*37110Ssklower 		splx(s);
589*37110Ssklower 		return (struct ex_msg *)0;
590*37110Ssklower 	}
591*37110Ssklower 	xs->xs_h2xnext = bp->mb_next;
592*37110Ssklower 	bp->mb_1rsrv = 0;
593*37110Ssklower 	bp->mb_rqst = req;
594*37110Ssklower 	bp->mb_length = MBDATALEN;
595*37110Ssklower 	bp->mb_pkb = (struct ifvba *)0;
596*37110Ssklower 	splx(s);
597*37110Ssklower 	return bp;
598*37110Ssklower }
599*37110Ssklower 
600*37110Ssklower /*
601*37110Ssklower  * Process Ethernet receive completion:  If input error just drop packet,
602*37110Ssklower  * otherwise examine packet to determine type.  If can't determine length from
603*37110Ssklower  * type, then have to drop packet, otherwise decapsulate packet based on type
604*37110Ssklower  * and pass to type-specific higher-level input routine.
605*37110Ssklower  */
606*37110Ssklower exrecv(unit, bp)
607*37110Ssklower int unit;
608*37110Ssklower register struct ex_msg *bp;
609*37110Ssklower {
610*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
611*37110Ssklower 	register struct ether_header *eh;
612*37110Ssklower     	register struct mbuf *m;
613*37110Ssklower 	int len, off, resid;
614*37110Ssklower 	register struct ifqueue *inq;
615*37110Ssklower 	int s;
616*37110Ssklower 
617*37110Ssklower 	xs->xs_if.if_ipackets++;
618*37110Ssklower 	/*     total length               - header                      - crc */
619*37110Ssklower 	len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
620*37110Ssklower 	if (bp->mb_rply != LL_OK) {
621*37110Ssklower 		if (xs->xs_if.if_ierrors++ % 100 == 0)
622*37110Ssklower 			printf("ex%d: 100 receive errors=%b\n",
623*37110Ssklower 				unit, bp->mb_rply, RECV_BITS);
624*37110Ssklower 		return;
625*37110Ssklower 	}
626*37110Ssklower 	eh = (struct ether_header *)(bp->mb_pkb->iff_buffer);
627*37110Ssklower 
628*37110Ssklower 	/*
629*37110Ssklower 	 * Deal with trailer protocol: if type is PUP trailer get true type from
630*37110Ssklower 	 * first 16-bit word past data.  Remember that type was trailer by
631*37110Ssklower 	 * setting off.
632*37110Ssklower 	 */
633*37110Ssklower 	eh->ether_type = ntohs((u_short)eh->ether_type);
634*37110Ssklower #define	exdataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
635*37110Ssklower 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
636*37110Ssklower 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
637*37110Ssklower 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
638*37110Ssklower 		if (off >= ETHERMTU)
639*37110Ssklower 			return;			/* sanity */
640*37110Ssklower 		eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
641*37110Ssklower 		resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
642*37110Ssklower 		if (off + resid > len)
643*37110Ssklower 			return;			/* sanity */
644*37110Ssklower 		len = off + resid;
645*37110Ssklower 	} else
646*37110Ssklower 		off = 0;
647*37110Ssklower 	if (len == 0)
648*37110Ssklower 		return;
649*37110Ssklower 	/*
650*37110Ssklower 	 * Pull packet off interface.  Off is nonzero if packet
651*37110Ssklower 	 * has trailing header; if_vbaget will then force this header
652*37110Ssklower 	 * information to be at the front, but we still have to drop
653*37110Ssklower 	 * the type and length which are at the front of any trailer data.
654*37110Ssklower 	 */
655*37110Ssklower 	m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0);
656*37110Ssklower 	if (m == 0)
657*37110Ssklower 		return;
658*37110Ssklower 	ether_input(&xs->xs_if, eh, m);
659*37110Ssklower 	return;
660*37110Ssklower }
661*37110Ssklower 
662*37110Ssklower /*
663*37110Ssklower  * Hang a receive request. This routine is called by exinit and excdint,
664*37110Ssklower  * with interrupts disabled in both cases.
665*37110Ssklower  */
666*37110Ssklower exhangrcv(unit)
667*37110Ssklower 	int unit;
668*37110Ssklower {
669*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
670*37110Ssklower 	register struct ex_msg *bp;
671*37110Ssklower 	register struct ifvba *pkb;
672*37110Ssklower 	short mustint = 0;
673*37110Ssklower 	union l_util {
674*37110Ssklower 		u_long	l;
675*37110Ssklower 		struct	i86_long i;
676*37110Ssklower 	} l_util;
677*37110Ssklower 
678*37110Ssklower 	while (xs->xs_nrec < NREC) {
679*37110Ssklower 		if (xs->xs_pkblist == (struct ifvba *)0)
680*37110Ssklower 			break;
681*37110Ssklower 		if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) {
682*37110Ssklower 			break;
683*37110Ssklower 		}
684*37110Ssklower 		pkb = bp->mb_pkb = xs->xs_pkblist;
685*37110Ssklower 		xs->xs_pkblist = (struct ifvba *)bp->mb_pkb->iff_mbuf;
686*37110Ssklower 
687*37110Ssklower 		xs->xs_nrec += 1;
688*37110Ssklower 		bp->mb_er.er_nblock = 1;
689*37110Ssklower 		bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
690*37110Ssklower 		l_util.l = BUSADDR(pkb->iff_buffer);
691*37110Ssklower 		bp->mb_er.er_blks[0].bb_addr = l_util.i;
692*37110Ssklower 		bp->mb_status |= MH_EXOS;
693*37110Ssklower 		mustint = 1;
694*37110Ssklower 	}
695*37110Ssklower 	if (mustint == 0)
696*37110Ssklower 		return;
697*37110Ssklower 	movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);
698*37110Ssklower }
699*37110Ssklower 
700*37110Ssklower /*
701*37110Ssklower  * Ethernet output routine is ether_output().
702*37110Ssklower  */
703*37110Ssklower 
704*37110Ssklower /*
705*37110Ssklower  * Watchdog routine (currently not used). Might use this to get stats from EXOS.
706*37110Ssklower  */
707*37110Ssklower exwatch(unit)
708*37110Ssklower int unit;
709*37110Ssklower {
710*37110Ssklower 	struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr;
711*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
712*37110Ssklower 	register struct ex_msg *bp;
713*37110Ssklower 	int s = splimp();
714*37110Ssklower 
715*37110Ssklower 	if (xs->xs_flags & EX_STATPENDING)
716*37110Ssklower 		goto exspnd;
717*37110Ssklower 	if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) {
718*37110Ssklower 		splx(s);
719*37110Ssklower 		return;
720*37110Ssklower 	}
721*37110Ssklower 	xs->xs_flags |= EX_STATPENDING;
722*37110Ssklower 	bp->mb_ns.ns_mask = READ_OBJ;
723*37110Ssklower 	bp->mb_ns.ns_rsrv = 0;
724*37110Ssklower 	bp->mb_ns.ns_nobj = 8;
725*37110Ssklower 	bp->mb_ns.ns_xobj = 0;
726*37110Ssklower 	bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET;
727*37110Ssklower 	bp->mb_status |= MH_EXOS;
728*37110Ssklower 	movow(&exaddr->ex_portb, EX_NTRUPT);
729*37110Ssklower exspnd:	splx(s);
730*37110Ssklower 	xs->xs_if.if_timer = EXWATCHINTVL;
731*37110Ssklower }
732*37110Ssklower 
733*37110Ssklower /*
734*37110Ssklower  * Process an ioctl request.
735*37110Ssklower  */
736*37110Ssklower exioctl(ifp, cmd, data)
737*37110Ssklower 	register struct ifnet *ifp;
738*37110Ssklower 	int cmd;
739*37110Ssklower 	caddr_t data;
740*37110Ssklower {
741*37110Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
742*37110Ssklower 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
743*37110Ssklower 	int s = splimp(), error = 0;
744*37110Ssklower 
745*37110Ssklower 	switch (cmd) {
746*37110Ssklower 
747*37110Ssklower 	case SIOCSIFADDR:
748*37110Ssklower                 ifp->if_flags |= IFF_UP;
749*37110Ssklower                 exinit(ifp->if_unit);
750*37110Ssklower 
751*37110Ssklower                 switch (ifa->ifa_addr->sa_family) {
752*37110Ssklower #ifdef INET
753*37110Ssklower 		case AF_INET:
754*37110Ssklower 			((struct arpcom *)ifp)->ac_ipaddr =
755*37110Ssklower 				IA_SIN(ifa)->sin_addr;
756*37110Ssklower 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
757*37110Ssklower 			break;
758*37110Ssklower #endif
759*37110Ssklower #ifdef NS
760*37110Ssklower 		case AF_NS:
761*37110Ssklower 		    {
762*37110Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
763*37110Ssklower 
764*37110Ssklower 			if (ns_nullhost(*ina))
765*37110Ssklower 				ina->x_host = *(union ns_host *)(xs->xs_addr);
766*37110Ssklower 			else
767*37110Ssklower 				ex_setaddr(ina->x_host.c_host,ifp->if_unit);
768*37110Ssklower 			break;
769*37110Ssklower 		    }
770*37110Ssklower #endif
771*37110Ssklower 		}
772*37110Ssklower 		break;
773*37110Ssklower 
774*37110Ssklower 	case SIOCSIFFLAGS:
775*37110Ssklower 		if ((ifp->if_flags & IFF_UP) == 0 &&
776*37110Ssklower 		    xs->xs_flags & EX_RUNNING) {
777*37110Ssklower 			movow(&((struct exdevice *)
778*37110Ssklower 			  (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET);
779*37110Ssklower 			xs->xs_flags &= ~EX_RUNNING;
780*37110Ssklower 		} else if (ifp->if_flags & IFF_UP &&
781*37110Ssklower 		    (xs->xs_flags & EX_RUNNING) == 0)
782*37110Ssklower 			exinit(ifp->if_unit);
783*37110Ssklower 		break;
784*37110Ssklower 
785*37110Ssklower 	default:
786*37110Ssklower 		error = EINVAL;
787*37110Ssklower 	}
788*37110Ssklower 	splx(s);
789*37110Ssklower 	return (error);
790*37110Ssklower }
791*37110Ssklower 
792*37110Ssklower /*
793*37110Ssklower  * set ethernet address for unit
794*37110Ssklower  */
795*37110Ssklower ex_setaddr(physaddr, unit)
796*37110Ssklower 	u_char *physaddr;
797*37110Ssklower 	int unit;
798*37110Ssklower {
799*37110Ssklower 	register struct ex_softc *xs = &ex_softc[unit];
800*37110Ssklower 	struct vba_device *ui = exinfo[unit];
801*37110Ssklower 	register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
802*37110Ssklower 	register struct ex_msg *bp;
803*37110Ssklower 
804*37110Ssklower 	if (physaddr) {
805*37110Ssklower 		xs->xs_flags |= EX_SETADDR;
806*37110Ssklower 		bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
807*37110Ssklower 	}
808*37110Ssklower 	if (! (xs->xs_flags & EX_RUNNING))
809*37110Ssklower 		return;
810*37110Ssklower 	bp = exgetcbuf(xs);
811*37110Ssklower 	bp->mb_rqst = LLNET_ADDRS;
812*37110Ssklower 	bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
813*37110Ssklower 	bp->mb_na.na_slot = PHYSSLOT;
814*37110Ssklower 	bcopy((caddr_t)xs->xs_addr, (caddr_t)bp->mb_na.na_addrs, 6);
815*37110Ssklower 	bp->mb_status |= MH_EXOS;
816*37110Ssklower 	movow(&addr->ex_portb, EX_NTRUPT);
817*37110Ssklower 	bp = xs->xs_x2hnext;
818*37110Ssklower 	do {
819*37110Ssklower 		uncache(&bp->mb_status);
820*37110Ssklower 	} while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
821*37110Ssklower #ifdef	DEBUG
822*37110Ssklower 	log(LOG_DEBUG, "ex%d: reset addr %s\n", ui->ui_unit,
823*37110Ssklower 		ether_sprintf(bp->mb_na.na_addrs));
824*37110Ssklower #endif
825*37110Ssklower 	/*
826*37110Ssklower 	 * Now, re-enable reception on phys slot.
827*37110Ssklower 	 */
828*37110Ssklower 	bp = exgetcbuf(xs);
829*37110Ssklower 	bp->mb_rqst = LLNET_RECV;
830*37110Ssklower 	bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
831*37110Ssklower 	bp->mb_nr.nr_slot = PHYSSLOT;
832*37110Ssklower 	bp->mb_status |= MH_EXOS;
833*37110Ssklower 	movow(&addr->ex_portb, EX_NTRUPT);
834*37110Ssklower 	bp = xs->xs_x2hnext;
835*37110Ssklower 	do {
836*37110Ssklower 		uncache(&bp->mb_status);
837*37110Ssklower 	} while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
838*37110Ssklower 		;
839*37110Ssklower }
840*37110Ssklower #endif
841