first working version of BSD/tahoe ex driver; checkpoint other
[unix-history] / usr / src / sys / tahoe / if / if_ace.c
index 2ff4d1a..fa7cc80 100644 (file)
@@ -1,4 +1,24 @@
-/*     if_ace.c        1.1     85/07/21        */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Computer Consoles Inc.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)if_ace.c    7.4 (Berkeley) %G%
+ */
 
 /*
  * ACC VERSAbus Ethernet controller
 
 /*
  * ACC VERSAbus Ethernet controller
 #include "ace.h"
 #if NACE > 0
 
 #include "ace.h"
 #if NACE > 0
 
-#include "../machine/pte.h"
-
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/mbuf.h"
-#include "../h/buf.h"
-#include "../h/protosw.h"
-#include "../h/socket.h"
-#include "../h/vmmac.h"
-#include "../h/ioctl.h"
-#include "../h/errno.h"
-#include "../h/vmparam.h"
+#include "param.h"
+#include "systm.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "vmparam.h"
+#include "syslog.h"
 
 #include "../net/if.h"
 #include "../net/netisr.h"
 #include "../net/route.h"
 
 #include "../net/if.h"
 #include "../net/netisr.h"
 #include "../net/route.h"
+#ifdef INET
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
 #include "../netinet/in.h"
 #include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_var.h"
 #include "../netinet/if_ether.h"
 #include "../netinet/ip.h"
 #include "../netinet/ip_var.h"
 #include "../netinet/if_ether.h"
-#include "../netpup/pup.h"
+#endif
+#ifdef NS
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#endif
+
+#include "../machine/cpu.h"
+#include "../machine/pte.h"
 
 #include "../tahoe/mtpr.h"
 #include "../tahoeif/if_acereg.h"
 
 #include "../tahoe/mtpr.h"
 #include "../tahoeif/if_acereg.h"
-#include "../vba/vbavar.h"
-
-#define        LONET   124
+#include "../tahoevba/vbavar.h"
 
 
-/*
- * Configuration table, for 2 units (should be defined by config)
- */
-#define        ACEVECTOR       0x90
-long   acestd[] = { 0x0ff0000, 0xff0100 };             /* controller */
-
-extern char ace0utl[], ace1utl[];                      /* dpm */
-char   *acemap[]= { ace0utl, ace1utl };
-extern long ACE0map[], ACE1map[];
-long   *ACEmap[] = { ACE0map, ACE1map };
-long   ACEmapa[] = { 0xfff80000, 0xfff90000 };
-
-/* station address */
-char   ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 };
-/* multicast hash table initializer */
-char   ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF };
-/* backoff table masks */
-short random_mask_tbl[16] = {
-       0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
-       0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
-};
-
-int    aceprobe(), aceattach(), acerint(), acecint();
+int    aceprobe(), aceattach(), acerint(), acecint(), acestart();
 struct vba_device *aceinfo[NACE];
 struct vba_device *aceinfo[NACE];
+long   acestd[] = { 0 };
 struct vba_driver acedriver =
 struct vba_driver acedriver =
