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 *
ix_GetReq(mp,addr,len)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 */
ixreset(unit,uban,softp)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 */
ixinit(unit)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 */
ixwatch(unit)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 */
ixioctl(ifp,cmd,data)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 */
ix_setaddr(physaddr,unit)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 }
showme()701 static showme() {
702 return ((int) &(ix_softc->ix_badcqe));
703 }
704 #endif
705