xref: /csrg-svn/sys/vax/if/if_ix.c (revision 26197)
1*26197Ssklower /*
2*26197Ssklower  * Copyright (c) 1986 Regents of the University of California.
3*26197Ssklower  * All rights reserved.  The Berkeley software License Agreement
4*26197Ssklower  * specifies the terms and conditions for redistribution.
5*26197Ssklower  *
6*26197Ssklower  *	@(#)if_ix.c	6.1 (Berkeley) 02/17/86
7*26197Ssklower  */
8*26197Ssklower 
9*26197Ssklower #include "np.h"
10*26197Ssklower #if NNP > 0
11*26197Ssklower 
12*26197Ssklower /*
13*26197Ssklower  * Interlan NP100 Ethernet Communications Controller interface
14*26197Ssklower  */
15*26197Ssklower #include "../machine/pte.h"
16*26197Ssklower 
17*26197Ssklower #include "param.h"
18*26197Ssklower #include "systm.h"
19*26197Ssklower #include "mbuf.h"
20*26197Ssklower #include "buf.h"
21*26197Ssklower #include "protosw.h"
22*26197Ssklower #include "socket.h"
23*26197Ssklower #include "vmmac.h"
24*26197Ssklower #include "ioctl.h"
25*26197Ssklower #include "errno.h"
26*26197Ssklower 
27*26197Ssklower #include "../net/if.h"
28*26197Ssklower #include "../net/netisr.h"
29*26197Ssklower #include "../net/route.h"
30*26197Ssklower 
31*26197Ssklower #ifdef INET
32*26197Ssklower #include "../netinet/in.h"
33*26197Ssklower #include "../netinet/in_systm.h"
34*26197Ssklower #include "../netinet/in_var.h"
35*26197Ssklower #include "../netinet/ip.h"
36*26197Ssklower #include "../netinet/if_ether.h"
37*26197Ssklower #endif
38*26197Ssklower 
39*26197Ssklower #ifdef NS
40*26197Ssklower #include "../netns/ns.h"
41*26197Ssklower #include "../netns/ns_if.h"
42*26197Ssklower #endif
43*26197Ssklower 
44*26197Ssklower #include "../vax/cpu.h"
45*26197Ssklower #include "../vax/mtpr.h"
46*26197Ssklower #include "../vaxif/if_uba.h"
47*26197Ssklower #include "../vaxuba/ubareg.h"
48*26197Ssklower #include "../vaxuba/ubavar.h"
49*26197Ssklower #include "../vaxuba/npreg.h"
50*26197Ssklower #include "../vaxif/if_ix.h"
51*26197Ssklower 
52*26197Ssklower int	ixattach(), ixrint(), ixcint();
53*26197Ssklower #define	ILUNIT(x)	minor(x)
54*26197Ssklower int	ixinit(), ixoutput(), ixioctl(), ixreset(), ixwatch();
55*26197Ssklower int (*IxAttach)() = ixattach;
56*26197Ssklower int (*IxReset)() = ixreset;
57*26197Ssklower 
58*26197Ssklower /*
59*26197Ssklower  * Ethernet software status per interface.
60*26197Ssklower  *
61*26197Ssklower  * Each interface is referenced by a network interface structure,
62*26197Ssklower  * ix_if, which the routing code uses to locate the interface.
63*26197Ssklower  * This structure contains the output queue for the interface, its address, ...
64*26197Ssklower  * We also have, for each interface, a UBA interface structure, which
65*26197Ssklower  * contains information about the UNIBUS resources held by the interface:
66*26197Ssklower  * map registers, buffered data paths, etc.  Information is cached in this
67*26197Ssklower  * structure for use by the if_uba.c routines in running the interface
68*26197Ssklower  * efficiently.
69*26197Ssklower  */
70*26197Ssklower struct	ix_softc {
71*26197Ssklower 	struct	arpcom ix_ac;		/* Ethernet common part */
72*26197Ssklower #define	ix_if	ix_ac.ac_if		/* network-visible interface */
73*26197Ssklower #define	ix_addr	ix_ac.ac_enaddr		/* hardware Ethernet address */
74*26197Ssklower 	int	ix_flags;
75*26197Ssklower #define	IXF_OACTIVE	0x1		/* output is active */
76*26197Ssklower #define	IXF_RCVPENDING	0x2		/* start rcv in ilcint */
77*26197Ssklower #define	IXF_GOTUBA	0x4		/* unibus resources mapped */
78*26197Ssklower #define	IXF_RUNNING	0x8		/* board is running */
79*26197Ssklower #define	IXF_SETADDR	0x10		/* physical address is changed */
80*26197Ssklower #define	IXF_STATPENDING	0x20		/* stat cmd pending */
81*26197Ssklower #define	IXF_GOTCQE	0x40		/* np resources available */
82*26197Ssklower 	struct	ifuba ix_ifuba;		/* unibus resources */
83*26197Ssklower 	u_short	ix_aid;			/* Access Id returned by open DDL */
84*26197Ssklower 	u_short ix_badcqe;
85*26197Ssklower 	struct	npmaster *ix_mp;	/* Board physio request header */
86*26197Ssklower 	struct	npreq *ix_rrp;		/* Cached npreq for recv */
87*26197Ssklower 	struct	npreq *ix_wrp;		/* Cached npreq for xmit */
88*26197Ssklower 	short	ix_scaninterval;	/* interval of stat collection */
89*26197Ssklower #define	IXWATCHINTERVAL	60		/* once every 60 seconds */
90*26197Ssklower 	union	ix_stats ix_stats;	/* holds on-board statistics */
91*26197Ssklower 	int	ix_ubaddr;		/* mapping registers of ix_stats */
92*26197Ssklower } ix_softc[NNP];
93*26197Ssklower extern struct uba_device *npdinfo[];
94*26197Ssklower 
95*26197Ssklower /*
96*26197Ssklower  * Interface exists: make available by filling in network interface
97*26197Ssklower  * record.  System will initialize the interface when it is ready
98*26197Ssklower  * to accept packets.  We can't even get the ethernet address
99*26197Ssklower  * or other interesting data until the board has been downloaded.
100*26197Ssklower  * running ifconfig will attempt to start unit.
101*26197Ssklower  */
102*26197Ssklower ixattach(ui)
103*26197Ssklower 	struct uba_device *ui;
104*26197Ssklower {
105*26197Ssklower 	register struct ix_softc *ix = &ix_softc[ui->ui_unit];
106*26197Ssklower 	register struct ifnet *ifp = &ix->ix_if;
107*26197Ssklower 	extern struct npmaster npmasters[];
108*26197Ssklower 
109*26197Ssklower 	ifp->if_unit = ui->ui_unit;
110*26197Ssklower 	ifp->if_name = "ix";
111*26197Ssklower 	ifp->if_mtu = ETHERMTU;
112*26197Ssklower 	ifp->if_flags = IFF_BROADCAST;
113*26197Ssklower 
114*26197Ssklower 	ifp->if_init = ixinit;
115*26197Ssklower 	ifp->if_output = ixoutput;
116*26197Ssklower 	ifp->if_ioctl = ixioctl;
117*26197Ssklower 	ifp->if_reset = ixreset;
118*26197Ssklower 
119*26197Ssklower 	ix->ix_mp = npmasters + ui->ui_unit;
120*26197Ssklower 	ix->ix_ifuba.ifu_flags = UBA_CANTWAIT;
121*26197Ssklower 
122*26197Ssklower 	if_attach(ifp);
123*26197Ssklower }
124*26197Ssklower 
125*26197Ssklower struct npreq *
126*26197Ssklower ix_GetReq(mp, addr, len)
127*26197Ssklower 	struct npmaster *mp;
128*26197Ssklower 	caddr_t addr;
129*26197Ssklower {
130*26197Ssklower 	int unit = mp->unit;
131*26197Ssklower 	register struct npreq *rp;
132*26197Ssklower 	register struct CQE *ep;
133*26197Ssklower 	struct ix_softc *ix = ix_softc + unit;
134*26197Ssklower 	extern struct npreq *NpGetReq();
135*26197Ssklower 
136*26197Ssklower 	while ((rp = NpGetReq(mp->reqtab)) == NULL) {
137*26197Ssklower 		mp->reqtab->flags |= WANTREQ;
138*26197Ssklower 		sleep((caddr_t)(mp->reqtab), PZERO - 1);
139*26197Ssklower 	}
140*26197Ssklower 	rp->flags = KERNREQ;			/* Clear flags */
141*26197Ssklower 
142*26197Ssklower 	ep = rp->element;			/* Associated CQE */
143*26197Ssklower 	ep->cqe_famid = (unsign32)ix;		/* Process ID */
144*26197Ssklower 	ep->cqe_wind = 0;			/* Amount of buffer mapped */
145*26197Ssklower 	ep->cqe_nbuf = 1;			/* Must be 1, no buffer chain */
146*26197Ssklower 	ep->cqe_char = 1;			/* Driver owns this CQE */
147*26197Ssklower 	ep->cqe_prot = NPDLA;			/* Data Link Access  protocol */
148*26197Ssklower 	ep->cqe_bcnt = len;			/* Byte count */
149*26197Ssklower 	rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */
150*26197Ssklower 	ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr);
151*26197Ssklower 	ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr);
152*26197Ssklower 	return (rp);
153*26197Ssklower }
154*26197Ssklower 
155*26197Ssklower ix_DoReq(mp, rp, cmd, addr, len, rpb, routine)
156*26197Ssklower 	struct npmaster *mp;
157*26197Ssklower 	register struct npreq *rp;
158*26197Ssklower 	u_short cmd;
159*26197Ssklower 	caddr_t addr;
160*26197Ssklower 	int len;
161*26197Ssklower 	register u_short *rpb;
162*26197Ssklower 	int (*routine)();
163*26197Ssklower {
164*26197Ssklower 	register struct CQE *ep = rp->element;
165*26197Ssklower 	register u_short *p = &ep->rpb1;
166*26197Ssklower 	u_short cnt = *rpb++;
167*26197Ssklower 	extern long NpDebug;
168*26197Ssklower 	int pri;
169*26197Ssklower 
170*26197Ssklower 	ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR;	/* Clear status */
171*26197Ssklower 	ep->cqe_bcnt = len;			/* Byte count */
172*26197Ssklower 	rp->flags = KERNREQ;			/* Clear flags */
173*26197Ssklower 	rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */
174*26197Ssklower 	rp->intr = routine;
175*26197Ssklower 	rp->user = (caddr_t) (ep->cqe_func = cmd);/* In case pissed on in CQE */
176*26197Ssklower 	ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr);
177*26197Ssklower 	ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr);
178*26197Ssklower 	ep->cqe_lenrpb = cnt + cnt;
179*26197Ssklower 	for (; cnt > 0; cnt--) *p++ = *rpb++;
180*26197Ssklower 
181*26197Ssklower 	if (NpDebug & DEBCQE)
182*26197Ssklower 		printf("Function is %x ep %x reqid %x\n", ep->cqe_func, ep, ep->cqe_reqid);
183*26197Ssklower 	if (NpDebug & DEBCQE)
184*26197Ssklower 		printf("irp len = %x rp = %x\n", ep->cqe_lenrpb, rp);
185*26197Ssklower 	if (routine == 0) {
186*26197Ssklower 		NpAddReq(mp->reqtab, rp);	/* Queue onto active list */
187*26197Ssklower 		while (!(rp->flags & REQDONE)) {
188*26197Ssklower 			pri = spl4();
189*26197Ssklower 			NpAddCQE(ep, &mp->shmemp->devcq, mp);
190*26197Ssklower 			sleep((caddr_t)rp, PZERO - 1);
191*26197Ssklower 			splx(pri);
192*26197Ssklower 		}
193*26197Ssklower 		if (rp->flags & IOABORT || ep->cqe_sts != NPDONE
194*26197Ssklower 		    || ep->cqe_ust0 != NPDONE
195*26197Ssklower 		    || ep->cqe_ust1 != NPOK) {
196*26197Ssklower 			struct ix_softc *ix = (struct ix_softc *)ep->cqe_famid;
197*26197Ssklower 			printf("ix%d: Req failed, cmd %x, stat %x, ",
198*26197Ssklower 				ix->ix_if.if_unit, rp->user, ep->cqe_sts);
199*26197Ssklower 			printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1);
200*26197Ssklower 		}
201*26197Ssklower 		NpRemReq(rp);			/* Clear request */
202*26197Ssklower 	} else {
203*26197Ssklower 		pri = spl4();
204*26197Ssklower 		NpAddCQE(ep, &mp->shmemp->devcq, mp);
205*26197Ssklower 		splx(pri);
206*26197Ssklower 	}
207*26197Ssklower }
208*26197Ssklower 
209*26197Ssklower /*
210*26197Ssklower  * Ethernet output routine.
211*26197Ssklower  * Encapsulate a packet of type family for the local net.
212*26197Ssklower  * Use trailer local net encapsulation if enough data in first
213*26197Ssklower  * packet leaves a multiple of 512 bytes of data in remainder.
214*26197Ssklower  */
215*26197Ssklower ixoutput(ifp, m0, dst)
216*26197Ssklower 	struct ifnet *ifp;
217*26197Ssklower 	struct mbuf *m0;
218*26197Ssklower 	struct sockaddr *dst;
219*26197Ssklower {
220*26197Ssklower 	int type, s, error;
221*26197Ssklower  	u_char edst[6];
222*26197Ssklower 	struct in_addr idst;
223*26197Ssklower 	register struct ix_softc *ix = &ix_softc[ifp->if_unit];
224*26197Ssklower 	register struct mbuf *m = m0;
225*26197Ssklower 	register struct ether_header *il;
226*26197Ssklower 	register int off;
227*26197Ssklower 	int usetrailers;
228*26197Ssklower 
229*26197Ssklower 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
230*26197Ssklower 		error = ENETDOWN;
231*26197Ssklower 		goto bad;
232*26197Ssklower 	}
233*26197Ssklower 	switch (dst->sa_family) {
234*26197Ssklower 
235*26197Ssklower #ifdef INET
236*26197Ssklower 	case AF_INET:
237*26197Ssklower 		idst = ((struct sockaddr_in *)dst)->sin_addr;
238*26197Ssklower  		if (!arpresolve(&ix->ix_ac, m, &idst, edst, &usetrailers))
239*26197Ssklower 			return (0);	/* if not yet resolved */
240*26197Ssklower 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
241*26197Ssklower 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
242*26197Ssklower 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
243*26197Ssklower 			type = ETHERTYPE_TRAIL + (off>>9);
244*26197Ssklower 			m->m_off -= 2 * sizeof (u_short);
245*26197Ssklower 			m->m_len += 2 * sizeof (u_short);
246*26197Ssklower 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
247*26197Ssklower 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
248*26197Ssklower 			goto gottrailertype;
249*26197Ssklower 		}
250*26197Ssklower 		type = ETHERTYPE_IP;
251*26197Ssklower 		off = 0;
252*26197Ssklower 		goto gottype;
253*26197Ssklower #endif
254*26197Ssklower #ifdef NS
255*26197Ssklower 	case AF_NS:
256*26197Ssklower 		type = ETHERTYPE_NS;
257*26197Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
258*26197Ssklower 		(caddr_t)edst, sizeof (edst));
259*26197Ssklower 		off = 0;
260*26197Ssklower 		goto gottype;
261*26197Ssklower #endif
262*26197Ssklower 
263*26197Ssklower 	case AF_UNSPEC:
264*26197Ssklower 		il = (struct ether_header *)dst->sa_data;
265*26197Ssklower  		bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst));
266*26197Ssklower 		type = il->ether_type;
267*26197Ssklower 		goto gottype;
268*26197Ssklower 
269*26197Ssklower 	default:
270*26197Ssklower 		printf("ix%d: can't handle af%d\n", ifp->if_unit,
271*26197Ssklower 			dst->sa_family);
272*26197Ssklower 		error = EAFNOSUPPORT;
273*26197Ssklower 		goto bad;
274*26197Ssklower 	}
275*26197Ssklower 
276*26197Ssklower gottrailertype:
277*26197Ssklower 	/*
278*26197Ssklower 	 * Packet to be sent as trailer: move first packet
279*26197Ssklower 	 * (control information) to end of chain.
280*26197Ssklower 	 */
281*26197Ssklower 	while (m->m_next)
282*26197Ssklower 		m = m->m_next;
283*26197Ssklower 	m->m_next = m0;
284*26197Ssklower 	m = m0->m_next;
285*26197Ssklower 	m0->m_next = 0;
286*26197Ssklower 	m0 = m;
287*26197Ssklower 
288*26197Ssklower gottype:
289*26197Ssklower 	/*
290*26197Ssklower 	 * Add local net header.  If no space in first mbuf,
291*26197Ssklower 	 * allocate another.
292*26197Ssklower 	 */
293*26197Ssklower 	if (m->m_off > MMAXOFF ||
294*26197Ssklower 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
295*26197Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
296*26197Ssklower 		if (m == 0) {
297*26197Ssklower 			error = ENOBUFS;
298*26197Ssklower 			goto bad;
299*26197Ssklower 		}
300*26197Ssklower 		m->m_next = m0;
301*26197Ssklower 		m->m_off = MMINOFF;
302*26197Ssklower 		m->m_len = sizeof (struct ether_header);
303*26197Ssklower 	} else {
304*26197Ssklower 		m->m_off -= sizeof (struct ether_header);
305*26197Ssklower 		m->m_len += sizeof (struct ether_header);
306*26197Ssklower 	}
307*26197Ssklower 	il = mtod(m, struct ether_header *);
308*26197Ssklower 	il->ether_type = htons((u_short)type);
309*26197Ssklower  	bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst));
310*26197Ssklower  	bcopy((caddr_t)ix->ix_addr, (caddr_t)il->ether_shost,
311*26197Ssklower 	    sizeof(il->ether_shost));
312*26197Ssklower 
313*26197Ssklower 	/*
314*26197Ssklower 	 * Queue message on interface, and start output if interface
315*26197Ssklower 	 * not yet active.
316*26197Ssklower 	 */
317*26197Ssklower 	s = splimp();
318*26197Ssklower 	if (IF_QFULL(&ifp->if_snd)) {
319*26197Ssklower 		IF_DROP(&ifp->if_snd);
320*26197Ssklower 		splx(s);
321*26197Ssklower 		m_freem(m);
322*26197Ssklower 		return (ENOBUFS);
323*26197Ssklower 	}
324*26197Ssklower 	IF_ENQUEUE(&ifp->if_snd, m);
325*26197Ssklower 	if ((ix->ix_flags & IXF_OACTIVE) == 0)
326*26197Ssklower 		ixstart(ifp->if_unit);
327*26197Ssklower 	splx(s);
328*26197Ssklower 	return (0);
329*26197Ssklower 
330*26197Ssklower bad:
331*26197Ssklower 	m_freem(m0);
332*26197Ssklower 	return (error);
333*26197Ssklower }
334*26197Ssklower /*
335*26197Ssklower  * Reset of interface after UNIBUS reset.
336*26197Ssklower  * If interface is on specified uba, reset its state.
337*26197Ssklower  */
338*26197Ssklower ixreset(unit, uban, softp)
339*26197Ssklower 	int unit, uban;
340*26197Ssklower 	caddr_t softp;
341*26197Ssklower {
342*26197Ssklower 	register struct uba_device *ui;
343*26197Ssklower 	int mask = IXF_SETADDR;		/* Only remember new physaddr */
344*26197Ssklower 
345*26197Ssklower 	if (unit >= NNP || (ui = npdinfo[unit]) == 0 || ui->ui_alive == 0 ||
346*26197Ssklower 	    ui->ui_ubanum != uban)
347*26197Ssklower 		return;
348*26197Ssklower 	printf(" ix%d reset", unit);
349*26197Ssklower 	if (softp)
350*26197Ssklower 		mask |= IXF_GOTUBA;	/* UBA mapping regs still valid; */
351*26197Ssklower 	ix_softc[unit].ix_if.if_flags &= ~IFF_RUNNING;
352*26197Ssklower 	ix_softc[unit].ix_flags &= mask;
353*26197Ssklower }
354*26197Ssklower 
355*26197Ssklower 
356*26197Ssklower /*
357*26197Ssklower  * Initialization of interface; clear recorded pending
358*26197Ssklower  * operations, and reinitialize UNIBUS usage.
359*26197Ssklower  */
360*26197Ssklower ixinit(unit)
361*26197Ssklower 	int unit;
362*26197Ssklower {
363*26197Ssklower 	register struct ix_softc *ix = &ix_softc[unit];
364*26197Ssklower 	struct uba_device *ui = npdinfo[unit];
365*26197Ssklower 	register struct ifnet *ifp = &ix->ix_if;
366*26197Ssklower 	register struct CQE *ep;
367*26197Ssklower 	struct npreq *rp;
368*26197Ssklower 	struct npmaster *mp = ix->ix_mp;
369*26197Ssklower 	register u_short *dpmp = & mp->shmemp->statblock.sb_dpm;
370*26197Ssklower 	u_short rpb[7];
371*26197Ssklower 	int s;
372*26197Ssklower 
373*26197Ssklower 	/* not yet, if address still unknown */
374*26197Ssklower 	if (ifp->if_addrlist == (struct ifaddr *)0)
375*26197Ssklower 		return;
376*26197Ssklower 	if (ix->ix_flags & IXF_RUNNING)
377*26197Ssklower 		return;
378*26197Ssklower 	if ((mp->flags & AVAILABLE) == 0 || (*dpmp & PROTOMASK(NPDLA)) == 0) {
379*26197Ssklower 		ifp->if_flags &= ~IFF_UP;
380*26197Ssklower 		return;
381*26197Ssklower 	}
382*26197Ssklower 	if ((ix->ix_flags & IXF_GOTUBA) == 0) {
383*26197Ssklower 		ix->ix_ifuba.ifu_flags = UBA_CANTWAIT;
384*26197Ssklower 		if (if_ubainit(&ix->ix_ifuba, ui->ui_ubanum,
385*26197Ssklower 		    sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) {
386*26197Ssklower 			printf("ix%d: can't initialize\n", unit);
387*26197Ssklower 			ix->ix_if.if_flags &= ~IFF_UP;
388*26197Ssklower 			return;
389*26197Ssklower 		}
390*26197Ssklower 		ix->ix_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&ix->ix_stats,
391*26197Ssklower 			sizeof (union ix_stats), 0);
392*26197Ssklower 		ix->ix_flags |= IXF_GOTUBA;
393*26197Ssklower 	}
394*26197Ssklower 	if ((ix->ix_flags & IXF_GOTCQE) == 0) {
395*26197Ssklower 		ix->ix_rrp = ix_GetReq(mp, ix->ix_ifuba.ifu_r.ifrw_info,
396*26197Ssklower 								ETHERMTU);
397*26197Ssklower 		ix->ix_wrp = ix_GetReq(mp, 0, 0);
398*26197Ssklower 		ix->ix_flags |= IXF_GOTCQE;
399*26197Ssklower 	}
400*26197Ssklower 
401*26197Ssklower 	rp = ix->ix_wrp;
402*26197Ssklower 	ep = rp->element;
403*26197Ssklower 
404*26197Ssklower 	/* Changing the ethernet address resets the dla module,
405*26197Ssklower 	   so must do it before opening the channel */
406*26197Ssklower 	if (ix->ix_flags & IXF_SETADDR) {
407*26197Ssklower 		register char *cp = (char *) &ix->ix_stats;
408*26197Ssklower 		int spincount;
409*26197Ssklower 		int x;
410*26197Ssklower 		*cp++ = 1;
411*26197Ssklower 		bcopy(ix->ix_addr, (caddr_t)cp, 6);
412*26197Ssklower 		rpb[0] = 1;				/* RPB length */
413*26197Ssklower 		ix_DoReq(mp, rp, IXC_LDPA, ix->ix_ubaddr, 7, rpb, 0);
414*26197Ssklower #ifndef TheyFinallyFixedTheBoard
415*26197Ssklower 		/* Board requires some time to reinitialize its protocols */
416*26197Ssklower 		x = spl1();
417*26197Ssklower 		spincount = 2000000;
418*26197Ssklower 		while (((*dpmp & PROTOMASK(NPDLA))==0) && spincount > 0)
419*26197Ssklower 			spincount--;
420*26197Ssklower 		if (spincount==0) {
421*26197Ssklower 			printf("ix%d: failed to reinitialize DLA module\n",
422*26197Ssklower 					unit);
423*26197Ssklower 			splx(x);
424*26197Ssklower 		}
425*26197Ssklower 		splx(x);
426*26197Ssklower #endif
427*26197Ssklower 	}
428*26197Ssklower 	rpb[0] = 6;		/* RPB length */
429*26197Ssklower 	rpb[2] = 0x10;		/* Share with any smart users */
430*26197Ssklower 	rpb[3] = 0;		/* Take (a copy of) all frames */
431*26197Ssklower 	rpb[5] = 8;		/* On board rcv queue length */
432*26197Ssklower 	rpb[6] = 0;		/* XMT packets as is */
433*26197Ssklower 	ix_DoReq(mp, rp, IXC_OPEN, 0, 0, rpb, 0);
434*26197Ssklower 
435*26197Ssklower 	ix->ix_aid = ep->rpb1;
436*26197Ssklower 
437*26197Ssklower 	/* Here we request our ethernet address, if we didn't reset it*/
438*26197Ssklower 	if ((ix->ix_flags & IXF_SETADDR)==0) {
439*26197Ssklower 		rpb[0] = 2;
440*26197Ssklower 		rpb[1] = ix->ix_aid;
441*26197Ssklower 		rpb[2] = 0;		/* get all stats */
442*26197Ssklower 		ix_DoReq(mp, rp, IXC_GSTAT,	/* Get Stats */
443*26197Ssklower 			 (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8,
444*26197Ssklower 			 rpb, 0);
445*26197Ssklower 		bcopy((caddr_t) &ix->ix_stats, (caddr_t) ix->ix_addr, 6);
446*26197Ssklower 	}
447*26197Ssklower 	ix->ix_if.if_flags |= IFF_RUNNING;
448*26197Ssklower 	ix->ix_flags |= IXF_RUNNING;
449*26197Ssklower 	ifp->if_watchdog = ixwatch;
450*26197Ssklower 	ifp->if_timer = ix->ix_scaninterval = IXWATCHINTERVAL;
451*26197Ssklower 	ixrint(mp, 0);
452*26197Ssklower }
453*26197Ssklower 
454*26197Ssklower /*
455*26197Ssklower  * Start output on interface.
456*26197Ssklower  * Get another datagram to send off of the interface queue,
457*26197Ssklower  * and map it to the interface before starting the output.
458*26197Ssklower  */
459*26197Ssklower ixstart(dev)
460*26197Ssklower dev_t dev;
461*26197Ssklower {
462*26197Ssklower         int len = 0;
463*26197Ssklower 	int unit = minor(dev);
464*26197Ssklower 	register struct ix_softc *ix = &ix_softc[unit];
465*26197Ssklower 	register struct mbuf *n;
466*26197Ssklower 	struct mbuf *m;
467*26197Ssklower 	int s, error = 0;
468*26197Ssklower 	struct npmaster *mp = ix->ix_mp;
469*26197Ssklower 	struct npreq *rp = ix->ix_wrp;
470*26197Ssklower 	struct CQE *ep;
471*26197Ssklower 	u_short rpb[8];
472*26197Ssklower 
473*26197Ssklower 	IF_DEQUEUE(&ix->ix_if.if_snd, m);
474*26197Ssklower 	if (m == 0) {
475*26197Ssklower 		if (ix->ix_flags & IXF_STATPENDING) {
476*26197Ssklower 			ix->ix_flags |= IXF_OACTIVE;
477*26197Ssklower 			rpb[0] = 2;
478*26197Ssklower 			rpb[1] = ix->ix_aid;
479*26197Ssklower 			rpb[2] = 0;			/* get all stats */
480*26197Ssklower 			ix_DoReq(mp, rp, IXC_GSTAT,	/* general Stats */
481*26197Ssklower 				 (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8,
482*26197Ssklower 				 rpb, ixcint);
483*26197Ssklower 		}
484*26197Ssklower 		return;
485*26197Ssklower 	}
486*26197Ssklower 	/*
487*26197Ssklower 	 * Ensure minimum packet length.
488*26197Ssklower 	 * This makes the safe assumtion that there are no virtual holes
489*26197Ssklower 	 * after the data.
490*26197Ssklower 	 * For security, it might be wise to zero out the added bytes,
491*26197Ssklower 	 * but we're mainly interested in speed at the moment.
492*26197Ssklower 	 */
493*26197Ssklower 	len = if_wubaput(&ix->ix_ifuba, m);
494*26197Ssklower 	if (len - sizeof(struct ether_header) < ETHERMIN)
495*26197Ssklower 		len = ETHERMIN + sizeof(struct ether_header);
496*26197Ssklower 
497*26197Ssklower 	ix->ix_flags |= IXF_OACTIVE;
498*26197Ssklower 
499*26197Ssklower 	/* Now setup to call np driver */
500*26197Ssklower 	rpb[0] = 8;
501*26197Ssklower 	rpb[1] = ix->ix_aid;
502*26197Ssklower 	ix_DoReq(mp, rp, IXC_XMIT,			 /* send frame */
503*26197Ssklower 		    ix->ix_ifuba.ifu_w.ifrw_info, len, rpb, ixcint);
504*26197Ssklower }
505*26197Ssklower 
506*26197Ssklower /*
507*26197Ssklower  * Command done interrupt. (almost)
508*26197Ssklower  */
509*26197Ssklower ixcint(mp, rp)
510*26197Ssklower 	struct npmaster *mp;
511*26197Ssklower 	struct npreq *rp;
512*26197Ssklower {
513*26197Ssklower 	struct CQE *ep;
514*26197Ssklower 	register struct ix_softc *ix;
515*26197Ssklower 	int s = splimp();
516*26197Ssklower 
517*26197Ssklower 	ep = rp->element;
518*26197Ssklower 	ix = (struct ix_softc *)ep->cqe_famid;
519*26197Ssklower 	if ((ix->ix_flags & IXF_OACTIVE) == 0) {
520*26197Ssklower 		printf("ix%d: stray xmit interrupt, npreq=%x\n",
521*26197Ssklower 			ix->ix_if.if_unit, rp);
522*26197Ssklower 	}
523*26197Ssklower 	ix->ix_flags &= ~IXF_OACTIVE;
524*26197Ssklower 
525*26197Ssklower 	switch (ep->cqe_func) {
526*26197Ssklower 
527*26197Ssklower 	case IXC_XMIT:
528*26197Ssklower 		if (ep->cqe_sts == 1)
529*26197Ssklower 			ix->ix_if.if_opackets++;
530*26197Ssklower 		else
531*26197Ssklower 			ix->ix_if.if_oerrors++;
532*26197Ssklower 		break;
533*26197Ssklower 
534*26197Ssklower 	case IXC_GSTAT:
535*26197Ssklower 		if (ep->cqe_sts == 1)
536*26197Ssklower 			ix->ix_if.if_collisions = ix->ix_stats.ixg.macg_xrty;
537*26197Ssklower 		break;
538*26197Ssklower 	}
539*26197Ssklower 	if (ix->ix_ifuba.ifu_xtofree) {
540*26197Ssklower 		m_freem(ix->ix_ifuba.ifu_xtofree);
541*26197Ssklower 		ix->ix_ifuba.ifu_xtofree = 0;
542*26197Ssklower 	}
543*26197Ssklower done:
544*26197Ssklower 	ixstart(ix->ix_if.if_unit);
545*26197Ssklower 	splx(s);
546*26197Ssklower }
547*26197Ssklower 
548*26197Ssklower /*
549*26197Ssklower  * Ethernet interface receiver interrupt.
550*26197Ssklower  * If input error just drop packet.
551*26197Ssklower  * Otherwise purge input buffered data path and examine
552*26197Ssklower  * packet to determine type.  If can't determine length
553*26197Ssklower  * from type, then have to drop packet.  Othewise decapsulate
554*26197Ssklower  * packet based on type and pass to type specific higher-level
555*26197Ssklower  * input routine.
556*26197Ssklower  */
557*26197Ssklower ixrint(mp, rp)
558*26197Ssklower 	struct npmaster *mp;
559*26197Ssklower 	struct npreq *rp;
560*26197Ssklower {
561*26197Ssklower 	struct CQE *ep;
562*26197Ssklower 	register struct ix_softc *ix = ix_softc + mp->unit;
563*26197Ssklower 	register struct ether_header *il;
564*26197Ssklower     	struct mbuf *m;
565*26197Ssklower 	int len, off, resid, s;
566*26197Ssklower 	register struct ifqueue *inq;
567*26197Ssklower 
568*26197Ssklower 	if ((ix->ix_flags & IXF_RUNNING) == 0)
569*26197Ssklower 		return;
570*26197Ssklower 	if (rp == 0)
571*26197Ssklower 		goto setup;
572*26197Ssklower 	ix->ix_flags &= ~IXF_RCVPENDING;
573*26197Ssklower 	ep = rp->element;
574*26197Ssklower 	ix->ix_if.if_ipackets++;
575*26197Ssklower 	if (ix->ix_ifuba.ifu_flags & UBA_NEEDBDP)
576*26197Ssklower 		UBAPURGE(ix->ix_ifuba.ifu_uba, ix->ix_ifuba.ifu_r.ifrw_bdp);
577*26197Ssklower 	il = (struct ether_header *)(ix->ix_ifuba.ifu_r.ifrw_addr);
578*26197Ssklower 	len = ep->cqe_bcnt - sizeof (struct ether_header);
579*26197Ssklower 	if (ep->cqe_sts != NPDONE
580*26197Ssklower 	    || ep->cqe_ust0 != NPDONE
581*26197Ssklower 	    || ep->cqe_ust1 != NPOK) {
582*26197Ssklower 		printf("ixrint: cqe error %x, %x, %x\n",
583*26197Ssklower 			ep->cqe_sts, ep->cqe_ust0, ep->cqe_ust1);
584*26197Ssklower 		if (++ix->ix_badcqe > 100) {
585*26197Ssklower 			ix->ix_badcqe = 0;
586*26197Ssklower 			printf("ixrint: shutting down unix dla\n");
587*26197Ssklower 			ix->ix_if.if_flags &= ~IFF_UP;
588*26197Ssklower 			return;
589*26197Ssklower 		}
590*26197Ssklower 		goto setup;
591*26197Ssklower 	}
592*26197Ssklower 
593*26197Ssklower 	if ( len < 46 || len > ETHERMTU) {
594*26197Ssklower 		ix->ix_if.if_ierrors++;
595*26197Ssklower #ifdef notdef
596*26197Ssklower 		if (ix->ix_if.if_ierrors % 100 == 0)
597*26197Ssklower 			printf("ix%d: += 100 input errors\n", unit);
598*26197Ssklower #endif
599*26197Ssklower 		goto setup;
600*26197Ssklower 	}
601*26197Ssklower 
602*26197Ssklower 	/*
603*26197Ssklower 	 * Deal with trailer protocol: if type is trailer type
604*26197Ssklower 	 * get true type from first 16-bit word past data.
605*26197Ssklower 	 * Remember that type was trailer by setting off.
606*26197Ssklower 	 */
607*26197Ssklower 	il->ether_type = ntohs((u_short)il->ether_type);
608*26197Ssklower #define	ildataaddr(il, off, type)	((type)(((caddr_t)((il)+1)+(off))))
609*26197Ssklower 	if (il->ether_type >= ETHERTYPE_TRAIL &&
610*26197Ssklower 	    il->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
611*26197Ssklower 		off = (il->ether_type - ETHERTYPE_TRAIL) * 512;
612*26197Ssklower 		if (off >= ETHERMTU)
613*26197Ssklower 			goto setup;		/* sanity */
614*26197Ssklower 		il->ether_type = ntohs(*ildataaddr(il, off, u_short *));
615*26197Ssklower 		resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
616*26197Ssklower 		if (off + resid > len)
617*26197Ssklower 			goto setup;		/* sanity */
618*26197Ssklower 		len = off + resid;
619*26197Ssklower 	} else
620*26197Ssklower 		off = 0;
621*26197Ssklower 	if (len == 0)
622*26197Ssklower 		goto setup;
623*26197Ssklower 
624*26197Ssklower 	/*
625*26197Ssklower 	 * Pull packet off interface.  Off is nonzero if packet
626*26197Ssklower 	 * has trailing header; ilget will then force this header
627*26197Ssklower 	 * information to be at the front, but we still have to drop
628*26197Ssklower 	 * the type and length which are at the front of any trailer data.
629*26197Ssklower 	 */
630*26197Ssklower 	m = if_rubaget(&ix->ix_ifuba, len, off, &ix->ix_if);
631*26197Ssklower 	if (m == 0)
632*26197Ssklower 		goto setup;
633*26197Ssklower 	if (off) {
634*26197Ssklower 		struct ifnet *ifp;
635*26197Ssklower 
636*26197Ssklower 		ifp = *(mtod(m, struct ifnet **));
637*26197Ssklower 		m->m_off += 2 * sizeof (u_short);
638*26197Ssklower 		m->m_len -= 2 * sizeof (u_short);
639*26197Ssklower 		*(mtod(m, struct ifnet **)) = ifp;
640*26197Ssklower 	}
641*26197Ssklower 	switch (il->ether_type) {
642*26197Ssklower 
643*26197Ssklower #ifdef INET
644*26197Ssklower 	case ETHERTYPE_IP:
645*26197Ssklower 		schednetisr(NETISR_IP);
646*26197Ssklower 		inq = &ipintrq;
647*26197Ssklower 		break;
648*26197Ssklower 
649*26197Ssklower 	case ETHERTYPE_ARP:
650*26197Ssklower 		arpinput(&ix->ix_ac, m);
651*26197Ssklower 		goto setup;
652*26197Ssklower #endif
653*26197Ssklower #ifdef NS
654*26197Ssklower 	case ETHERTYPE_NS:
655*26197Ssklower 		schednetisr(NETISR_NS);
656*26197Ssklower 		inq = &nsintrq;
657*26197Ssklower 		break;
658*26197Ssklower 
659*26197Ssklower #endif
660*26197Ssklower 	default:
661*26197Ssklower 		m_freem(m);
662*26197Ssklower 		goto setup;
663*26197Ssklower 	}
664*26197Ssklower 
665*26197Ssklower 	s = splimp();
666*26197Ssklower 	if (IF_QFULL(inq)) {
667*26197Ssklower 		IF_DROP(inq);
668*26197Ssklower 		m_freem(m);
669*26197Ssklower 	} else
670*26197Ssklower 		IF_ENQUEUE(inq, m);
671*26197Ssklower 	splx(s);
672*26197Ssklower 
673*26197Ssklower setup:
674*26197Ssklower 	/*
675*26197Ssklower 	 * Reset for next packet if possible.
676*26197Ssklower 	 * If waiting for transmit command completion, set flag
677*26197Ssklower 	 * and wait until command completes.
678*26197Ssklower 	 */
679*26197Ssklower 	if (rp == 0) {
680*26197Ssklower 		rp = ix->ix_rrp;
681*26197Ssklower 		rp->intr = ixrint;
682*26197Ssklower 		ep = rp->element;
683*26197Ssklower 	}
684*26197Ssklower 	len = ETHERMTU + sizeof(struct ether_header);
685*26197Ssklower 
686*26197Ssklower 	/* Now setup to call np driver */
687*26197Ssklower 	/* Initializations of request structure */
688*26197Ssklower 
689*26197Ssklower 	ep->cqe_func = IXC_RECV;			/* get frame */
690*26197Ssklower 	ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR;		/* Clear status */
691*26197Ssklower 	ep->cqe_bcnt = len;				/* Byte count */
692*26197Ssklower 	ep->cqe_lenrpb = 10;				/* RPB length */
693*26197Ssklower 	ep->rpb1 = ix->ix_aid;				/* which channel */
694*26197Ssklower 	ep->rpb2 = 65535;				/* Timeout */
695*26197Ssklower 
696*26197Ssklower 	ix->ix_flags |= IXF_RCVPENDING;
697*26197Ssklower 
698*26197Ssklower 	s = spl4();
699*26197Ssklower 	NpAddCQE(ep, &mp->shmemp->devcq, mp); /* Add CQE to device's queue */
700*26197Ssklower 	splx(s);
701*26197Ssklower }
702*26197Ssklower 
703*26197Ssklower 
704*26197Ssklower /*
705*26197Ssklower  * Watchdog routine, request statistics from board.
706*26197Ssklower  */
707*26197Ssklower ixwatch(unit)
708*26197Ssklower 	int unit;
709*26197Ssklower {
710*26197Ssklower 	register struct ix_softc *ix = &ix_softc[unit];
711*26197Ssklower 	register struct ifnet *ifp = &ix->ix_if;
712*26197Ssklower 	int s;
713*26197Ssklower 
714*26197Ssklower 	if (ix->ix_flags & IXF_STATPENDING) {
715*26197Ssklower 		ifp->if_timer = ix->ix_scaninterval;
716*26197Ssklower 		return;
717*26197Ssklower 	}
718*26197Ssklower 	s = splimp();
719*26197Ssklower 	ix->ix_flags |= IXF_STATPENDING;
720*26197Ssklower 	if ((ix->ix_flags & IXF_OACTIVE) == 0)
721*26197Ssklower 		ixstart(ifp->if_unit);
722*26197Ssklower 	splx(s);
723*26197Ssklower 	ifp->if_timer = ix->ix_scaninterval;
724*26197Ssklower }
725*26197Ssklower /*
726*26197Ssklower  * Process an ioctl request.
727*26197Ssklower  */
728*26197Ssklower ixioctl(ifp, cmd, data)
729*26197Ssklower 	register struct ifnet *ifp;
730*26197Ssklower 	int cmd;
731*26197Ssklower 	caddr_t data;
732*26197Ssklower {
733*26197Ssklower 	register struct ifaddr *ifa = (struct ifaddr *)data;
734*26197Ssklower 	register struct ix_softc *ix = &ix_softc[ifp->if_unit];
735*26197Ssklower 	int s = splimp(), error = 0;
736*26197Ssklower 
737*26197Ssklower 	switch (cmd) {
738*26197Ssklower 
739*26197Ssklower 	case SIOCSIFADDR:
740*26197Ssklower 		ifp->if_flags |= IFF_UP;
741*26197Ssklower 		ixinit(ifp->if_unit);
742*26197Ssklower 		if ((ifp->if_flags & IFF_UP) == 0)
743*26197Ssklower 			return (EBUSY);
744*26197Ssklower 
745*26197Ssklower 		switch (ifa->ifa_addr.sa_family) {
746*26197Ssklower #ifdef INET
747*26197Ssklower 		case AF_INET:
748*26197Ssklower 			((struct arpcom *)ifp)->ac_ipaddr =
749*26197Ssklower 				IA_SIN(ifa)->sin_addr;
750*26197Ssklower 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
751*26197Ssklower 			break;
752*26197Ssklower #endif
753*26197Ssklower #ifdef NS
754*26197Ssklower 		case AF_NS:
755*26197Ssklower 		    {
756*26197Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
757*26197Ssklower 
758*26197Ssklower 			if (ns_nullhost(*ina)) {
759*26197Ssklower 				ina->x_host = * (union ns_host *)
760*26197Ssklower 				     (ix_softc[ifp->if_unit].ix_addr);
761*26197Ssklower 			} else {
762*26197Ssklower 			    return
763*26197Ssklower 				ix_setaddr(ina->x_host.c_host, ifp->if_unit);
764*26197Ssklower 			}
765*26197Ssklower 			break;
766*26197Ssklower 		    }
767*26197Ssklower #endif
768*26197Ssklower 		}
769*26197Ssklower 		break;
770*26197Ssklower 
771*26197Ssklower 	case SIOCSIFFLAGS:
772*26197Ssklower 		if ((ifp->if_flags & IFF_UP) == 0 &&
773*26197Ssklower 		    ix->ix_flags & IXF_RUNNING) {
774*26197Ssklower 			ix->ix_flags &= ~IXF_RUNNING;
775*26197Ssklower 			NpReset(ix->ix_mp, 0);
776*26197Ssklower 		} else if (ifp->if_flags & IFF_UP &&
777*26197Ssklower 		    (ix->ix_flags & IXF_RUNNING) == 0)
778*26197Ssklower 			ixinit(ifp->if_unit);
779*26197Ssklower 		break;
780*26197Ssklower 
781*26197Ssklower 	default:
782*26197Ssklower 		error = EINVAL;
783*26197Ssklower 	}
784*26197Ssklower 	splx(s);
785*26197Ssklower 	return (error);
786*26197Ssklower }
787*26197Ssklower 
788*26197Ssklower /*
789*26197Ssklower  * set ethernet address for unit
790*26197Ssklower  */
791*26197Ssklower ix_setaddr(physaddr, unit)
792*26197Ssklower u_char *physaddr;
793*26197Ssklower int unit;
794*26197Ssklower {
795*26197Ssklower 	register struct ix_softc *ix = &ix_softc[unit];
796*26197Ssklower 
797*26197Ssklower 	if (! (ix->ix_flags & IXF_RUNNING))
798*26197Ssklower 		return (EBUSY);
799*26197Ssklower 
800*26197Ssklower 	/* The following is a big cop out due to the fact that
801*26197Ssklower 	   Changing the ethernet address resets the dla module,
802*26197Ssklower 	   so must re-open the channel, anyway. */
803*26197Ssklower 
804*26197Ssklower 
805*26197Ssklower 	bcopy((caddr_t)physaddr, (caddr_t)ix->ix_addr, sizeof ix->ix_addr);
806*26197Ssklower 	ix->ix_flags &= ~IXF_RUNNING;
807*26197Ssklower 	ix->ix_flags |= IXF_SETADDR;
808*26197Ssklower 	ixinit(unit);
809*26197Ssklower 	NpKill(ix->ix_mp, ix->ix_rrp);
810*26197Ssklower }
811*26197Ssklower #endif
812