-       { aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
-       
-#define        ACEUNIT(x)      minor(x)
+    { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 };
 
 int    aceinit(), aceoutput(), aceioctl(), acereset();
 struct mbuf *aceget();
 
 int    aceinit(), aceoutput(), aceioctl(), acereset();
 struct mbuf *aceget();
@@ -78,7 +82,6 @@ struct        ace_softc {
        struct  arpcom is_ac;           /* Ethernet common part */
 #define        is_if   is_ac.ac_if             /* network-visible interface */
 #define        is_addr is_ac.ac_enaddr         /* hardware Ethernet address */
        struct  arpcom is_ac;           /* Ethernet common part */
 #define        is_if   is_ac.ac_if             /* network-visible interface */
 #define        is_addr is_ac.ac_enaddr         /* hardware Ethernet address */
-       char    *is_dpm;
        short   is_flags;
 #define        ACEF_OACTIVE    0x1             /* output is active */
 #define        ACEF_RCVPENDING 0x2             /* start rcv in acecint */
        short   is_flags;
 #define        ACEF_OACTIVE    0x1             /* output is active */
 #define        ACEF_RCVPENDING 0x2             /* start rcv in acecint */
@@ -91,22 +94,43 @@ struct      ace_softc {
        struct  ace_stats is_stats;     /* holds board statistics */
        short   is_xcnt;                /* count xmitted segments to be acked 
                                           by the controller */
        struct  ace_stats is_stats;     /* holds board statistics */
        short   is_xcnt;                /* count xmitted segments to be acked 
                                           by the controller */
+       long    is_ivec;                /* autoconfig interrupt vector base */
+       struct  pte *is_map;            /* pte map for dual ported memory */
+       caddr_t is_dpm;                 /* address of mapped memory */
 } ace_softc[NACE];
 extern struct ifnet loif;
 
 } ace_softc[NACE];
 extern struct ifnet loif;
 
-aceprobe(reg)
+aceprobe(reg, vi)
        caddr_t reg;
        caddr_t reg;
+       struct vba_device *vi;
 {
 {
-       register struct acedevice *addr = (struct acedevice *)reg;
+       register br, cvec;              /* must be r12, r11 */
+       struct acedevice *ap = (struct acedevice *)reg;
+       struct ace_softc *is = &ace_softc[vi->ui_unit];
 
 #ifdef lint
 
 #ifdef lint
+       br = 0; cvec = br; br = cvec;
        acerint(0); acecint(0);
 #endif
        if (badaddr(reg, 2))
        acerint(0); acecint(0);
 #endif
        if (badaddr(reg, 2))
-               return(0);
-       movew((short)CSR_RESET, &addr->csr);
+               return (0);
+       movow(&ap->csr, CSR_RESET);
        DELAY(10000);
        DELAY(10000);
-       return (sizeof (struct acedevice));
+#ifdef notdef
+       /*
+        * Select two spaces for the interrupts aligned to an
+        * eight vector boundary and fitting in 8 bits (as
+        * required by the controller) -- YECH.  The controller
+        * will be notified later at initialization time.
+        */
+       if ((vi->ui_hd->vh_lastiv -= 2) > 0xff)
+               vi->ui_hd->vh_lastiv  = 0x200;
+       is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7;
+#else
+       is->is_ivec = 0x90+vi->ui_unit*8;
+#endif
+       br = 0x14, cvec = is->is_ivec;          /* XXX */
+       return (sizeof (*ap));
 }
 
 /*
 }
 
 /*
@@ -122,52 +146,40 @@ aceattach(ui)
        register struct ifnet *ifp = &is->is_if;
        register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
        register short *wp, i;
        register struct ifnet *ifp = &is->is_if;
        register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
        register short *wp, i;
-       struct sockaddr_in *sin;
 
        ifp->if_unit = unit;
        ifp->if_name = "ace";
        ifp->if_mtu = ETHERMTU;
        /*
 
        ifp->if_unit = unit;
        ifp->if_name = "ace";
        ifp->if_mtu = ETHERMTU;
        /*
-        * Set station's addresses, multicast
-        * hash table, and initialize dual ported memory.
+        * Get station's addresses and set multicast hash table.
         */
         */
-       ace_station[5] = ~(unit + 1);
-       acesetetaddr(unit, addr, ace_station);
+       for (wp = (short *)addr->station, i = 0; i < 6; i++)
+               is->is_addr[i] = ~*wp++;
+       printf("ace%d: hardware address %s\n", unit,
+           ether_sprintf(is->is_addr));
        is->is_promiscuous = 0;
        is->is_promiscuous = 0;
-       wp = (short *)addr->hash;
-       for (i =  0; i < 8; i++)
-               movew((short)ace_hash[i], wp++); 
-       movew((short)~0xffff, &addr->bcastena[0]); 
-       movew((short)~0xffff, &addr->bcastena[1]);
-       aceclean(unit);
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       sin->sin_family = AF_INET;
+       for (wp = (short *)addr->hash, i =  0; i < 8; i++)
+               movow(wp++, ~0xf); 
+       movow(&addr->bcastena[0], ~0xffff); 
+       movow(&addr->bcastena[1], ~0xffff);
+       /*
+        * Allocate and map dual ported VERSAbus memory.
+        */
+       if (vbmemalloc(32, (caddr_t)ui->ui_flags,
+           &is->is_map, &is->is_dpm) == 0) {
+               printf("ace%d: can't allocate VERSAbus memory map\n", unit);
+               return;
+       }
+
        ifp->if_init = aceinit;
        ifp->if_init = aceinit;
-       ifp->if_output = aceoutput;
+       ifp->if_output = ether_output;
+       ifp->if_start = acestart;
        ifp->if_ioctl = aceioctl;
        ifp->if_reset = acereset;
        ifp->if_ioctl = aceioctl;
        ifp->if_reset = acereset;
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
        if_attach(ifp);
 }
 
        if_attach(ifp);
 }
 
-acesetetaddr(unit, addr, station_addr)
-       short unit;
-       struct acedevice *addr;
-       char *station_addr;
-{
-       register short *wp, i;
-       register char *cp;
-       struct ace_softc *is = &ace_softc[unit];
-
-       wp = (short *)addr->station;
-       cp = station_addr;
-       for (i = 0; i < 6; i++)
-               movew((short)*cp++, wp++); 
-       wp = (short *)addr->station;
-       cp = (char *)&is->is_addr;
-       for (i = 0; i < 6; i++)
-               *cp++ = ~(*wp++);
-}
-
 /*
  * Reset of interface after "system" reset.
  */
 /*
  * Reset of interface after "system" reset.
  */
@@ -192,81 +204,72 @@ aceinit(unit)
        register struct ace_softc *is = &ace_softc[unit];
        register struct vba_device *ui = aceinfo[unit];
        register struct acedevice *addr;
        register struct ace_softc *is = &ace_softc[unit];
        register struct vba_device *ui = aceinfo[unit];
        register struct acedevice *addr;
