merge 4.1b with 4.1c
[unix-history] / usr / src / sys / vax / if / if_il.c
index a4a64b4..60fc050 100644 (file)
@@ -1,13 +1,10 @@
-/*     if_il.c 4.3     82/05/25        */
+/*     if_il.c 4.14    82/11/13        */
 
 #include "il.h"
 
 #include "il.h"
-#include "imp.h"
-#include "loop.h"
 
 /*
  * Interlan Ethernet Communications Controller interface
  */
 
 /*
  * Interlan Ethernet Communications Controller interface
  */
-
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.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/buf.h"
 #include "../h/protosw.h"
 #include "../h/socket.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/ilreg.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
 #include "../h/vmmac.h"
 #include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
+#include <errno.h>
+
 #include "../net/if.h"
 #include "../net/if.h"
-#include "../net/if_il.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/pup.h"
+#include "../net/netisr.h"
 #include "../net/route.h"
 #include "../net/route.h"
-#include <errno.h>
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_ilreg.h"
+#include "../vaxif/if_il.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
 
 #define        ILMTU   1500
 
 #define        ILMTU   1500
+#define        ILMIN   (60-14)
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
 u_short ilstd[] = { 0 };
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
 
 int    ilprobe(), ilattach(), ilrint(), ilcint();
 struct uba_device *ilinfo[NIL];
 u_short ilstd[] = { 0 };
 struct uba_driver ildriver =
        { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
-u_char il_ectop[3] = { 0x02, 0x60, 0x8c };
 #define        ILUNIT(x)       minor(x)
 #define        ILUNIT(x)       minor(x)
+int    ilinit(),iloutput(),ilreset(),ilwatch();
 
 
-int    ilinit(),iloutput(),ilreset();
+u_char il_ectop[3] = { 0x02, 0x60, 0x8c };
+u_char ilbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 /*
  * Ethernet software status per interface.
 
 /*
  * Ethernet software status per interface.
@@ -59,15 +61,18 @@ int ilinit(),iloutput(),ilreset();
 struct il_softc {
        struct  ifnet is_if;            /* network-visible interface */
        struct  ifuba is_ifuba;         /* UNIBUS resources */
 struct il_softc {
        struct  ifnet is_if;            /* network-visible interface */
        struct  ifuba is_ifuba;         /* UNIBUS resources */
-       short   is_oactive;             /* is output active? */
-       short   is_startrcv;            /* hang receive next chance */
-       u_char  is_enaddr[6];           /* board's ethernet address */
+       int     is_flags;
+#define        ILF_OACTIVE     0x1             /* output is active */
+#define        ILF_RCVPENDING  0x2             /* start rcv in ilcint */
+#define        ILF_STATPENDING 0x4             /* stat cmd pending */
+       short   is_lastcmd;             /* can't read csr, so must save it */
+       short   is_scaninterval;        /* interval of stat collection */
+#define        ILWATCHINTERVAL 60              /* once every 60 seconds */
+       struct  il_stats is_stats;      /* holds on-board statistics */
+       struct  il_stats is_sum;        /* summation over time */
+       int     is_ubaddr;              /* mapping registers of is_stats */
 } il_softc[NIL];
 
 } il_softc[NIL];
 
-/*
- * Do an OFFLINE command.  This will cause an interrupt for the
- * autoconfigure stuff.
- */
 ilprobe(reg)
        caddr_t reg;
 {
 ilprobe(reg)
        caddr_t reg;
 {
@@ -75,21 +80,19 @@ ilprobe(reg)
        register struct ildevice *addr = (struct ildevice *)reg;
        register i;
 
        register struct ildevice *addr = (struct ildevice *)reg;
        register i;
 
-COUNT(ILPROBE);
 #ifdef lint
        br = 0; cvec = br; br = cvec;
 #ifdef lint
        br = 0; cvec = br; br = cvec;
-       ilrint(0); ilcint(0);
+       i = 0; ilrint(i); ilcint(i); ilwatch(i);
 #endif
 
        addr->il_csr = ILC_OFFLINE|IL_CIE;
        DELAY(100000);
 #endif
 
        addr->il_csr = ILC_OFFLINE|IL_CIE;
        DELAY(100000);
-       i = addr->il_csr;               /* Clear CDONE */
+       i = addr->il_csr;               /* clear CDONE */
        if (cvec > 0 && cvec != 0x200)
                cvec -= 4;
        return (1);
 }
 
        if (cvec > 0 && cvec != 0x200)
                cvec -= 4;
        return (1);
 }
 
