date and time created 86/07/20 11:25:41 by sam
authorSam Leffler <sam@ucbvax.Berkeley.EDU>
Mon, 21 Jul 1986 02:25:41 +0000 (18:25 -0800)
committerSam Leffler <sam@ucbvax.Berkeley.EDU>
Mon, 21 Jul 1986 02:25:41 +0000 (18:25 -0800)
SCCS-vsn: sys/tahoe/if/if_enp.c 1.1
SCCS-vsn: sys/tahoe/if/if_enpreg.h 1.1

usr/src/sys/tahoe/if/if_enp.c [new file with mode: 0644]
usr/src/sys/tahoe/if/if_enpreg.h [new file with mode: 0644]

diff --git a/usr/src/sys/tahoe/if/if_enp.c b/usr/src/sys/tahoe/if/if_enp.c
new file mode 100644 (file)
index 0000000..356cd30
--- /dev/null
@@ -0,0 +1,1157 @@
+/*     if_enp.c        1.1     86/07/20        */
+
+#include "enp.h"
+#define ENPBPTE 128
+#if NENP > 0
+
+/*
+ * Modified 3 Com Ethernet Controller interface
+ * enp modifications added S. F. Holmgren
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "errno.h"
+#include "time.h"
+#include "kernel.h"
+#include "uio.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../h/ioctl.h"
+
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/if_ether.h"
+
+#include "../tahoevba/vbavar.h"
+#include "../tahoeif/if_enp.h"
+#include "../machine/mtpr.h"
+#include "../tahoeif/if_debug.h"
+
+#define ENP0_PHYSADDR  0xf40000        /* board # 0 physical base addr */
+#define ENP1_PHYSADDR  0xf60000        /* board # 1 physical base addr */
+#define ENPSTART       0xf02000        /* standard enp start addr      */
+
+int    enpprobe(), enpattach(), enpintr();
+extern nulldev();
+caddr_t        vtoph();
+struct  mbuf *m_tofree();
+struct  vba_device *enpinfo[ NENP ];
+
+/*     Maximun 2 controllers per system supported                      */
+
+long  enpstd[] = { ENP0_PHYSADDR+0x1000,ENP1_PHYSADDR+0x1000, 0 };
+extern char    enp0utl[], enp1utl[];   /* enp accessible ram map       */
+char   *enpmap[]= { enp0utl, enp1utl };
+extern long    ENP0map[], ENP1map[];
+long   *ENPmap[] = {ENP0map, ENP1map};
+long   ENPmapa[] = {0xfff41000, 0xfff61000};
+long   enpismapped[NENP];
+
+unsigned short intvec[4] = 
+       { 0xc1, 0xc2, 0xc3, 0xc4 };     /* intrvec of upto 4 enps       */
+
+struct  vba_driver enpdriver = 
+{
+/* use of prom based version 
+       enpprobe, 0, enpattach, 0, 0,   enpintr,
+*/
+       enpprobe, 0, nulldev, 0, 
+       enpstd,   "enp", enpinfo, "ENP 20", 0
+};
+
+int     enpinit(),
+       enpioctl(),
+       enpoutput(),
+       enpreset(),
+       enpbroadcast(),
+       enptimeout();
+
+int    enpcopy();
+
+struct  mbuf *enpget();
+
+extern  struct ifnet loif;
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * es_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+
+struct         enp_softc       enp_softc[NENP];
+long   stat_addr[NENP];        /* enp statistic addr (for nstat use) */
+long   ring_addr[NENP];        /* enp dev ring addresses (for nstat use) */
+int    numenp = NENP;
+int    enp_intr = 0,           /* no. of enp_to_host interrupts */
+       host_intr = 0;          /* no. of host_to_enp interrupts */
+short  enpram[NENP];           /* open/close flags for enp devices */
+/*     Debugging tools, used to trace input packets */
+extern         int     printerror;     /* error print flag, from if_ace.c */
+int    save_enp_inpkt = 0;
+#define        ENPTRACE(X)     if (save_enp_inpkt) X;
+
+struct         inp_err         enperr[NENP];
+
+/*
+ * Probe for device.
+ */
+
+enpprobe(reg)
+caddr_t reg;
+{
+       static  int     unit=0;
+       register ENPDEVICE      *addr = (ENPDEVICE *)reg;
+
+       if( (badaddr( addr, 2 ) ) || (badaddr( &addr->enp_ram[0], 2 ) ) )
+               return( 0 );
+       addr->enp_state = S_ENPRESET; /* controller is reset by vbus reset */
+       /* save address of statistic area for nstat uses        */
+
+       stat_addr[unit] = (long) &(addr->enp_stat); 
+       ring_addr[unit++] = (long) &(addr->enp_toenp); 
+
+       return( ENPSIZE );
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets. 
+ */
+
+enpattach( md )
+register struct vba_device *md;
+{
+       struct enp_softc        *es = &enp_softc[md->ui_unit];
+       register struct ifnet   *ifp = &es->es_if;
+       register ENPDEVICE      *addr = (ENPDEVICE *)md->ui_addr;
+       struct sockaddr_in      *sin;
+
+       enpgetaddr( md->ui_unit );
+
+       ifp->if_unit = md->ui_unit;
+       ifp->if_name = "enp";
+       ifp->if_mtu = ETHERMTU;
+
+/*     bcopy(&es->es_boardaddr, es->es_enaddr, sizeof(es->es_enaddr)); */
+
+       sin = (struct sockaddr_in *)&es->es_if.if_addr;
+       sin->sin_family = AF_INET;
+
+       ifp->if_init = enpinit;
+       ifp->if_ioctl = enpioctl;
+       ifp->if_output = enpoutput;
+       ifp->if_reset = enpreset;
+       if_attach(ifp);
+}
+
+
+/*
+ * Reset of interface after UNIBUS reset.
+ */
+enpreset(unit)
+int unit;
+{
+       register struct vba_device *md;
+
+       if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
+               return(ENODEV);
+
+       enpinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations.
+ */
+
+enpinit( unit )
+int unit;
+{
+       struct enp_softc        *es = &enp_softc[unit];
+       ENPDEVICE               *addr;
+       int i, s;
+       u_char *cp, *ap;
+       register struct ifnet   *ifp = &es->es_if;
+       register struct sockaddr_in *sin, *sinb;
+
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+
+       if ( !enpismapped[unit] ) {
+               ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
+               ++enpismapped[unit];
+       }
+       if ((addr = (ENPDEVICE *)enpinfo[unit]->ui_addr) == (ENPDEVICE *)0)
+               return(ENODEV);
+       s = splimp();
+       RESET_ENP( addr );
+       DELAY( 200000 );
+
+#ifdef notdef
+/* only needed if not downloading ( ie, ROM-resident ENP code) */
+       addr->enp_intrvec = intvec[unit];
+       ENP_GO( addr,ENPSTART );
+       DELAY( 200000 );
+/* end of ROM-resident */
+#endif notdef
+
+       es->es_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business*/
+       splx(s);
+
+       if_rtinit( &es->es_if,RTF_UP );
+       arpwhohas(&es->es_ac, &sin->sin_addr);
+}
+
+
+/*
+ * Ethernet interface interrupt.
+ */
+
+enpintr( unit )
+{
+       register ENPDEVICE              *addr;
+       register BCB                    *bcbp;
+       register struct vba_device       *md;
+
+       enp_intr++;
+
+       if (unit >= NENP || (md = enpinfo[unit]) == 0)
+               return;
+
+       addr = (ENPDEVICE *)md->ui_addr;
+
+       if( IS_ENP_INTR(addr) == 0 )
+               return;
+
+       ACK_ENP_INTR( addr );
+
+       while( (bcbp = (BCB *)ringget( &addr->enp_tohost )) != 0 )
+       {
+               enpread( &enp_softc[ unit ],bcbp, unit );
+               ringput( &addr->enp_enpfree,bcbp ); 
+       }
+       return(0);
+}
+
+#define        MAXBLEN 1500
+char   errpkt[MAXBLEN];
+int    bufptr = 0;
+int    maxl_tosave = 200;              /* save only the first 200 bytes */
+
+saverrpkt(errbuf, errtype, len)
+register u_char *errbuf;
+int errtype, len;
+{
+       int remain, newptr;
+
+       remain = MAXBLEN - bufptr;
+       if (remain < 50)                /* if too small                 */
+               return;                 /* no space avail               */
+       len = (len > maxl_tosave || len <= 0) ? maxl_tosave : len;
+       len = len > remain ? (remain - 2*sizeof(len)): len;
+       newptr = bufptr + len + 2*sizeof(len);
+       if (newptr <= MAXBLEN) {
+               enpcopy((char *)&len, &errpkt[bufptr], sizeof(len));
+               enpcopy((char *)&errtype, &errpkt[bufptr+sizeof(len)],
+                       sizeof(errtype));
+               enpcopy(errbuf, &errpkt[bufptr+(2*sizeof(len))], len);
+       }
+       bufptr = newptr;
+}
+
+/*
+ * Read input packet, examine its packet type, and enqueue it.
+ */
+
+enpread( es, bcbp, unit )
+struct enp_softc *es;
+register BCB *bcbp;
+int    unit;
+{
+       register struct ether_header *enp;
+       struct mbuf *m;
+       long int  s, v;
+       register short *vp = (short *)&v,
+                       *sp;
+       int len, off, resid, enptype;
+       register struct ifqueue *inq;
+
+       es->es_if.if_ipackets++; 
+
+       /*
+        * Get input data length.
+        * Get pointer to ethernet header (in input buffer).
+        * Deal with trailer protocol: if type is PUP trailer
+        * get true type from first 16-bit word past data.
+        * Remember that type was trailer by setting off.
+        */
+
+       len = bcbp->b_msglen - SIZEOF_ETHEADER;
+#ifdef TAHOE
+       sp = (short *)&bcbp->b_addr;
+       *vp = *sp; vp[1] = sp[1];
+       enp = (struct ether_header *) v;
+#else
+       enp = (struct ether_header *)bcbp->b_addr;
+#endif TAHOE
+
+#define enpdataaddr(enp, off, type) ((type)(((caddr_t)(((char *)enp)+SIZEOF_ETHEADER)+(off))))
+
+       enptype = enp->ether_type;
+       if (enptype >= ETHERPUP_TRAIL && enptype < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) 
+       {
+               off = (enptype - ETHERPUP_TRAIL) * 512;
+               if (off >= ETHERMTU) {
+                       enperr[unit].bad_offset++;
+                       ENPTRACE(saverrpkt((char *)enp, B_OFFSET, bcbp->b_msglen)); 
+
+                       goto badinput;
+               }
+               enptype = *enpdataaddr(enp, off, u_short *);
+               resid = *(enpdataaddr(enp, off+2, u_short *));
+
+               if (off + resid > len) {
+                       enperr[unit].bad_length++;
+                       ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen)); 
+                       goto badinput;
+               }
+               len = off + resid;
+       } 
+       else
+               off = 0;
+
+       if( len == 0 ) {
+               enperr[unit].bad_length++;
+               ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen)); 
+               goto badinput;
+       }
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; enpget will then force this header
+        * information to be at the front, but we still have to drop
+        * the type and length which are at the front of any trailer data.
+        */
+
+       m = enpget(bcbp, len, off);
+       if( m == 0 )  {
+               enperr[unit].h_nobuffer++; /* host runs out of buf */
+               goto badinput;
+       }
+       if( off )
+       {
+               m->m_off += 2 * sizeof (u_short);
+               m->m_len -= 2 * sizeof (u_short);
+       }
+
+       switch (enptype) 
+       {
+#ifdef INET
+       case ETHERPUP_IPTYPE:
+#ifdef notdef
+               arpipin(enp, m);
+#endif notdef
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+
+       case ETHERPUP_ARPTYPE:
+               arpinput(&es->es_ac, m);
+               return(0);
+#endif
+       default:        /* unrecognized ethernet header */
+               enperr[unit].bad_packetype++;
+               if (printerror) { 
+                       printf("\nenp%d: Undefined packet type 0x%x ", unit,
+                               enp->ether_type);
+                       printf("from host: %x.%x.%x.%x.%x.%x\n", 
+                               enp->ether_shost[0], enp->ether_shost[1], 
+                               enp->ether_shost[2], enp->ether_shost[3],
+                               enp->ether_shost[4], enp->ether_shost[5]);
+               }       /* end debugging aid    */
+               ENPTRACE(saverrpkt((char *)enp, B_PACKETYPE, bcbp->b_msglen)); 
+               m_freem(m);
+               goto badinput;
+       }
+
+       if (IF_QFULL(inq)) 
+       {
+               enperr[unit].inq_full++;
+               IF_DROP(inq);
+               m_freem(m);
+               return(0);
+       }
+       s = splimp();
+       IF_ENQUEUE(inq, m);
+       splx(s);
+badinput:
+       return(0);         /* sanity */
+}
+
+/*
+ * Ethernet output routine. (called by user)
+ * Encapsulate a packet of type family for the local net.
+ * Use trailer local net encapsulation if enough data in first
+ * packet leaves a multiple of 512 bytes of data in remainder.
+ * If destination is this address or broadcast, send packet to
+ * loop device to kludge around the fact that 3com interfaces can't
+ * talk to themselves.
+ */
+
+enpoutput(ifp, m0, dst)
+struct ifnet *ifp;
+struct mbuf *m0;
+struct sockaddr *dst;
+{
+       int type, s, error;
+       struct ether_addr edst;
+       struct in_addr idst;
+
+       register struct enp_softc *es = &enp_softc[ifp->if_unit];
+       register struct mbuf *m = m0;
+       register struct ether_header *enp;
+       register int off, i;
+
+       struct mbuf *mcopy = (struct mbuf *) 0;         /* Null */
+       int unit = ifp->if_unit;
+
+       switch( dst->sa_family )
+       {
+#ifdef INET
+       case AF_INET:
+               idst = ((struct sockaddr_in *)dst)->sin_addr;
+
+               /* translate internet to ethernet address */
+
+               switch(arpresolve(&es->es_ac, m, &idst, &edst)) {
+
+                       case ARPRESOLVE_WILLSEND:
+                               return (0);     /* if not yet resolved */
+                       case ARPRESOLVE_BROADCAST:
+                               mcopy = m_copy(m, 0, (int)M_COPYALL);
+                               if (mcopy)
+                                       looutput(&loif, mcopy, dst);
+
+                               /* falls through ... */
+                       case ARPRESOLVE_OK:
+                               break;
+               }
+               off = ((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+               if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+                       if (off > 0 && (off & 0x1ff) == 0 &&
+                           m->m_off >= MMINOFF + 2 * sizeof (u_short)) 
+                       {
+                               type = ETHERPUP_TRAIL + (off>>9);
+                               m->m_off -= 2 * sizeof (u_short);
+                               m->m_len += 2 * sizeof (u_short);
+                               *mtod(m, u_short *) = ETHERPUP_IPTYPE;
+                               *(mtod(m, u_short *) + 1) = m->m_len;
+                               goto gottrailertype;
+                       }
+
+               type = ETHERPUP_IPTYPE;
+               off = 0;
+               goto gottype;
+#endif
+
+#ifdef notdef
+       case AF_RAW:
+               enp = mtod(m, struct ether_header *);
+               if (m->m_len < sizeof *enp) 
+               {
+                       error = EMSGSIZE;
+                       goto bad;
+               }
+               goto gotheader;
+#endif
+
+       case AF_UNSPEC:
+               enp = (struct ether_header *)dst->sa_data;
+               bcopy( enp->ether_dhost, &edst, sizeof(edst));
+               type = enp->ether_type;
+               goto gottype;
+
+       default:
+               if (printerror)
+                   printf("enp%d: can't handle af%d\n", unit,dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
+       }
+
+gottrailertype:
+       /*
+        * Packet to be sent as trailer: move first packet
+        * (control information) to end of chain.
+        */
+       while (m->m_next)
+               m = m->m_next;
+       m->m_next = m0;
+       m = m0->m_next;
+       m0->m_next = 0;
+       m0 = m;
+
+gottype:
+       /*
+         * Add local net header.  If no space in first mbuf,
+         * allocate another.
+         */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + SIZEOF_ETHEADER > m->m_off) 
+       {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) 
+               {
+                       enperr[unit].h_nobuffer++; /* host runs out of buf */
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = SIZEOF_ETHEADER;
+       } 
+       else
+       {
+               m->m_off -= SIZEOF_ETHEADER;
+               m->m_len += SIZEOF_ETHEADER;
+       }
+       enp = mtod(m, struct ether_header *);
+       bcopy( &edst, enp->ether_dhost, sizeof(enp->ether_dhost) );
+       enp->ether_type = type;
+gotheader:
+       bcopy( es->es_enaddr, enp->ether_shost, sizeof(enp->ether_shost));
+
+       /*
+        * Queue message on interface if possible 
+        */
+
+       s = splimp();   
+       if( enpput( unit,m ) )
+       {
+               error = ENOBUFS;
+               enperr[unit].c_nobuffer++; /* controller runs out of buf */
+               goto qfull;
+       }
+       splx( s );      
+       es->es_if.if_opackets++; 
+       return(0);
+qfull:
+       splx( s );      
+       m0 = m;
+bad:
+       m_freem(m0);
+       return(error);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmitter
+ * buffer in Multibus memory.
+ */
+
+enpput( unit,m )
+int unit;
+struct mbuf *m;
+{
+       register BCB *bcbp;
+       register ENPDEVICE *addr;
+       register struct mbuf *mp;
+       register u_char *bp;
+       int      ctr = 0;
+       long int        v;
+       register short *vp = (short *)&v,
+                       *sp;
+
+       addr = (ENPDEVICE *)enpinfo[ unit ]->ui_addr;
+
+       if ( ringempty( &addr->enp_hostfree ) ) 
+                       return( 1 );    
+
+       bcbp = (BCB *)ringget( &addr->enp_hostfree );
+       bcbp->b_len = 0;
+#ifdef TAHOE
+       sp = (short *)&bcbp->b_addr;
+       *vp = *sp; vp[1] = sp[1];
+       bp = (u_char *)v;
+#else
+       bp = (u_char *)bcbp->b_addr;
+#endif TAHOE
+       for (mp = m; mp; mp = mp->m_next) 
+       {
+               register unsigned len;
+               u_char *mcp;
+
+               len = mp->m_len;
+               if( len == 0 )
+                       continue;
+               mcp = mtod( mp,u_char * );
+               enpcopy( mcp,bp,len );
+               bp += len;
+               bcbp->b_len += len;
+       }
+       bcbp->b_len = max( MINPKTSIZE,bcbp->b_len );
+       bcbp->b_reserved = 0;
+       if ( ringput( &addr->enp_toenp,bcbp ) == 1 ) {
+               host_intr++;
+               INTR_ENP( addr );
+       }
+       m_freem(m);
+       return( 0 );
+}
+
+/*
+ * Routine to copy from Multibus memory into mbufs.
+ *
+ * Warning: This makes the fairly safe assumption that
+ * mbufs have even lengths.
+ */
+struct mbuf *
+enpget( bcbp, totlen, off0 )
+register BCB *bcbp;
+int totlen, off0;
+{
+       register struct mbuf *m;
+       register int off = off0;
+       register unsigned char *cp;
+       long int        v;
+       register short *vp = (short *)&v,
+                       *sp;
+
+       int len;
+       struct mbuf *top = 0;
+       struct mbuf **mp = &top;
+
+#ifdef TAHOE
+       sp = (short *)&bcbp->b_addr;
+       *vp = *sp; vp[1] = sp[1];
+       cp = (unsigned char *)v + SIZEOF_ETHEADER;
+#else
+       cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
+#endif TAHOE
+
+       while( totlen > 0 )
+       {
+               u_char *mcp;
+
+               MGET(m, M_DONTWAIT, MT_DATA);
+               if (m == 0) 
+                       goto bad;
+               if( off )
+               {
+                       len = totlen - off;
+#ifdef TAHOE
+                       sp = (short *)&bcbp->b_addr;
+                       *vp = *sp; vp[1] = sp[1];
+                       cp = (unsigned char *)v + SIZEOF_ETHEADER
+                               + off;
+#else
+                       cp = (unsigned char *)bcbp->b_addr + 
+                               SIZEOF_ETHEADER + off;
+#endif TAHOE
+               } 
+               else
+                       len = totlen;
+
+
+               if (len >= CLBYTES) {
+                       struct mbuf *p;
+
+                       MCLGET(p, 1);
+                       if (p != 0) {
+                               m->m_len = len = CLBYTES;
+                               m->m_off = (int)p - (int)m;
+                       } else  {
+                               m->m_len = len = MIN(MLEN, len);
+                               m->m_off = MMINOFF;
+                               }
+               } else  { 
+                       m->m_len = len = MIN(MLEN, len);
+                       m->m_off = MMINOFF;
+               }
+
+               mcp = mtod(m, u_char *);
+               enpcopy(cp, mcp, len);
+               cp += len;
+               *mp = m;
+               mp = &m->m_next;
+               if (off == 0) 
+               {
+                       totlen -= len;
+                       continue;
+               }
+               off += len;
+               if (off == totlen) 
+               {
+#ifdef TAHOE
+                       sp = (short *)&bcbp->b_addr;
+                       *vp = *sp; vp[1] = sp[1];
+                       cp = (unsigned char *)v + SIZEOF_ETHEADER;
+#else
+                       cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
+#endif TAHOE
+                       off = 0;
+                       totlen = off0;
+               }
+       }
+       return (top);
+bad:
+       m_freem(top);
+       return (0);
+}
+
+/*
+ * Process an ioctl request.
+ *    this can be called via the "socket" route for SIOCSIFADDR or
+ *     by the cdev/inode route for SIOCSIFCCFWR/RD
+ *
+ */
+
+enpioctl(ifp, cmd, data)
+register struct ifnet *ifp;
+int cmd;
+caddr_t data;
+{
+       register int    unit = ifp->if_unit;
+       register struct vba_device *md;
+       int s, error = 0;
+       struct sockaddr_in      *sin;
+       struct sockaddr         *sa;
+       struct enp_softc        *es = &enp_softc[ifp->if_unit];
+       ENPDEVICE               *addr;
+       struct config_entry     *cf;
+       struct ifreq *ifr       = (struct ifreq *)data;
+       struct sockaddr_in      *et_addr;
+       int code, i;
+
+
+       if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
+               return(ENODEV);
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               s = splimp();
+               sa = (struct sockaddr *)&ifr->ifr_addr;
+               if (sa->sa_family == AF_UNSPEC ) {
+                       if (sa->sa_data[0] & 1){ /*broad or multi-cast*/
+                               splx( s );
+                               return( EINVAL );
+                       }
+                       bcopy(sa->sa_data,es->es_enaddr,sizeof(es->es_enaddr));
+                       enpinit( ifp->if_unit);
+                       break;
+               }
+               sin = (struct sockaddr_in *)&ifr->ifr_addr;
+               if (sin->sin_family != AF_INET){
+                       splx( s );
+                       return( EINVAL );
+               }
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               enpsetaddr(ifp, sin);
+               enpinit(ifp->if_unit);
+               enpgetaddr( ifp->if_unit );
+               splx(s);
+               break;
+
+
+       case SIOCSETETADDR:     /* Set Ethernet station address */
+               s = splimp();
+               ifp->if_flags &= (~IFF_RUNNING | IFF_UP);
+               et_addr = (struct sockaddr_in *)&ifr->ifr_addr;
+               addr = (ENPDEVICE *)enpinfo[ifp->if_unit]->ui_addr;
+
+               /* Set station address and reset controller board */
+               {
+               u_char  *to = &addr->enp_addr.e_baseaddr.ea_addr[0];
+               char    *from = &et_addr->sin_zero[2];
+               int     i;
+
+               for (i = 0 ; i < ETHADDR_SIZE; i++) 
+                       *to++ = (u_char) (~(*from++ & 0xff));
+               }
+               enpcopy(&addr->enp_addr.e_listsize, &code, sizeof(code)); 
+               code |= E_ADDR_SUPP;
+               enpcopy(&code, &addr->enp_addr.e_listsize, sizeof(code)); 
+               enpreset(ifp->if_unit);         /* Re-initialize */
+               enpgetaddr(ifp->if_unit);
+               splx(s);
+               break;
+
+       case SIOCGETETADDR:     /* Get Foreign Hosts' Ethernet addresses */
+               arpwhohas(&es->es_ac, (struct in_addr *)ifr->ifr_data);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       return(error);
+}
+
+enpsetaddr(ifp, sin)
+register struct ifnet *ifp;
+register struct sockaddr_in *sin;
+{
+
+       ifp->if_addr = *(struct sockaddr *)sin;
+       ifp->if_net = in_netof(sin->sin_addr);
+       ifp->if_host[0] = in_lnaof(sin->sin_addr);
+       sin = (struct sockaddr_in *)&ifp->if_broadaddr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+       ifp->if_flags |= IFF_BROADCAST;
+}
+
+
+/*
+ * Get the ethernet addr, store it and print it
+ * Read the ethernet address off the board, one byte at a time.
+ *     put it in enp_softc
+ */
+
+
+enpgetaddr( unit )
+int unit;
+{
+       register struct enp_softc       *es = &enp_softc[unit];
+       register ENPDEVICE *addr =(ENPDEVICE *)enpinfo[unit]->ui_addr;
+       int i;
+       
+#ifdef TAHOE
+       enpcopy(&addr->enp_addr.e_baseaddr, &es->es_boardaddr, sizeof(es->es_boardaddr));
+#else
+       es->es_boardaddr = addr->enp_addr.e_baseaddr;
+#endif TAHOE
+       bcopy(&es->es_boardaddr, es->es_enaddr, ETHADDR_SIZE);
+       return( 1 );
+}
+
+/*
+ * enpram device
+ *
+ */
+
+enpr_open( dev )
+{
+       register int    unit = minor(dev);
+       register struct vba_device *md;
+       register ENPDEVICE      *addr;
+
+       if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
+           (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
+               return(ENODEV);
+       if (addr->enp_state != S_ENPRESET)
+               return(EACCES);  /* enp is not in reset state, don't open  */
+       if ( !enpismapped[unit] ) {
+               ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
+               ++enpismapped[unit];
+       }
+       enpram[unit] = ENP_OPEN;
+       return( 0 );
+}
+
+enpr_close(dev)
+{
+       enpram[minor(dev)] = ENP_CLOSE;
+       return( 0 );
+}
+
+enpr_read( dev,uio )
+int dev;
+register struct uio *uio;
+{
+       register ENPDEVICE *addr;
+       register struct iovec *iov;
+       register r=0;
+
+       if (enpram[minor(dev)] != ENP_OPEN)
+               return(EACCES);
+       if ( uio->uio_offset > RAM_SIZE )
+               return( ENODEV );
+       if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
+               iov->iov_len = RAM_SIZE - uio->uio_offset;
+       addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
+       iov  = uio->uio_iov;
+
+       if( r = enpcopyout( &addr->enp_ram[ uio->uio_offset ], iov->iov_base,
+                        iov->iov_len ) )
+                return( r );
+
+       uio->uio_resid -= iov->iov_len;
+       iov->iov_len = 0;
+
+       return( 0 );
+}
+
+enpr_write( dev,uio )
+int dev;
+register struct uio *uio;
+{
+       register ENPDEVICE *addr;
+       register struct iovec *iov;
+       register r=0;
+
+       if (enpram[minor(dev)] != ENP_OPEN)
+               return(EACCES);
+       addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
+       iov  = uio->uio_iov;
+
+       if ( uio->uio_offset > RAM_SIZE )
+               return( ENODEV );
+       if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
+               iov->iov_len = RAM_SIZE - uio->uio_offset;
+       if( r = enpcopyin( iov->iov_base, &addr->enp_ram[ uio->uio_offset ],
+                       iov->iov_len ) )
+               return( r );
+
+       uio->uio_resid -= iov->iov_len;
+       iov->iov_len = 0;
+
+       return( 0 );
+}
+
+enpr_ioctl( dev,cmd,arg,fflag )
+dev_t dev;
+caddr_t *arg;
+{
+       register ENPDEVICE *addr;
+       long int        v;
+       register short  *vp = (short *)&v, *sp;
+       register unit = minor(dev);
+       register struct vba_device *md;
+
+       if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
+           (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
+               return(ENODEV);
+       switch( cmd )
+       {
+               case ENPIOGO:
+/* not needed if prom based version */
+#ifdef TAHOE
+                       sp = (short *)&addr->enp_base;
+                       v = (int)addr;
+                       *sp = *vp; sp[1] = vp[1];
+#else
+                       addr->enp_base = (int)addr;
+#endif TAHOE
+                       addr->enp_intrvec = intvec[ unit ];
+                       ENP_GO( addr, ENPSTART );
+                       DELAY( 200000 );
+                       enpattach( enpinfo[ unit ] );
+                       enpinit( unit );
+                       addr->enp_state = S_ENPRUN;  /* it is running now */
+/* end of not needed */
+
+                       break;
+
+               case ENPIORESET:
+                       RESET_ENP( addr );
+                       addr->enp_state = S_ENPRESET;  /* it is reset now */
+                       DELAY( 100000 );
+                       break;
+       }
+       return( 0 );
+}
+
+/* 
+ * routines to synchronize enp and host 
+ */
+
+static
+ringinit( rp,size )
+register RING *rp;
+{
+       register int    i;
+       register short *sp; 
+
+       rp->r_rdidx = rp->r_wrtidx = 0;
+       rp->r_size = size;
+}
+
+static
+ringempty( rp )
+register RING *rp;
+{
+       return( rp->r_rdidx == rp->r_wrtidx );
+}
+
+static
+ringfull( rp )
+register RING *rp;
+{
+       register short idx;
+
+       idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
+       return( idx == rp->r_rdidx );
+}
+
+static
+ringput( rp,v )
+register RING *rp;
+{
+       register int idx;
+       register short *vp = (short *)&v,
+                      *sp;
+
+       idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
+       if( idx != rp->r_rdidx )
+       {
+#ifdef TAHOE
+               sp = (short *)&rp->r_slot[ rp->r_wrtidx ];
+               *sp = *vp; sp[1] = vp[1];
+#else
+               rp->r_slot[ rp->r_wrtidx ] = v;
+#endif TAHOE
+               rp->r_wrtidx = idx;
+               if( (idx -= rp->r_rdidx) < 0 )
+                       idx += rp->r_size;
+               return( idx );                  /* num ring entries */
+       }
+       return( 0 );
+}
+
+static
+ringget( rp )
+register RING *rp;
+{
+       register int i = 0;
+       long int v;
+       register short *vp = (short *)&v,
+                      *sp;
+
+       if( rp->r_rdidx != rp->r_wrtidx )
+       {
+#ifdef TAHOE
+               sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+               *vp = *sp; vp[1] = sp[1];
+               i = v;
+#else
+               i = rp->r_slot[ rp->r_rdidx ];
+#endif TAHOE
+               rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
+       }
+       return( i );
+}
+
+#ifdef notdef
+struct mbuf *
+m_tofree( rp )
+register RING *rp;
+{
+       long int v = 0;
+       register short *vp = (short *)&v,
+                      *sp;
+
+       if( rp->r_rdidx != rp->r_wrtidx )
+       {
+#ifdef TAHOE
+               sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+               *vp = *sp; vp[1] = sp[1];
+               /* *sp = 0xffff; sp[1] = 0xffff; */
+#else
+               v = rp->r_slot[ rp->r_rdidx ];
+#endif TAHOE
+               rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
+       }
+       return( (struct mbuf *)v );
+}
+#endif
+static
+fir( rp )
+register RING *rp;
+{
+       long int v;
+       register short *vp = (short *)&v,
+                      *sp;
+
+       if( rp->r_rdidx != rp->r_wrtidx )
+#ifdef TAHOE
+       {
+               sp = (short *)&rp->r_slot[ rp->r_rdidx ];
+               *vp = *sp; vp[1] = sp[1];
+               return( v );
+       }
+#else
+               return( rp->r_slot[ rp->r_rdidx ] );
+#endif TAHOE
+       else   
+               return( 0 );
+}
+
+
+static
+prtbytes( addr )
+register char *addr;
+{
+       register int i;
+
+       for( i = 0; i < 12; i++ )
+       {
+               printf("%X ",*addr&0377);
+               addr++;
+       }
+       printf("\n");
+}
+
+static
+enpcopy(from, to, cnt)
+register char *from, *to;
+register cnt;
+{
+       register c;
+       register short *f, *t;
+
+       if (((int)from & 01) && ((int)to & 01)) {
+                                       /* source & dest at odd addresses */
+               *to++ = *from++;
+               --cnt;
+       }
+       if (cnt > 1 && (((int)to & 01)==0) && (((int)from & 01)==0)) {
+               t = (short *) to;
+               f = (short *) from;
+               for( c = cnt>>1; c; --c)        /* even address copy */
+                       *t++ = *f++;
+               cnt &= 1;
+               if ( cnt ) {                    /* odd len */
+                       from = (char *) f;
+                       to   = (char *) t;
+                       *to = *from;
+               }
+       }
+       while (cnt-- > 0)       /* one of the address(es) must be odd */
+               *to++ = *from++;
+
+}
+
+static
+enpcopyin(userv, kernv, cnt)
+{
+
+       if (useracc(userv, cnt, 1)) {
+               enpcopy( userv, kernv, cnt );
+               return( 0 );
+       }
+       else    return( EFAULT );
+}
+
+
+static
+enpcopyout(kernv, userv, cnt)
+{
+
+       if (useracc(userv, cnt, 0)) {
+               enpcopy( kernv, userv, cnt );
+               return( 0 );
+       }
+       else    return( EFAULT );
+}
+#endif
diff --git a/usr/src/sys/tahoe/if/if_enpreg.h b/usr/src/sys/tahoe/if/if_enpreg.h
new file mode 100644 (file)
index 0000000..596dd4b
--- /dev/null
@@ -0,0 +1,312 @@
+/*     if_enpreg.h     1.1     86/07/20        */
+
+/*     Copyright (c) 1984 by Communication Machinery Corporation
+ *
+ *     This file contains material which is proprietary to
+ *     Communication Machinery Corporation (CMC) and which
+ *     may not be divulged without the written permission
+ *     of CMC.
+ *
+ *     ENP-10 Ram Definition
+ *
+ *     3/15/85 Jon Phares
+ *     Update 7/10/85 S. Holmgren
+ *     ENP-10 update 7/21/85 J. Mullen
+ *     ENP-20 update 8/11/85 J. Mullen
+ *     Mods for CCI TAHOE system 8/14/85 J. Mullen
+ * 
+ */
+
+#define K              *1024
+
+#define ENPSIZE                (124 K)         /* VME bus space allocated to enp */
+#define MINPKTSIZE     60              /* minimum ethernet packet size */
+
+/* Note: paged window (4 K) is identity mapped by ENP kernel to provide
+ * 124 K contiguous RAM (as reflected in RAM_SIZE)
+ */
+
+#define RAM_WINDOW     (128 K)
+#define IOACCESS_WINDOW (512)
+#define FIXED_WINDOW   (RAM_WINDOW - IOACCESS_WINDOW)
+#define RAMROM_SWAP    (4 K)
+#define RAM_SIZE       (FIXED_WINDOW - RAMROM_SWAP)
+
+#define HOST_RAMSIZE   (48 K)
+#define ENP_RAMSIZE    (20 K)
+
+/* ...top of 4K local i/o space for ENP */
+
+#ifdef notdef
+typedef struct iow10 {
+       char    pad1[0x81];
+/* written to: causes an interrupt on the host at the vector written
+   read from : returns the most significant 8 bits of the slave address */
+       char    vector;
+       char    pad2[0x1F];
+       char    csrarr[0x1E];
+       char    pad3[2];
+       char    ier;            /* intr. enable reg., 0x80 == enable,0 == off*/
+       char    pad4[1];
+       char    tir;            /* transmit intr. (Level 4 INP autovector) */
+       char    pad5[1];
+       char    rir;            /* receive intr. (Level 5 INP autovector) */
+       char    pad6[1];
+       char    uir;            /* utility intr. (Level 1 INP autovector) */
+       char    pad7[7];
+       char    mapfirst4k;     /* bit 7 set means ram, clear means rom */
+       char    pad8[0x11];
+       char    exr;            /* exception register, see bit defines above */
+       char    pad9[0xD1F];
+       char    hst2enp_interrupt;      /* R or W interrupts ENP */
+       char    pad10[0xFF];
+       char    hst2enp_reset;  /* R or W resets ENP */
+} iow10;
+#endif notdef
+
+typedef struct iow20
+{
+       char    pad0;   
+       char    hst2enp_interrupt;
+       char    pad1[510];
+} iow20;
+
+
+#ifdef notdef
+typedef struct iow30 
+{
+       char    pad0;
+       char    impucsr;
+       char    pad1[0x1d];
+       short   bus2mpu_interrupt;
+       short   bs2enp_wsctl;
+       short   bs2enp_rsctl;
+       short   enp2hst_clear_intr;  /* 0x27 */
+       short   enp_rcv_intr;
+       short   enp_xmit_intr;
+       short   hst2enp_interrupt;   /* 0x2d */
+       short   pad2;
+       char    pad3[0xf];
+       short   bus_page;       /* Bus page register */ 
+       char    pad4[0x1d];
+       short   lock_ctrl;
+       char    pad5[0x1d];
+       short   duart[0x10];    /* 16 duart regs */
+       char    pad6[0x1f];
+       short   bus_window;
+} iow30; 
+#endif notdef
+
+struct ether_addr
+{
+       u_char ea_addr[6];
+};
+
+#define ETHADDR                struct ether_addr
+#define ETHADDR_SIZE   6               /* size of ethernet address     */
+
+typedef
+struct ethlist
+{
+       int     e_listsize;             /* active addr entries */
+       ETHADDR e_baseaddr;             /* addr lance is working with */
+       ETHADDR e_addrs[ 16 ];          /* possible addresses */
+} ETHLIST;
+
+typedef
+struct enpstat
+{
+       unsigned long e_xmit_successful;        /* Successful transmissions */
+       unsigned long e_mult_retry;             /* multiple retries on xmit */
+       unsigned long e_one_retry;              /* single retries */
+       unsigned long e_fail_retry;             /* too many retries */
+       unsigned long e_deferrals;              /* transmission delayed due
+                                                  to active medium */
+       unsigned long e_xmit_buff_err;          /* xmit data chaining failed --
+                                                  "can't happen" */
+       unsigned long e_silo_underrun;          /* transmit data fetch failed */
+       unsigned long e_late_coll;              /* collision after xmit */
+       unsigned long e_lost_carrier;
+       unsigned long e_babble;                 /* xmit length > 1518 */
+       unsigned long e_collision;
+       unsigned long e_xmit_mem_err;
+       unsigned long e_rcv_successful;         /* good receptions */
+       unsigned long e_rcv_missed;             /* no recv buff available */
+       unsigned long e_crc_err;                /* checksum failed */
+       unsigned long e_frame_err;              /* crc error AND
+                                                  data length != 0 mod 8 */
+       unsigned long e_rcv_buff_err;           /* rcv data chain failure --
+                                                  "can't happen" */
+       unsigned long e_silo_overrun;           /* receive data store failed */
+       unsigned long e_rcv_mem_err;
+} ENPSTAT;
+
+typedef struct RING
+{
+       short   r_rdidx;
+       short   r_wrtidx;
+       short   r_size;
+       short   r_pad;
+       int     r_slot[1];
+} RING;
+
+typedef struct RING32
+{
+       short   r_rdidx;
+       short   r_wrtidx;
+       short   r_size;
+       short   r_pad;                  /* to make VAXen happy */
+       int     r_slot[ 32 ];
+} RING32;
+
+/*
+ *     ENP Ram data layout
+ *
+ *     If you don't put it here - it isn't there
+ *
+ */
+
+typedef struct enpdevice {
+#ifdef notdef
+       char    enp_ram_rom[4 K];
+#endif notdef
+       union {
+               char    all_ram[RAM_SIZE];
+               struct {
+                       unsigned int    t_go;
+                       unsigned int    t_pstart;
+               } t;
+               struct {
+                       char    nram[RAM_SIZE - (HOST_RAMSIZE + ENP_RAMSIZE)];
+                       char    hram[HOST_RAMSIZE];
+                       char    kram[ENP_RAMSIZE];
+               } u_ram;
+               struct
+               {
+                       char    pad7[ 0x100 ];  /* starts 0x1100 - 0x2000 */
+                       short   e_enpstate;     /* 1102 */
+                       short   e_enpmode;      /* 1104 */
+                       int     e_enpbase;      /* 1104 */
+                       int     e_enprun;       /* 1108 */
+                       unsigned short  e_intrvec;
+                       unsigned short  e_dummy[3];
+
+                       RING32  h_toenp;        /* 110C */
+                       RING32  h_hostfree;             
+                       RING32  e_tohost;               
+                       RING32  e_enpfree;              
+
+                       ENPSTAT e_stat;
+                       ETHLIST e_netaddr;              
+               } iface;
+       } enp_u;
+       iow20   enp_iow;
+} ENPDEVICE;
+
+#define        enp_ram         enp_u.all_ram
+#define        enp_nram        enp_u.u_ram.nram
+#define        enp_hram        enp_u.u_ram.hram
+#define        enp_kram        enp_u.u_ram.kram
+#define        enp_go          enp_u.t.t_go
+#define        enp_prog_start  enp_u.t.t_pstart
+#define        enp_intrvec     enp_u.iface.e_intrvec
+#define enp_state      enp_u.iface.e_enpstate
+#define enp_mode       enp_u.iface.e_enpmode
+#define enp_base       enp_u.iface.e_enpbase
+#define enp_enprun     enp_u.iface.e_enprun
+#define enp_toenp      enp_u.iface.h_toenp
+#define enp_hostfree   enp_u.iface.h_hostfree
+#define enp_tohost     enp_u.iface.e_tohost
+#define enp_enpfree    enp_u.iface.e_enpfree
+#define enp_freembuf   enp_u.iface.h_freembuf
+#define enp_stat       enp_u.iface.e_stat
+#define enp_addr       enp_u.iface.e_netaddr
+
+#define ENPVAL         0xff    /* value to poke in enp_iow.hst2enp_interrupt */
+#define RESETVAL       0x00    /* value to poke in enp_iow.enp2hst_clear_intr */
+
+#define INTR_ENP(addr)         addr->enp_iow.hst2enp_interrupt = ENPVAL
+
+#if ENP == 30
+#define ACK_ENP_INTR(addr)     addr->enp_iow.enp2hst_clear_intr = RESETVAL
+#define IS_ENP_INTR(addr)      (addr->enp_iow.enp2hst_clear_intr&0x80)
+# else
+#define ACK_ENP_INTR(addr)
+#define IS_ENP_INTR(addr)      ( 1 )
+#endif ENP == 30
+
+#ifdef notdef
+#define RESET_ENP(addr)                addr->enp_iow.hst2enp_reset = 01
+# else
+#define RESET_ENP(addr)
+#endif notdef
+
+#ifdef TAHOE
+#define ENP_GO( addr,start )   {int v; v = start; \
+                       enpcopy(&v, &addr->enp_prog_start, sizeof(v) ); \
+                       v = 0x80800000; \
+                       enpcopy( &v, &addr->enp_go, sizeof(v) ); }
+#else
+#define ENP_GO( addr,start,intvec ) { addr->enp_prog_start = (unsigned int)(start); \
+                               addr->enp_intrvec = (unsigned short) intvec; \
+                               addr->enp_go = 0x80800000; }
+#endif TAHOE
+
+#define SPL_ENP                        spl4
+
+
+/*
+ * state bits
+ */
+
+#define S_ENPRESET     01              /* enp is in reset state */
+#define S_ENPRUN       02              /* enp is in run state */
+
+/*
+ * mode bits
+ */
+
+#define E_SWAP16               0x1             /* swap two octets within 16 */
+#define E_SWAP32               0x2             /* swap 16s within 32 */
+#define E_SWAPRD               0x4             /* swap on read */
+#define E_SWAPWRT              0x8             /* swap on write */
+#define E_DMA                  0x10            /* enp does data moving */
+
+#define E_EXAM_LIST            0x80000000      /*enp should examine addrlist */
+#define E_ADDR_SUPP            0x40000000      /*enp should use supplied addr*/
+
+
+/*
+ *     Download ioctl definitions
+ */
+
+#define mkioctl(type,value) (0x20000000|('type'<<8)|value)
+
+#define ENPIOGO                mkioctl( S,1 )          /* start the enp */
+#define ENPIORESET     mkioctl( S,2 )          /* reset the enp */
+
+/*
+ *     The ENP Data Buffer Structure
+ */
+
+typedef struct BCB
+{
+       struct BCB *b_link;
+       short    b_stat;
+       short    b_len;
+       char    *b_addr;
+       short    b_msglen;
+       short    b_reserved;
+}BCB;
+
+struct  enp_softc 
+{
+       struct  arpcom es_ac;           /* common ethernet structures */
+       struct  ether_addr es_boardaddr;/* board ethernet address */
+}; 
+
+#define es_if           es_ac.ac_if     /* network-visible interface */
+#define es_enaddr       es_ac.ac_enaddr /* hardware ethernet address */
+
+#define        ENP_OPEN        1               /* device enpram opened */
+#define ENP_CLOSE      2               /* device enpram closed */