-       register struct ifnet *ifp = &is->is_if;
-       register struct sockaddr_in *sin;
        register short Csr;
        register short Csr;
-       register int i, s;
+       register int s;
 
 
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       if (sin->sin_addr.s_addr == 0)          /* address still unknown */
+       if (is->is_if.if_addrlist == (struct ifaddr *)0)
                return;
                return;
-       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+       if ((is->is_if.if_flags & IFF_RUNNING) == 0) {
                /*
                 * Reset the controller, initialize the recieve buffers,
                 * and turn the controller on again and set board online.
                 */
                addr = (struct acedevice *)ui->ui_addr;
                s = splimp();
                /*
                 * Reset the controller, initialize the recieve buffers,
                 * and turn the controller on again and set board online.
                 */
                addr = (struct acedevice *)ui->ui_addr;
                s = splimp();
-               movew((short)CSR_RESET, &addr->csr);
+               movow(&addr->csr, CSR_RESET);
                DELAY(10000);
 
                /*
                DELAY(10000);
 
                /*
-                * clean up dpm since the controller might
-                * jumble dpm after reset
+                * Clean up dpm since the controller might
+                * jumble dpm after reset.
                 */
                 */
-               aceclean(unit);
-               movew((short)CSR_GO, &addr->csr);
+               acesetup(unit);
+               movow(&addr->csr, CSR_GO);
                Csr = addr->csr;
                if (Csr & CSR_ACTIVE) {
                Csr = addr->csr;
                if (Csr & CSR_ACTIVE) {
-                       movew((short)(ACEVECTOR + unit*8), &addr->ivct);
+                       movow(&addr->ivct, is->is_ivec);
                        Csr |= CSR_IENA | is->is_promiscuous;
                        Csr |= CSR_IENA | is->is_promiscuous;
-                       if (ifp->if_net == LONET)
-                               Csr |= CSR_LOOP3;
-                       movew(Csr, &addr->csr);
+                       movow(&addr->csr, Csr);
                        is->is_flags = 0;
                        is->is_xcnt = 0;
                        is->is_flags = 0;
                        is->is_xcnt = 0;
-                       is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
+                       is->is_if.if_flags |= IFF_RUNNING;
                }
                splx(s);
        }
                }
                splx(s);
        }
-
-       if (is->is_if.if_flags & IFF_UP) {
-               if_rtinit(&is->is_if, RTF_UP);
-               aceStart(unit);
-       }
-       arpwhohas(&is->is_ac, &sin->sin_addr);
+       if (is->is_if.if_snd.ifq_head)
+               acestart(&is->is_if);
 }
 
 /*
  * Start output on interface.
  * Get another datagram to send off of the interface queue,
  * and map it to the interface before starting the output.
 }
 
 /*
  * Start output on interface.
  * Get another datagram to send off of the interface queue,
  * and map it to the interface before starting the output.
- *
  */
  */
