if_eg.c revision 1.23 1 /* $NetBSD: if_eg.c,v 1.23 1996/03/17 00:53:22 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1993 Dean Huxley <dean (at) fsa.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Dean Huxley.
18 * 4. The name of Dean Huxley may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * Support for 3Com 3c505 Etherlink+ card.
34 */
35
36 /* To do:
37 * - multicast
38 * - promiscuous
39 */
40 #include "bpfilter.h"
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/mbuf.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/syslog.h>
49 #include <sys/select.h>
50 #include <sys/device.h>
51
52 #include <net/if.h>
53 #include <net/netisr.h>
54 #include <net/if_dl.h>
55 #include <net/if_types.h>
56 #include <net/netisr.h>
57
58 #ifdef INET
59 #include <netinet/in.h>
60 #include <netinet/in_systm.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip.h>
63 #include <netinet/if_ether.h>
64 #endif
65
66 #ifdef NS
67 #include <netns/ns.h>
68 #include <netns/ns_if.h>
69 #endif
70
71 #if NBPFILTER > 0
72 #include <net/bpf.h>
73 #include <net/bpfdesc.h>
74 #endif
75
76 #include <machine/cpu.h>
77 #include <machine/pio.h>
78
79 #include <dev/isa/isavar.h>
80 #include <dev/isa/if_egreg.h>
81 #include <dev/isa/elink.h>
82
83 /* for debugging convenience */
84 #ifdef EGDEBUG
85 #define dprintf(x) printf x
86 #else
87 #define dprintf(x)
88 #endif
89
90 #define ETHER_MIN_LEN 64
91 #define ETHER_MAX_LEN 1518
92 #define ETHER_ADDR_LEN 6
93
94 #define EG_INLEN 10
95 #define EG_BUFLEN 0x0670
96
97 /*
98 * Ethernet software status per interface.
99 */
100 struct eg_softc {
101 struct device sc_dev;
102 void *sc_ih;
103 struct arpcom sc_arpcom; /* Ethernet common part */
104 int eg_cmd; /* Command register R/W */
105 int eg_ctl; /* Control register R/W (EG_CTL_*) */
106 int eg_stat; /* Status register R/O (EG_STAT_*) */
107 int eg_data; /* Data register R/W (16 bits) */
108 u_char eg_rom_major; /* Cards ROM version (major number) */
109 u_char eg_rom_minor; /* Cards ROM version (minor number) */
110 short eg_ram; /* Amount of RAM on the card */
111 u_char eg_pcb[64]; /* Primary Command Block buffer */
112 u_char eg_incount; /* Number of buffers currently used */
113 u_char *eg_inbuf; /* Incoming packet buffer */
114 u_char *eg_outbuf; /* Outgoing packet buffer */
115 };
116
117 int egprobe __P((struct device *, void *, void *));
118 void egattach __P((struct device *, struct device *, void *));
119
120 struct cfattach eg_ca = {
121 sizeof(struct eg_softc), egprobe, egattach
122 };
123
124 struct cfdriver eg_cd = {
125 NULL, "eg", DV_IFNET
126 };
127
128 int egintr __P((void *));
129 void eginit __P((struct eg_softc *));
130 int egioctl __P((struct ifnet *, u_long, caddr_t));
131 void egrecv __P((struct eg_softc *));
132 void egstart __P((struct ifnet *));
133 void egwatchdog __P((int));
134 void egreset __P((struct eg_softc *));
135 void egread __P((struct eg_softc *, caddr_t, int));
136 struct mbuf *egget __P((struct eg_softc *, caddr_t, int));
137 void egstop __P((struct eg_softc *));
138
139 /*
140 * Support stuff
141 */
142
143 static inline void
144 egprintpcb(sc)
145 struct eg_softc *sc;
146 {
147 int i;
148
149 for (i = 0; i < sc->eg_pcb[1] + 2; i++)
150 dprintf(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
151 }
152
153
154 static inline void
155 egprintstat(b)
156 u_char b;
157 {
158 dprintf(("%s %s %s %s %s %s %s\n",
159 (b & EG_STAT_HCRE)?"HCRE":"",
160 (b & EG_STAT_ACRF)?"ACRF":"",
161 (b & EG_STAT_DIR )?"DIR ":"",
162 (b & EG_STAT_DONE)?"DONE":"",
163 (b & EG_STAT_ASF3)?"ASF3":"",
164 (b & EG_STAT_ASF2)?"ASF2":"",
165 (b & EG_STAT_ASF1)?"ASF1":""));
166 }
167
168 static int
169 egoutPCB(sc, b)
170 struct eg_softc *sc;
171 u_char b;
172 {
173 int i;
174
175 for (i=0; i < 4000; i++) {
176 if (inb(sc->eg_stat) & EG_STAT_HCRE) {
177 outb(sc->eg_cmd, b);
178 return 0;
179 }
180 delay(10);
181 }
182 dprintf(("egoutPCB failed\n"));
183 return 1;
184 }
185
186 static int
187 egreadPCBstat(sc, statb)
188 struct eg_softc *sc;
189 u_char statb;
190 {
191 int i;
192
193 for (i=0; i < 5000; i++) {
194 if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL)
195 break;
196 delay(10);
197 }
198 if ((inb(sc->eg_stat) & EG_PCB_STAT) == statb)
199 return 0;
200 return 1;
201 }
202
203 static int
204 egreadPCBready(sc)
205 struct eg_softc *sc;
206 {
207 int i;
208
209 for (i=0; i < 10000; i++) {
210 if (inb(sc->eg_stat) & EG_STAT_ACRF)
211 return 0;
212 delay(5);
213 }
214 dprintf(("PCB read not ready\n"));
215 return 1;
216 }
217
218 static int
219 egwritePCB(sc)
220 struct eg_softc *sc;
221 {
222 int i;
223 u_char len;
224
225 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
226
227 len = sc->eg_pcb[1] + 2;
228 for (i = 0; i < len; i++)
229 egoutPCB(sc, sc->eg_pcb[i]);
230
231 for (i=0; i < 4000; i++) {
232 if (inb(sc->eg_stat) & EG_STAT_HCRE)
233 break;
234 delay(10);
235 }
236
237 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_DONE);
238
239 egoutPCB(sc, len);
240
241 if (egreadPCBstat(sc, EG_PCB_ACCEPT))
242 return 1;
243 return 0;
244 }
245
246 static int
247 egreadPCB(sc)
248 struct eg_softc *sc;
249 {
250 int i;
251 u_char b;
252
253 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_NULL);
254
255 bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
256
257 if (egreadPCBready(sc))
258 return 1;
259
260 sc->eg_pcb[0] = inb(sc->eg_cmd);
261
262 if (egreadPCBready(sc))
263 return 1;
264
265 sc->eg_pcb[1] = inb(sc->eg_cmd);
266
267 if (sc->eg_pcb[1] > 62) {
268 dprintf(("len %d too large\n", sc->eg_pcb[1]));
269 return 1;
270 }
271
272 for (i = 0; i < sc->eg_pcb[1]; i++) {
273 if (egreadPCBready(sc))
274 return 1;
275 sc->eg_pcb[2+i] = inb(sc->eg_cmd);
276 }
277 if (egreadPCBready(sc))
278 return 1;
279 if (egreadPCBstat(sc, EG_PCB_DONE))
280 return 1;
281 if ((b = inb(sc->eg_cmd)) != sc->eg_pcb[1] + 2) {
282 dprintf(("%d != %d\n", b, sc->eg_pcb[1] + 2));
283 return 1;
284 }
285
286 outb(sc->eg_ctl, (inb(sc->eg_ctl) & ~EG_PCB_STAT) | EG_PCB_ACCEPT);
287
288 return 0;
289 }
290
291 /*
292 * Real stuff
293 */
294
295 int
296 egprobe(parent, match, aux)
297 struct device *parent;
298 void *match, *aux;
299 {
300 struct eg_softc *sc = match;
301 struct isa_attach_args *ia = aux;
302 int i;
303
304 if (ia->ia_iobase & ~0x07f0 != 0) {
305 dprintf(("Weird iobase %x\n", ia->ia_iobase));
306 return 0;
307 }
308
309 sc->eg_cmd = ia->ia_iobase + EG_COMMAND;
310 sc->eg_ctl = ia->ia_iobase + EG_CONTROL;
311 sc->eg_stat = ia->ia_iobase + EG_STATUS;
312 sc->eg_data = ia->ia_iobase + EG_DATA;
313
314 /* hard reset card */
315 outb(sc->eg_ctl, EG_CTL_RESET);
316 outb(sc->eg_ctl, 0);
317 for (i = 0; i < 5000; i++) {
318 delay(1000);
319 if ((inb(sc->eg_stat) & EG_PCB_STAT) == EG_PCB_NULL)
320 break;
321 }
322 if ((inb(sc->eg_stat) & EG_PCB_STAT) != EG_PCB_NULL) {
323 dprintf(("eg: Reset failed\n"));
324 return 0;
325 }
326 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
327 sc->eg_pcb[1] = 0;
328 if (egwritePCB(sc) != 0)
329 return 0;
330
331 if (egreadPCB(sc) != 0) {
332 egprintpcb(sc);
333 return 0;
334 }
335
336 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
337 sc->eg_pcb[1] != 0x0a) {
338 egprintpcb(sc);
339 return 0;
340 }
341 sc->eg_rom_major = sc->eg_pcb[3];
342 sc->eg_rom_minor = sc->eg_pcb[2];
343 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
344
345 ia->ia_iosize = 0x08;
346 ia->ia_msize = 0;
347 return 1;
348 }
349
350 void
351 egattach(parent, self, aux)
352 struct device *parent, *self;
353 void *aux;
354 {
355 struct eg_softc *sc = (void *)self;
356 struct isa_attach_args *ia = aux;
357 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
358 int i;
359
360 egstop(sc);
361
362 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
363 sc->eg_pcb[1] = 0;
364 if (egwritePCB(sc) != 0) {
365 dprintf(("write error\n"));
366 return;
367 }
368 if (egreadPCB(sc) != 0) {
369 dprintf(("read error\n"));
370 egprintpcb(sc);
371 return;
372 }
373
374 /* check Get station address response */
375 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
376 dprintf(("parse error\n"));
377 egprintpcb(sc);
378 return;
379 }
380 bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
381
382 printf(": ROM v%d.%02d %dk address %s\n",
383 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
384 ether_sprintf(sc->sc_arpcom.ac_enaddr));
385
386 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
387 if (egwritePCB(sc) != 0) {
388 dprintf(("write error2\n"));
389 return;
390 }
391 if (egreadPCB(sc) != 0) {
392 dprintf(("read error2\n"));
393 egprintpcb(sc);
394 return;
395 }
396 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
397 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
398 dprintf(("parse error2\n"));
399 egprintpcb(sc);
400 return;
401 }
402
403 /* Initialize ifnet structure. */
404 ifp->if_unit = sc->sc_dev.dv_unit;
405 ifp->if_name = eg_cd.cd_name;
406 ifp->if_start = egstart;
407 ifp->if_ioctl = egioctl;
408 ifp->if_watchdog = egwatchdog;
409 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
410
411 /* Now we can attach the interface. */
412 if_attach(ifp);
413 ether_ifattach(ifp);
414
415 #if NBPFILTER > 0
416 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
417 #endif
418
419 sc->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_NET, egintr,
420 sc);
421 }
422
423 void
424 eginit(sc)
425 register struct eg_softc *sc;
426 {
427 register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
428
429 /* soft reset the board */
430 outb(sc->eg_ctl, EG_CTL_FLSH);
431 delay(100);
432 outb(sc->eg_ctl, EG_CTL_ATTN);
433 delay(100);
434 outb(sc->eg_ctl, 0);
435 delay(200);
436
437 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
438 sc->eg_pcb[1] = 2;
439 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
440 sc->eg_pcb[3] = 0;
441 if (egwritePCB(sc) != 0)
442 dprintf(("write error3\n"));
443
444 if (egreadPCB(sc) != 0) {
445 dprintf(("read error\n"));
446 egprintpcb(sc);
447 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
448 printf("%s: configure card command failed\n",
449 sc->sc_dev.dv_xname);
450
451 if (sc->eg_inbuf == 0)
452 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
453 sc->eg_incount = 0;
454
455 if (sc->eg_outbuf == 0)
456 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
457
458 outb(sc->eg_ctl, EG_CTL_CMDE);
459
460 sc->eg_incount = 0;
461 egrecv(sc);
462
463 /* Interface is now `running', with no output active. */
464 ifp->if_flags |= IFF_RUNNING;
465 ifp->if_flags &= ~IFF_OACTIVE;
466
467 /* Attempt to start output, if any. */
468 egstart(ifp);
469 }
470
471 void
472 egrecv(sc)
473 struct eg_softc *sc;
474 {
475
476 while (sc->eg_incount < EG_INLEN) {
477 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
478 sc->eg_pcb[1] = 0x08;
479 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
480 sc->eg_pcb[3] = 0;
481 sc->eg_pcb[4] = 0;
482 sc->eg_pcb[5] = 0;
483 sc->eg_pcb[6] = EG_BUFLEN; /* our buffer size */
484 sc->eg_pcb[7] = EG_BUFLEN >> 8;
485 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
486 sc->eg_pcb[9] = 0;
487 if (egwritePCB(sc) != 0)
488 break;
489 sc->eg_incount++;
490 }
491 }
492
493 void
494 egstart(ifp)
495 struct ifnet *ifp;
496 {
497 register struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit];
498 struct mbuf *m0, *m;
499 caddr_t buffer;
500 int len;
501 u_short *ptr;
502
503 /* Don't transmit if interface is busy or not running */
504 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
505 return;
506
507 loop:
508 /* Dequeue the next datagram. */
509 IF_DEQUEUE(&ifp->if_snd, m0);
510 if (m0 == 0)
511 return;
512
513 ifp->if_flags |= IFF_OACTIVE;
514
515 /* We need to use m->m_pkthdr.len, so require the header */
516 if ((m0->m_flags & M_PKTHDR) == 0)
517 panic("egstart: no header mbuf");
518 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
519
520 #if NBPFILTER > 0
521 if (ifp->if_bpf)
522 bpf_mtap(ifp->if_bpf, m0);
523 #endif
524
525 sc->eg_pcb[0] = EG_CMD_SENDPACKET;
526 sc->eg_pcb[1] = 0x06;
527 sc->eg_pcb[2] = 0; /* address not used, we send zero */
528 sc->eg_pcb[3] = 0;
529 sc->eg_pcb[4] = 0;
530 sc->eg_pcb[5] = 0;
531 sc->eg_pcb[6] = len; /* length of packet */
532 sc->eg_pcb[7] = len >> 8;
533 if (egwritePCB(sc) != 0) {
534 dprintf(("egwritePCB in egstart failed\n"));
535 ifp->if_oerrors++;
536 ifp->if_flags &= ~IFF_OACTIVE;
537 goto loop;
538 }
539
540 buffer = sc->eg_outbuf;
541 for (m = m0; m != 0; m = m->m_next) {
542 bcopy(mtod(m, caddr_t), buffer, m->m_len);
543 buffer += m->m_len;
544 }
545
546 /* set direction bit: host -> adapter */
547 outb(sc->eg_ctl, inb(sc->eg_ctl) & ~EG_CTL_DIR);
548
549 for (ptr = (u_short *) sc->eg_outbuf; len > 0; len -= 2) {
550 outw(sc->eg_data, *ptr++);
551 while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
552 ; /* XXX need timeout here */
553 }
554
555 m_freem(m0);
556 }
557
558 int
559 egintr(arg)
560 void *arg;
561 {
562 register struct eg_softc *sc = arg;
563 int i, len;
564 u_short *ptr;
565
566 while (inb(sc->eg_stat) & EG_STAT_ACRF) {
567 egreadPCB(sc);
568 switch (sc->eg_pcb[0]) {
569 case EG_RSP_RECVPACKET:
570 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
571
572 /* Set direction bit : Adapter -> host */
573 outb(sc->eg_ctl, inb(sc->eg_ctl) | EG_CTL_DIR);
574
575 for (ptr = (u_short *) sc->eg_inbuf; len > 0; len -= 2) {
576 while (!(inb(sc->eg_stat) & EG_STAT_HRDY))
577 ;
578 *ptr++ = inw(sc->eg_data);
579 }
580
581 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
582 egread(sc, sc->eg_inbuf, len);
583
584 sc->eg_incount--;
585 egrecv(sc);
586 break;
587
588 case EG_RSP_SENDPACKET:
589 if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
590 dprintf(("packet dropped\n"));
591 sc->sc_arpcom.ac_if.if_oerrors++;
592 } else
593 sc->sc_arpcom.ac_if.if_opackets++;
594 sc->sc_arpcom.ac_if.if_collisions += sc->eg_pcb[8] & 0xf;
595 sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
596 egstart(&sc->sc_arpcom.ac_if);
597 break;
598
599 case EG_RSP_GETSTATS:
600 dprintf(("Card Statistics\n"));
601 bcopy(&sc->eg_pcb[2], &i, sizeof(i));
602 dprintf(("Receive Packets %d\n", i));
603 bcopy(&sc->eg_pcb[6], &i, sizeof(i));
604 dprintf(("Transmit Packets %d\n", i));
605 dprintf(("CRC errors %d\n", *(short*) &sc->eg_pcb[10]));
606 dprintf(("alignment errors %d\n", *(short*) &sc->eg_pcb[12]));
607 dprintf(("no resources errors %d\n", *(short*) &sc->eg_pcb[14]));
608 dprintf(("overrun errors %d\n", *(short*) &sc->eg_pcb[16]));
609 break;
610
611 default:
612 dprintf(("egintr: Unknown response %x??\n",
613 sc->eg_pcb[0]));
614 egprintpcb(sc);
615 break;
616 }
617 }
618
619 return 0;
620 }
621
622 /*
623 * Pass a packet up to the higher levels.
624 */
625 void
626 egread(sc, buf, len)
627 struct eg_softc *sc;
628 caddr_t buf;
629 int len;
630 {
631 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
632 struct mbuf *m;
633 struct ether_header *eh;
634
635 if (len <= sizeof(struct ether_header) ||
636 len > ETHER_MAX_LEN) {
637 printf("%s: invalid packet size %d; dropping\n",
638 sc->sc_dev.dv_xname, len);
639 ifp->if_ierrors++;
640 return;
641 }
642
643 /* Pull packet off interface. */
644 m = egget(sc, buf, len);
645 if (m == 0) {
646 ifp->if_ierrors++;
647 return;
648 }
649
650 ifp->if_ipackets++;
651
652 /* We assume the header fit entirely in one mbuf. */
653 eh = mtod(m, struct ether_header *);
654
655 #if NBPFILTER > 0
656 /*
657 * Check if there's a BPF listener on this interface.
658 * If so, hand off the raw packet to BPF.
659 */
660 if (ifp->if_bpf) {
661 bpf_mtap(ifp->if_bpf, m);
662
663 /*
664 * Note that the interface cannot be in promiscuous mode if
665 * there are no BPF listeners. And if we are in promiscuous
666 * mode, we have to check if this packet is really ours.
667 */
668 if ((ifp->if_flags & IFF_PROMISC) &&
669 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
670 bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
671 sizeof(eh->ether_dhost)) != 0) {
672 m_freem(m);
673 return;
674 }
675 }
676 #endif
677
678 /* We assume the header fit entirely in one mbuf. */
679 m_adj(m, sizeof(struct ether_header));
680 ether_input(ifp, eh, m);
681 }
682
683 /*
684 * convert buf into mbufs
685 */
686 struct mbuf *
687 egget(sc, buf, totlen)
688 struct eg_softc *sc;
689 caddr_t buf;
690 int totlen;
691 {
692 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
693 struct mbuf *top, **mp, *m;
694 int len;
695
696 MGETHDR(m, M_DONTWAIT, MT_DATA);
697 if (m == 0)
698 return 0;
699 m->m_pkthdr.rcvif = ifp;
700 m->m_pkthdr.len = totlen;
701 len = MHLEN;
702 top = 0;
703 mp = ⊤
704
705 while (totlen > 0) {
706 if (top) {
707 MGET(m, M_DONTWAIT, MT_DATA);
708 if (m == 0) {
709 m_freem(top);
710 return 0;
711 }
712 len = MLEN;
713 }
714 if (totlen >= MINCLSIZE) {
715 MCLGET(m, M_DONTWAIT);
716 if (m->m_flags & M_EXT)
717 len = MCLBYTES;
718 }
719 m->m_len = len = min(totlen, len);
720 bcopy((caddr_t)buf, mtod(m, caddr_t), len);
721 buf += len;
722 totlen -= len;
723 *mp = m;
724 mp = &m->m_next;
725 }
726
727 return top;
728 }
729
730 int
731 egioctl(ifp, cmd, data)
732 register struct ifnet *ifp;
733 u_long cmd;
734 caddr_t data;
735 {
736 struct eg_softc *sc = eg_cd.cd_devs[ifp->if_unit];
737 struct ifaddr *ifa = (struct ifaddr *)data;
738 struct ifreq *ifr = (struct ifreq *)data;
739 int s, error = 0;
740
741 s = splnet();
742
743 switch (cmd) {
744
745 case SIOCSIFADDR:
746 ifp->if_flags |= IFF_UP;
747
748 switch (ifa->ifa_addr->sa_family) {
749 #ifdef INET
750 case AF_INET:
751 eginit(sc);
752 arp_ifinit(&sc->sc_arpcom, ifa);
753 break;
754 #endif
755 #ifdef NS
756 case AF_NS:
757 {
758 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
759
760 if (ns_nullhost(*ina))
761 ina->x_host =
762 *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
763 else
764 bcopy(ina->x_host.c_host,
765 sc->sc_arpcom.ac_enaddr,
766 sizeof(sc->sc_arpcom.ac_enaddr));
767 /* Set new address. */
768 eginit(sc);
769 break;
770 }
771 #endif
772 default:
773 eginit(sc);
774 break;
775 }
776 break;
777
778 case SIOCSIFFLAGS:
779 if ((ifp->if_flags & IFF_UP) == 0 &&
780 (ifp->if_flags & IFF_RUNNING) != 0) {
781 /*
782 * If interface is marked down and it is running, then
783 * stop it.
784 */
785 egstop(sc);
786 ifp->if_flags &= ~IFF_RUNNING;
787 } else if ((ifp->if_flags & IFF_UP) != 0 &&
788 (ifp->if_flags & IFF_RUNNING) == 0) {
789 /*
790 * If interface is marked up and it is stopped, then
791 * start it.
792 */
793 eginit(sc);
794 } else {
795 sc->eg_pcb[0] = EG_CMD_GETSTATS;
796 sc->eg_pcb[1] = 0;
797 if (egwritePCB(sc) != 0)
798 dprintf(("write error\n"));
799 /*
800 * XXX deal with flags changes:
801 * IFF_MULTICAST, IFF_PROMISC,
802 * IFF_LINK0, IFF_LINK1,
803 */
804 }
805 break;
806
807 default:
808 error = EINVAL;
809 break;
810 }
811
812 splx(s);
813 return error;
814 }
815
816 void
817 egreset(sc)
818 struct eg_softc *sc;
819 {
820 int s;
821
822 dprintf(("egreset()\n"));
823 s = splnet();
824 egstop(sc);
825 eginit(sc);
826 splx(s);
827 }
828
829 void
830 egwatchdog(unit)
831 int unit;
832 {
833 struct eg_softc *sc = eg_cd.cd_devs[unit];
834
835 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
836 sc->sc_arpcom.ac_if.if_oerrors++;
837
838 egreset(sc);
839 }
840
841 void
842 egstop(sc)
843 register struct eg_softc *sc;
844 {
845
846 outb(sc->eg_ctl, 0);
847 }
848