-struct il_stat ilbuf;
 /*
  * Interface exists: make available by filling in network interface
  * record.  System will initialize the interface when it is ready
 /*
  * Interface exists: make available by filling in network interface
  * record.  System will initialize the interface when it is ready
@@ -100,77 +103,67 @@ ilattach(ui)
        struct uba_device *ui;
 {
        register struct il_softc *is = &il_softc[ui->ui_unit];
        struct uba_device *ui;
 {
        register struct il_softc *is = &il_softc[ui->ui_unit];
-       register struct sockaddr_in *sin;
+       register struct ifnet *ifp = &is->is_if;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
-       register int i;
-       int s;
-       int ubaddr;
-COUNT(ILATTACH);
+       struct sockaddr_in *sin;
 
 
-       is->is_if.if_unit = ui->ui_unit;
-       is->is_if.if_name = "il";
-       is->is_if.if_mtu = ILMTU;
-       is->is_if.if_net = ui->ui_flags & 0xff;
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "il";
+       ifp->if_mtu = ILMTU;
+       ifp->if_net = ui->ui_flags;
 
        /*
 
        /*
-        * Reset the board
+        * Reset the board and map the statistics
+        * buffer onto the Unibus.
         */
         */
-       s = splimp();
-       addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_RESET;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       if (addr->il_csr & IL_STATUS)
-               printf("il%d: %s\n", ui->ui_unit,
-                   ildiag[addr->il_csr & IL_STATUS]);
-       splx(s);
+       addr->il_csr = ILC_RESET;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
        
        
-       /*
-        * Map the status buffer to the Unibus, do the status command,
-        * and unmap the buffer.
-        */ 
-       ubaddr = uballoc(ui->ui_ubanum, &ilbuf, sizeof(ilbuf), 0);
-       s = splimp();
-       addr->il_bar = ubaddr & 0xffff;
-       addr->il_bcr = sizeof(ilbuf);
-       addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_STAT;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       if (addr->il_csr & IL_STATUS)
-               printf("il%d: %s\n", ui->ui_unit,
-                   ilerrs[addr->il_csr & IL_STATUS]);
-       splx(s);
-       ubarelse(ui->ui_ubanum, &ubaddr);
-       /*
-        * Fill in the Ethernet address from the status buffer
-        */
-       for (i=0; i<6; i++)
-               is->is_enaddr[i] = ilbuf.ils_addr[i];
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+               sizeof (struct il_stats), 0);
+       addr->il_bar = is->is_ubaddr & 0xffff;
+       addr->il_bcr = sizeof (struct il_stats);
+       addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
+       while ((addr->il_csr&IL_CDONE) == 0)
+               ;
+       if (addr->il_csr&IL_STATUS)
+               printf("il%d: status failed, csr=%b\n", ui->ui_unit,
+                       addr->il_csr, IL_BITS);
+       ubarelse(ui->ui_ubanum, &is->is_ubaddr);
        printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
                ui->ui_unit,
        printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
                ui->ui_unit,
-               is->is_enaddr[0]&0xff, is->is_enaddr[1]&0xff,
-               is->is_enaddr[2]&0xff, is->is_enaddr[3]&0xff,
-               is->is_enaddr[4]&0xff, is->is_enaddr[5]&0xff,
-               ilbuf.ils_module, ilbuf.ils_firmware);
-       is->is_if.if_host[0] = ((is->is_enaddr[3]&0xff)<<16) | 0x800000 |
-           ((is->is_enaddr[4]&0xff)<<8) | (is->is_enaddr[5]&0xff);
-       sin = (struct sockaddr_in *)&is->is_if.if_addr;
+               is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
+               is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
+               is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
+               is->is_stats.ils_module, is->is_stats.ils_firmware);
+       ifp->if_host[0] =
+           ((is->is_stats.ils_addr[3]&0xff)<<16) | 0x800000 |
+           ((is->is_stats.ils_addr[4]&0xff)<<8) |
+           (is->is_stats.ils_addr[5]&0xff);
+       sin = (struct sockaddr_in *)&ifp->if_addr;
        sin->sin_family = AF_INET;
        sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(is->is_if.if_net, is->is_if.if_host[0]);