-acestart(dev)
-       dev_t dev;
+acestart(ifp)
+       register struct ifnet *ifp;
 {
        register struct tx_segment *txs;
 {
        register struct tx_segment *txs;
-       register long len, x;
-       int unit = ACEUNIT(dev);
-       struct vba_device *ui = aceinfo[unit];
-       register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
-       register struct ace_softc *is = &ace_softc[unit];
+       register long len;
+       register int s;
        struct mbuf *m;
        struct mbuf *m;
-       short retries, idx;
+       short retries;
+#define        is ((struct ace_softc *)ifp)
 
 again:
        txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
        if (txs->tx_csr & TCS_TBFULL) {
                is->is_stats.tx_busy++;
 
 again:
        txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
        if (txs->tx_csr & TCS_TBFULL) {
                is->is_stats.tx_busy++;
-               return;
+               ifp->if_flags |= IFF_OACTIVE;
+               return (0);
        }
        }
-       x = splimp();
-       IF_DEQUEUE(&is->is_if.if_snd, m);
-       splx(x);
-       if (m == 0)
-               return;
-       len = aceput(unit, txs->tx_data, m);
+       s = splimp();
+       IF_DEQUEUE(&ifp->if_snd, m);
+       splx(s);
+       if (m == 0) {
+               ifp->if_flags &= ~IFF_OACTIVE;
+               return (0);
+       }
+       len = aceput(txs->tx_data, m);
        retries = txs->tx_csr & TCS_RTC;
        if (retries > 0)
                acebakoff(is, txs, retries);
        retries = txs->tx_csr & TCS_RTC;
        if (retries > 0)
                acebakoff(is, txs, retries);
@@ -278,20 +281,16 @@ again:
         * For security, it might be wise to zero out the added bytes,
         * but we're mainly interested in speed at the moment.
         */
         * For security, it might be wise to zero out the added bytes,
         * but we're mainly interested in speed at the moment.
         */
-#ifdef notdef
        if (len - sizeof (struct ether_header) < ETHERMIN)
                len = ETHERMIN + sizeof (struct ether_header);
        if (len - sizeof (struct ether_header) < ETHERMIN)
                len = ETHERMIN + sizeof (struct ether_header);
-#else
-       if (len - 14 < ETHERMIN)
-               len = ETHERMIN + 14;
-#endif
        if (++is->is_txnext > SEG_MAX) 
                is->is_txnext = is->is_segboundry;
        if (++is->is_txnext > SEG_MAX) 
                is->is_txnext = is->is_segboundry;
-       is->is_if.if_opackets++;
+       ifp->if_opackets++;
        is->is_xcnt++;
        len = (len & 0x7fff) | TCS_TBFULL;
        is->is_xcnt++;
        len = (len & 0x7fff) | TCS_TBFULL;
-       movew((short)len, txs);
+       movow(txs, len);
        goto again;
        goto again;
+#undef is
 }
 
 /*
 }
 
 /*
@@ -301,17 +300,15 @@ acecint(unit)
        int unit;
 {
        register struct ace_softc *is = &ace_softc[unit];
        int unit;
 {
        register struct ace_softc *is = &ace_softc[unit];
-       struct vba_device *ui = aceinfo[unit];
-       register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
        register struct tx_segment *txseg;
        register struct tx_segment *txseg;
-       short txidx, eostat;
+       short eostat;
 
        if (is->is_xcnt <= 0)  {
 
        if (is->is_xcnt <= 0)  {
-               txidx = (addr->tseg >> 11) & 0xf;
-               printf("ace%d: stray xmit interrupt, xcnt %d\n",
+               log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n",
                    unit, is->is_xcnt);
                is->is_xcnt = 0;
                    unit, is->is_xcnt);
                is->is_xcnt = 0;
-               aceStart(unit);
+               if (is->is_if.if_snd.ifq_head)
+                       acestart(&is->is_if);
                return;
        }
        is->is_xcnt--;
                return;
        }
        is->is_xcnt--;
@@ -327,7 +324,8 @@ acecint(unit)
                if (++is->is_eoctr >= 16)
                        is->is_eoctr = is->is_segboundry; 
        } 
                if (++is->is_eoctr >= 16)
                        is->is_eoctr = is->is_segboundry; 
        } 
-       aceStart(unit);
+       if (is->is_if.if_snd.ifq_head)
+               acestart(&is->is_if);
 }
 
 /*
 }
 
 /*
@@ -346,11 +344,12 @@ acerint(unit)
        register struct ifqueue *inq;
        register struct ether_header *ace;
        register struct rx_segment *rxseg;
        register struct ifqueue *inq;
        register struct ether_header *ace;
        register struct rx_segment *rxseg;
-       struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr;
        int len, s, off, resid;
        struct mbuf *m;
        short eistat;
 
        int len, s, off, resid;
        struct mbuf *m;
        short eistat;
 
+       if ((is->is_if.if_flags&IFF_RUNNING) == 0)
+               return;
 again:
        rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
        eistat = rxseg->rx_csr;
 again:
        rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
        eistat = rxseg->rx_csr;
@@ -378,27 +377,18 @@ again:
        } else
                is->is_stats.rx_datagrams++;
        ace = (struct ether_header *)rxseg->rx_data;
        } else
                is->is_stats.rx_datagrams++;
        ace = (struct ether_header *)rxseg->rx_data;
-#ifdef notdef
        len -= sizeof (struct ether_header);
        len -= sizeof (struct ether_header);
-#else
-       len -= 14;
-#endif
        /*
        /*
-        * Deal with trailer protocol: if type is PUP trailer
+        * Deal with trailer protocol: if type is trailer
         * get true type from first 16-bit word past data.
         * Remember that type was trailer by setting off.
         */
        ace->ether_type = ntohs((u_short)ace->ether_type);
         * get true type from first 16-bit word past data.
         * Remember that type was trailer by setting off.
         */
        ace->ether_type = ntohs((u_short)ace->ether_type);
-#ifdef notdef
 #define        acedataaddr(ace, off, type) \
     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
 #define        acedataaddr(ace, off, type) \
     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
-#else
-#define        acedataaddr(ace, off, type) \
-    ((type)(((caddr_t)(((char *)ace)+14)+(off))))
-#endif
-       if (ace->ether_type >= ETHERPUP_TRAIL &&
-           ace->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
-               off = (ace->ether_type - ETHERPUP_TRAIL) * 512;
+       if (ace->ether_type >= ETHERTYPE_TRAIL &&
+           ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+               off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
                if (off >= ETHERMTU)
                        goto setup;             /* sanity */
                ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
                if (off >= ETHERMTU)
                        goto setup;             /* sanity */
                ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
@@ -414,27 +404,29 @@ again:
        /*
         * Pull packet off interface.  Off is nonzero if packet
         * has trailing header; aceget will then force this header
        /*
         * Pull packet off interface.  Off is nonzero if packet
         * has trailing header; aceget 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.
+        * information to be at the front.
         */
         */
-       m = aceget(unit, rxseg->rx_data, len, off);
+       m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if);
        if (m == 0)
                goto setup;
        if (m == 0)
                goto setup;
-       if (off) {
-               m->m_off += 2 * sizeof (u_short);
-               m->m_len -= 2 * sizeof (u_short);
-       }
        switch (ace->ether_type) {
 
 #ifdef INET
        switch (ace->ether_type) {
 
 #ifdef INET
-       case ETHERPUP_IPTYPE:
+       case ETHERTYPE_IP:
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
                schednetisr(NETISR_IP);
                inq = &ipintrq;
                break;
+#endif
 
 
-       case ETHERPUP_ARPTYPE:
+       case ETHERTYPE_ARP:
                arpinput(&is->is_ac, m);
                goto setup;
                arpinput(&is->is_ac, m);
                goto setup;
+#ifdef NS
+       case ETHERTYPE_NS:
+               schednetisr(NETISR_NS);
+               inq = &nsintrq;
+               break;
+
 #endif
        default:
                m_freem(m);
 #endif
        default:
                m_freem(m);
@@ -454,178 +446,63 @@ setup:
 }
 
 /*
 }
 
 /*
- * Ethernet output routine.
- * 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.
+ * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
+ * If packet size is less than the minimum legal size,
+ * the buffer is expanded.  We probably should zero out the extra
+ * bytes for security, but that would slow things down.
  */
  */
-aceoutput(ifp, m0, dst)
-       struct ifnet *ifp;
-       struct mbuf *m0;
-       struct sockaddr *dst;
+aceput(txbuf, m)
+       char *txbuf;
+       struct mbuf *m;
+#ifdef notdef
 {
 {
-       register struct ace_softc *is = &ace_softc[ifp->if_unit];
-       register struct mbuf *m = m0;
-       register struct ether_header *ace;
-       register int off;
-       struct mbuf *mcopy = (struct mbuf *)0;
-       int type, s, error;
-       struct ether_addr edst;
-       struct in_addr idst;
-
-       switch (dst->sa_family) {
+       register u_char *bp, *mcp;
+       register short *s1, *s2;
+       register u_int len;
+       register struct mbuf *mp;
+       int total;
 
 
-#ifdef INET
-       case AF_INET:
-               idst = ((struct sockaddr_in *)dst)->sin_addr;
-               if (!arpresolve(&is->is_ac, m, &idst, &edst))
-                       return (0);     /* if not yet resolved */
-               if (in_lnaof(idst) == INADDR_ANY)
-                       mcopy = m_copy(m, 0, (int)M_COPYALL);
-               off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
-               /* need per host negotiation */
-               if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && 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 *) = htons((u_short)ETHERPUP_IPTYPE);
-                       *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
-                       goto gottrailertype;
+       total = mp->m_pkthdr.len;
+       bp = (u_char *)txbuf;
+       for (mp = m; mp; mp = mp->m_next) {
+               len = mp->m_len;
+               if (len == 0)
+                       continue;
+               mcp = mtod(mp, u_char *);
+               if (((int)mcp & 01) && ((int)bp & 01)) {
+                       /* source & destination at odd addresses */
+                       movob(bp++, *mcp++);
+                       --len;
                }
                }
-               type = ETHERPUP_IPTYPE;
-               off = 0;
-               goto gottype;
-#endif
-
-       case AF_UNSPEC:
-               ace = (struct ether_header *)dst->sa_data;
-#ifdef notdef
-               edst = ace->ether_dhost;
-#else
-               bcopy((caddr_t)ace->ether_dhost, (caddr_t)&edst, 6);
-#endif
-               type = ace->ether_type;
-               goto gottype;
-
-       default:
-               printf("ace%d: can't handle af%d\n",
-                   ifp->if_unit, dst->sa_family);
-               error = EAFNOSUPPORT;
-               goto bad;
-       }
+               if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
+                       int l = len & 1;
 
 
-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 ||
-#ifdef notdef
-           MMINOFF + sizeof (struct ether_header) > m->m_off) { 
-#else
-           MMINOFF + 14 > m->m_off) { 
-#endif
-               m = m_get(M_DONTWAIT, MT_HEADER);
-               if (m == 0) {
-                       error = ENOBUFS;
-                       goto bad;
+                       s1 = (short *)bp;
+                       s2 = (short *)mcp;
+                       len >>= 1;              /* count # of shorts */
+                       while (len-- != 0)
+                               movow(s1++, *s2++);
+                       len = l;                /* # remaining bytes */
+                       bp = (u_char *)s1;
+                       mcp = (u_char *)s2;
                }
                }
-               m->m_next = m0;
-               m->m_off = MMINOFF;
-#ifdef notdef
-               m->m_len = sizeof (struct ether_header);
-#else
-               m->m_len = 14;
-#endif
-       } else {
-#ifdef notdef
-               m->m_off -= sizeof (struct ether_header);
-               m->m_len += sizeof (struct ether_header);
-#else
-               m->m_off -= 14;
-               m->m_len += 14;
-#endif
+               while (len-- != 0)
+                       movob(bp++, *mcp++);
        }
        }
-       ace = mtod(m, struct ether_header *);
-#ifdef notdef
-       ace->ether_dhost = edst;
-       ace->ether_shost = is->is_addr;
-#else
-       bcopy((caddr_t)&edst, (caddr_t)ace->ether_dhost, 6);
-       bcopy((caddr_t)&is->is_addr, (caddr_t)ace->ether_shost, 6);
-#endif
-       ace->ether_type = htons((u_short)type);
-
-       /*
-        * Queue message on interface, and start output if interface
-        * not yet active.
-        */
-       s = splimp();
-       if (IF_QFULL(&ifp->if_snd)) {
-               IF_DROP(&ifp->if_snd);
-               error = ENOBUFS;
-               goto qfull;
-       }
-       IF_ENQUEUE(&ifp->if_snd, m);
-       splx(s);
-       aceStart(ifp->if_unit);
-       return (mcopy ? looutput(&loif, mcopy, dst) : 0);
-qfull:
-       m0 = m;
-       splx(s);
-bad:
-       m_freem(m0);
-       if (mcopy)
-               m_freem(mcopy);
-       return (error);
-}
-
-aceStart(unit)
-       int unit;
-{
-       register struct ace_softc *is = &ace_softc[unit];
-
-       if (is->is_flags & ACEF_OACTIVE)
-               return;
-       is->is_flags |= ACEF_OACTIVE;
-       acestart((dev_t)unit);
-       is->is_flags &= ~ACEF_OACTIVE;
+       m_freem(m);
+       return (total);
 }
 }
