|
|
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 */
1.1.1.2 ! root 99: #define ns_if ns_ac.ac_if /* network-visible interface */
! 100: #define ns_addrp ns_ac.ac_enaddr /* hardware Ethernet address */
1.1 root 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 */
1.1.1.2 ! root 149: for(i=0; i < 6; i++) ns->ns_addrp[i] = inb(isc+(i*2));
1.1 root 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: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
188: ifp->if_init = isinit;
189: ifp->if_output = ether_output;
190: ifp->if_start = isstart;
191: ifp->if_ioctl = isioctl;
192: ifp->if_reset = isreset;
193: ifp->if_watchdog = 0;
194: if_attach(ifp);
1.1.1.2 ! root 195:
! 196: printf("is%d: ethernet address %s\n", unit, ether_sprintf(is->ns_addrp));
1.1 root 197: }
198:
199:
200: /* Lance initialisation block set up */
201: init_mem()
202: {
203: int i;
204: u_long temp;
205:
206: /* Allocate memory */
207: /* Temporary hack, will use kmem_alloc in future */
208: #define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) + 8)
209: static u_char lance_mem[MAXMEM];
210:
211:
212: /* Align message descriptors on quad word boundary
213: (this is essential) */
214:
215: temp = (u_long) &lance_mem;
216: temp = (temp+8) - (temp%8);
217: rd = (struct mds *) temp;
218: td = (struct mds *) (temp + (NRBUF*sizeof(struct mds)));
219: temp += (NRBUF+NTBUF) * sizeof(struct mds);
220:
221: init_block.mode = 0;
222:
223: /* Get ethernet address */
224: for (i=0; i<6; i++)
225: init_block.padr[i] = inb(isc+(i*2));
226:
227: /* Clear multicast address for now */
228: for (i=0; i<8; i++)
229: init_block.ladrf[i] = 0;
230:
231: init_block.rdra = kvtop(rd);
232: init_block.rlen = ((kvtop(rd) >> 16) & 0xff) | (RLEN<<13);
233: init_block.tdra = kvtop(td);
234: init_block.tlen = ((kvtop(td) >> 16) & 0xff) | (TLEN<<13);
235:
236: /* Set up receive ring descriptors */
237: rbuf = (unsigned char *)temp;
238: for (i=0; i<NRBUF; i++) {
239: (rd+i)->addr = kvtop(temp);
240: (rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN;
241: (rd+i)->bcnt = -BUFSIZE;
242: (rd+i)->mcnt = 0;
243: temp += BUFSIZE;
244: }
245:
246: /* Set up transmit ring descriptors */
247: tbuf = (unsigned char *)temp;
248: #ifdef ISDEBUG
249: printf("rd = %x,td = %x, rbuf = %x, tbuf = %x,td+1=%x\n",rd,td,rbuf,tbuf,td+1);
250: #endif
251: for (i=0; i<NTBUF; i++) {
252: (td+i)->addr = kvtop(temp);
253: (td+i)->flags= ((kvtop(temp) >> 16) & 0xff);
254: (td+i)->bcnt = 0;
255: (td+i)->mcnt = 0;
256: temp += BUFSIZE;
257: }
258:
259: }
260:
261: /*
262: * Initialization of interface; set up initialization block
263: * and transmit/receive descriptor rings.
264: */
265: isinit(unit)
266: int unit;
267: {
268: register struct is_softc *ns = &is_softc[unit];
269: struct ifnet *ifp = &ns->ns_if;
270: int s;
271: register i;
272:
273: if (ifp->if_addrlist == (struct ifaddr *)0) return;
274:
275: ns->last_rd = ns->last_td = ns->no_td = 0;
276: s = splimp();
277:
278: /* Set up lance's memory area */
279: init_mem();
280:
281: /* Stop Lance to get access to other registers */
282: iswrcsr(0,STOP);
283:
284: /* I wish I knew what this was */
285: iswrcsr(3,0);
286:
287: /* Give lance the physical address of its memory area */
288: iswrcsr(1,kvtop(&init_block));
289: iswrcsr(2,(kvtop(&init_block) >> 16) & 0xff);
290:
291: /* OK, let's try and initialise the Lance */
292: iswrcsr(0,INIT);
293:
294: /* Wait for initialisation to finish */
295: for(i=0; i<1000; i++){
296: if (isrdcsr(0)&IDON)
297: break;
298: }
299: if (isrdcsr(0)&IDON) {
300: /* Start lance */
301: iswrcsr(0,STRT|IDON|INEA);
302: ns->ns_if.if_flags |= IFF_RUNNING;
303: isstart(ifp);
304: }
305: else
306: printf("Isolink card failed to initialise\n");
307:
308: splx(s);
309: }
310:
311: /*
312: * Setup output on interface.
313: * Get another datagram to send off of the interface queue,
314: * and map it to the interface before starting the output.
315: * called only at splimp or interrupt level.
316: */
317: isstart(ifp)
318: struct ifnet *ifp;
319: {
320: register struct is_softc *ns = &is_softc[ifp->if_unit];
321: struct mbuf *m0, *m;
322: unsigned char *buffer;
323: u_short len;
324: int i;
325: struct mds *cdm;
326:
327:
328: if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
329: return;
330:
331: do {
332: cdm = (td + ns->last_td);
333: if (cdm->flags&OWN)
334: return;
335:
336: IF_DEQUEUE(&ns->ns_if.if_snd, m);
337:
338: if (m == 0)
339: return;
340:
341: /*
342: * Copy the mbuf chain into the transmit buffer
343: */
344:
345: buffer = tbuf+(BUFSIZE*ns->last_td);
346: len=0;
347: for (m0=m; m != 0; m=m->m_next) {
348: bcopy(mtod(m,caddr_t),buffer,m->m_len);
349: buffer += m->m_len;
350: len += m->m_len;
351: }
352:
353: m_freem(m0);
354: len = MAX(len,ETHER_MIN_LEN);
355:
356: /*
357: * Init transmit registers, and set transmit start flag.
358: */
359:
360: cdm->flags |= (OWN|STP|ENP);
361: cdm->bcnt = -len;
362: cdm->mcnt = 0;
363: #ifdef ISDEBUG
364: xmit_print(ns->last_td);
365: #endif
366:
367: iswrcsr(0,TDMD|INEA);
368: if (++ns->last_td >= NTBUF)
369: ns->last_td=0;
370: }while(++ns->no_td < NTBUF);
371: ns->no_td = NTBUF;
372: ns->ns_if.if_flags |= IFF_OACTIVE;
373: #ifdef ISDEBUG
374: printf("no_td = %x, last_td = %x\n",ns->no_td, ns->last_td);
375: #endif
376: return(0);
377: }
378:
379:
380: /*
381: * Controller interrupt.
382: */
383: isintr(unit)
384: {
385: register struct is_softc *ns = &is_softc[unit];
386: u_short isr;
387:
388: while((isr=isrdcsr(0))&INTR) {
389: if (isr&ERR) {
390: if (isr&BABL)
391: printf("BABL\n");
392: if (isr&CERR)
393: printf("CERR\n");
394: if (isr&MISS)
395: printf("MISS\n");
396: if (isr&MERR)
397: printf("MERR\n");
398: iswrcsr(0,BABL|CERR|MISS|MERR|INEA);
399: }
400: if (!(isr&TXON)) {
401: isreset(unit);
402: return(1);
403: }
404: if (!(isr&RXON)) {
405: isreset(unit);
406: return(1);
407: }
408: if (isr&RINT) {
409: isrint(unit);
410: }
411: if (isr&TINT) {
412: iswrcsr(0,TINT|INEA);
413: istint(unit);
414: }
415: }
416: }
417:
418: istint(unit)
419: int unit;
420: {
421: struct is_softc *is = &is_softc[unit];
422: register struct ifnet *ifp = &is->ns_if;
423: int i,loopcount=0;
424: struct mds *cdm;
425:
426: do {
427: if ((i=is->last_td - is->no_td) < 0)
428: i+=NTBUF;
429: cdm = (td+i);
430: #ifdef ISDEBUG
431: printf("Trans cdm = %x\n",cdm);
432: #endif
433: if (cdm->flags&OWN) {
434: if (loopcount)
435: break;
436: return;
437: }
438: loopcount++;
439: is->ns_if.if_flags &= ~IFF_OACTIVE;
440: }while(--is->no_td > 0);
441: isstart(ifp);
442:
443: }
444:
445: #define NEXTRDS \
446: if (++rmd == NRBUF) rmd=0, cdm=rd; else ++cdm
447:
448: isrint(unit)
449: int unit;
450: {
451: register struct is_softc *is=&is_softc[unit];
452: register int rmd = is->last_rd;
453: struct mds *cdm = (rd + rmd);
454:
455: /* Out of sync with hardware, should never happen */
456:
457: if (cdm->flags & OWN) {
458: printf("is0 error: out of sync\n");
459: iswrcsr(0,RINT|INEA);
460: return;
461: }
462:
463: /* Process all buffers with valid data */
464: while (!(cdm->flags&OWN)) {
465: /* Clear interrupt to avoid race condition */
466: iswrcsr(0,RINT|INEA);
467: if (cdm->flags&ERR) {
468: if (cdm->flags&FRAM)
469: printf("FRAM\n");
470: if (cdm->flags&OFLO)
471: printf("OFLO\n");
472: if (cdm->flags&CRC)
473: printf("CRC\n");
474: if (cdm->flags&RBUFF)
475: printf("RBUFF\n");
476: }else
477: if (cdm->flags&(STP|ENP) != (STP|ENP)) {
478: do {
479: iswrcsr(0,RINT|INEA);
480: cdm->mcnt = 0;
481: cdm->flags |= OWN;
482: NEXTRDS;
483: }while (!(cdm->flags&(OWN|ERR|STP|ENP)));
484: is->last_rd = rmd;
485: printf("Chained buffer\n");
486: if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
487: isreset(unit);
488: return;
489: }
490: }else
491: {
492: #ifdef ISDEBUG
493: recv_print(is->last_rd);
494: #endif
495: isread(is,rbuf+(BUFSIZE*rmd),cdm->mcnt);
496: }
497:
498: cdm->flags |= OWN;
499: cdm->mcnt = 0;
500: NEXTRDS;
501: #ifdef ISDEBUG
502: printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm);
503: #endif
504: } /* while */
505: is->last_rd = rmd;
506: } /* isrint */
507:
508: /*
509: * Pass a packet to the higher levels.
510: * We deal with the trailer protocol here.
511: */
512: isread(ns, buf, len)
513: register struct is_softc *ns;
514: char *buf;
515: int len;
516: {
517: register struct ether_header *eh;
518: struct mbuf *m;
519: int off, resid;
520: register struct ifqueue *inq;
521:
522: /*
523: * Deal with trailer protocol: if type is trailer type
524: * get true type from first 16-bit word past data.
525: * Remember that type was trailer by setting off.
526: */
527: eh = (struct ether_header *)buf;
528: eh->ether_type = ntohs((u_short)eh->ether_type);
529: len = len - sizeof(struct ether_header) - 4;
530: #define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
531: if (eh->ether_type >= ETHERTYPE_TRAIL &&
532: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
533: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
534: if (off >= ETHERMTU) return; /* sanity */
535: eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
536: resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
537: if (off + resid > len) return; /* sanity */
538: len = off + resid;
539: } else off = 0;
540:
541: if (len == 0) return;
542:
543: /*
544: * Pull packet off interface. Off is nonzero if packet
545: * has trailing header; neget will then force this header
546: * information to be at the front, but we still have to drop
547: * the type and length which are at the front of any trailer data.
548: */
549: m = isget(buf, len, off, &ns->ns_if);
550: if (m == 0) return;
551:
552: ether_input(&ns->ns_if, eh, m);
553: }
554:
555: /*
556: * Supporting routines
557: */
558:
559: /*
560: * Pull read data off a interface.
561: * Len is length of data, with local net header stripped.
562: * Off is non-zero if a trailer protocol was used, and
563: * gives the offset of the trailer information.
564: * We copy the trailer information and then all the normal
565: * data into mbufs. When full cluster sized units are present
566: * we copy into clusters.
567: */
568: struct mbuf *
569: isget(buf, totlen, off0, ifp)
570: caddr_t buf;
571: int totlen, off0;
572: struct ifnet *ifp;
573: {
574: struct mbuf *top, **mp, *m, *p;
575: int off = off0, len;
576: register caddr_t cp = buf;
577: char *epkt;
578:
579: buf += sizeof(struct ether_header);
580: cp = buf;
581: epkt = cp + totlen;
582:
583:
584: if (off) {
585: cp += off + 2 * sizeof(u_short);
586: totlen -= 2 * sizeof(u_short);
587: }
588:
589: MGETHDR(m, M_DONTWAIT, MT_DATA);
590: if (m == 0)
591: return (0);
592: m->m_pkthdr.rcvif = ifp;
593: m->m_pkthdr.len = totlen;
594: m->m_len = MHLEN;
595:
596: top = 0;
597: mp = ⊤
598: while (totlen > 0) {
599: if (top) {
600: MGET(m, M_DONTWAIT, MT_DATA);
601: if (m == 0) {
602: m_freem(top);
603: return (0);
604: }
605: m->m_len = MLEN;
606: }
607: len = min(totlen, epkt - cp);
608: if (len >= MINCLSIZE) {
609: MCLGET(m, M_DONTWAIT);
610: if (m->m_flags & M_EXT)
611: m->m_len = len = min(len, MCLBYTES);
612: else
613: len = m->m_len;
614: } else {
615: /*
616: * Place initial small packet/header at end of mbuf.
617: */
618: if (len < m->m_len) {
619: if (top == 0 && len + max_linkhdr <= m->m_len)
620: m->m_data += max_linkhdr;
621: m->m_len = len;
622: } else
623: len = m->m_len;
624: }
625: bcopy(cp, mtod(m, caddr_t), (unsigned)len);
626: cp += len;
627: *mp = m;
628: mp = &m->m_next;
629: totlen -= len;
630: if (cp == epkt)
631: cp = buf;
632: }
633: return (top);
634: }
635:
636: /*
637: * Process an ioctl request.
638: */
639: isioctl(ifp, cmd, data)
640: register struct ifnet *ifp;
641: int cmd;
642: caddr_t data;
643: {
644: register struct ifaddr *ifa = (struct ifaddr *)data;
645: struct is_softc *ns = &is_softc[ifp->if_unit];
646: struct ifreq *ifr = (struct ifreq *)data;
647: int s = splimp(), error = 0;
648:
649:
650: switch (cmd) {
651:
652: case SIOCSIFADDR:
653: ifp->if_flags |= IFF_UP;
654:
655: switch (ifa->ifa_addr->sa_family) {
656: #ifdef INET
657: case AF_INET:
658: isinit(ifp->if_unit); /* before arpwhohas */
659: ((struct arpcom *)ifp)->ac_ipaddr =
660: IA_SIN(ifa)->sin_addr;
661: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
662: break;
663: #endif
664: #ifdef NS
665: case AF_NS:
666: {
667: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
668:
669: if (ns_nullhost(*ina))
1.1.1.2 ! root 670: ina->x_host = *(union ns_host *)(ns->ns_addrp);
1.1 root 671: else {
672: /*
673: * The manual says we can't change the address
674: * while the receiver is armed,
675: * so reset everything
676: */
677: ifp->if_flags &= ~IFF_RUNNING;
678: bcopy((caddr_t)ina->x_host.c_host,
1.1.1.2 ! root 679: (caddr_t)ns->ns_addrp, sizeof(ns->ns_addrp));
1.1 root 680: }
681: isinit(ifp->if_unit); /* does ne_setaddr() */
682: break;
683: }
684: #endif
685: default:
686: isinit(ifp->if_unit);
687: break;
688: }
689: break;
690:
691: case SIOCSIFFLAGS:
692: if ((ifp->if_flags & IFF_UP) == 0 &&
693: ifp->if_flags & IFF_RUNNING) {
694: ifp->if_flags &= ~IFF_RUNNING;
695: iswrcsr(0,STOP);
696: } else if (ifp->if_flags & IFF_UP &&
697: (ifp->if_flags & IFF_RUNNING) == 0)
698: isinit(ifp->if_unit);
699: break;
700:
701: #ifdef notdef
702: case SIOCGHWADDR:
703: bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
704: sizeof(ns->ns_addr));
705: break;
706: #endif
707:
708: default:
709: error = EINVAL;
710: }
711: splx(s);
712: return (error);
713: }
714:
715: recv_print(no)
716: int no;
717: {
718: struct mds *rmd;
719: int len,i;
720:
721: rmd = (rd+no);
722: len = rmd->mcnt;
723: printf("Receive buffer %d, len = %d\n",no,len);
724: printf("Status %x\n",isrdcsr(0));
725: for (i=0; i<len; i++)
726: printf("%x ",*(rbuf+(BUFSIZE*no)+i));
727: printf("\n");
728: }
729:
730: xmit_print(no)
731: int no;
732: {
733: struct mds *rmd;
734: int i;
735: u_short len;
736:
737: rmd = (td+no);
738: len = -(rmd->bcnt);
739: printf("Transmit buffer %d, len = %d\n",no,len);
740: printf("Status %x\n",isrdcsr(0));
741: printf("addr %x, flags %x, bcnt %x, mcnt %x\n",
742: rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt);
743: for (i=0; i<len; i++)
744: printf("%x ",*(tbuf+(BUFSIZE*no)+i));
745: printf("\n");
746: }
747:
748: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.