+       sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
 
 
-       sin = (struct sockaddr_in *)&is->is_if.if_broadaddr;
+       sin = (struct sockaddr_in *)&ifp->if_broadaddr;
        sin->sin_family = AF_INET;
        sin->sin_family = AF_INET;
-       sin->sin_addr = if_makeaddr(is->is_if.if_net, 0);
-       is->is_if.if_flags = IFF_BROADCAST;
-
-       is->is_if.if_init = ilinit;
-       is->is_if.if_output = iloutput;
-       is->is_if.if_ubareset = ilreset;
+       sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+       ifp->if_flags = IFF_BROADCAST;
+
+       ifp->if_init = ilinit;
+       ifp->if_output = iloutput;
+       ifp->if_reset = ilreset;
+       ifp->if_watchdog = ilwatch;
+       is->is_scaninterval = ILWATCHINTERVAL;
+       ifp->if_timer = is->is_scaninterval;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
        is->is_ifuba.ifu_flags = UBA_CANTWAIT;
-       if_attach(&is->is_if);
-#if NIMP == 0
-       if (ui->ui_flags &~ 0xff)
-               illhinit(&is->is_if, (ui->ui_flags &~ 0xff) | 0x0a);
+#ifdef notdef
+       is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
 #endif
 #endif
+       if_attach(ifp);
 }
 
 /*
 }
 
 /*
@@ -181,7 +174,6 @@ ilreset(unit, uban)
        int unit, uban;
 {
        register struct uba_device *ui;
        int unit, uban;
 {
        register struct uba_device *ui;
-COUNT(ILRESET);
 
        if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
 
        if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
            ui->ui_ubanum != uban)
@@ -200,7 +192,6 @@ ilinit(unit)
        register struct il_softc *is = &il_softc[unit];
        register struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr;
        register struct il_softc *is = &il_softc[unit];
        register struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr;
-       register i;
        int s;
 
        if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
        int s;
 
        if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
@@ -209,8 +200,21 @@ ilinit(unit)
                is->is_if.if_flags &= ~IFF_UP;
                return;
        }
                is->is_if.if_flags &= ~IFF_UP;
                return;
        }
+       is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+               sizeof (struct il_stats), 0);
        addr = (struct ildevice *)ui->ui_addr;
 
        addr = (struct ildevice *)ui->ui_addr;
 
+       /*
+        * Turn off source address insertion (it's faster this way),
+        * and set board online.
+        */
+       s = splimp();
+       addr->il_csr = ILC_CISA;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       addr->il_csr = ILC_ONLINE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
        /*
         * Set board online.
         * Hang receive buffer and start any pending
        /*
         * Set board online.
         * Hang receive buffer and start any pending
@@ -220,20 +224,20 @@ ilinit(unit)
         */
        s = splimp();
        addr->il_csr = ILC_ONLINE;
         */
        s = splimp();
        addr->il_csr = ILC_ONLINE;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
        addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
        addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
        addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
        addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-       addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                       ILC_RCV|IL_RIE;
-       while (!(addr->il_csr & IL_CDONE))
-               /* Busy wait */;
-       is->is_startrcv = 0;
-       is->is_oactive = 1;
+       addr->il_csr =
+               ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
+       is->is_flags = ILF_OACTIVE;
        is->is_if.if_flags |= IFF_UP;
        is->is_if.if_flags |= IFF_UP;
+       is->is_lastcmd = 0;
        ilcint(unit);
        splx(s);
        ilcint(unit);
        splx(s);