-
-/*
- * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
- * If packet size is less than the minimum legal size,
- * the buffer is expanded.  We probably should zero out the extra
- * bytes for security, but that would slow things down.
- */
-aceput(unit, txbuf, m)
-       int unit;                       /* for statistics collection */
-       u_char *txbuf;
-       struct mbuf *m;
+#else
 {
 {
-       register u_char *bp, *mcp;      /* known to be r12, r11 */
-       register short *s1, *s2;        /* known to be r10, r9 */
-       register unsigned len;
+       register u_char *bp, *mcp;
+       register short *s1, *s2;
+       register u_int len;
        register struct mbuf *mp;
        register struct mbuf *mp;
-       int total, idx;
+       int total;
 
        total = 0;
 
        total = 0;
-       bp = txbuf;
-       for (mp = m;(mp); mp = mp->m_next) {
+       bp = (u_char *)txbuf;
+       for (mp = m; (mp); mp = mp->m_next) {
                len = mp->m_len;
                if (len == 0)
                        continue;
                len = mp->m_len;
                if (len == 0)
                        continue;
@@ -633,42 +510,28 @@ aceput(unit, txbuf, m)
                mcp = mtod(mp, u_char *);
                if (((int)mcp & 01) && ((int)bp & 01)) {
                        /* source & destination at odd addresses */
                mcp = mtod(mp, u_char *);
                if (((int)mcp & 01) && ((int)bp & 01)) {
                        /* source & destination at odd addresses */
-                       /* *bp++ = *mcp++; */
-                       asm("movob (r11),(r12)");
-                       bp++, mcp++;
+                       movob(bp++, *mcp++);
                        --len;
                }
                if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
                        --len;
                }
                if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
-                       register int l;
+                       register u_int l;
 
                        s1 = (short *)bp;
                        s2 = (short *)mcp;
                        l = len >> 1;           /* count # of shorts */
 
                        s1 = (short *)bp;
                        s2 = (short *)mcp;
                        l = len >> 1;           /* count # of shorts */
-                       while (l-- > 0) {
-                               /* *s1++ = *s2++; */
-                               asm("movow (r9),(r10)");
-                               s1++, s2++;
-                       }
+                       while (l-- != 0)
+                               movow(s1++, *s2++);
                        len &= 1;               /* # remaining bytes */
                        bp = (u_char *)s1;
                        mcp = (u_char *)s2;
                }
                        len &= 1;               /* # remaining bytes */
                        bp = (u_char *)s1;
                        mcp = (u_char *)s2;
                }
-               while (len-- > 0) {
-                       /* *bp++ = *mcp++;  */
-                       asm("movob (r11),(r12)");
-                       bp++, mcp++;
-               }
+               while (len-- != 0)
+                       movob(bp++, *mcp++);
        }
        m_freem(m);
        return (total);
 }
        }
        m_freem(m);
        return (total);
 }
