|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: if_3c501.c
28: * Author: Philippe Bernadat
29: * Date: 1989
30: * Copyright (c) 1989 OSF Research Institute
31: *
32: * 3COM Etherlink 3C501 Mach Ethernet drvier
33: */
34: /*
35: Copyright 1990 by Open Software Foundation,
36: Cambridge, MA.
37:
38: All Rights Reserved
39:
40: Permission to use, copy, modify, and distribute this software and
41: its documentation for any purpose and without fee is hereby granted,
42: provided that the above copyright notice appears in all copies and
43: that both the copyright notice and this permission notice appear in
44: supporting documentation, and that the name of OSF or Open Software
45: Foundation not be used in advertising or publicity pertaining to
46: distribution of the software without specific, written prior
47: permission.
48:
49: OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
50: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
51: IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
52: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
53: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
54: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
55: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56: */
57:
58: #include <at3c501.h>
59:
60: #ifdef MACH_KERNEL
61: #include <kern/time_out.h>
62: #include <device/device_types.h>
63: #include <device/errno.h>
64: #include <device/io_req.h>
65: #include <device/if_hdr.h>
66: #include <device/if_ether.h>
67: #include <device/net_status.h>
68: #include <device/net_io.h>
69: #else MACH_KERNEL
70: #include <sys/param.h>
71: #include <mach/machine/vm_param.h>
72: #include <sys/systm.h>
73: #include <sys/mbuf.h>
74: #include <sys/buf.h>
75: #include <sys/protosw.h>
76: #include <sys/socket.h>
77: #include <sys/vmmac.h>
78: #include <sys/ioctl.h>
79: #include <sys/errno.h>
80: #include <sys/syslog.h>
81:
82: #include <net/if.h>
83: #include <net/netisr.h>
84: #include <net/route.h>
85:
86: #ifdef INET
87: #include <netinet/in.h>
88: #include <netinet/in_systm.h>
89: #include <netinet/in_var.h>
90: #include <netinet/ip.h>
91: #include <netinet/if_ether.h>
92: #endif
93:
94: #ifdef NS
95: #include <netns/ns.h>
96: #include <netns/ns_if.h>
97: #endif
98: #endif MACH_KERNEL
99:
100: #include <i386/ipl.h>
101: #include <chips/busses.h>
102: #include <i386at/if_3c501.h>
103:
104: #define SPLNET spl6
105:
106: int at3c501probe();
107: void at3c501attach();
108: int at3c501intr();
109: int at3c501init();
110: int at3c501output();
111: int at3c501ioctl();
112: int at3c501reset();
113: int at3c501watch();
114:
115: static vm_offset_t at3c501_std[NAT3C501] = { 0 };
116: static struct bus_device *at3c501_info[NAT3C501];
117: struct bus_driver at3c501driver =
118: {at3c501probe, 0, at3c501attach, 0, at3c501_std, "et", at3c501_info, };
119:
120: int watchdog_id;
121:
122: typedef struct {
123: #ifdef MACH_KERNEL
124: struct ifnet ds_if; /* generic interface header */
125: u_char ds_addr[6]; /* Ethernet hardware address */
126: #else MACH_KERNEL
127: struct arpcom at3c501_ac;
128: #define ds_if at3c501_ac.ac_if
129: #define ds_addr at3c501_ac.ac_enaddr
130: #endif MACH_KERNEL
131: int flags;
132: int timer;
133: char *base;
134: u_char address[ETHER_ADD_SIZE];
135: short mode;
136: int badxmt;
137: int badrcv;
138: int spurious;
139: int rcv;
140: int xmt;
141: } at3c501_softc_t;
142:
143: at3c501_softc_t at3c501_softc[NAT3C501];
144:
145: /*
146: * at3c501probe:
147: *
148: * This function "probes" or checks for the 3c501 board on the bus to see
149: * if it is there. As far as I can tell, the best break between this
150: * routine and the attach code is to simply determine whether the board
151: * is configured in properly. Currently my approach to this is to write
152: * and read a string from the Packet Buffer on the board being probed.
153: * If the string comes back properly then we assume the board is there.
154: * The config code expects to see a successful return from the probe
155: * routine before attach will be called.
156: *
157: * input : address device is mapped to, and unit # being checked
158: * output : a '1' is returned if the board exists, and a 0 otherwise
159: *
160: */
161: at3c501probe(port, dev)
162: struct bus_device *dev;
163: {
164: caddr_t base = (caddr_t)dev->address;
165: int unit = dev->unit;
166: char inbuf[50];
167: char *str = "3c501 ethernet board %d out of range\n";
168: int strsize = strlen(str);
169:
170: if ((unit < 0) || (unit >= NAT3C501)) {
171: printf(str, unit);
172: return(0);
173: }
174:
175: /* reset */
176: outb(IE_CSR(base), IE_RESET);
177:
178: /* write a string to the packet buffer */
179:
180: outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
181: outw(IE_GP(base), 0);
182: loutb(IE_BFR(base), str, strsize);
183:
184: /* read it back */
185:
186: outb(IE_CSR(base), IE_RIDE | IE_SYSBFR);
187: outw(IE_GP(base), 0);
188: linb(IE_BFR(base), inbuf, strsize);
189: /* compare them */
190:
191: #ifdef MACH_KERNEL
192: if (strncmp(str, inbuf, strsize))
193: #else MACH_KERNEL
194: if (bcmp(str, inbuf, strsize))
195: #endif MACH_KERNEL
196: {
197: return(0);
198: }
199: at3c501_softc[unit].base = base;
200:
201: return(1);
202: }
203:
204: /*
205: * at3c501attach:
206: *
207: * This function attaches a 3C501 board to the "system". The rest of
208: * runtime structures are initialized here (this routine is called after
209: * a successful probe of the board). Once the ethernet address is read
210: * and stored, the board's ifnet structure is attached and readied.
211: *
212: * input : bus_device structure setup in autoconfig
213: * output : board structs and ifnet is setup
214: *
215: */
216: void at3c501attach(dev)
217: struct bus_device *dev;
218: {
219: at3c501_softc_t *sp;
220: struct ifnet *ifp;
221: u_char unit;
222: caddr_t base;
223: #ifdef MACH_KERNEL
224: #else MACH_KERNEL
225: extern int tcp_recvspace;
226: tcp_recvspace = 0x300; /* empircal messure */
227: #endif MACH_KERNEL
228:
229: take_dev_irq(dev);
230: unit = (u_char)dev->unit;
231: printf(", port = %x, spl = %d, pic = %d. ",
232: dev->address, dev->sysdep, dev->sysdep1);
233:
234: sp = &at3c501_softc[unit];
235: base = sp->base;
236: if (base != (caddr_t)dev->address) {
237: printf("3C501 board %d attach address error\n", unit);
238: return;
239: }
240: sp->timer = -1;
241: sp->flags = 0;
242: sp->mode = 0;
243: outb(IE_CSR(sp->base), IE_RESET);
244: at3c501geteh(base, sp->ds_addr);
245: at3c501geteh(base, sp->address);
246: at3c501seteh(base, sp->address);
247: printf("ethernet id [%x:%x:%x:%x:%x:%x]",
248: sp->address[0],sp->address[1],sp->address[2],
249: sp->address[3],sp->address[4],sp->address[5]);
250: ifp = &(sp->ds_if);
251: ifp->if_unit = unit;
252: ifp->if_mtu = ETHERMTU;
253: ifp->if_flags = IFF_BROADCAST;
254: #ifdef MACH_KERNEL
255: ifp->if_header_size = sizeof(struct ether_header);
256: ifp->if_header_format = HDR_ETHERNET;
257: ifp->if_address_size = 6;
258: ifp->if_address = (char *)&sp->address[0];
259: if_init_queues(ifp);
260: #else MACH_KERNEL
261: ifp->if_name = "et";
262: ifp->if_init = at3c501init;
263: ifp->if_output = at3c501output;
264: ifp->if_ioctl = at3c501ioctl;
265: ifp->if_reset = at3c501reset;
266: ifp->if_next = NULL;
267: if_attach(ifp);
268: #ifdef notdef
269: watchdog_id = timeout(at3c501watch, &(ifp->if_unit), 20*HZ);
270: #endif
271: #endif MACH_KERNEL
272: }
273:
274: /*
275: * at3c501watch():
276: *
277: */
278: at3c501watch(b_ptr)
279:
280: caddr_t b_ptr;
281:
282: {
283: int x,
284: y,
285: opri,
286: unit;
287: at3c501_softc_t *is;
288:
289: unit = *b_ptr;
290: #ifdef MACH_KERNEL
291: timeout(at3c501watch,b_ptr,20*hz);
292: #else MACH_KERNEL
293: watchdog_id = timeout(at3c501watch,b_ptr,20*HZ);
294: #endif MACH_KERNEL
295: is = &at3c501_softc[unit];
296: printf("\nxmt/bad rcv/bad spurious\n");
297: printf("%d/%d %d/%d %d\n", is->xmt, is->badxmt, \
298: is->rcv, is->badrcv, is->spurious);
299: is->rcv=is->badrcv=is->xmt=is->badxmt=is->spurious=0;
300: }
301:
302: /*
303: * at3c501geteh:
304: *
305: * This function gets the ethernet address (array of 6 unsigned
306: * bytes) from the 3c501 board prom.
307: *
308: */
309:
310: at3c501geteh(base, ep)
311: caddr_t base;
312: char *ep;
313: {
314: int i;
315:
316: for (i = 0; i < ETHER_ADD_SIZE; i++) {
317: outw(IE_GP(base), i);
318: *ep++ = inb(IE_SAPROM(base));
319: }
320: }
321:
322: /*
323: * at3c501seteh:
324: *
325: * This function sets the ethernet address (array of 6 unsigned
326: * bytes) on the 3c501 board.
327: *
328: */
329:
330: at3c501seteh(base, ep)
331: caddr_t base;
332: char *ep;
333: {
334: int i;
335:
336: for (i = 0; i < ETHER_ADD_SIZE; i++) {
337: outb(EDLC_ADDR(base) + i, *ep++);
338: }
339: }
340:
341: #ifdef MACH_KERNEL
342: int at3c501start(); /* forward */
343:
344: at3c501output(dev, ior)
345: dev_t dev;
346: io_req_t ior;
347: {
348: register int unit = minor(dev);
349:
350: if (unit < 0 || unit >= NAT3C501 ||
351: at3c501_softc[unit].base == 0)
352: return (ENXIO);
353:
354: return (net_write(&at3c501_softc[unit].ds_if, at3c501start, ior));
355: }
356:
357: at3c501setinput(dev, receive_port, priority, filter, filter_count)
358: dev_t dev;
359: mach_port_t receive_port;
360: int priority;
361: filter_t filter[];
362: u_int filter_count;
363: {
364: register int unit = minor(dev);
365:
366: if (unit < 0 || unit >= NAT3C501 ||
367: at3c501_softc[unit].base == 0)
368: return (ENXIO);
369:
370: return (net_set_filter(&at3c501_softc[unit].ds_if,
371: receive_port, priority,
372: filter, filter_count));
373: }
374:
375: #else MACH_KERNEL
376: /*
377: * at3c501output:
378: *
379: * This routine is called by the "if" layer to output a packet to
380: * the network. This code resolves the local ethernet address, and
381: * puts it into the mbuf if there is room. If not, then a new mbuf
382: * is allocated with the header information and precedes the data
383: * to be transmitted.
384: *
385: * input: ifnet structure pointer, an mbuf with data, and address
386: * to be resolved
387: * output: mbuf is updated to hold enet address, or a new mbuf
388: * with the address is added
389: *
390: */
391: at3c501output(ifp, m0, dst)
392: struct ifnet *ifp;
393: struct mbuf *m0;
394: struct sockaddr *dst;
395: {
396: int type, error;
397: spl_t opri;
398: u_char edst[6];
399: struct in_addr idst;
400: register at3c501_softc_t *is;
401: register struct mbuf *m = m0;
402: register struct ether_header *eh;
403: register int off;
404: int usetrailers;
405:
406: is = &at3c501_softc[ifp->if_unit];
407: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
408: printf("3C501 Turning off board %d\n", ifp->if_unit);
409: at3c501intoff(ifp->if_unit);
410: error = ENETDOWN;
411: goto bad;
412: }
413: switch (dst->sa_family) {
414:
415: #ifdef INET
416: case AF_INET:
417: idst = ((struct sockaddr_in *)dst)->sin_addr;
418: if (!arpresolve(&is->at3c501_ac, m, &idst, edst, &usetrailers)){
419: return (0); /* if not yet resolved */
420: }
421: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
422:
423: if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
424: m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
425: type = ETHERTYPE_TRAIL + (off>>9);
426: m->m_off -= 2 * sizeof (u_short);
427: m->m_len += 2 * sizeof (u_short);
428: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
429: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
430: goto gottrailertype;
431: }
432: type = ETHERTYPE_IP;
433: off = 0;
434: goto gottype;
435: #endif
436: #ifdef NS
437: case AF_NS:
438: type = ETHERTYPE_NS;
439: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
440: (caddr_t)edst, sizeof (edst));
441: off = 0;
442: goto gottype;
443: #endif
444:
445: case AF_UNSPEC:
446: eh = (struct ether_header *)dst->sa_data;
447: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
448: type = eh->ether_type;
449: goto gottype;
450:
451: default:
452: printf("at3c501%d: can't handle af%d\n", ifp->if_unit,
453: dst->sa_family);
454: error = EAFNOSUPPORT;
455: goto bad;
456: }
457:
458: gottrailertype:
459: /*
460: * Packet to be sent as trailer: move first packet
461: * (control information) to end of chain.
462: */
463: while (m->m_next)
464: m = m->m_next;
465: m->m_next = m0;
466: m = m0->m_next;
467: m0->m_next = 0;
468: m0 = m;
469:
470: gottype:
471: /*
472: * Add local net header. If no space in first mbuf,
473: * allocate another.
474: */
475: if (m->m_off > MMAXOFF ||
476: MMINOFF + sizeof (struct ether_header) > m->m_off) {
477: m = m_get(M_DONTWAIT, MT_HEADER);
478: if (m == 0) {
479: error = ENOBUFS;
480: goto bad;
481: }
482: m->m_next = m0;
483: m->m_off = MMINOFF;
484: m->m_len = sizeof (struct ether_header);
485: } else {
486: m->m_off -= sizeof (struct ether_header);
487: m->m_len += sizeof (struct ether_header);
488: }
489: eh = mtod(m, struct ether_header *);
490: eh->ether_type = htons((u_short)type);
491: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
492: bcopy((caddr_t)is->address,(caddr_t)eh->ether_shost,
493: sizeof(edst));
494: /*
495: * Queue message on interface, and start output if interface
496: * not yet active.
497: */
498: opri = SPLNET();
499: if (IF_QFULL(&ifp->if_snd)) {
500: IF_DROP(&ifp->if_snd);
501: splx(opri);
502: m_freem(m);
503: return (ENOBUFS);
504: }
505: IF_ENQUEUE(&ifp->if_snd, m);
506: /*
507: * Some action needs to be added here for checking whether the
508: * board is already transmitting. If it is, we don't want to
509: * start it up (ie call at3c501start()). We will attempt to send
510: * packets that are queued up after an interrupt occurs. Some
511: * flag checking action has to happen here and/or in the start
512: * routine. This note is here to remind me that some thought
513: * is needed and there is a potential problem here.
514: *
515: */
516: at3c501start(ifp->if_unit);
517: splx(opri);
518: return (0);
519:
520: bad:
521: m_freem(m0);
522: return (error);
523: }
524: #endif MACH_KERNEL
525:
526: /*
527: * at3c501reset:
528: *
529: * This routine is in part an entry point for the "if" code. Since most
530: * of the actual initialization has already (we hope already) been done
531: * by calling at3c501attach().
532: *
533: * input : unit number or board number to reset
534: * output : board is reset
535: *
536: */
537: at3c501reset(unit)
538: int unit;
539: {
540: at3c501_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
541: return(at3c501init(unit));
542: }
543:
544:
545:
546: /*
547: * at3c501init:
548: *
549: * Another routine that interfaces the "if" layer to this driver.
550: * Simply resets the structures that are used by "upper layers".
551: * As well as calling at3c501hwrst that does reset the at3c501 board.
552: *
553: * input : board number
554: * output : structures (if structs) and board are reset
555: *
556: */
557: at3c501init(unit)
558: int unit;
559: {
560: struct ifnet *ifp;
561: int stat;
562: spl_t oldpri;
563:
564: ifp = &(at3c501_softc[unit].ds_if);
565: #ifdef MACH_KERNEL
566: #else MACH_KERNEL
567: if (ifp->if_addrlist == (struct ifaddr *)0) {
568: return;
569: }
570: #endif MACH_KERNEL
571: oldpri = SPLNET();
572: if ((stat = at3c501hwrst(unit)) == TRUE) {
573: at3c501_softc[unit].ds_if.if_flags |= IFF_RUNNING;
574: at3c501_softc[unit].flags |= DSF_RUNNING;
575: at3c501start(unit);
576: }
577: else
578: printf("3C501 trouble resetting board %d\n", unit);
579: at3c501_softc[unit].timer = 5;
580: splx(oldpri);
581: return(stat);
582:
583: }
584:
585: #ifdef MACH_KERNEL
586: /*ARGSUSED*/
587: at3c501open(dev, flag)
588: dev_t dev;
589: int flag;
590: {
591: register int unit = minor(dev);
592:
593: if (unit < 0 || unit >= NAT3C501 ||
594: at3c501_softc[unit].base == 0)
595: return (ENXIO);
596:
597: at3c501_softc[unit].ds_if.if_flags |= IFF_UP;
598: at3c501init(unit);
599: return(0);
600: }
601: #endif MACH_KERNEL
602:
603: /*
604: * at3c501start:
605: *
606: * This is yet another interface routine that simply tries to output a
607: * in an mbuf after a reset.
608: *
609: * input : board number
610: * output : stuff sent to board if any there
611: *
612: */
613: at3c501start(unit)
614: int unit;
615:
616: {
617: #ifdef MACH_KERNEL
618: io_req_t m;
619: #else MACH_KERNEL
620: struct mbuf *m;
621: #endif MACH_KERNEL
622: struct ifnet *ifp;
623:
624: ifp = &(at3c501_softc[unit].ds_if);
625: for(;;) {
626: IF_DEQUEUE(&ifp->if_snd, m);
627: #ifdef MACH_KERNEL
628: if (m != 0)
629: #else MACH_KERNEL
630: if (m != (struct mbuf *)0)
631: #endif MACH_KERNEL
632: at3c501xmt(unit, m);
633: else
634: return;
635: }
636: }
637:
638: #ifdef MACH_KERNEL
639: /*ARGSUSED*/
640: at3c501getstat(dev, flavor, status, count)
641: dev_t dev;
642: int flavor;
643: dev_status_t status; /* pointer to OUT array */
644: u_int *count; /* out */
645: {
646: register int unit = minor(dev);
647:
648: if (unit < 0 || unit >= NAT3C501 ||
649: at3c501_softc[unit].base == 0)
650: return (ENXIO);
651:
652: return (net_getstat(&at3c501_softc[unit].ds_if,
653: flavor,
654: status,
655: count));
656: }
657:
658: at3c501setstat(dev, flavor, status, count)
659: dev_t dev;
660: int flavor;
661: dev_status_t status;
662: u_int count;
663: {
664: register int unit = minor(dev);
665: register at3c501_softc_t *sp;
666:
667: if (unit < 0 || unit >= NAT3C501 ||
668: at3c501_softc[unit].base == 0)
669: return (ENXIO);
670:
671: sp = &at3c501_softc[unit];
672:
673: switch (flavor) {
674: case NET_STATUS:
675: {
676: /*
677: * All we can change are flags, and not many of those.
678: */
679: register struct net_status *ns = (struct net_status *)status;
680: int mode = 0;
681:
682: if (count < NET_STATUS_COUNT)
683: return (D_INVALID_SIZE);
684:
685: if (ns->flags & IFF_ALLMULTI)
686: mode |= MOD_ENAL;
687: if (ns->flags & IFF_PROMISC)
688: mode |= MOD_PROM;
689:
690: /*
691: * Force a compilete reset if the receive mode changes
692: * so that these take effect immediately.
693: */
694: if (sp->mode != mode) {
695: sp->mode = mode;
696: if (sp->flags & DSF_RUNNING) {
697: sp->flags &= ~(DSF_LOCK | DSF_RUNNING);
698: at3c501init(unit);
699: }
700: }
701: break;
702: }
703: case NET_ADDRESS:
704: {
705: register union ether_cvt {
706: char addr[6];
707: int lwd[2];
708: } *ec = (union ether_cvt *)status;
709:
710: if (count < sizeof(*ec)/sizeof(int))
711: return (D_INVALID_SIZE);
712:
713: ec->lwd[0] = ntohl(ec->lwd[0]);
714: ec->lwd[1] = ntohl(ec->lwd[1]);
715: at3c501seteh(sp->base, ec->addr);
716: break;
717: }
718:
719: default:
720: return (D_INVALID_OPERATION);
721: }
722: return (D_SUCCESS);
723: }
724: #else MACH_KERNEL
725:
726: /*
727: * at3c501ioctl:
728: *
729: * This routine processes an ioctl request from the "if" layer
730: * above.
731: *
732: * input : pointer the appropriate "if" struct, command, and data
733: * output : based on command appropriate action is taken on the
734: * at3c501 board(s) or related structures
735: * return : error is returned containing exit conditions
736: *
737: */
738: int curr_ipl;
739: u_short curr_pic_mask;
740: u_short pic_mask[];
741:
742: at3c501ioctl(ifp, cmd, data)
743: struct ifnet *ifp;
744: int cmd;
745: caddr_t data;
746: {
747: register struct ifaddr *ifa = (struct ifaddr *)data;
748: register at3c501_softc_t *is;
749: int error;
750: spl_t opri;
751: short mode = 0;
752:
753: is = &at3c501_softc[ifp->if_unit];
754: opri = SPLNET();
755: error = 0;
756: switch (cmd) {
757: case SIOCSIFADDR:
758: ifp->if_flags |= IFF_UP;
759: at3c501init(ifp->if_unit);
760: switch (ifa->ifa_addr.sa_family) {
761: #ifdef INET
762: case AF_INET:
763: ((struct arpcom *)ifp)->ac_ipaddr =
764: IA_SIN(ifa)->sin_addr;
765: arpwhohas((struct arpcom *)ifp,
766: &IA_SIN(ifa)->sin_addr);
767: break;
768: #endif
769: #ifdef NS
770: case AF_NS:
771: {
772: register struct ns_addr *ina =
773: &(IA_SNS(ifa)->sns_addr);
774: if (ns_nullhost(*ina))
775: ina->x_host =
776: *(union ns_host *)(ds->ds_addr);
777: else
778: at3c501seteh(ina->x_host.c_host,
779: at3c501_softc[ifp->if_unit].base);
780: break;
781: }
782: #endif
783: }
784: break;
785: case SIOCSIFFLAGS:
786: if (ifp->if_flags & IFF_ALLMULTI)
787: mode |= MOD_ENAL;
788: if (ifp->if_flags & IFF_PROMISC)
789: mode |= MOD_PROM;
790: /*
791: * force a complete reset if the receive multicast/
792: * promiscuous mode changes so that these take
793: * effect immediately.
794: *
795: */
796: if (is->mode != mode) {
797: is->mode = mode;
798: if (is->flags & DSF_RUNNING) {
799: is->flags &=
800: ~(DSF_LOCK|DSF_RUNNING);
801: at3c501init(ifp->if_unit);
802: }
803: }
804: if ((ifp->if_flags & IFF_UP) == 0 &&
805: is->flags & DSF_RUNNING) {
806: printf("AT3C501 ioctl: turning off board %d\n",
807: ifp->if_unit);
808: is->flags &= ~(DSF_LOCK | DSF_RUNNING);
809: is->timer = -1;
810: at3c501intoff(ifp->if_unit);
811: } else
812: if (ifp->if_flags & IFF_UP &&
813: (is->flags & DSF_RUNNING) == 0)
814: at3c501init(ifp->if_unit);
815: break;
816: default:
817: error = EINVAL;
818: }
819: splx(opri);
820: return (error);
821: }
822: #endif MACH_KERNEL
823:
824:
825: /*
826: * at3c501hwrst:
827: *
828: * This routine resets the at3c501 board that corresponds to the
829: * board number passed in.
830: *
831: * input : board number to do a hardware reset
832: * output : board is reset
833: *
834: */
835: #define XMT_STAT (EDLC_16|EDLC_JAM|EDLC_UNDER|EDLC_IDLE)
836: #define RCV_STAT (EDLC_STALE|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_OVER|EDLC_FCS)
837: int
838: at3c501hwrst(unit)
839: int unit;
840: {
841: u_char stat;
842: caddr_t base = at3c501_softc[unit].base;
843:
844: outb(IE_CSR(base), IE_RESET);
845: outb(IE_CSR(base), 0);
846: at3c501seteh(base, at3c501_softc[unit].address);
847: if ((stat = inb(IE_CSR(base))) != IE_RESET) {
848: printf("at3c501reset: can't reset CSR: %x\n", stat);
849: return(FALSE);
850: }
851: if ((stat = inb(EDLC_XMT(base))) & XMT_STAT) {
852: printf("at3c501reset: can't reset XMT: %x\n", stat);
853: return(FALSE);
854: }
855: if (((stat = inb(EDLC_RCV(base))) & RCV_STAT) != EDLC_STALE) {
856: printf("at3c501reset: can't reset RCV: %x\n", stat);
857: return(FALSE);
858: }
859: if (at3c501config(unit) == FALSE) {
860: printf("at3c501hwrst(): failed to config\n");
861: return(FALSE);
862: }
863: outb(IE_RP(base), 0);
864: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
865: return(TRUE);
866: }
867:
868: /*
869: * at3c501intr:
870: *
871: * This function is the interrupt handler for the at3c501 ethernet
872: * board. This routine will be called whenever either a packet
873: * is received, or a packet has successfully been transfered and
874: * the unit is ready to transmit another packet.
875: *
876: * input : board number that interrupted
877: * output : either a packet is received, or a packet is transfered
878: *
879: */
880: at3c501intr(unit)
881: int unit;
882: {
883: at3c501rcv(unit);
884: at3c501start(unit);
885:
886: return(0);
887: }
888:
889:
890: /*
891: * at3c501rcv:
892: *
893: * This routine is called by the interrupt handler to initiate a
894: * packet transfer from the board to the "if" layer above this
895: * driver. This routine checks if a buffer has been successfully
896: * received by the at3c501. If so, the routine at3c501read is called
897: * to do the actual transfer of the board data (including the
898: * ethernet header) into a packet (consisting of an mbuf chain).
899: *
900: * input : number of the board to check
901: * output : if a packet is available, it is "sent up"
902: *
903: */
904: at3c501rcv(unit)
905: int unit;
906: {
907: int stat;
908: caddr_t base;
909: #ifdef MACH_KERNEL
910: ipc_kmsg_t new_kmsg;
911: struct ether_header *ehp;
912: struct packet_header *pkt;
913: #else MACH_KERNEL
914: struct mbuf *m, *tm;
915: #endif MACH_KERNEL
916: u_short len;
917: register struct ifnet *ifp;
918: struct ether_header header;
919: int tlen;
920: register at3c501_softc_t *is;
921: register struct ifqueue *inq;
922: spl_t opri;
923: struct ether_header eh;
924:
925: is = &at3c501_softc[unit];
926: ifp = &is->ds_if;
927: base = at3c501_softc[unit].base;
928: is->rcv++;
929: if (inb(IE_CSR(base)) & IE_RCVBSY)
930: is->spurious++;
931: while (!((stat=inb(EDLC_RCV(base))) & EDLC_STALE)) {
932: outb(IE_CSR(base), IE_SYSBFR);
933: if (!(stat & EDLC_ANY)) {
934: outw(IE_GP(base), 0);
935: len = inw(IE_RP(base))-sizeof(struct ether_header);
936: outb(IE_RP(base), 0);
937: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
938: is->badrcv++;
939: #ifdef DEBUG
940: printf("at3c501rcv: received %d bad bytes", len);
941: if (stat & EDLC_SHORT)
942: printf(" Short frame");
943: if (stat & EDLC_OVER)
944: printf(" Data overflow");
945: if (stat & EDLC_DRIBBLE)
946: printf(" Dribble error");
947: if (stat & EDLC_FCS)
948: printf(" CRC error");
949: printf("\n");
950: #endif DEBUG
951: } else {
952: outw(IE_GP(base), 0);
953: len = inw(IE_RP(base));
954: if (len < 60) {
955: outb(IE_RP(base), 0);
956: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
957: return;
958: }
959: linb(IE_BFR(base), &eh, sizeof(struct ether_header));
960: #ifdef MACH_KERNEL
961: new_kmsg = net_kmsg_get();
962: if (new_kmsg == IKM_NULL) {
963: /*
964: * Drop the packet.
965: */
966: is->ds_if.if_rcvdrops++;
967:
968: outb(IE_RP(base), 0);
969: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
970: return;
971: }
972:
973: ehp = (struct ether_header *)
974: (&net_kmsg(new_kmsg)->header[0]);
975: pkt = (struct packet_header *)
976: (&net_kmsg(new_kmsg)->packet[0]);
977:
978: /*
979: * Get header.
980: */
981: *ehp = eh;
982:
983: /*
984: * Get body
985: */
986: linb(IE_BFR(base),
987: (char *)(pkt + 1),
988: len - sizeof(struct ether_header));
989:
990: outb(IE_RP(base), 0);
991: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
992:
993: pkt->type = ehp->ether_type;
994: pkt->length = len - sizeof(struct ether_header)
995: + sizeof(struct packet_header);
996:
997: /*
998: * Hand the packet to the network module.
999: */
1000: net_packet(ifp, new_kmsg, pkt->length,
1001: ethernet_priority(new_kmsg));
1002:
1003: #else MACH_KERNEL
1004: eh.ether_type = htons(eh.ether_type);
1005: m =(struct mbuf *)0;
1006: #ifdef DEBUG
1007: printf("received %d bytes\n", len);
1008: #endif DEBUG
1009: len -= sizeof(struct ether_header);
1010: while ( len ) {
1011: if (m == (struct mbuf *)0) {
1012: m = m_get(M_DONTWAIT, MT_DATA);
1013: if (m == (struct mbuf *)0) {
1014: printf("at3c501rcv: Lost frame\n");
1015: outb(IE_RP(base), 0);
1016: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
1017:
1018: return;
1019: }
1020: tm = m;
1021: tm->m_off = MMINOFF;
1022: /*
1023: * first mbuf in the packet must contain a pointer to the
1024: * ifnet structure. other mbufs that follow and make up
1025: * the packet do not need this pointer in the mbuf.
1026: *
1027: */
1028: *(mtod(tm, struct ifnet **)) = ifp;
1029: tm->m_len = sizeof(struct ifnet **);
1030: }
1031: else {
1032: tm->m_next = m_get(M_DONTWAIT, MT_DATA);
1033: tm = tm->m_next;
1034: tm->m_off = MMINOFF;
1035: tm->m_len = 0;
1036: if (tm == (struct mbuf *)0) {
1037: m_freem(m);
1038: printf("at3c501rcv: No mbufs, lost frame\n");
1039: outb(IE_RP(base), 0);
1040: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
1041: return;
1042: }
1043: }
1044: tlen = MIN( MLEN - tm->m_len, len );
1045: tm->m_next = (struct mbuf *)0;
1046: linb(IE_BFR(base), mtod(tm, char *)+tm->m_len, tlen );
1047: tm->m_len += tlen;
1048: len -= tlen;
1049: }
1050: outb(IE_RP(base), 0);
1051: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
1052: /*
1053: * received packet is now in a chain of mbuf's. next step is
1054: * to pass the packet upwards.
1055: *
1056: */
1057: switch (eh.ether_type) {
1058: #ifdef INET
1059: case ETHERTYPE_IP:
1060: schednetisr(NETISR_IP);
1061: inq = &ipintrq;
1062: break;
1063: case ETHERTYPE_ARP:
1064: arpinput(&is->at3c501_ac, m);
1065: return;
1066: #endif
1067: #ifdef NS
1068: case ETHERTYPE_NS:
1069: schednetisr(NETISR_NS);
1070: inq = &nsintrq;
1071: break;
1072: #endif
1073: default:
1074: m_freem(m);
1075: return;
1076: }
1077: opri = SPLNET();
1078: if (IF_QFULL(inq)) {
1079: IF_DROP(inq);
1080: splx(opri);
1081: m_freem(m);
1082: return;
1083: }
1084: IF_ENQUEUE(inq, m);
1085: splx(opri);
1086: #endif MACH_KERNEL
1087: }
1088: }
1089: }
1090:
1091:
1092: /*
1093: * at3c501xmt:
1094: *
1095: * This routine fills in the appropriate registers and memory
1096: * locations on the 3C501 board and starts the board off on
1097: * the transmit.
1098: *
1099: * input : board number of interest, and a pointer to the mbuf
1100: * output : board memory and registers are set for xfer and attention
1101: *
1102: */
1103: at3c501xmt(unit, m)
1104: int unit;
1105: #ifdef MACH_KERNEL
1106: io_req_t m;
1107: #else MACH_KERNEL
1108: struct mbuf *m;
1109: #endif MACH_KERNEL
1110: {
1111: #ifdef MACH_KERNEL
1112: #else MACH_KERNEL
1113: register struct mbuf *tm_p;
1114: #endif MACH_KERNEL
1115: int i;
1116: at3c501_softc_t *is = &at3c501_softc[unit];
1117: caddr_t base = is->base;
1118: u_short count = 0;
1119: u_short bytes_in_msg;
1120:
1121: is->xmt++;
1122: outb(IE_CSR(base), IE_SYSBFR);
1123: #ifdef MACH_KERNEL
1124: count = m->io_count;
1125: #define max(a,b) (((a) > (b)) ? (a) : (b))
1126: bytes_in_msg = max(count,
1127: ETHERMIN + sizeof(struct ether_header));
1128: #else MACH_KERNEL
1129: bytes_in_msg = max(m_length(m), ETHERMIN + sizeof(struct ether_header));
1130: #endif MACH_KERNEL
1131: outw(IE_GP(base), BFRSIZ-bytes_in_msg);
1132: #ifdef MACH_KERNEL
1133: loutb(IE_BFR(base), m->io_data, count);
1134: #else MACH_KERNEL
1135: for (tm_p = m; tm_p != (struct mbuf *)0; tm_p = tm_p->m_next) {
1136: if (count + tm_p->m_len > ETHERMTU + sizeof(struct ether_header))
1137: break;
1138: if (tm_p->m_len == 0)
1139: continue;
1140: loutb(IE_BFR(base), mtod(tm_p, caddr_t), tm_p->m_len);
1141: count += tm_p->m_len;
1142: }
1143: #endif MACH_KERNEL
1144: while (count < bytes_in_msg) {
1145: outb(IE_BFR(base), 0);
1146: count++;
1147: }
1148: do {
1149: if (!(int)m) {
1150: outb(IE_CSR(base), IE_SYSBFR);
1151: }
1152: outw(IE_GP(base), BFRSIZ-bytes_in_msg);
1153: outb(IE_CSR(base), IE_RIDE|IE_XMTEDLC);
1154: if (m) {
1155: #ifdef MACH_KERNEL
1156: iodone(m);
1157: m = 0;
1158: #else MACH_KERNEL
1159: m_freem(m);
1160: m = (struct mbuf *) 0;
1161: #endif MACH_KERNEL
1162: }
1163: for (i=0; inb(IE_CSR(base)) & IE_XMTBSY; i++);
1164: if ((i=inb(EDLC_XMT(base))) & EDLC_JAM) {
1165: is->badxmt++;
1166: #ifdef DEBUG
1167: printf("at3c501xmt jam\n");
1168: #endif DEBUG
1169: }
1170: } while ((i & EDLC_JAM) && !(i & EDLC_16));
1171:
1172: if (i & EDLC_16) {
1173: printf("%");
1174: }
1175: return;
1176:
1177: }
1178:
1179: /*
1180: * at3c501config:
1181: *
1182: * This routine does a standard config of the at3c501 board.
1183: *
1184: */
1185: at3c501config(unit)
1186: int unit;
1187: {
1188: caddr_t base = at3c501_softc[unit].base;
1189: u_char stat;
1190:
1191: /* Enable DMA & Interrupts */
1192:
1193: outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
1194:
1195: /* No Transmit Interrupts */
1196:
1197: outb(EDLC_XMT(base), 0);
1198: inb(EDLC_XMT(base));
1199:
1200: /* Setup Receive Interrupts */
1201:
1202: outb(EDLC_RCV(base), EDLC_BROAD|EDLC_SHORT|EDLC_GOOD|EDLC_DRIBBLE|EDLC_OVER);
1203: inb(EDLC_RCV(base));
1204:
1205: outb(IE_CSR(base), IE_RIDE|IE_SYSBFR);
1206: outb(IE_RP(base), 0);
1207: outb(IE_CSR(base), IE_RIDE|IE_RCVEDLC);
1208: return(TRUE);
1209: }
1210:
1211: /*
1212: * at3c501intoff:
1213: *
1214: * This function turns interrupts off for the at3c501 board indicated.
1215: *
1216: */
1217: at3c501intoff(unit)
1218: int unit;
1219: {
1220: caddr_t base = at3c501_softc[unit].base;
1221: outb(IE_CSR(base), 0);
1222: }
1223:
1224: #ifdef MACH_KERNEL
1225: #else MACH_KERNEL
1226: /*
1227: * The length of an mbuf chain
1228: */
1229: m_length(m)
1230: register struct mbuf *m;
1231: {
1232: register int len = 0;
1233:
1234: while (m) {
1235: len += m->m_len;
1236: m = m->m_next;
1237: }
1238: return len;
1239: }
1240: #endif MACH_KERNEL
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.