-       if_rtinit(&is->is_if, RTF_DIRECT|RTF_UP);
+       if_rtinit(&is->is_if, RTF_UP);
 }
 
 /*
 }
 
 /*
@@ -244,81 +248,97 @@ ilinit(unit)
 ilstart(dev)
        dev_t dev;
 {
 ilstart(dev)
        dev_t dev;
 {
-        int unit = ILUNIT(dev);
+        int unit = ILUNIT(dev), len;
        struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct ildevice *addr;
        struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct ildevice *addr;
-       register len;
        struct mbuf *m;
        struct mbuf *m;
-       int dest;
-COUNT(ILSTART);
+       short csr;
 
 
-       /*
-        * Dequeue another request and copy it into the buffer.
-        * If no more requests, just return.
-        */
        IF_DEQUEUE(&is->is_if.if_snd, m);
        IF_DEQUEUE(&is->is_if.if_snd, m);
-       if (m == 0)
-               return;
+       addr = (struct ildevice *)ui->ui_addr;
+       if (m == 0) {
+               if ((is->is_flags & ILF_STATPENDING) == 0)
+                       return;
+               addr->il_bar = is->is_ubaddr & 0xffff;
+               addr->il_bcr = sizeof (struct il_stats);
+               csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
+               is->is_flags &= ~ILF_STATPENDING;
+               goto startcmd;
+       }
        len = if_wubaput(&is->is_ifuba, m);
        len = if_wubaput(&is->is_ifuba, m);
-
        /*
        /*
-        * Flush BDP, then start the output.
+        * Ensure minimum packet length.
+        * This makes the safe assumtion that there are no virtual holes
+        * after the data.
+        * For security, it might be wise to zero out the added bytes,
+        * but we're mainly interested in speed at the moment.
         */
         */
+       if (len - sizeof(struct il_xheader) < ILMIN)
+               len = ILMIN + sizeof(struct il_xheader);
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
-       addr = (struct ildevice *)ui->ui_addr;
        addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
        addr->il_bcr = len;
        addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
        addr->il_bcr = len;
-       addr->il_csr = ((is->is_ifuba.ifu_w.ifrw_info>>2)&0xc000)|
-                       ILC_XMIT|IL_CIE|IL_RIE;
-       is->is_oactive = 1;
+       csr =
+         ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
+
+startcmd:
+       is->is_lastcmd = csr & IL_CMD;
+       addr->il_csr = csr;
+       is->is_flags |= ILF_OACTIVE;
 }
 
 /*
  * Command done interrupt.
 }
 
 /*
  * Command done interrupt.
- * This should only happen after a transmit command,
- * so it is equivalent to a transmit interrupt.
- * Start another output if more data to send.
  */
 ilcint(unit)
        int unit;
 {
  */
 ilcint(unit)
        int unit;
 {
-       register struct uba_device *ui = ilinfo[unit];
        register struct il_softc *is = &il_softc[unit];
        register struct il_softc *is = &il_softc[unit];
+       struct uba_device *ui = ilinfo[unit];
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
        register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
-       register int err;
-COUNT(ILCINT);
+       short csr;
 
 
-       if (is->is_oactive == 0) {
-               printf("il%d: strange xmit interrupt!\n", unit);
+       if ((is->is_flags & ILF_OACTIVE) == 0) {
+               printf("il%d: stray xmit interrupt, csr=%b\n", unit,
+                       addr->il_csr, IL_BITS);
                return;
        }
                return;
        }
-       is->is_if.if_opackets++;
-       is->is_oactive = 0;
-       if (err = (addr->il_csr & IL_STATUS)){
-               is->is_if.if_oerrors++;
-               printf("il%d: output error %d\n", unit, err);
-       }
+
+       csr = addr->il_csr;
        /*
        /*
-        * Hang receive buffer if it couldn't be done earlier (in ilrint).
+        * Hang receive buffer if it couldn't
+        * be done earlier (in ilrint).
         */
         */
-       if (is->is_startrcv) {
+       if (is->is_flags & ILF_RCVPENDING) {
                addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
                addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
                addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
                addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-               addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                               ILC_RCV|IL_RIE;
-               while (!(addr->il_csr & IL_CDONE))
-                       /* Busy wait */;
-               is->is_startrcv = 0;
+               addr->il_csr =
+                 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+               while ((addr->il_csr & IL_CDONE) == 0)
+                       ;
+               is->is_flags &= ~ILF_RCVPENDING;
+       }
+       is->is_flags &= ~ILF_OACTIVE;
+       csr &= IL_STATUS;
+       switch (is->is_lastcmd) {
+
+       case ILC_XMIT:
+               is->is_if.if_opackets++;
+               if (csr > ILERR_RETRIES)
+                       is->is_if.if_oerrors++;
+               break;
+
+       case ILC_STAT:
+               if (csr == ILERR_SUCCESS)
+                       iltotal(is);
+               break;
        }
        if (is->is_ifuba.ifu_xtofree) {
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
        }
        if (is->is_ifuba.ifu_xtofree) {
                m_freem(is->is_ifuba.ifu_xtofree);
                is->is_ifuba.ifu_xtofree = 0;
        }
-       if (is->is_if.if_snd.ifq_head == 0) {
-               return;
-       }
        ilstart(unit);
 }
 
        ilstart(unit);
 }
 
@@ -341,20 +361,17 @@ ilrint(unit)
        int len, off, resid;
        register struct ifqueue *inq;
 
        int len, off, resid;
        register struct ifqueue *inq;
 
-COUNT(ILRINT);
        is->is_if.if_ipackets++;
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
        il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
        len = il->ilr_length - sizeof(struct il_rheader);
        is->is_if.if_ipackets++;
        if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
                UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
        il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
        len = il->ilr_length - sizeof(struct il_rheader);
-       if (il->ilr_status&0x3 || len < 46 || len > ILMTU) {
+       if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || len > ILMTU) {
                is->is_if.if_ierrors++;
 #ifdef notdef
                if (is->is_if.if_ierrors % 100 == 0)
                        printf("il%d: += 100 input errors\n", unit);
 #endif
                is->is_if.if_ierrors++;
 #ifdef notdef
                if (is->is_if.if_ierrors % 100 == 0)
                        printf("il%d: += 100 input errors\n", unit);
 #endif
-               printf("il%d: input error (status=%x, len=%d)\n", unit,
-                   il->ilr_status, len);
                goto setup;
        }
 
                goto setup;
        }
 