-
-movew(data, to)
-       short data, *to;
-{
-
-       asm("movow 6(fp),*8(fp)");
-}
+#endif
 
 /*
  * Routine to copy from VERSAbus memory into mbufs.
 
 /*
  * Routine to copy from VERSAbus memory into mbufs.
@@ -677,51 +540,60 @@ movew(data, to)
  * mbufs have even lengths.
  */
 struct mbuf *
  * mbufs have even lengths.
  */
 struct mbuf *
-aceget(unit, rxbuf, totlen, off0)
-       int unit;                       /* for statistics collection */
+aceget(rxbuf, totlen, off, ifp)
        u_char *rxbuf;
        u_char *rxbuf;
-       int totlen, off0;
+       int totlen, off;
+       struct ifnet *ifp;
 {
 {
-       register u_char *cp, *mcp;      /* known to be r12, r11 */
-       register int tlen;
+       register u_char *cp, *mcp;
        register struct mbuf *m;
        register struct mbuf *m;
+       register int tlen;
        struct mbuf *top = 0, **mp = &top;
        struct mbuf *top = 0, **mp = &top;
-       int len, off = off0;
+       int len;
+       u_char *packet_end;
 
 
-#ifdef notdef
-       cp = rxbuf + sizeof (struct ether_header);
-#else
-       cp = rxbuf + 14;
-#endif
-       while (totlen > 0) {
-               register int words;
+       rxbuf += sizeof (struct ether_header);
+       cp = rxbuf;
+       packet_end = cp + totlen;
+       if (off) {
+               off += 2 * sizeof(u_short);
+               totlen -= 2 *sizeof(u_short);
+               cp = rxbuf + off;
+       }
 
 
-               MGET(m, M_DONTWAIT, MT_DATA);
-               if (m == 0)
-                       goto bad;
-               if (off) {
-                       len = totlen - off;
-#ifdef notdef
-                       cp = rxbuf + sizeof (struct ether_header) + off;
-#else
-                       cp = rxbuf + 14 + off;
-#endif
-               } 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;
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == 0)
+               return (0);
+       m->m_pkthdr.rcvif = ifp;
+       m->m_pkthdr.len = totlen;
+       m->m_len = MHLEN;
+
+       while (totlen > 0) {
+               if (top) {
+                       MGET(m, M_DONTWAIT, MT_DATA);
+                       if (m == 0) {
+                               m_freem(top);
+                               return (0);
                        }
                        }
+                       m->m_len = MLEN;
+               }
+               len = min(totlen, (packet_end - cp));
+               if (len >= MINCLSIZE) {
+                       MCLGET(m, M_DONTWAIT);
+                       if (m->m_flags & M_EXT)
+                               m->m_len = len = min(len, MCLBYTES);
+                       else
+                               len = m->m_len;
                } else {
                } else {
-                       m->m_len = len = MIN(MLEN, len);
-                       m->m_off = MMINOFF;
+                       /*
+                        * Place initial small packet/header at end of mbuf.
+                        */
+                       if (len < m->m_len) {
+                               if (top == 0 && len + max_linkhdr <= m->m_len)
+                                       m->m_data += max_linkhdr;
+                               m->m_len = len;
+                       } else
+                               len = m->m_len;
                }
                mcp = mtod(m, u_char *);
                /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
                }
                mcp = mtod(m, u_char *);
                /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
@@ -749,27 +621,19 @@ aceget(unit, rxbuf, totlen, off0)
                        *mcp++ = *cp++;
                *mp = m;
                mp = &m->m_next;
                        *mcp++ = *cp++;
                *mp = m;
                mp = &m->m_next;
-               if (off == 0) {
-                       totlen -= len;
-                       continue;
-               }
-               off += len;
-               if (off == totlen) {
-#ifdef notdef
-                       cp = rxbuf + sizeof (struct ether_header);
-#else
-                       cp = rxbuf + 14;
-#endif
-                       off = 0;
-                       totlen = off0;
-               }
+               totlen -= len;
+               if (cp == packet_end)
+                       cp = rxbuf;
        }
        return (top);
        }
        return (top);
