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