@@ -408,8 +425,9 @@ COUNT(ILRINT);
        if (IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
        if (IF_QFULL(inq)) {
                IF_DROP(inq);
                m_freem(m);
-       } else
-               IF_ENQUEUE(inq, m);
+               goto setup;
+       }
+       IF_ENQUEUE(inq, m);
 
 setup:
        /*
 
 setup:
        /*
@@ -417,15 +435,16 @@ setup:
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
         * If waiting for transmit command completion, set flag
         * and wait until command completes.
         */
-       if (!is->is_oactive) {
-               addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
-               addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
-               addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|
-                               ILC_RCV|IL_RIE;
-               while (!(addr->il_csr & IL_CDONE))
-                       /* Busy wait */;
-       } else
-               is->is_startrcv = 1;
+       if (is->is_flags & ILF_OACTIVE) {
+               is->is_flags |= ILF_RCVPENDING;
+               return;
+       }
+       addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
+       addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
+       addr->il_csr =
+               ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
+       while ((addr->il_csr & IL_CDONE) == 0)
+               ;
 }
 
 /*
 }
 
 /*
@@ -444,9 +463,7 @@ iloutput(ifp, m0, dst)
        register struct mbuf *m = m0;
        register struct il_xheader *il;
        register int off;
        register struct mbuf *m = m0;
        register struct il_xheader *il;
        register int off;
-       register int i;
 
 
-COUNT(ILOUTPUT);
        switch (dst->sa_family) {
 
 #ifdef INET
        switch (dst->sa_family) {
 
 #ifdef INET
@@ -507,22 +524,16 @@ gottype:
        }
        il = mtod(m, struct il_xheader *);
        if ((dest &~ 0xff) == 0)
        }
        il = mtod(m, struct il_xheader *);
        if ((dest &~ 0xff) == 0)
-               for (i=0; i<6; i++)
-                       il->ilx_dhost[i] = 0xff;
+               bcopy((caddr_t)ilbroadcastaddr, (caddr_t)il->ilx_dhost, 6);
        else {
        else {
-               if (dest & 0x8000) {
-                       il->ilx_dhost[0] = is->is_enaddr[0];
-                       il->ilx_dhost[1] = is->is_enaddr[1];
-                       il->ilx_dhost[2] = is->is_enaddr[2];
-               } else {
-                       il->ilx_dhost[0] = il_ectop[0];
-                       il->ilx_dhost[1] = il_ectop[1];
-                       il->ilx_dhost[2] = il_ectop[2];
-               }
+               u_char *to = dest & 0x8000 ? is->is_stats.ils_addr : il_ectop;
+
+               bcopy((caddr_t)to, (caddr_t)il->ilx_dhost, 3);
                il->ilx_dhost[3] = (dest>>8) & 0x7f;
                il->ilx_dhost[4] = (dest>>16) & 0xff;
                il->ilx_dhost[5] = (dest>>24) & 0xff;
        }
                il->ilx_dhost[3] = (dest>>8) & 0x7f;
                il->ilx_dhost[4] = (dest>>16) & 0xff;
                il->ilx_dhost[5] = (dest>>24) & 0xff;
        }
+       bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)il->ilx_shost, 6);
        il->ilx_type = type;
 
        /*
        il->ilx_type = type;
 
        /*
@@ -532,58 +543,55 @@ gottype:
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
        s = splimp();
        if (IF_QFULL(&ifp->if_snd)) {
                IF_DROP(&ifp->if_snd);
-               error = ENOBUFS;
-               goto qfull;
+               splx(s);
+               m_freem(m);
+               return (ENOBUFS);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
        }
        IF_ENQUEUE(&ifp->if_snd, m);
-       if (is->is_oactive == 0)
+       if ((is->is_flags & ILF_OACTIVE) == 0)
                ilstart(ifp->if_unit);
        splx(s);
        return (0);
                ilstart(ifp->if_unit);
        splx(s);
        return (0);
-qfull:
-       m0 = m;
-       splx(s);
+
 bad:
        m_freem(m0);
 bad:
        m_freem(m0);
-       return(error);
+       return (error);
 }
 
 }
 
-#if NIMP == 0 && NIL > 0
 /*
 /*
- * Logical host interface driver.
- * Allows host to appear as an ARPAnet
- * logical host.  Must also have routing
- * table entry set up to forward packets
- * to appropriate gateway on localnet.
+ * Watchdog routine, request statistics from board.
  */
  */