-bad:
-       m_freem(top);
-       return (0);
 }
 
 }
 
+/* backoff table masks */
+short  random_mask_tbl[16] = {
+       0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0,
+       0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0
+};
+
 acebakoff(is, txseg, retries)
        struct ace_softc *is;
        struct tx_segment *txseg;
 acebakoff(is, txseg, retries)
        struct ace_softc *is;
        struct tx_segment *txseg;
@@ -783,7 +647,7 @@ acebakoff(is, txseg, retries)
        while (--retries >= 0) {
                random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
                random_num &= *pMask++;
        while (--retries >= 0) {
                random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
                random_num &= *pMask++;
-               *pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC);
+               *pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc);
        }
 }
 
        }
 }
 
@@ -795,37 +659,59 @@ aceioctl(ifp, cmd, data)
        int cmd;
        caddr_t data;
 {
        int cmd;
        caddr_t data;
 {
-       register struct ifreq *ifr = (struct ifreq *)data;
-       int s, error = 0;
+       register struct ifaddr *ifa = (struct ifaddr *)data;
+       struct acedevice *addr;
+       int s = splimp(), error = 0;
 
 
-       s = splimp();
        switch (cmd) {
 
        case SIOCSIFADDR:
        switch (cmd) {
 
        case SIOCSIFADDR:
-               if (ifp->if_flags & IFF_RUNNING)
-                       if_rtinit(ifp, -1);     /* delete previous route */
-               acesetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
-               aceinit(ifp->if_unit);
+               ifp->if_flags |= IFF_UP;
+               switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       aceinit(ifp->if_unit);  /* before arpwhohas */
+                       ((struct arpcom *)ifp)->ac_ipaddr =
+                               IA_SIN(ifa)->sin_addr;
+                       arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+                       break;
+#endif
+#ifdef NS
+               case AF_NS: {
+                       struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+                       struct ace_softc *is = &ace_softc[ifp->if_unit];
+
+                       if (!ns_nullhost(*ina)) {
+                               ifp->if_flags &= ~IFF_RUNNING;
+                               addr = (struct acedevice *)
+                                   aceinfo[ifp->if_unit]->ui_addr;
+                               movow(&addr->csr, CSR_RESET);
+                               DELAY(10000);
+                               /* set station address & copy addr to arp */
+                               acesetaddr(ifp->if_unit, addr, 
+                                   ina->x_host.c_host);
+                       } else
+                               ina->x_host = *(union ns_host *)is->is_addr;
+                       aceinit(ifp->if_unit);
+                       break;
+               }
+#endif
+               default:
+                       aceinit(ifp->if_unit);
+                       break;
+               }
                break;
 
                break;
 
-#ifdef notdef
-       case SIOCSETETADDR: {           /* set Ethernet station address */
-               struct vba_device *ui;
-               struct acedevice *addr;
-               struct sockaddr_in *sin;
-
-               ifp->if_flags &= ~IFF_RUNNING | IFF_UP;
-               sin = (struct sockaddr_in *)&ifr->ifr_addr;
-               ui = aceinfo[ifp->if_unit];
-               addr = (struct acedevice *)ui->ui_addr;
-               movew((short)CSR_RESET, &addr->csr);
-               DELAY(10000);
-               /* set station address and copy addr to arp struct */
-               acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]);
-               aceinit(ifp->if_unit);          /* Re-initialize */
+       case SIOCSIFFLAGS:
+               if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
+                       addr = (struct acedevice *)
+                           (aceinfo[ifp->if_unit]->ui_addr);
+                       movow(&addr->csr, CSR_RESET);
+                       ifp->if_flags &= ~IFF_RUNNING;
+               } else if (ifp->if_flags&IFF_UP &&
+                   (ifp->if_flags&IFF_RUNNING) == 0)
+                       aceinit(ifp->if_unit);
                break;
                break;
-       }
-#endif
 
        default:
                error = EINVAL;
 
        default:
                error = EINVAL;
