|
|
1.1 root 1: /*-
2: * Copyright (c) 1990, 1991 William F. Jolitz.
3: * Copyright (c) 1990 The Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: * 3. All advertising materials mentioning features or use of this software
15: * must display the following acknowledgement:
16: * This product includes software developed by the University of
17: * California, Berkeley and its contributors.
18: * 4. Neither the name of the University nor the names of its contributors
19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: *
34: * @(#)if_ne.c 7.4 (Berkeley) 5/21/91
35: */
36:
37: /*
38: * Isolink 4110-2 Ethernet driver
39: */
40:
41: #include "is.h"
42: #if NIS > 0
43:
44: #include "param.h"
45: #include "systm.h"
46: #include "mbuf.h"
47: #include "buf.h"
48: #include "protosw.h"
49: #include "socket.h"
50: #include "ioctl.h"
51: #include "errno.h"
52: #include "syslog.h"
53:
54: #include "net/if.h"
55: #include "net/netisr.h"
56: #include "net/route.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: #include "i386/isa/isa_device.h"
72: #include "i386/isa/if_isreg.h"
73: #include "i386/isa/icu.h"
74:
75: #include "vm/vm.h"
76:
77: /* Function prototypes */
78: int isprobe(), isattach();
79: int isioctl(),isinit(),isstart();
80:
81: struct isa_driver isdriver = {
82: isprobe, isattach, "is",
83: };
84:
85:
86: struct mbuf *isget();
87:
88: #define ETHER_MIN_LEN 64
89:
90: /*
91: * Ethernet software status per interface.
92: *
93: * Each interface is referenced by a network interface structure,
94: * ns_if, which the routing code uses to locate the interface.
95: * This structure contains the output queue for the interface, its address, ...
96: */
97: struct is_softc {
98: struct arpcom ns_ac; /* Ethernet common part */
99: #define ns_if ns_ac.ac_if /* network-visible interface */
100: #define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */
101: int last_rd;
102: int last_td;
103: int no_td;
104: } is_softc[NIS] ;
105:
106: struct init_block init_block;
107: struct mds *td, *rd;
108: unsigned char *rbuf,*tbuf;
109:
110: int isc;
111:
112: iswrcsr(port,val)
113: u_short port;
114: u_short val;
115: {
116: outw(isc+RAP,port);
117: outw(isc+RDP,val);
118: }
119:
120: u_short isrdcsr(port)
121: u_short port;
122: {
123: outw(isc+RAP,port);
124: return(inw(isc+RDP));
125: }
126:
127: isprobe(dvp)
128: struct isa_device *dvp;
129: {
130: int val,i,s;
131: register struct is_softc *ns = &is_softc[0];
132:
133: isc = dvp->id_iobase;
134: s = splimp();
135:
136: /* Stop the lance chip, put it known state */
137: iswrcsr(0,STOP);
138: DELAY(100);
139:
140: /* is there a lance? */
141: iswrcsr(3, 0xffff);
142: if (isrdcsr(3) != 7) {
143: isc = 0;
144: return (0);
145: }
146: iswrcsr(3, 0);
147:
148: /* Extract board address */
149: for(i=0; i < 6; i++) ns->ns_addr[i] = inb(isc+(i*2));
150:
151: splx(s);
152: return (1);
153: }
154:
155:
156:
157: /*
158: * Reset of interface.
159: */
160: isreset(unit, uban)
161: int unit, uban;
162: {
163: if (unit >= NIS)
164: return;
165: printf("is%d: reset\n", unit);
166: isinit(unit);
167: }
168:
169: /*
170: * Interface exists: make available by filling in network interface
171: * record. System will initialize the interface when it is ready
172: * to accept packets. We get the ethernet address here.
173: */
174: isattach(dvp)
175: struct isa_device *dvp;
176: {
177: int unit = dvp->id_unit;
178: register struct is_softc *is = &is_softc[unit];
179: register struct ifnet *ifp = &is->ns_if;
180:
181: /* Set up DMA */
182: isa_dmacascade(dvp->id_drq);
183:
184: ifp->if_unit = unit;
185: ifp->if_name = isdriver.name ;
186: ifp->if_mtu = ETHERMTU;
187: printf (" ethernet address %s", ether_sprintf(is->ns_addr)) ;
188: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
189: ifp->if_init = isinit;
190: ifp->if_output = ether_output;
191: ifp->if_start = isstart;
192: ifp->if_ioctl = isioctl;
193: ifp->if_reset = isreset;
194: ifp->if_watchdog = 0;
195: if_attach(ifp);
196: }
197:
198:
199: /* Lance initialisation block set up */
200: init_mem()
201: {
202: int i;
203: u_long temp;
204:
205: /* Allocate memory */
206: /* Temporary hack, will use kmem_alloc in future */
207: #define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) + 8)
208: static u_char lance_mem[MAXMEM];
209:
210:
211: /* Align message descriptors on quad word boundary
212: (this is essential) */
213:
214: temp = (u_long) &lance_mem;
215: temp = (temp+8) - (temp%8);
216: rd = (struct mds *) temp;
217: td = (struct mds *) (temp + (NRBUF*sizeof(struct mds)));
218: temp += (NRBUF+NTBUF) * sizeof(struct mds);
219:
220: init_block.mode = 0;
221:
222: /* Get ethernet address */
223: for (i=0; i<6; i++)
224: init_block.padr[i] = inb(isc+(i*2));
225:
226: /* Clear multicast address for now */
227: for (i=0; i<8; i++)
228: init_block.ladrf[i] = 0;
229:
230: init_block.rdra = kvtop(rd);
231: init_block.rlen = ((kvtop(rd) >> 16) & 0xff) | (RLEN<<13);
232: init_block.tdra = kvtop(td);
233: init_block.tlen = ((kvtop(td) >> 16) & 0xff) | (TLEN<<13);
234:
235: /* Set up receive ring descriptors */
236: rbuf = (unsigned char *)temp;
237: for (i=0; i<NRBUF; i++) {
238: (rd+i)->addr = kvtop(temp);
239: (rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN;
240: (rd+i)->bcnt = -BUFSIZE;
241: (rd+i)->mcnt = 0;
242: temp += BUFSIZE;
243: }
244:
245: /* Set up transmit ring descriptors */
246: tbuf = (unsigned char *)temp;
247: #ifdef ISDEBUG
248: printf("rd = %x,td = %x, rbuf = %x, tbuf = %x,td+1=%x\n",rd,td,rbuf,tbuf,td+1);
249: #endif
250: for (i=0; i<NTBUF; i++) {
251: (td+i)->addr = kvtop(temp);
252: (td+i)->flags= ((kvtop(temp) >> 16) & 0xff);
253: (td+i)->bcnt = 0;
254: (td+i)->mcnt = 0;
255: temp += BUFSIZE;
256: }
257:
258: }
259:
260: /*
261: * Initialization of interface; set up initialization block
262: * and transmit/receive descriptor rings.
263: */
264: isinit(unit)
265: int unit;
266: {
267: register struct is_softc *ns = &is_softc[unit];
268: struct ifnet *ifp = &ns->ns_if;
269: int s;
270: register i;
271:
272: if (ifp->if_addrlist == (struct ifaddr *)0) return;
273:
274: ns->last_rd = ns->last_td = ns->no_td = 0;
275: s = splimp();
276:
277: /* Set up lance's memory area */
278: init_mem();
279:
280: /* Stop Lance to get access to other registers */
281: iswrcsr(0,STOP);
282:
283: /* I wish I knew what this was */
284: iswrcsr(3,0);
285:
286: /* Give lance the physical address of its memory area */
287: iswrcsr(1,kvtop(&init_block));
288: iswrcsr(2,(kvtop(&init_block) >> 16) & 0xff);
289:
290: /* OK, let's try and initialise the Lance */
291: iswrcsr(0,INIT);
292:
293: /* Wait for initialisation to finish */
294: for(i=0; i<1000; i++){
295: if (isrdcsr(0)&IDON)
296: break;
297: }
298: if (isrdcsr(0)&IDON) {
299: /* Start lance */
300: iswrcsr(0,STRT|IDON|INEA);
301: ns->ns_if.if_flags |= IFF_RUNNING;
302: isstart(ifp);
303: }
304: else
305: printf("Isolink card failed to initialise\n");
306:
307: splx(s);
308: }
309:
310: /*
311: * Setup output on interface.
312: * Get another datagram to send off of the interface queue,
313: * and map it to the interface before starting the output.
314: * called only at splimp or interrupt level.
315: */
316: isstart(ifp)
317: struct ifnet *ifp;
318: {
319: register struct is_softc *ns = &is_softc[ifp->if_unit];
320: struct mbuf *m0, *m;
321: unsigned char *buffer;
322: u_short len;
323: int i;
324: struct mds *cdm;
325:
326:
327: if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
328: return;
329:
330: do {
331: cdm = (td + ns->last_td);
332: if (cdm->flags&OWN)
333: return;
334:
335: IF_DEQUEUE(&ns->ns_if.if_snd, m);
336:
337: if (m == 0)
338: return;
339:
340: /*
341: * Copy the mbuf chain into the transmit buffer
342: */
343:
344: buffer = tbuf+(BUFSIZE*ns->last_td);
345: len=0;
346: for (m0=m; m != 0; m=m->m_next) {
347: bcopy(mtod(m,caddr_t),buffer,m->m_len);
348: buffer += m->m_len;
349: len += m->m_len;
350: }
351:
352: m_freem(m0);
353: len = MAX(len,ETHER_MIN_LEN);
354:
355: /*
356: * Init transmit registers, and set transmit start flag.
357: */
358:
359: cdm->flags |= (OWN|STP|ENP);
360: cdm->bcnt = -len;
361: cdm->mcnt = 0;
362: #ifdef ISDEBUG
363: xmit_print(ns->last_td);
364: #endif
365:
366: iswrcsr(0,TDMD|INEA);
367: if (++ns->last_td >= NTBUF)
368: ns->last_td=0;
369: }while(++ns->no_td < NTBUF);
370: ns->no_td = NTBUF;
371: ns->ns_if.if_flags |= IFF_OACTIVE;
372: #ifdef ISDEBUG
373: printf("no_td = %x, last_td = %x\n",ns->no_td, ns->last_td);
374: #endif
375: return(0);
376: }
377:
378:
379: /*
380: * Controller interrupt.
381: */
382: isintr(unit)
383: {
384: register struct is_softc *ns = &is_softc[unit];
385: u_short isr;
386:
387: while((isr=isrdcsr(0))&INTR) {
388: if (isr&ERR) {
389: if (isr&BABL)
390: printf("BABL\n");
391: if (isr&CERR)
392: printf("CERR\n");
393: if (isr&MISS)
394: printf("MISS\n");
395: if (isr&MERR)
396: printf("MERR\n");
397: iswrcsr(0,BABL|CERR|MISS|MERR|INEA);
398: }
399: if (!(isr&TXON)) {
400: isreset(unit);
401: return(1);
402: }
403: if (!(isr&RXON)) {
404: isreset(unit);
405: return(1);
406: }
407: if (isr&RINT) {
408: isrint(unit);
409: }
410: if (isr&TINT) {
411: iswrcsr(0,TINT|INEA);
412: istint(unit);
413: }
414: }
415: }
416:
417: istint(unit)
418: int unit;
419: {
420: struct is_softc *is = &is_softc[unit];
421: register struct ifnet *ifp = &is->ns_if;
422: int i,loopcount=0;
423: struct mds *cdm;
424:
425: do {
426: if ((i=is->last_td - is->no_td) < 0)
427: i+=NTBUF;
428: cdm = (td+i);
429: #ifdef ISDEBUG
430: printf("Trans cdm = %x\n",cdm);
431: #endif
432: if (cdm->flags&OWN) {
433: if (loopcount)
434: break;
435: return;
436: }
437: loopcount++;
438: is->ns_if.if_flags &= ~IFF_OACTIVE;
439: }while(--is->no_td > 0);
440: isstart(ifp);
441:
442: }
443:
444: #define NEXTRDS \
445: if (++rmd == NRBUF) rmd=0, cdm=rd; else ++cdm
446:
447: isrint(unit)
448: int unit;
449: {
450: register struct is_softc *is=&is_softc[unit];
451: register int rmd = is->last_rd;
452: struct mds *cdm = (rd + rmd);
453:
454: /* Out of sync with hardware, should never happen */
455:
456: if (cdm->flags & OWN) {
457: printf("is0 error: out of sync\n");
458: iswrcsr(0,RINT|INEA);
459: return;
460: }
461:
462: /* Process all buffers with valid data */
463: while (!(cdm->flags&OWN)) {
464: /* Clear interrupt to avoid race condition */
465: iswrcsr(0,RINT|INEA);
466: if (cdm->flags&ERR) {
467: if (cdm->flags&FRAM)
468: printf("FRAM\n");
469: if (cdm->flags&OFLO)
470: printf("OFLO\n");
471: if (cdm->flags&CRC)
472: printf("CRC\n");
473: if (cdm->flags&RBUFF)
474: printf("RBUFF\n");
475: }else
476: if (cdm->flags&(STP|ENP) != (STP|ENP)) {
477: do {
478: iswrcsr(0,RINT|INEA);
479: cdm->mcnt = 0;
480: cdm->flags |= OWN;
481: NEXTRDS;
482: }while (!(cdm->flags&(OWN|ERR|STP|ENP)));
483: is->last_rd = rmd;
484: printf("Chained buffer\n");
485: if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
486: isreset(unit);
487: return;
488: }
489: }else
490: {
491: #ifdef ISDEBUG
492: recv_print(is->last_rd);
493: #endif
494: isread(is,rbuf+(BUFSIZE*rmd),cdm->mcnt);
495: }
496:
497: cdm->flags |= OWN;
498: cdm->mcnt = 0;
499: NEXTRDS;
500: #ifdef ISDEBUG
501: printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm);
502: #endif
503: } /* while */
504: is->last_rd = rmd;
505: } /* isrint */
506:
507: /*
508: * Pass a packet to the higher levels.
509: * We deal with the trailer protocol here.
510: */
511: isread(ns, buf, len)
512: register struct is_softc *ns;
513: char *buf;
514: int len;
515: {
516: register struct ether_header *eh;
517: struct mbuf *m;
518: int off, resid;
519: register struct ifqueue *inq;
520:
521: /*
522: * Deal with trailer protocol: if type is trailer type
523: * get true type from first 16-bit word past data.
524: * Remember that type was trailer by setting off.
525: */
526: eh = (struct ether_header *)buf;
527: eh->ether_type = ntohs((u_short)eh->ether_type);
528: len = len - sizeof(struct ether_header) - 4;
529: #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
530: if (eh->ether_type >= ETHERTYPE_TRAIL &&
531: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
532: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
533: if (off >= ETHERMTU) return; /* sanity */
534: eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
535: resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
536: if (off + resid > len) return; /* sanity */
537: len = off + resid;
538: } else off = 0;
539:
540: if (len == 0) return;
541:
542: /*
543: * Pull packet off interface. Off is nonzero if packet
544: * has trailing header; neget will then force this header
545: * information to be at the front, but we still have to drop
546: * the type and length which are at the front of any trailer data.
547: */
548: m = isget(buf, len, off, &ns->ns_if);
549: if (m == 0) return;
550:
551: ether_input(&ns->ns_if, eh, m);
552: }
553:
554: /*
555: * Supporting routines
556: */
557:
558: /*
559: * Pull read data off a interface.
560: * Len is length of data, with local net header stripped.
561: * Off is non-zero if a trailer protocol was used, and
562: * gives the offset of the trailer information.
563: * We copy the trailer information and then all the normal
564: * data into mbufs. When full cluster sized units are present
565: * we copy into clusters.
566: */
567: struct mbuf *
568: isget(buf, totlen, off0, ifp)
569: caddr_t buf;
570: int totlen, off0;
571: struct ifnet *ifp;
572: {
573: struct mbuf *top, **mp, *m, *p;
574: int off = off0, len;
575: register caddr_t cp = buf;
576: char *epkt;
577:
578: buf += sizeof(struct ether_header);
579: cp = buf;
580: epkt = cp + totlen;
581:
582:
583: if (off) {
584: cp += off + 2 * sizeof(u_short);
585: totlen -= 2 * sizeof(u_short);
586: }
587:
588: MGETHDR(m, M_DONTWAIT, MT_DATA);
589: if (m == 0)
590: return (0);
591: m->m_pkthdr.rcvif = ifp;
592: m->m_pkthdr.len = totlen;
593: m->m_len = MHLEN;
594:
595: top = 0;
596: mp = ⊤
597: while (totlen > 0) {
598: if (top) {
599: MGET(m, M_DONTWAIT, MT_DATA);
600: if (m == 0) {
601: m_freem(top);
602: return (0);
603: }
604: m->m_len = MLEN;
605: }
606: len = min(totlen, epkt - cp);
607: if (len >= MINCLSIZE) {
608: MCLGET(m, M_DONTWAIT);
609: if (m->m_flags & M_EXT)
610: m->m_len = len = min(len, MCLBYTES);
611: else
612: len = m->m_len;
613: } else {
614: /*
615: * Place initial small packet/header at end of mbuf.
616: */
617: if (len < m->m_len) {
618: if (top == 0 && len + max_linkhdr <= m->m_len)
619: m->m_data += max_linkhdr;
620: m->m_len = len;
621: } else
622: len = m->m_len;
623: }
624: bcopy(cp, mtod(m, caddr_t), (unsigned)len);
625: cp += len;
626: *mp = m;
627: mp = &m->m_next;
628: totlen -= len;
629: if (cp == epkt)
630: cp = buf;
631: }
632: return (top);
633: }
634:
635: /*
636: * Process an ioctl request.
637: */
638: isioctl(ifp, cmd, data)
639: register struct ifnet *ifp;
640: int cmd;
641: caddr_t data;
642: {
643: register struct ifaddr *ifa = (struct ifaddr *)data;
644: struct is_softc *ns = &is_softc[ifp->if_unit];
645: struct ifreq *ifr = (struct ifreq *)data;
646: int s = splimp(), error = 0;
647:
648:
649: switch (cmd) {
650:
651: case SIOCSIFADDR:
652: ifp->if_flags |= IFF_UP;
653:
654: switch (ifa->ifa_addr->sa_family) {
655: #ifdef INET
656: case AF_INET:
657: isinit(ifp->if_unit); /* before arpwhohas */
658: ((struct arpcom *)ifp)->ac_ipaddr =
659: IA_SIN(ifa)->sin_addr;
660: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
661: break;
662: #endif
663: #ifdef NS
664: case AF_NS:
665: {
666: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
667:
668: if (ns_nullhost(*ina))
669: ina->x_host = *(union ns_host *)(ns->ns_addr);
670: else {
671: /*
672: * The manual says we can't change the address
673: * while the receiver is armed,
674: * so reset everything
675: */
676: ifp->if_flags &= ~IFF_RUNNING;
677: bcopy((caddr_t)ina->x_host.c_host,
678: (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
679: }
680: isinit(ifp->if_unit); /* does ne_setaddr() */
681: break;
682: }
683: #endif
684: default:
685: isinit(ifp->if_unit);
686: break;
687: }
688: break;
689:
690: case SIOCSIFFLAGS:
691: if ((ifp->if_flags & IFF_UP) == 0 &&
692: ifp->if_flags & IFF_RUNNING) {
693: ifp->if_flags &= ~IFF_RUNNING;
694: iswrcsr(0,STOP);
695: } else if (ifp->if_flags & IFF_UP &&
696: (ifp->if_flags & IFF_RUNNING) == 0)
697: isinit(ifp->if_unit);
698: break;
699:
700: #ifdef notdef
701: case SIOCGHWADDR:
702: bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
703: sizeof(ns->ns_addr));
704: break;
705: #endif
706:
707: default:
708: error = EINVAL;
709: }
710: splx(s);
711: return (error);
712: }
713:
714: recv_print(no)
715: int no;
716: {
717: struct mds *rmd;
718: int len,i;
719:
720: rmd = (rd+no);
721: len = rmd->mcnt;
722: printf("Receive buffer %d, len = %d\n",no,len);
723: printf("Status %x\n",isrdcsr(0));
724: for (i=0; i<len; i++)
725: printf("%x ",*(rbuf+(BUFSIZE*no)+i));
726: printf("\n");
727: }
728:
729: xmit_print(no)
730: int no;
731: {
732: struct mds *rmd;
733: int i;
734: u_short len;
735:
736: rmd = (td+no);
737: len = -(rmd->bcnt);
738: printf("Transmit buffer %d, len = %d\n",no,len);
739: printf("Status %x\n",isrdcsr(0));
740: printf("addr %x, flags %x, bcnt %x, mcnt %x\n",
741: rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt);
742: for (i=0; i<len; i++)
743: printf("%x ",*(tbuf+(BUFSIZE*no)+i));
744: printf("\n");
745: }
746:
747: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.