xref: /csrg-svn/sys/vax/if/if_ex.c (revision 19880)
1*19880Skarels /*	@(#)if_ex.c	6.1 (Berkeley) 05/01/85 */
2*19880Skarels /*	from @(#)if_ex.c	1.4 (Excelan)	84/10/11 */
3*19880Skarels 
4*19880Skarels #include "ex.h"
5*19880Skarels 
6*19880Skarels /*
7*19880Skarels  * Excelan EXOS 204 Interface
8*19880Skarels  *
9*19880Skarels  *	George Powers
10*19880Skarels  *	Excelan Inc.
11*19880Skarels  */
12*19880Skarels 
13*19880Skarels #include "../machine/pte.h"
14*19880Skarels 
15*19880Skarels #include "../h/param.h"
16*19880Skarels #include "../h/systm.h"
17*19880Skarels #include "../h/mbuf.h"
18*19880Skarels #include "../h/buf.h"
19*19880Skarels #include "../h/protosw.h"
20*19880Skarels #include "../h/socket.h"
21*19880Skarels #include "../h/vmmac.h"
22*19880Skarels #include "../h/ioctl.h"
23*19880Skarels #include "../h/errno.h"
24*19880Skarels 
25*19880Skarels #include "../net/if.h"
26*19880Skarels #include "../net/netisr.h"
27*19880Skarels #include "../net/route.h"
28*19880Skarels #include "../netinet/in.h"
29*19880Skarels #include "../netinet/in_systm.h"
30*19880Skarels #include "../netinet/ip.h"
31*19880Skarels #include "../netinet/ip_var.h"
32*19880Skarels #include "../netinet/if_ether.h"
33*19880Skarels #include "../netpup/pup.h"
34*19880Skarels 
35*19880Skarels #include "../vax/cpu.h"
36*19880Skarels #include "../vax/mtpr.h"
37*19880Skarels #include "../vaxif/if_exreg.h"
38*19880Skarels #include "../vaxif/if_uba.h"
39*19880Skarels #include "../vaxuba/ubareg.h"
40*19880Skarels #include "../vaxuba/ubavar.h"
41*19880Skarels 
42*19880Skarels #define DEBUG			/* check for "impossible" events */
43*19880Skarels 
44*19880Skarels #define	NH2X 4			/* a sufficient number is critical */
45*19880Skarels #define	NX2H 4			/* this is pretty arbitrary */
46*19880Skarels #define	EXWATCHINTVL 10		/* call exwatch() every 10 seconds */
47*19880Skarels 
48*19880Skarels int	exprobe(), exattach(), excdint();
49*19880Skarels struct	uba_device *exinfo[NEX];
50*19880Skarels u_short exstd[] = { 0 };
51*19880Skarels struct	uba_driver exdriver =
52*19880Skarels 	{ exprobe, 0, exattach, 0, exstd, "ex", exinfo };
53*19880Skarels int	exinit(),exoutput(),exioctl(),exreset(),exwatch();
54*19880Skarels struct ex_msg *exgetcbuf();
55*19880Skarels 
56*19880Skarels /*
57*19880Skarels  * Ethernet software status per interface.
58*19880Skarels  *
59*19880Skarels  * Each interface is referenced by a network interface structure,
60*19880Skarels  * xs_if, which the routing code uses to locate the interface.
61*19880Skarels  * This structure contains the output queue for the interface, its address, ...
62*19880Skarels  * We also have, for each interface, a UBA interface structure, which
63*19880Skarels  * contains information about the UNIBUS resources held by the interface:
64*19880Skarels  * map registers, buffered data paths, etc.  Information is cached in this
65*19880Skarels  * structure for use by the if_uba.c routines in running the interface
66*19880Skarels  * efficiently.
67*19880Skarels  */
68*19880Skarels struct	ex_softc {
69*19880Skarels #ifdef DEBUG
70*19880Skarels 	int	xs_wait;
71*19880Skarels #endif
72*19880Skarels 	struct	arpcom xs_ac;		/* Ethernet common part */
73*19880Skarels #define	xs_if	xs_ac.ac_if		/* network-visible interface */
74*19880Skarels #define	xs_addr	xs_ac.ac_enaddr		/* hardware Ethernet address */
75*19880Skarels 	struct	ifuba xs_ifuba;		/* UNIBUS resources */
76*19880Skarels 	int	xs_flags;		/* private flags */
77*19880Skarels #define	EX_XPENDING	1		/* xmit rqst pending on EXOS */
78*19880Skarels #define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */
79*19880Skarels 	struct	ex_msg *xs_h2xnext;	/* host pointer to request queue */
80*19880Skarels 	struct	ex_msg *xs_x2hnext;	/* host pointer to reply queue */
81*19880Skarels 	u_long	xs_ubaddr;		/* map info for structs below */
82*19880Skarels #define	UNIADDR(x)	((u_long)(x)&0x3FFFF)
83*19880Skarels #define	P_UNIADDR(x)	((u_long)(x)&0x3FFF0)
84*19880Skarels 	/* the following structures are always mapped in */
85*19880Skarels 	u_short	xs_h2xhdr;		/* EXOS's request queue header */
86*19880Skarels 	u_short	xs_x2hhdr;		/* EXOS's reply queue header */
87*19880Skarels 	struct	ex_msg xs_h2xent[NH2X];	/* request msg buffers */
88*19880Skarels 	struct	ex_msg xs_x2hent[NX2H];	/* reply msg buffers */
89*19880Skarels 	struct	confmsg xs_cm;		/* configuration message */
90*19880Skarels 	struct	stat_array xs_xsa;	/* EXOS writes stats here */
91*19880Skarels 	/* end mapped area */
92*19880Skarels #define	INCORE_BASE(p)	(((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0)
93*19880Skarels #define	RVAL_OFF(n)	((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0]))
94*19880Skarels #define	LVAL_OFF(n)	((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0]))
95*19880Skarels #define	H2XHDR_OFFSET	RVAL_OFF(xs_h2xhdr)
96*19880Skarels #define	X2HHDR_OFFSET	RVAL_OFF(xs_x2hhdr)
97*19880Skarels #define	H2XENT_OFFSET	LVAL_OFF(xs_h2xent)
98*19880Skarels #define	X2HENT_OFFSET	LVAL_OFF(xs_x2hent)
99*19880Skarels #define	CM_OFFSET	RVAL_OFF(xs_cm)
100*19880Skarels #define	SA_OFFSET	RVAL_OFF(xs_xsa)
101*19880Skarels #define	INCORE_SIZE	RVAL_OFF(xs_end)
102*19880Skarels 	int	xs_end;			/* place holder */
103*19880Skarels } ex_softc[NEX];
104*19880Skarels 
105*19880Skarels /*
106*19880Skarels  * The following structure is a kludge to store a cvec value
107*19880Skarels  * between the time exprobe is called, and exconfig.
108*19880Skarels  */
109*19880Skarels struct	ex_cvecs {
110*19880Skarels 	struct	exdevice *xc_csraddr;
111*19880Skarels 	int	xc_cvec;
112*19880Skarels }ex_cvecs[NEX];
113*19880Skarels 
114*19880Skarels int	ex_ncall = 0;			/* counts calls to exprobe */
115*19880Skarels 
116*19880Skarels exprobe(reg)
117*19880Skarels 	caddr_t reg;
118*19880Skarels {
119*19880Skarels 	register int br, cvec;		/* r11, r10 value-result */
120*19880Skarels 	register struct exdevice *addr = (struct exdevice *)reg;
121*19880Skarels 	register i;
122*19880Skarels 
123*19880Skarels 	/*
124*19880Skarels 	 * We program the EXOS interrupt vector, like dmf device.
125*19880Skarels 	 */
126*19880Skarels 	br = 0x15;
127*19880Skarels 	cvec = (uba_hd[numuba].uh_lastiv -= 4);
128*19880Skarels #ifdef DEBUG
129*19880Skarels printf("exprobe%d: cvec = %o\n", ex_ncall, cvec);
130*19880Skarels #endif
131*19880Skarels 	ex_cvecs[ex_ncall].xc_csraddr = addr;
132*19880Skarels 	ex_cvecs[ex_ncall++].xc_cvec = cvec;
133*19880Skarels 	/*
134*19880Skarels 	 * Reset EXOS and run self-test (guaranteed to
135*19880Skarels 	 * complete within 2 seconds).
136*19880Skarels 	 */
137*19880Skarels 	addr->xd_porta = EX_RESET;
138*19880Skarels 	i = 1000000;
139*19880Skarels 	while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
140*19880Skarels 		;
141*19880Skarels 	if ((addr->xd_portb & EX_TESTOK) == 0) {
142*19880Skarels 		printf("ex: self-test failed\n");
143*19880Skarels 		return 0;
144*19880Skarels 	}
145*19880Skarels 	return (sizeof(struct exdevice));
146*19880Skarels }
147*19880Skarels 
148*19880Skarels /*
149*19880Skarels  * Interface exists: make available by filling in network interface
150*19880Skarels  * record.  System will initialize the interface when it is ready
151*19880Skarels  * to accept packets.  Board is temporarily configured and issues
152*19880Skarels  * a NET_ADDRS command, only to get the Ethernet address.
153*19880Skarels  */
154*19880Skarels exattach(ui)
155*19880Skarels 	struct uba_device *ui;
156*19880Skarels {
157*19880Skarels 	register struct ex_softc *xs = &ex_softc[ui->ui_unit];
158*19880Skarels 	register struct ifnet *ifp = &xs->xs_if;
159*19880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
160*19880Skarels 	struct sockaddr_in *sin;
161*19880Skarels 	register struct ex_msg *bp;
162*19880Skarels 
163*19880Skarels 	ifp->if_unit = ui->ui_unit;
164*19880Skarels 	ifp->if_name = "ex";
165*19880Skarels 	ifp->if_mtu = ETHERMTU;
166*19880Skarels 
167*19880Skarels 	/*
168*19880Skarels 	 * Temporarily map queues in order to configure EXOS
169*19880Skarels 	 */
170*19880Skarels 	xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE, 0);
171*19880Skarels 	exconfig(ui, 0);			/* without interrupts */
172*19880Skarels 	if (xs->xs_cm.cm_cc) goto badconf;
173*19880Skarels 
174*19880Skarels 	bp = exgetcbuf(xs);
175*19880Skarels 	bp->mb_rqst = LLNET_ADDRS;
176*19880Skarels 	bp->mb_na.na_mask = READ_OBJ;
177*19880Skarels 	bp->mb_na.na_slot = PHYSSLOT;
178*19880Skarels 	bp->mb_status |= MH_EXOS;
179*19880Skarels 	addr->xd_portb = EX_NTRUPT;
180*19880Skarels 	bp = xs->xs_x2hnext;
181*19880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
182*19880Skarels 		;
183*19880Skarels 	printf("ex%d: HW %c.%c, NX %c.%c, addr %x.%x.%x.%x.%x.%x\n",
184*19880Skarels 		ui->ui_unit,
185*19880Skarels 		xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
186*19880Skarels 		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
187*19880Skarels 		bp->mb_na.na_addrs[0], bp->mb_na.na_addrs[1],
188*19880Skarels 		bp->mb_na.na_addrs[2], bp->mb_na.na_addrs[3],
189*19880Skarels 		bp->mb_na.na_addrs[4], bp->mb_na.na_addrs[5]);
190*19880Skarels 	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
191*19880Skarels 	    sizeof (xs->xs_addr));
192*19880Skarels 
193*19880Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
194*19880Skarels 	sin->sin_family = AF_INET;
195*19880Skarels 	sin->sin_addr = arpmyaddr((struct arpcom *)0);
196*19880Skarels 	ifp->if_init = exinit;
197*19880Skarels 	ifp->if_output = exoutput;
198*19880Skarels 	ifp->if_ioctl = exioctl;
199*19880Skarels 	ifp->if_reset = exreset;
200*19880Skarels 	xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
201*19880Skarels 	if_attach(ifp);
202*19880Skarels badconf:
203*19880Skarels 	ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
204*19880Skarels }
205*19880Skarels 
206*19880Skarels /*
207*19880Skarels  * Reset of interface after UNIBUS reset.
208*19880Skarels  * If interface is on specified uba, reset its state.
209*19880Skarels  */
210*19880Skarels exreset(unit, uban)
211*19880Skarels 	int unit, uban;
212*19880Skarels {
213*19880Skarels 	register struct uba_device *ui;
214*19880Skarels 
215*19880Skarels 	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
216*19880Skarels 	    ui->ui_ubanum != uban)
217*19880Skarels 		return;
218*19880Skarels 	printf(" ex%d", unit);
219*19880Skarels 	exinit(unit);
220*19880Skarels }
221*19880Skarels 
222*19880Skarels /*
223*19880Skarels  * Initialization of interface; clear recorded pending
224*19880Skarels  * operations, and reinitialize UNIBUS usage.
225*19880Skarels  * Called at boot time (with interrupts disabled?),
226*19880Skarels  * and at ifconfig time via exioctl, with interrupts disabled.
227*19880Skarels  */
228*19880Skarels exinit(unit)
229*19880Skarels 	int unit;
230*19880Skarels {
231*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
232*19880Skarels 	register struct uba_device *ui = exinfo[unit];
233*19880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
234*19880Skarels 	register struct ifnet *ifp = &xs->xs_if;
235*19880Skarels 	register struct sockaddr_in *sin;
236*19880Skarels 	register struct ex_msg *bp;
237*19880Skarels 	int s;
238*19880Skarels 
239*19880Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
240*19880Skarels 	if (sin->sin_addr.s_addr == 0)		/* address still unknown */
241*19880Skarels 		return;
242*19880Skarels 
243*19880Skarels 	if (ifp->if_flags & IFF_RUNNING)
244*19880Skarels 		goto justarp;
245*19880Skarels 	if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
246*19880Skarels 	    sizeof (struct ether_header),
247*19880Skarels 	    (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
248*19880Skarels 		printf("ex%d: can't initialize\n", unit);
249*19880Skarels 		xs->xs_if.if_flags &= ~IFF_UP;
250*19880Skarels 		return;
251*19880Skarels 	}
252*19880Skarels 	xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE, 0);
253*19880Skarels 	exconfig(ui, 4);		/* with vectored interrupts*/
254*19880Skarels 	/*
255*19880Skarels 	 * Put EXOS on the Ethernet, using NET_MODE command
256*19880Skarels 	 */
257*19880Skarels 	bp = exgetcbuf(xs);
258*19880Skarels 	bp->mb_rqst = LLNET_MODE;
259*19880Skarels 	bp->mb_nm.nm_mask = WRITE_OBJ;
260*19880Skarels 	bp->mb_nm.nm_optn = 0;
261*19880Skarels 	bp->mb_nm.nm_mode = MODE_PERF;
262*19880Skarels 	bp->mb_status |= MH_EXOS;
263*19880Skarels 	addr->xd_portb = EX_NTRUPT;
264*19880Skarels 	bp = xs->xs_x2hnext;
265*19880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_EXOS)	/* poll for reply */
266*19880Skarels 		;
267*19880Skarels 	bp->mb_length = MBDATALEN;
268*19880Skarels 	bp->mb_status |= MH_EXOS;		/* free up buffer */
269*19880Skarels 	addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
270*19880Skarels 	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
271*19880Skarels 
272*19880Skarels 	ifp->if_watchdog = exwatch;
273*19880Skarels 	ifp->if_timer = EXWATCHINTVL;
274*19880Skarels 	s = splimp();	/* are interrupts always disabled here, anyway? */
275*19880Skarels 	exhangrcv(unit);			/* hang receive request */
276*19880Skarels 	exstart(unit);				/* start transmits */
277*19880Skarels 	xs->xs_if.if_flags |= IFF_UP|IFF_RUNNING;
278*19880Skarels 	splx(s);
279*19880Skarels justarp:
280*19880Skarels 	if_rtinit(&xs->xs_if, RTF_UP);
281*19880Skarels 	arpattach(&xs->xs_ac);
282*19880Skarels 	arpwhohas(&xs->xs_ac, &sin->sin_addr);
283*19880Skarels }
284*19880Skarels 
285*19880Skarels /*
286*19880Skarels  * Reset, test, and configure EXOS.  This routine assumes
287*19880Skarels  * that message queues, etc. have already been mapped into
288*19880Skarels  * the UBA.  It is called by exinit, and should also be
289*19880Skarels  * callable by exattach.
290*19880Skarels  */
291*19880Skarels exconfig(ui, itype)
292*19880Skarels 	struct	uba_device *ui;
293*19880Skarels 	int itype;
294*19880Skarels {
295*19880Skarels 	register int unit = ui->ui_unit;
296*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
297*19880Skarels 	register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
298*19880Skarels 	register struct confmsg *cm = &xs->xs_cm;
299*19880Skarels 	register struct ex_msg *bp;
300*19880Skarels 	int i;
301*19880Skarels 	u_long shiftreg;
302*19880Skarels 
303*19880Skarels 	xs->xs_flags = 0;
304*19880Skarels 	/*
305*19880Skarels 	 * Reset EXOS, wait for self-test to complete
306*19880Skarels 	 */
307*19880Skarels 	addr->xd_porta = EX_RESET;
308*19880Skarels 	while ((addr->xd_portb & EX_TESTOK) == 0)
309*19880Skarels 		;
310*19880Skarels 	/*
311*19880Skarels 	 * Set up configuration message.
312*19880Skarels 	 */
313*19880Skarels 	cm->cm_1rsrv = 1;
314*19880Skarels 	cm->cm_cc = 0xFF;
315*19880Skarels 	cm->cm_opmode = 0;		/* link-level controller mode */
316*19880Skarels 	cm->cm_dfo = 0x0101;		/* enable host data order conversion */
317*19880Skarels 	cm->cm_dcn1 = 1;
318*19880Skarels 	cm->cm_2rsrv[0] =
319*19880Skarels 		cm->cm_2rsrv[1] = 0;
320*19880Skarels 	cm->cm_ham = 3;			/* absolute address mode */
321*19880Skarels 	cm->cm_3rsrv = 0;
322*19880Skarels 	cm->cm_mapsiz = 0;
323*19880Skarels 	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */
324*19880Skarels 	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */
325*19880Skarels 	cm->cm_byteptrn[2] = 0x07;
326*19880Skarels 	cm->cm_byteptrn[3] = 0x0F;
327*19880Skarels 	cm->cm_wordptrn[0] = 0x0103;
328*19880Skarels 	cm->cm_wordptrn[1] = 0x070F;
329*19880Skarels 	cm->cm_lwordptrn = 0x0103070F;
330*19880Skarels 	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
331*19880Skarels 	cm->cm_mba = 0xFFFFFFFF;
332*19880Skarels 	cm->cm_nproc = 0xFF;
333*19880Skarels 	cm->cm_nmbox = 0xFF;
334*19880Skarels 	cm->cm_nmcast = 0xFF;
335*19880Skarels 	cm->cm_nhost = 1;
336*19880Skarels 	cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
337*19880Skarels 	cm->cm_h2xhdr = H2XHDR_OFFSET;
338*19880Skarels 	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */
339*19880Skarels 	cm->cm_x2hba = cm->cm_h2xba;
340*19880Skarels 	cm->cm_x2hhdr = X2HHDR_OFFSET;
341*19880Skarels 	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */
342*19880Skarels 	for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
343*19880Skarels #ifdef DEBUG
344*19880Skarels 	if (i >= NEX)
345*19880Skarels 		panic("ex: matching csr address not found");
346*19880Skarels #endif
347*19880Skarels 		;
348*19880Skarels 	cm->cm_x2haddr = ex_cvecs[i].xc_cvec;	/* stashed here by exprobe */
349*19880Skarels 	/*
350*19880Skarels 	 * Set up message queues and headers.
351*19880Skarels 	 * First the request queue.
352*19880Skarels 	 */
353*19880Skarels 	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
354*19880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
355*19880Skarels 		bp->mb_rsrv = 0;
356*19880Skarels 		bp->mb_length = MBDATALEN;
357*19880Skarels 		bp->mb_status = MH_HOST;
358*19880Skarels 		bp->mb_next = bp+1;
359*19880Skarels 	}
360*19880Skarels 	xs->xs_h2xhdr =
361*19880Skarels 		xs->xs_h2xent[NH2X-1].mb_link =
362*19880Skarels 		(u_short)H2XENT_OFFSET;
363*19880Skarels 	xs->xs_h2xnext =
364*19880Skarels 		xs->xs_h2xent[NH2X-1].mb_next =
365*19880Skarels 		xs->xs_h2xent;
366*19880Skarels 
367*19880Skarels 	/* Now the reply queue. */
368*19880Skarels 	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
369*19880Skarels 		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
370*19880Skarels 		bp->mb_rsrv = 0;
371*19880Skarels 		bp->mb_length = MBDATALEN;
372*19880Skarels 		bp->mb_status = MH_EXOS;
373*19880Skarels 		bp->mb_next = bp+1;
374*19880Skarels 	}
375*19880Skarels 	xs->xs_x2hhdr =
376*19880Skarels 		xs->xs_x2hent[NX2H-1].mb_link =
377*19880Skarels 		(u_short)X2HENT_OFFSET;
378*19880Skarels 	xs->xs_x2hnext =
379*19880Skarels 		xs->xs_x2hent[NX2H-1].mb_next =
380*19880Skarels 		xs->xs_x2hent;
381*19880Skarels 
382*19880Skarels 	/*
383*19880Skarels 	 * Write config msg address to EXOS and wait for
384*19880Skarels 	 * configuration to complete (guaranteed response
385*19880Skarels 	 * within 2 seconds).
386*19880Skarels 	 */
387*19880Skarels 	shiftreg = (u_long)0x0000FFFF;
388*19880Skarels 	for (i = 0; i < 8; i++) {
389*19880Skarels 		if (i == 4)
390*19880Skarels 			shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET;
391*19880Skarels 		while (addr->xd_portb & EX_UNREADY)
392*19880Skarels 			;
393*19880Skarels 		addr->xd_portb = (u_char)(shiftreg & 0xFF);
394*19880Skarels 		shiftreg >>= 8;
395*19880Skarels 	}
396*19880Skarels 	for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
397*19880Skarels 	if (cm->cm_cc)
398*19880Skarels 		printf("ex%d: configuration failed; cc = %x\n",
399*19880Skarels 			unit, cm->cm_cc);
400*19880Skarels }
401*19880Skarels 
402*19880Skarels /*
403*19880Skarels  * Start or re-start output on interface.
404*19880Skarels  * Get another datagram to send off of the interface queue,
405*19880Skarels  * and map it to the interface before starting the output.
406*19880Skarels  * This routine is called by exinit(), exoutput(), and excdint().
407*19880Skarels  * In all cases, interrupts by EXOS are disabled.
408*19880Skarels  */
409*19880Skarels exstart(unit)
410*19880Skarels 	int unit;
411*19880Skarels {
412*19880Skarels 	struct uba_device *ui = exinfo[unit];
413*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
414*19880Skarels 	register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
415*19880Skarels 	register struct ex_msg *bp;
416*19880Skarels 	struct mbuf *m;
417*19880Skarels         int len;
418*19880Skarels 
419*19880Skarels #ifdef DEBUG
420*19880Skarels 	if (xs->xs_flags & EX_XPENDING)
421*19880Skarels 		panic("exstart(): xmit still pending");
422*19880Skarels #endif
423*19880Skarels 	IF_DEQUEUE(&xs->xs_if.if_snd, m);
424*19880Skarels 	if (m == 0)
425*19880Skarels 		return;
426*19880Skarels 	len = if_wubaput(&xs->xs_ifuba, m);
427*19880Skarels 	if (len - sizeof(struct ether_header) < ETHERMIN)
428*19880Skarels 		len = ETHERMIN + sizeof(struct ether_header);
429*19880Skarels 	/*
430*19880Skarels 	 * Place a transmit request.
431*19880Skarels 	 */
432*19880Skarels 	bp = exgetcbuf(xs);
433*19880Skarels 	bp->mb_rqst = LLRTRANSMIT;
434*19880Skarels 	bp->mb_et.et_nblock = 1;
435*19880Skarels 	bp->mb_et.et_blks[0].bb_len = (u_short)len;
436*19880Skarels 	*(u_long *)bp->mb_et.et_blks[0].bb_addr =
437*19880Skarels 		UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
438*19880Skarels 	xs->xs_flags |= EX_XPENDING;
439*19880Skarels 	bp->mb_status |= MH_EXOS;
440*19880Skarels 	addr->xd_portb = EX_NTRUPT;
441*19880Skarels }
442*19880Skarels 
443*19880Skarels /*
444*19880Skarels  * Command done interrupt.
445*19880Skarels  */
446*19880Skarels excdint(unit)
447*19880Skarels 	int unit;
448*19880Skarels {
449*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
450*19880Skarels 	register struct ex_msg *bp = xs->xs_x2hnext;
451*19880Skarels 	struct uba_device *ui = exinfo[unit];
452*19880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
453*19880Skarels 
454*19880Skarels 	while ((bp->mb_status & MH_OWNER) == MH_HOST) {
455*19880Skarels 		switch (bp->mb_rqst) {
456*19880Skarels 		case LLRECEIVE:
457*19880Skarels 			exrecv(unit, bp);
458*19880Skarels 			exhangrcv(unit);
459*19880Skarels 			break;
460*19880Skarels 		case LLRTRANSMIT:
461*19880Skarels #ifdef DEBUG
462*19880Skarels 			if ((xs->xs_flags & EX_XPENDING) == 0)
463*19880Skarels 				panic("exxmit: no xmit pending");
464*19880Skarels #endif
465*19880Skarels 			xs->xs_flags &= ~EX_XPENDING;
466*19880Skarels 			xs->xs_if.if_opackets++;
467*19880Skarels 			if (bp->mb_rply == LL_OK) {
468*19880Skarels 				;
469*19880Skarels 			} else if (bp->mb_rply & LLXM_1RTRY) {
470*19880Skarels 				xs->xs_if.if_collisions++;
471*19880Skarels 			} else if (bp->mb_rply & LLXM_RTRYS) {
472*19880Skarels 				xs->xs_if.if_collisions += 2;	/* guess */
473*19880Skarels 			} else if (bp->mb_rply & LLXM_ERROR) {
474*19880Skarels 				xs->xs_if.if_oerrors++;
475*19880Skarels 				printf("ex%d: transmit error=%b\n",
476*19880Skarels 					unit, bp->mb_rply, XMIT_BITS);
477*19880Skarels 			}
478*19880Skarels 			if (xs->xs_ifuba.ifu_xtofree) {
479*19880Skarels 				m_freem(xs->xs_ifuba.ifu_xtofree);
480*19880Skarels 				xs->xs_ifuba.ifu_xtofree = 0;
481*19880Skarels 			}
482*19880Skarels 			exstart(unit);
483*19880Skarels 			break;
484*19880Skarels 		case LLNET_STSTCS:
485*19880Skarels 			xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
486*19880Skarels 			xs->xs_flags &= ~EX_STATPENDING;
487*19880Skarels 			break;
488*19880Skarels #ifdef	DEBUG
489*19880Skarels 		default:
490*19880Skarels 			panic("ex%d: unknown reply");
491*19880Skarels #endif
492*19880Skarels 		} /* end of switch */
493*19880Skarels 		bp->mb_length = MBDATALEN;
494*19880Skarels 		bp->mb_status |= MH_EXOS;		/* free up buffer */
495*19880Skarels 		addr->xd_portb = EX_NTRUPT;		/* tell EXOS about it */
496*19880Skarels 		bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
497*19880Skarels 	}
498*19880Skarels }
499*19880Skarels 
500*19880Skarels /*
501*19880Skarels  * Get a request buffer, fill in standard values, advance pointer.
502*19880Skarels  */
503*19880Skarels struct ex_msg *
504*19880Skarels exgetcbuf(xs)
505*19880Skarels 	struct ex_softc *xs;
506*19880Skarels {
507*19880Skarels 	register struct ex_msg *bp = xs->xs_h2xnext;
508*19880Skarels 
509*19880Skarels #ifdef DEBUG
510*19880Skarels 	if ((bp->mb_status & MH_OWNER) == MH_EXOS)
511*19880Skarels 		panic("exgetcbuf(): EXOS owns message buffer");
512*19880Skarels #endif
513*19880Skarels 	bp->mb_1rsrv = 0;
514*19880Skarels 	bp->mb_length = MBDATALEN;
515*19880Skarels 	xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
516*19880Skarels 	return bp;
517*19880Skarels }
518*19880Skarels 
519*19880Skarels /*
520*19880Skarels  * Process Ethernet receive completion:
521*19880Skarels  *	If input error just drop packet.
522*19880Skarels  *	Otherwise purge input buffered data path and examine
523*19880Skarels  *	packet to determine type.  If can't determine length
524*19880Skarels  *	from type, then have to drop packet.  Otherwise decapsulate
525*19880Skarels  *	packet based on type and pass to type-specific higher-level
526*19880Skarels  *	input routine.
527*19880Skarels  */
528*19880Skarels exrecv(unit, bp)
529*19880Skarels 	int unit;
530*19880Skarels 	register struct ex_msg *bp;
531*19880Skarels {
532*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
533*19880Skarels 	register struct ether_header *eh;
534*19880Skarels     	struct mbuf *m;
535*19880Skarels 	register int len, off, resid;
536*19880Skarels 	register struct ifqueue *inq;
537*19880Skarels 
538*19880Skarels 	xs->xs_if.if_ipackets++;
539*19880Skarels 	len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
540*19880Skarels 	if (bp->mb_rply != LL_OK) {
541*19880Skarels 		xs->xs_if.if_ierrors++;
542*19880Skarels 		printf("ex%d: receive error=%b\n",
543*19880Skarels 			unit, bp->mb_rply, RECV_BITS);
544*19880Skarels 		return;
545*19880Skarels 	}
546*19880Skarels 	eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
547*19880Skarels 
548*19880Skarels 	/*
549*19880Skarels 	 * Deal with trailer protocol: if type is PUP trailer
550*19880Skarels 	 * get true type from first 16-bit word past data.
551*19880Skarels 	 * Remember that type was trailer by setting off.
552*19880Skarels 	 */
553*19880Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
554*19880Skarels #define	exdataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
555*19880Skarels 	if (eh->ether_type >= ETHERPUP_TRAIL &&
556*19880Skarels 	    eh->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
557*19880Skarels 		off = (eh->ether_type - ETHERPUP_TRAIL) * 512;
558*19880Skarels 		if (off >= ETHERMTU)
559*19880Skarels 			return;		/* sanity */
560*19880Skarels 		eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
561*19880Skarels 		resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
562*19880Skarels 		if (off + resid > len)
563*19880Skarels 			return;		/* sanity */
564*19880Skarels 		len = off + resid;
565*19880Skarels 	} else
566*19880Skarels 		off = 0;
567*19880Skarels 	if (len == 0)
568*19880Skarels 		return;
569*19880Skarels 
570*19880Skarels 	/*
571*19880Skarels 	 * Pull packet off interface.  Off is nonzero if packet
572*19880Skarels 	 * has trailing header; if_rubaget will then force this header
573*19880Skarels 	 * information to be at the front, but we still have to drop
574*19880Skarels 	 * the type and length which are at the front of any trailer data.
575*19880Skarels 	 */
576*19880Skarels 	m = if_rubaget(&xs->xs_ifuba, len, off);
577*19880Skarels 	if (m == 0)
578*19880Skarels 		return;
579*19880Skarels 	if (off) {
580*19880Skarels 		m->m_off += 2 * sizeof (u_short);
581*19880Skarels 		m->m_len -= 2 * sizeof (u_short);
582*19880Skarels 	}
583*19880Skarels 	switch (eh->ether_type) {
584*19880Skarels 
585*19880Skarels #ifdef INET
586*19880Skarels 	case ETHERPUP_IPTYPE:
587*19880Skarels 		schednetisr(NETISR_IP);	/* is this necessary */
588*19880Skarels 		inq = &ipintrq;
589*19880Skarels 		break;
590*19880Skarels 
591*19880Skarels 	case ETHERPUP_ARPTYPE:
592*19880Skarels 		arpinput(&xs->xs_ac, m);
593*19880Skarels 		return;
594*19880Skarels #endif
595*19880Skarels 	default:
596*19880Skarels 		m_freem(m);
597*19880Skarels 		return;
598*19880Skarels 	}
599*19880Skarels 
600*19880Skarels 	if (IF_QFULL(inq)) {
601*19880Skarels 		IF_DROP(inq);
602*19880Skarels 		m_freem(m);
603*19880Skarels 		return;
604*19880Skarels 	}
605*19880Skarels 	IF_ENQUEUE(inq, m);
606*19880Skarels }
607*19880Skarels 
608*19880Skarels /*
609*19880Skarels  * Send receive request to EXOS.
610*19880Skarels  * This routine is called by exinit and excdint,
611*19880Skarels  * with interrupts disabled in both cases.
612*19880Skarels  */
613*19880Skarels exhangrcv(unit)
614*19880Skarels 	int unit;
615*19880Skarels {
616*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
617*19880Skarels 	register struct ex_msg *bp = exgetcbuf(xs);
618*19880Skarels 	struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
619*19880Skarels 
620*19880Skarels 	bp->mb_rqst = LLRECEIVE;
621*19880Skarels 	bp->mb_er.er_nblock = 1;
622*19880Skarels 	bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
623*19880Skarels 	*(u_long *)bp->mb_er.er_blks[0].bb_addr =
624*19880Skarels 		UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
625*19880Skarels 	bp->mb_status |= MH_EXOS;
626*19880Skarels 	addr->xd_portb = EX_NTRUPT;
627*19880Skarels }
628*19880Skarels 
629*19880Skarels /*
630*19880Skarels  * Ethernet output routine.
631*19880Skarels  * Encapsulate a packet of type family for the local net.
632*19880Skarels  * Use trailer local net encapsulation if enough data in first
633*19880Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
634*19880Skarels  */
635*19880Skarels exoutput(ifp, m0, dst)
636*19880Skarels 	register struct ifnet *ifp;
637*19880Skarels 	register struct mbuf *m0;
638*19880Skarels 	struct sockaddr *dst;
639*19880Skarels {
640*19880Skarels 	int type, s, error;
641*19880Skarels 	u_char edst[6];
642*19880Skarels 	struct in_addr idst;
643*19880Skarels 	register struct ex_softc *xs = &ex_softc[ifp->if_unit];
644*19880Skarels 	register struct mbuf *m = m0;
645*19880Skarels 	register struct ether_header *eh;
646*19880Skarels 	register int off;
647*19880Skarels 
648*19880Skarels 	switch (dst->sa_family) {
649*19880Skarels 
650*19880Skarels #ifdef INET
651*19880Skarels 	case AF_INET:
652*19880Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
653*19880Skarels 		if (!arpresolve(&xs->xs_ac, m, &idst, edst))
654*19880Skarels 			return (0);	/* if not yet resolved */
655*19880Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
656*19880Skarels 		/* need per host negotiation */
657*19880Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
658*19880Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
659*19880Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
660*19880Skarels 			type = ETHERPUP_TRAIL + (off>>9);
661*19880Skarels 			m->m_off -= 2 * sizeof (u_short);
662*19880Skarels 			m->m_len += 2 * sizeof (u_short);
663*19880Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
664*19880Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
665*19880Skarels 			goto gottrailertype;
666*19880Skarels 		}
667*19880Skarels 		type = ETHERPUP_IPTYPE;
668*19880Skarels 		off = 0;
669*19880Skarels 		goto gottype;
670*19880Skarels #endif
671*19880Skarels 
672*19880Skarels 	case AF_UNSPEC:
673*19880Skarels 		eh = (struct ether_header *)dst->sa_data;
674*19880Skarels 		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
675*19880Skarels 		type = eh->ether_type;
676*19880Skarels 		goto gottype;
677*19880Skarels 
678*19880Skarels 	default:
679*19880Skarels 		printf("ex%d: can't handle af%d\n", ifp->if_unit,
680*19880Skarels 			dst->sa_family);
681*19880Skarels 		error = EAFNOSUPPORT;
682*19880Skarels 		goto bad;
683*19880Skarels 	}
684*19880Skarels 
685*19880Skarels gottrailertype:
686*19880Skarels 	/*
687*19880Skarels 	 * Packet to be sent as trailer: move first packet
688*19880Skarels 	 * (control information) to end of chain.
689*19880Skarels 	 */
690*19880Skarels 	while (m->m_next)
691*19880Skarels 		m = m->m_next;
692*19880Skarels 	m->m_next = m0;
693*19880Skarels 	m = m0->m_next;
694*19880Skarels 	m0->m_next = 0;
695*19880Skarels 	m0 = m;
696*19880Skarels 
697*19880Skarels gottype:
698*19880Skarels 	/*
699*19880Skarels 	 * Add local net header.  If no space in first mbuf,
700*19880Skarels 	 * allocate another.
701*19880Skarels 	 */
702*19880Skarels 	if (m->m_off > MMAXOFF ||
703*19880Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
704*19880Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
705*19880Skarels 		if (m == 0) {
706*19880Skarels 			error = ENOBUFS;
707*19880Skarels 			goto bad;
708*19880Skarels 		}
709*19880Skarels 		m->m_next = m0;
710*19880Skarels 		m->m_off = MMINOFF;
711*19880Skarels 		m->m_len = sizeof (struct ether_header);
712*19880Skarels 	} else {
713*19880Skarels 		m->m_off -= sizeof (struct ether_header);
714*19880Skarels 		m->m_len += sizeof (struct ether_header);
715*19880Skarels 	}
716*19880Skarels 	eh = mtod(m, struct ether_header *);
717*19880Skarels 	eh->ether_type = htons((u_short)type);
718*19880Skarels 	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
719*19880Skarels 	bcopy((caddr_t)xs->xs_addr, (caddr_t)eh->ether_shost, 6);
720*19880Skarels 
721*19880Skarels 	/*
722*19880Skarels 	 * Queue message on interface, and start output if interface
723*19880Skarels 	 * not yet active.
724*19880Skarels 	 */
725*19880Skarels 	s = splimp();
726*19880Skarels 	if (IF_QFULL(&ifp->if_snd)) {
727*19880Skarels 		IF_DROP(&ifp->if_snd);
728*19880Skarels 		splx(s);
729*19880Skarels 		m_freem(m);
730*19880Skarels 		return (ENOBUFS);
731*19880Skarels 	}
732*19880Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
733*19880Skarels 	/*
734*19880Skarels 	 * If transmit request not already pending, then
735*19880Skarels 	 * kick the back end.
736*19880Skarels 	 */
737*19880Skarels 	if ((xs->xs_flags & EX_XPENDING) == 0) {
738*19880Skarels 		exstart(ifp->if_unit);
739*19880Skarels 	}
740*19880Skarels #ifdef DEBUG
741*19880Skarels 	else {
742*19880Skarels 		xs->xs_wait++;
743*19880Skarels 	}
744*19880Skarels #endif
745*19880Skarels 	splx(s);
746*19880Skarels 	return (0);
747*19880Skarels 
748*19880Skarels bad:
749*19880Skarels 	m_freem(m0);
750*19880Skarels 	return (error);
751*19880Skarels }
752*19880Skarels 
753*19880Skarels /*
754*19880Skarels  * Watchdog routine - place stats request to EXOS
755*19880Skarels  * (This could be dispensed with, if you don't care
756*19880Skarels  *  about the if_ierrors count, or are willing to receive
757*19880Skarels  *  bad packets in order to derive it.)
758*19880Skarels  */
759*19880Skarels exwatch(unit)
760*19880Skarels 	int unit;
761*19880Skarels {
762*19880Skarels 	struct uba_device *ui = exinfo[unit];
763*19880Skarels 	struct exdevice *addr = (struct exdevice *)ui->ui_addr;
764*19880Skarels 	register struct ex_softc *xs = &ex_softc[unit];
765*19880Skarels 	register struct ex_msg *bp;
766*19880Skarels 	int s = splimp();
767*19880Skarels 
768*19880Skarels 	if (xs->xs_flags & EX_STATPENDING) goto exspnd;
769*19880Skarels 	bp = exgetcbuf(xs);
770*19880Skarels 	xs->xs_flags |= EX_STATPENDING;
771*19880Skarels 	bp->mb_rqst = LLNET_STSTCS;
772*19880Skarels 	bp->mb_ns.ns_mask = READ_OBJ;
773*19880Skarels 	bp->mb_ns.ns_rsrv = 0;
774*19880Skarels 	bp->mb_ns.ns_nobj = 8;		/* read all 8 stats objects */
775*19880Skarels 	bp->mb_ns.ns_xobj = 0;		/* starting with the 1st one */
776*19880Skarels 	bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET;
777*19880Skarels 	bp->mb_status |= MH_EXOS;
778*19880Skarels 	addr->xd_portb = EX_NTRUPT;
779*19880Skarels exspnd:
780*19880Skarels 	splx(s);
781*19880Skarels 	xs->xs_if.if_timer = EXWATCHINTVL;
782*19880Skarels }
783*19880Skarels 
784*19880Skarels /*
785*19880Skarels  * Process an ioctl request.
786*19880Skarels  */
787*19880Skarels exioctl(ifp, cmd, data)
788*19880Skarels 	register struct ifnet *ifp;
789*19880Skarels 	int cmd;
790*19880Skarels 	caddr_t data;
791*19880Skarels {
792*19880Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
793*19880Skarels 	int s = splimp(), error = 0;
794*19880Skarels 
795*19880Skarels 	switch (cmd) {
796*19880Skarels 
797*19880Skarels 	case SIOCSIFADDR:
798*19880Skarels 		if (ifp->if_flags & IFF_RUNNING)
799*19880Skarels 			if_rtinit(ifp, -1);	/* delete previous route */
800*19880Skarels 		exsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
801*19880Skarels 		exinit(ifp->if_unit);
802*19880Skarels 		break;
803*19880Skarels 
804*19880Skarels 	default:
805*19880Skarels 		error = EINVAL;
806*19880Skarels 	}
807*19880Skarels 	splx(s);
808*19880Skarels 	return (error);
809*19880Skarels }
810*19880Skarels 
811*19880Skarels exsetaddr(ifp, sin)
812*19880Skarels 	register struct ifnet *ifp;
813*19880Skarels 	register struct sockaddr_in *sin;
814*19880Skarels {
815*19880Skarels 	ifp->if_addr = *(struct sockaddr *)sin;
816*19880Skarels 	ifp->if_net = in_netof(sin->sin_addr);
817*19880Skarels 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
818*19880Skarels 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
819*19880Skarels 	sin->sin_family = AF_INET;
820*19880Skarels 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
821*19880Skarels 	ifp->if_flags |= IFF_BROADCAST;
822*19880Skarels }
823