@@ -834,37 +720,43 @@ aceioctl(ifp, cmd, data)
        return (error);
 }
 
        return (error);
 }
 
-acesetaddr(ifp, sin)
-       register struct ifnet *ifp;
-       register struct sockaddr_in *sin;
+/*
+ * Set the on-board station address, then read it back
+ * to initialize the address used by ARP (among others).
+ */
+acesetaddr(unit, addr, station)
+       short unit;
+       struct acedevice *addr;
+       u_char *station;
 {
 {
+       struct ace_softc *is = &ace_softc[unit];
+       register short *wp, i;
 
 
-       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;
+       for (wp = (short *)addr->station, i = 0; i < 6; i++)
+               movow(wp++, ~*station++); 
+       for (wp = (short *)addr->station, i = 0; i < 6; i++)
+               is->is_addr[i] = ~*wp++;
+       printf("ace%d: hardware address %s\n", unit,
+           ether_sprintf(is->is_addr));
 }
 
 }
 
-aceclean(unit)
+/*
+ * Setup the device for use.  Initialize dual-ported memory,
+ * backoff parameters, and various other software state.
+ */
+acesetup(unit)
        int unit;
 {
        register struct ace_softc *is = &ace_softc[unit];
        int unit;
 {
        register struct ace_softc *is = &ace_softc[unit];
-       register struct ifnet *ifp = &is->is_if;
-       register struct vba_device *ui = aceinfo[unit];
-       register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
-       register short i, data;
        register char *pData1;
        register char *pData1;
+       register short i;
+       struct acedevice *addr;
 
 
-       ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE);
-       is->is_dpm = acemap[unit];              /* init dpm */
-       bzero((char *)is->is_dpm, 16384*2);
-
+       bzero(is->is_dpm, 16384*2);
        is->is_currnd = 49123;
        is->is_currnd = 49123;
+       addr = (struct acedevice *)aceinfo[unit]->ui_addr;
        is->is_segboundry = (addr->segb >> 11) & 0xf;
        is->is_segboundry = (addr->segb >> 11) & 0xf;
-       pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11));
+       pData1 = is->is_dpm + (is->is_segboundry << 11);
        for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
                acebakoff(is, (struct tx_segment *)pData1, 15);
                pData1 += sizeof (struct tx_segment);
        for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
                acebakoff(is, (struct tx_segment *)pData1, 15);
                pData1 += sizeof (struct tx_segment);