+ilwatch(unit)
+       int unit;
+{
+       register struct il_softc *is = &il_softc[unit];
+       register struct ifnet *ifp = &is->is_if;
+       int s;
 
 
-struct ifnet illhif;
-int    looutput();
+       if (is->is_flags & ILF_STATPENDING) {
+               ifp->if_timer = is->is_scaninterval;
+               return;
+       }
+       s = splimp();
+       is->is_flags |= ILF_STATPENDING;
+       if ((is->is_flags & ILF_OACTIVE) == 0)
+               ilstart(ifp->if_unit);
+       splx(s);
+       ifp->if_timer = is->is_scaninterval;
+}
 
 /*
 
 /*
- * Called by localnet interface to allow logical
- * host interface to "attach".  Nothing should ever
- * be sent locally to this interface, it's purpose
- * is simply to establish the host's arpanet address.
+ * Total up the on-board statistics.
  */
  */
-illhinit(ilifp, addr)
-       struct ifnet *ilifp;
-       int addr;
+iltotal(is)
+       register struct il_softc *is;
 {
 {
-       register struct ifnet *ifp = &illhif;
-       register struct sockaddr_in *sin;
-
-COUNT(ILLHINIT);
-       ifp->if_name = "lh";
-       ifp->if_mtu = ILMTU;
-       sin = (struct sockaddr_in *)&ifp->if_addr;
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = addr;
-       ifp->if_net = sin->sin_addr.s_net;
-       ifp->if_dstaddr = ilifp->if_addr;
-       ifp->if_flags = IFF_UP|IFF_POINTOPOINT;
-       ifp->if_output = looutput;
-       if_attach(ifp);
-       rtinit(&ifp->if_addr, &ifp->if_addr, RTF_UP|RTF_DIRECT|RTF_HOST);
+       register u_short *interval, *sum, *end;
+
+       interval = &is->is_stats.ils_frames;
+       sum = &is->is_sum.ils_frames;
+       end = is->is_sum.ils_fill2;
+       while (sum < end)
+               *sum++ += *interval++;
+       is->is_if.if_collisions = is->is_sum.ils_collis;
 }
 }
-#endif