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