BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:40:40 +0000 (16:40 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 29 Jul 1983 00:40:40 +0000 (16:40 -0800)
Work on file usr/src/sys/vaxif/if_accreg.h
Work on file usr/src/sys/vaxif/if_acc.c
Work on file usr/src/sys/vaxif/if_dmc.h
Work on file usr/src/sys/vaxif/if_ecreg.h
Work on file usr/src/sys/vaxif/if_dmc.c
Work on file usr/src/sys/vaxif/if_css.c
Work on file usr/src/sys/vaxif/if_cssreg.h
Work on file usr/src/sys/vaxif/if_ec.c
Work on file usr/src/sys/vaxif/if_hy.c
Work on file usr/src/sys/vaxif/if_en.c
Work on file usr/src/sys/vaxif/if_enreg.h
Work on file usr/src/sys/vaxif/if_hy.h
Work on file usr/src/sys/vaxif/if_en.h
Work on file usr/src/sys/vaxif/if_ether.h
Work on file usr/src/sys/vaxif/if_pclreg.h
Work on file usr/src/sys/vaxif/if_hyreg.h
Work on file usr/src/sys/vaxif/if_pcl.c
Work on file usr/src/sys/vaxif/if_il.h
Work on file usr/src/sys/vaxif/if_ilreg.h
Work on file usr/src/sys/vaxif/if_uba.h
Work on file usr/src/sys/vaxif/if_un.h
Work on file usr/src/sys/vaxif/if_unreg.h
Work on file usr/src/sys/vaxif/if_uba.c
Work on file usr/src/sys/vaxif/if_vv.h
Work on file usr/src/sys/vaxif/if_un.c
Work on file usr/src/sys/vaxif/if_vv.c

Synthesized-from: CSRG/cd1/4.2

26 files changed:
usr/src/sys/vaxif/if_acc.c [new file with mode: 0644]
usr/src/sys/vaxif/if_accreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_css.c [new file with mode: 0644]
usr/src/sys/vaxif/if_cssreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_dmc.c [new file with mode: 0644]
usr/src/sys/vaxif/if_dmc.h [new file with mode: 0644]
usr/src/sys/vaxif/if_ec.c [new file with mode: 0644]
usr/src/sys/vaxif/if_ecreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_en.c [new file with mode: 0644]
usr/src/sys/vaxif/if_en.h [new file with mode: 0644]
usr/src/sys/vaxif/if_enreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_ether.h [new file with mode: 0644]
usr/src/sys/vaxif/if_hy.c [new file with mode: 0644]
usr/src/sys/vaxif/if_hy.h [new file with mode: 0644]
usr/src/sys/vaxif/if_hyreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_il.h [new file with mode: 0644]
usr/src/sys/vaxif/if_ilreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_pcl.c [new file with mode: 0644]
usr/src/sys/vaxif/if_pclreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_uba.c [new file with mode: 0644]
usr/src/sys/vaxif/if_uba.h [new file with mode: 0644]
usr/src/sys/vaxif/if_un.c [new file with mode: 0644]
usr/src/sys/vaxif/if_un.h [new file with mode: 0644]
usr/src/sys/vaxif/if_unreg.h [new file with mode: 0644]
usr/src/sys/vaxif/if_vv.c [new file with mode: 0644]
usr/src/sys/vaxif/if_vv.h [new file with mode: 0644]

diff --git a/usr/src/sys/vaxif/if_acc.c b/usr/src/sys/vaxif/if_acc.c
new file mode 100644 (file)
index 0000000..b800bad
--- /dev/null
@@ -0,0 +1,366 @@
+/*     if_acc.c        6.1     83/07/29        */
+
+#include "acc.h"
+#ifdef NACC > 0
+
+/*
+ * ACC LH/DH ARPAnet IMP interface driver.
+ */
+#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 "../net/if.h"
+#include "../netimp/if_imp.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_accreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+int     accprobe(), accattach(), accrint(), accxint();
+struct  uba_device *accinfo[NACC];
+u_short accstd[] = { 0 };
+struct  uba_driver accdriver =
+       { accprobe, 0, accattach, 0, accstd, "acc", accinfo };
+#define        ACCUNIT(x)      minor(x)
+
+int    accinit(), accstart(), accreset();
+
+/*
+ * "Lower half" of IMP interface driver.
+ *
+ * Each IMP interface is handled by a common module which handles
+ * the IMP-host protocol and a hardware driver which manages the
+ * hardware specific details of talking with the IMP.
+ *
+ * The hardware portion of the IMP driver handles DMA and related
+ * management of UNIBUS resources.  The IMP protocol module interprets
+ * contents of these messages and "controls" the actions of the
+ * hardware module during IMP resets, but not, for instance, during
+ * UNIBUS resets.
+ *
+ * The two modules are coupled at "attach time", and ever after,
+ * through the imp interface structure.  Higher level protocols,
+ * e.g. IP, interact with the IMP driver, rather than the ACC.
+ */
+struct acc_softc {
+       struct  ifnet *acc_if;          /* pointer to IMP's ifnet struct */
+       struct  impcb *acc_ic;          /* data structure shared with IMP */
+       struct  ifuba acc_ifuba;        /* UNIBUS resources */
+       struct  mbuf *acc_iq;           /* input reassembly queue */
+       short   acc_olen;               /* size of last message sent */
+       char    acc_flush;              /* flush remainder of message */
+} acc_softc[NACC];
+
+/*
+ * Reset the IMP and cause a transmitter interrupt by
+ * performing a null DMA.
+ */
+accprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct accdevice *addr = (struct accdevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       accrint(0); accxint(0);
+#endif
+       addr->icsr = ACC_RESET; DELAY(5000);
+       addr->ocsr = ACC_RESET; DELAY(5000);
+       addr->ocsr = OUT_BBACK; DELAY(5000);
+       addr->owc = 0;
+       addr->ocsr = ACC_IE | ACC_GO; DELAY(5000);
+       addr->ocsr = 0;
+       if (cvec && cvec != 0x200)      /* transmit -> receive */
+               cvec -= 4;
+       return (1);
+}
+
+/*
+ * Call the IMP module to allow it to set up its internal
+ * state, then tie the two modules together by setting up
+ * the back pointers to common data structures.
+ */
+accattach(ui)
+       struct uba_device *ui;
+{
+       register struct acc_softc *sc = &acc_softc[ui->ui_unit];
+       register struct impcb *ip;
+       struct ifimpcb {
+               struct  ifnet ifimp_if;
+               struct  impcb ifimp_impcb;
+       } *ifimp;
+
+       if ((ifimp = (struct ifimpcb *)impattach(ui, accreset)) == 0)
+               panic("accattach");
+       sc->acc_if = &ifimp->ifimp_if;
+       ip = &ifimp->ifimp_impcb;
+       sc->acc_ic = ip;
+       ip->ic_init = accinit;
+       ip->ic_start = accstart;
+       sc->acc_ifuba.ifu_flags = UBA_CANTWAIT;
+#ifdef notdef
+       sc->acc_ifuba.ifu_flags |= UBA_NEEDBDP;
+#endif
+}
+
+/*
+ * Reset interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+accreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+       struct acc_softc *sc;
+
+       if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" acc%d", unit);
+       sc = &acc_softc[unit];
+       /* must go through IMP to allow it to set state */
+       (*sc->acc_if->if_init)(unit);
+}
+
+/*
+ * Initialize interface: clear recorded pending operations,
+ * and retrieve, and initialize UNIBUS resources.  Note
+ * return value is used by IMP init routine to mark IMP
+ * unavailable for outgoing traffic.
+ */
+accinit(unit)
+       int unit;
+{      
+       register struct acc_softc *sc;
+       register struct uba_device *ui;
+       register struct accdevice *addr;
+       int info;
+
+       if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0) {
+               printf("acc%d: not alive\n", unit);
+               return (0);
+       }
+       sc = &acc_softc[unit];
+       /*
+        * Header length is 0 since we have to passs
+        * the IMP leader up to the protocol interpretation
+        * routines.  If we had the header length as
+        * sizeof(struct imp_leader), then the if_ routines
+        * would asssume we handle it on input and output.
+        */
+       if (if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0,
+            (int)btoc(IMPMTU)) == 0) {
+               printf("acc%d: can't initialize\n", unit);
+               ui->ui_alive = 0;
+               return (0);
+       }
+       addr = (struct accdevice *)ui->ui_addr;
+
+       /*
+        * Reset the imp interface;
+        * the delays are pure guesswork.
+        */
+        addr->ocsr = ACC_RESET; DELAY(5000);
+       addr->ocsr = OUT_BBACK; DELAY(5000);    /* reset host master ready */
+       addr->ocsr = 0;
+       if (accinputreset(addr, unit) == 0) {
+               ui->ui_alive = 0;
+               return (0);
+       }
+
+       /*
+        * Put up a read.  We can't restart any outstanding writes
+        * until we're back in synch with the IMP (i.e. we've flushed
+        * the NOOPs it throws at us).
+        * Note: IMPMTU includes the leader.
+        */
+       info = sc->acc_ifuba.ifu_r.ifrw_info;
+       addr->iba = (u_short)info;
+       addr->iwc = -(IMPMTU >> 1);
+#ifdef LOOPBACK
+       addr->ocsr |= OUT_BBACK;
+#endif
+       addr->icsr = 
+               IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
+       return (1);
+}
+
+accinputreset(addr, unit)
+       register struct accdevice *addr;
+       register int unit;
+{
+       register int i;
+
+       addr->icsr = ACC_RESET; DELAY(5000);
+       addr->icsr = IN_MRDY | IN_WEN;          /* close the relay */
+       DELAY(10000);
+       /* YECH!!! */
+       for (i = 0; i < 500; i++) {
+               if ((addr->icsr & IN_HRDY) ||
+                   (addr->icsr & (IN_RMR | IN_IMPBSY)) == 0)
+                       return (1);
+               addr->icsr = IN_MRDY | IN_WEN; DELAY(10000);
+               /* keep turning IN_RMR off */
+       }
+       printf("acc%d: imp doesn't respond, icsr=%b\n", unit,
+               addr->icsr, ACC_INBITS);
+       return (0);
+}
+
+/*
+ * Start output on an interface.
+ */
+accstart(dev)
+       dev_t dev;
+{
+       int unit = ACCUNIT(dev), info;
+       register struct acc_softc *sc = &acc_softc[unit];
+       register struct accdevice *addr;
+       struct mbuf *m;
+       u_short cmd;
+
+       if (sc->acc_ic->ic_oactive)
+               goto restart;
+       
+       /*
+        * Not already active, deqeue a request and
+        * map it onto the UNIBUS.  If no more
+        * requeusts, just return.
+        */
+       IF_DEQUEUE(&sc->acc_if->if_snd, m);
+       if (m == 0) {
+               sc->acc_ic->ic_oactive = 0;
+               return;
+       }
+       sc->acc_olen = if_wubaput(&sc->acc_ifuba, m);
+
+restart:
+       /*
+        * Have request mapped to UNIBUS for
+        * transmission; start the output.
+        */
+       if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_w.ifrw_bdp);
+       addr = (struct accdevice *)accinfo[unit]->ui_addr;
+       info = sc->acc_ifuba.ifu_w.ifrw_info;
+       addr->oba = (u_short)info;
+       addr->owc = -((sc->acc_olen + 1) >> 1);
+       cmd = ACC_IE | OUT_ENLB | ((info & 0x30000) >> 12) | ACC_GO;
+#ifdef LOOPBACK
+       cmd |= OUT_BBACK;
+#endif
+       addr->ocsr = cmd;
+       sc->acc_ic->ic_oactive = 1;
+}
+
+/*
+ * Output interrupt handler.
+ */
+accxint(unit)
+       int unit;
+{
+       register struct acc_softc *sc = &acc_softc[unit];
+       register struct accdevice *addr;
+
+       addr = (struct accdevice *)accinfo[unit]->ui_addr;
+       if (sc->acc_ic->ic_oactive == 0) {
+               printf("acc%d: stray xmit interrupt, csr=%b\n", unit,
+                       addr->ocsr, ACC_OUTBITS);
+               return;
+       }
+       sc->acc_if->if_opackets++;
+       sc->acc_ic->ic_oactive = 0;
+       if (addr->ocsr & ACC_ERR) {
+               printf("acc%d: output error, ocsr=%b, icsr=%b\n", unit,
+                       addr->ocsr, ACC_OUTBITS, addr->icsr, ACC_INBITS);
+               sc->acc_if->if_oerrors++;
+       }
+       if (sc->acc_ifuba.ifu_xtofree) {
+               m_freem(sc->acc_ifuba.ifu_xtofree);
+               sc->acc_ifuba.ifu_xtofree = 0;
+       }
+       if (sc->acc_if->if_snd.ifq_head)
+               accstart(unit);
+}
+
+/*
+ * Input interrupt handler
+ */
+accrint(unit)
+       int unit;
+{
+       register struct acc_softc *sc = &acc_softc[unit];
+       register struct accdevice *addr;
+       struct mbuf *m;
+       int len, info;
+
+       addr = (struct accdevice *)accinfo[unit]->ui_addr;
+       sc->acc_if->if_ipackets++;
+
+       /*
+        * Purge BDP; flush message if error indicated.
+        */
+       if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp);
+       if (addr->icsr & ACC_ERR) {
+               printf("acc%d: input error, csr=%b\n", unit,
+                   addr->icsr, ACC_INBITS);
+               sc->acc_if->if_ierrors++;
+               sc->acc_flush = 1;
+       }
+
+       if (sc->acc_flush) {
+               if (addr->icsr & IN_EOM)
+                       sc->acc_flush = 0;
+               goto setup;
+       }
+       len = IMPMTU + (addr->iwc << 1);
+       if (len < 0 || len > IMPMTU) {
+               printf("acc%d: bad length=%d\n", len);
+               sc->acc_if->if_ierrors++;
+               goto setup;
+       }
+
+       /*
+        * The last parameter is always 0 since using
+        * trailers on the ARPAnet is insane.
+        */
+       m = if_rubaget(&sc->acc_ifuba, len, 0);
+       if (m == 0)
+               goto setup;
+       if ((addr->icsr & IN_EOM) == 0) {
+               if (sc->acc_iq)
+                       m_cat(sc->acc_iq, m);
+               else
+                       sc->acc_iq = m;
+               goto setup;
+       }
+       if (sc->acc_iq) {
+               m_cat(sc->acc_iq, m);
+               m = sc->acc_iq;
+               sc->acc_iq = 0;
+       }
+       impinput(unit, m);
+
+setup:
+       /*
+        * Setup for next message.
+        */
+       info = sc->acc_ifuba.ifu_r.ifrw_info;
+       addr->iba = (u_short)info;
+       addr->iwc = -(IMPMTU >> 1);
+       addr->icsr =
+               IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_accreg.h b/usr/src/sys/vaxif/if_accreg.h
new file mode 100644 (file)
index 0000000..d6310bb
--- /dev/null
@@ -0,0 +1,59 @@
+/*     if_accreg.h     6.1     83/07/29        */
+
+/*
+ * ACC LH/DH-11 interface
+ */
+
+struct accdma {
+       short   csr;    /* control and status */
+       short   db;     /* data buffer */
+       u_short ba;     /* buss address */
+       short   wc;     /* word count */
+};
+
+struct accdevice {
+       struct  accdma input;
+       struct  accdma output;
+};
+
+#define        icsr    input.csr
+#define        iba     input.ba
+#define        iwc     input.wc
+#define        ocsr    output.csr
+#define        oba     output.ba
+#define        owc     output.wc
+
+/*
+ * Bits Common to both input and out CSR's
+ */
+#define        ACC_ERR         0x8000          /* error present */
+#define        ACC_NXM         0x4000          /* non-existant memory */
+#define        ACC_RDY         0x0080          /* ready */
+#define        ACC_IE          0x0040          /* interrupt enable */
+#define        ACC_RESET       0x0002          /* reset interface */
+#define        ACC_GO          0x0001          /* start operation */
+
+/*
+ * Input Control Status Register
+ */
+#define IN_EOM         0x2000          /* end-of-message recieved */
+#define IN_HRDY                0x0800          /* host ready */
+#define IN_IMPBSY      0x0400          /* IMP not ready */
+#define IN_RMR         0x0200          /* receive master ready error */
+#define IN_IBF         0x0100          /* input data buffer full */
+#define IN_WEN         0x0008          /* write enable */
+#define IN_MRDY                0x0004          /* master ready */
+
+#define ACC_INBITS \
+"\20\20ERR\17NXM\16EOM\14HRDY\13IMPBSY\12RMR\11IBF\10RDY\7IE\
+\4WEN\3MRDY\2RESET\1GO"
+
+/*
+ * Output Control Status Register
+ */
+#define OUT_TMR                0x0200          /* transmit master ready error */
+#define OUT_BBACK      0x0008          /* bus back */
+#define OUT_ENLB       0x0004          /* enable last bit */
+
+#define ACC_OUTBITS \
+"\20\20ERR\17NXM\12TMR\10RDY\7IE\4BBACK\3ENLB\2RESET\1GO"
diff --git a/usr/src/sys/vaxif/if_css.c b/usr/src/sys/vaxif/if_css.c
new file mode 100644 (file)
index 0000000..e47f840
--- /dev/null
@@ -0,0 +1,391 @@
+/*      if_css.c     6.1     83/07/29     */
+
+#include "css.h"
+
+/*
+ * DEC/CSS IMP11-A ARPAnet IMP interface driver.
+ * Since "imp11a" is such a mouthful, it is called
+ * "css" after the LH/DH being called "acc".
+ *
+ * Configuration notes:
+ *
+ * As delivered from DEC/CSS, it
+ * is addressed and vectored as two DR11-B's.  This makes
+ * Autoconfig almost IMPOSSIBLE.  To make it work, the
+ * interrupt vectors must be restrapped to make the vectors
+ * consecutive.  The 020 hole between the CSR addresses is
+ * tolerated, althought that could be cleaned-up also.
+ *
+ * Additionally, the TRANSMIT side of the IMP11-A has the
+ * lower address of the two subunits, so the vector ordering
+ * in the CONFIG file is reversed from most other devices.
+ * It should be:
+ *
+ * device css0 ....  cssxint cssrint
+ *
+ * If you get it wrong, it will still autoconfig, but will just
+ * sit there with RECIEVE IDLE indicated on the front panel.
+ */
+#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 "../net/if.h"
+#include "../netimp/if_imp.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_cssreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+int     cssprobe(), cssattach(), cssrint(), cssxint();
+struct  uba_device *cssinfo[NCSS];
+u_short cssstd[] = { 0 };
+struct  uba_driver cssdriver =
+        { cssprobe, 0, cssattach, 0, cssstd, "css", cssinfo };
+#define CSSUNIT(x)      minor(x)
+
+int     cssinit(), cssstart(), cssreset();
+
+/*
+ * "Lower half" of IMP interface driver.
+ *
+ * Each IMP interface is handled by a common module which handles
+ * the IMP-host protocol and a hardware driver which manages the
+ * hardware specific details of talking with the IMP.
+ *
+ * The hardware portion of the IMP driver handles DMA and related
+ * management of UNIBUS resources.  The IMP protocol module interprets
+ * contents of these messages and "controls" the actions of the
+ * hardware module during IMP resets, but not, for instance, during
+ * UNIBUS resets.
+ *
+ * The two modules are coupled at "attach time", and ever after,
+ * through the imp interface structure.  Higher level protocols,
+ * e.g. IP, interact with the IMP driver, rather than the CSS.
+ */
+struct  css_softc {
+        struct  ifnet *css_if;          /* pointer to IMP's ifnet struct */
+        struct  impcb *css_ic;          /* data structure shared with IMP */
+        struct  ifuba css_ifuba;        /* UNIBUS resources */
+        struct  mbuf *css_iq;           /* input reassembly queue */
+        short   css_olen;               /* size of last message sent */
+        char    css_flush;              /* flush remainder of message */
+} css_softc[NCSS];
+
+/*
+ * Reset the IMP and cause a transmitter interrupt by
+ * performing a null DMA.
+ */
+cssprobe(reg)
+        caddr_t reg;
+{
+        register int br, cvec;          /* r11, r10 value-result */
+        register struct cssdevice *addr = (struct cssdevice *)reg;
+
+#ifdef lint
+        br = 0; cvec = br; br = cvec;
+        cssrint(0); cssxint(0);
+#endif
+
+
+        addr->css_icsr = CSS_CLR;
+        addr->css_ocsr = CSS_CLR;
+        DELAY(50000);
+       addr->css_icsr = 0;
+       addr->css_ocsr = 0;
+        DELAY(50000);
+
+       addr->css_oba = 0;
+       addr->css_owc = -1;
+        addr->css_ocsr = CSS_IE | CSS_GO;      /* enable interrupts */
+        DELAY(50000);
+        addr->css_ocsr = 0;
+
+        return (1);
+}
+
+/*
+ * Call the IMP module to allow it to set up its internal
+ * state, then tie the two modules together by setting up
+ * the back pointers to common data structures.
+ */
+cssattach(ui)
+        struct uba_device *ui;
+{
+        register struct css_softc *sc = &css_softc[ui->ui_unit];
+        register struct impcb *ip;
+        struct ifimpcb {
+                struct  ifnet ifimp_if;
+                struct  impcb ifimp_impcb;
+        } *ifimp;
+
+        if ((ifimp = (struct ifimpcb *)impattach(ui, cssreset)) == 0)
+                panic("cssattach");             /* XXX */
+        sc->css_if = &ifimp->ifimp_if;
+        ip = &ifimp->ifimp_impcb;
+        sc->css_ic = ip;
+        ip->ic_init = cssinit;
+        ip->ic_start = cssstart;
+       sc->css_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEED16;
+#ifdef notdef
+       sc->css_ifuba.ifu_flags =| UBA_NEEDBDP;
+#endif
+}
+
+/*
+ * Reset interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+cssreset(unit, uban)
+        int unit, uban;
+{
+        register struct uba_device *ui;
+        struct css_softc *sc;
+
+        if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0 ||
+            ui->ui_ubanum != uban)
+                return;
+        printf(" css%d", unit);
+        sc = &css_softc[unit];
+        /* must go through IMP to allow it to set state */
+        (*sc->css_if->if_init)(unit);
+}
+
+/*
+ * Initialize interface: clear recorded pending operations,
+ * and retrieve, and reinitialize UNIBUS resources.
+ */
+cssinit(unit)
+        int unit;
+{       
+        register struct css_softc *sc;
+        register struct uba_device *ui;
+        register struct cssdevice *addr;
+        int x, info;
+
+       if (unit >= NCSS || (ui = cssinfo[unit]) == 0 || ui->ui_alive == 0) {
+               printf("css%d: not alive\n", unit);
+               return(0);
+       }
+       sc = &css_softc[unit];
+
+       /*
+        * Header length is 0 to if_ubainit since we have to pass
+        * the IMP leader up to the protocol interpretaion
+        * routines.  If we had the deader length as
+        * sizeof(struct imp_leader), then the if_ routines
+        * would assume we handle it on input and output.
+        */
+       
+        if (if_ubainit(&sc->css_ifuba, ui->ui_ubanum, 0,(int)btoc(IMPMTU)) == 0) {
+                printf("css%d: can't initialize\n", unit);
+               ui->ui_alive = 0;
+               return(0);
+        }
+        addr = (struct cssdevice *)ui->ui_addr;
+
+        /* reset the imp interface. */
+        x = spl5();
+        addr->css_icsr = CSS_CLR;
+        addr->css_ocsr = CSS_CLR;
+       DELAY(100);
+       addr->css_icsr = 0;
+       addr->css_ocsr = 0;
+        addr->css_icsr = IN_HRDY;       /* close the relay */
+       DELAY(5000);
+        splx(x);
+
+        /*
+        * This may hang if the imp isn't really there.
+        * Will test and verify safe operation.
+        */
+
+       x = 500;
+       while (x-- > 0) {
+               if ((addr->css_icsr & (IN_HRDY|IN_IMPNR)) == IN_HRDY) 
+                       break;
+                addr->css_icsr = IN_HRDY;      /* close the relay */
+                DELAY(5000);
+        }
+
+       if (x <= 0) {
+               printf("css%d: imp doesn't respond, icsr=%b\n", unit,
+                       CSS_INBITS, addr->css_icsr);
+               goto down;
+       }
+
+        /*
+         * Put up a read.  We can't restart any outstanding writes
+         * until we're back in synch with the IMP (i.e. we've flushed
+         * the NOOPs it throws at us).
+        * Note: IMPMTU includes the leader.
+         */
+
+        x = spl5();
+        info = sc->css_ifuba.ifu_r.ifrw_info;
+        addr->css_iba = (u_short)info;
+        addr->css_iwc = -(IMPMTU >> 1);
+        addr->css_icsr = 
+                IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
+        splx(x);
+       return(1);
+
+down:
+       ui->ui_alive = 0;
+       return(0);
+}
+
+/*
+ * Start output on an interface.
+ */
+cssstart(dev)
+        dev_t dev;
+{
+        int unit = CSSUNIT(dev), info;
+        struct uba_device *ui = cssinfo[unit];
+        register struct css_softc *sc = &css_softc[unit];
+        register struct cssdevice *addr;
+        struct mbuf *m;
+        u_short cmd;
+
+        if (sc->css_ic->ic_oactive)
+                goto restart;
+        
+        /*
+         * Not already active, deqeue a request and
+         * map it onto the UNIBUS.  If no more
+         * requeusts, just return.
+         */
+        IF_DEQUEUE(&sc->css_if->if_snd, m);
+        if (m == 0) {
+                sc->css_ic->ic_oactive = 0;
+                return;
+        }
+        sc->css_olen = if_wubaput(&sc->css_ifuba, m);
+
+restart:
+        /*
+         * Have request mapped to UNIBUS for transmission.
+         * Purge any stale data from the BDP, and start the output.
+         */
+       if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_w.ifrw_bdp);
+        addr = (struct cssdevice *)ui->ui_addr;
+        info = sc->css_ifuba.ifu_w.ifrw_info;
+        addr->css_oba = (u_short)info;
+        addr->css_owc = -((sc->css_olen + 1) >> 1);
+        cmd = CSS_IE | OUT_ENLB | ((info & 0x30000) >> 12) | CSS_GO;
+        addr->css_ocsr = cmd;
+        sc->css_ic->ic_oactive = 1;
+}
+
+/*
+ * Output interrupt handler.
+ */
+cssxint(unit)
+{
+        register struct uba_device *ui = cssinfo[unit];
+        register struct css_softc *sc = &css_softc[unit];
+        register struct cssdevice *addr;
+
+        addr = (struct cssdevice *)ui->ui_addr;
+        if (sc->css_ic->ic_oactive == 0) {
+                printf("css%d: stray output interrupt csr=%b\n",
+                       unit, addr->css_ocsr, CSS_OUTBITS);
+                return;
+        }
+        sc->css_if->if_opackets++;
+        sc->css_ic->ic_oactive = 0;
+        if (addr->css_ocsr & CSS_ERR){
+                sc->css_if->if_oerrors++;
+                printf("css%d: output error, ocsr=%b icsr=%b\n", unit,
+                        addr->css_ocsr, CSS_OUTBITS,
+                       addr->css_icsr, CSS_INBITS);
+       }
+       if (sc->css_ifuba.ifu_xtofree) {
+               m_freem(sc->css_ifuba.ifu_xtofree);
+               sc->css_ifuba.ifu_xtofree = 0;
+       }
+       if (sc->css_if->if_snd.ifq_head)
+               cssstart(unit);
+}
+
+/*
+ * Input interrupt handler
+ */
+cssrint(unit)
+{
+        register struct css_softc *sc = &css_softc[unit];
+        register struct cssdevice *addr;
+        struct mbuf *m;
+        int len, info;
+
+        sc->css_if->if_ipackets++;
+
+        /*
+         * Purge BDP; flush message if error indicated.
+         */
+
+        addr = (struct cssdevice *)cssinfo[unit]->ui_addr;
+       if (sc->css_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->css_ifuba.ifu_uba, sc->css_ifuba.ifu_r.ifrw_bdp);
+        if (addr->css_icsr & CSS_ERR) {
+                printf("css%d: recv error, csr=%b\n", unit,
+                    addr->css_icsr, CSS_INBITS);
+                sc->css_if->if_ierrors++;
+                sc->css_flush = 1;
+        }
+
+        if (sc->css_flush) {
+                if (addr->css_icsr & IN_EOM)
+                        sc->css_flush = 0;
+                goto setup;
+        }
+
+        len = IMPMTU + (addr->css_iwc << 1);
+       if (len < 0 || len > IMPMTU) {
+               printf("css%d: bad length=%d\n", len);
+               sc->css_if->if_ierrors++;
+               goto setup;
+       }
+
+        /*
+         * The last parameter is always 0 since using
+         * trailers on the ARPAnet is insane.
+         */
+        m = if_rubaget(&sc->css_ifuba, len, 0);
+        if (m == 0)
+                goto setup;
+        if ((addr->css_icsr & IN_EOM) == 0) {
+               if (sc->css_iq)
+                       m_cat(sc->css_iq, m);
+               else
+                       sc->css_iq = m;
+               goto setup;
+       }
+       if (sc->css_iq) {
+               m_cat(sc->css_iq, m);
+               m = sc->css_iq;
+               sc->css_iq = 0;
+        }
+        impinput(unit, m);
+
+setup:
+        /*
+         * Setup for next message.
+         */
+        info = sc->css_ifuba.ifu_r.ifrw_info;
+        addr->css_iba = (u_short)info;
+        addr->css_iwc = - (IMPMTU >> 1);
+        addr->css_icsr =
+                IN_HRDY | CSS_IE | IN_WEN | ((info & 0x30000) >> 12) | CSS_GO;
+}
diff --git a/usr/src/sys/vaxif/if_cssreg.h b/usr/src/sys/vaxif/if_cssreg.h
new file mode 100644 (file)
index 0000000..0b1c413
--- /dev/null
@@ -0,0 +1,61 @@
+/*     if_cssreg.h     6.1     83/07/29        */
+
+/* 
+ * DEC/CSS IMP11-A ARPAnet interface
+ */
+
+struct cssdma {
+       short   wc;             /* word count */
+       u_short ba;             /* bus address (low 16 bits) */
+       short   csr;            /* status register */
+       short   db;             /* data buffer*/
+};
+
+struct cssdevice {
+       struct  cssdma  css_output;     /* transmit DR11-B */
+       struct  cssdma  css_hole;       /* unclever gap */
+       struct  cssdma  css_input;      /* receive DR11-B */
+};
+
+#define css_icsr        css_input.csr
+#define css_iba         css_input.ba
+#define css_iwc         css_input.wc
+#define css_ocsr        css_output.csr
+#define css_oba         css_output.ba
+#define css_owc         css_output.wc
+
+/*
+ * Bits Common to both input and out CSR's
+ */
+#define CSS_ERR         0x8000          /* error present */
+#define CSS_NXM         0x4000          /* non-existant memory */
+#define        CSS_ATTN        0x2000          /* attention */
+#define        CSS_MAINT       0x1000          /* maintenance mode */
+#define        CSS_CYCLE       0x0100          /* force bus cycle */
+#define CSS_RDY         0x0080          /* ready */
+#define CSS_IE          0x0040          /* interrupt enable */
+#define        CSS_XA          0x0030          /* extended address bits */
+#define        CSS_CLR         0x0020          /* clear status (reset) */
+#define CSS_GO          0x0001          /* start operation */
+
+/*
+ * Input Control Status Register
+ */
+#define IN_EOM          0x0800          /* end-of-message recieved */
+#define IN_IMPNR       0x0400          /* IMP not ready */
+#define IN_RLE          0x0200          /* ready line error */
+#define IN_WEN          0x0008          /* write enable */
+#define IN_HRDY         0x0004          /* host ready */
+
+#define CSS_INBITS \
+"\20\20ERR\17NXM\16ATTN\15MAINT\14EOM\13IMPNR\12RLE\11CYCLE\10RDY\7IE\6XBA17\5XBA16\4WE\3HRDY\2CLR\1GO"
+
+
+/*
+ * Output Control Status Register
+ */
+#define OUT_TXEC       0x0008          /* tx error clear */
+#define OUT_ENLB       0x0004          /* enable last bit */
+
+#define CSS_OUTBITS \
+"\20\20ERR\17NXM\16ATTN\15MAINT\11CYCLE\10RDY\7IE\6XBA17\5XBA16\4TXEC\3ENLB\2CLR\1GO"
diff --git a/usr/src/sys/vaxif/if_dmc.c b/usr/src/sys/vaxif/if_dmc.c
new file mode 100644 (file)
index 0000000..4ee789a
--- /dev/null
@@ -0,0 +1,467 @@
+/*     if_dmc.c        6.1     83/07/29        */
+
+#include "dmc.h"
+#if NDMC > 0
+#define printd if(dmcdebug)printf
+int dmcdebug = 0;
+/*
+ * DMC11 device driver, internet version
+ *
+ * TODO
+ *     allow more than one outstanding read or write.
+ *
+ * UNTESTED WITH 4.2
+ */
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mbuf.h"
+#include "../h/buf.h"
+#include "../h/ioctl.h"                        /* must precede tty.h */
+#include "../h/tty.h"
+#include "../h/protosw.h"
+#include "../h/socket.h"
+#include "../h/vmmac.h"
+#include "../h/errno.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxif/if_dmc.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#ifndef DMC_USEMAINT
+#define        DMC_USEMAINT    1       /* use maintenance mode */
+#endif
+
+/*
+ * Driver information for auto-configuration stuff.
+ */
+int    dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
+int    dmcoutput(), dmcreset();
+struct uba_device *dmcinfo[NDMC];
+u_short        dmcstd[] = { 0 };
+struct uba_driver dmcdriver =
+       { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
+
+/*
+ * DMC software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * sc_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct dmc_softc {
+       struct  ifnet sc_if;            /* network-visible interface */
+       struct  ifuba sc_ifuba;         /* UNIBUS resources */
+       short   sc_flag;                /* flags */
+       short   sc_oactive;             /* output active */
+       int     sc_ubinfo;              /* UBA mapping info for base table */
+       struct clist sc_que;            /* command queue */
+} dmc_softc[NDMC];
+
+/* flags */
+#define        DMCRUN          01
+#define        DMCBMAPPED      02              /* base table mapped */
+
+struct dmc_base {
+       short   d_base[128];            /* DMC base table */
+} dmc_base[NDMC];
+
+#define        loword(x)       ((short *)&x)[0]
+#define        hiword(x)       ((short *)&x)[1]
+
+dmcprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+       register struct dmcdevice *addr = (struct dmcdevice *)reg;
+       register int i;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       dmcrint(0); dmcxint(0);
+#endif
+       addr->bsel1 = DMC_MCLR;
+       for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
+               ;
+       if ((addr->bsel1 & DMC_RUN) == 0)
+               return (0);
+       addr->bsel1 &= ~DMC_MCLR;
+       addr->bsel0 = DMC_RQI|DMC_IEI;
+       DELAY(100000);
+       addr->bsel1 = DMC_MCLR;
+       for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
+               ;
+       return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+dmcattach(ui)
+       register struct uba_device *ui;
+{
+       register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
+
+       sc->sc_if.if_unit = ui->ui_unit;
+       sc->sc_if.if_name = "dmc";
+       sc->sc_if.if_mtu = DMCMTU;
+       sc->sc_if.if_init = dmcinit;
+       sc->sc_if.if_output = dmcoutput;
+       sc->sc_if.if_ioctl = dmcioctl;
+       sc->sc_if.if_reset = dmcreset;
+       /* DON'T KNOW IF THIS WILL WORK WITH A BDP AT HIGH SPEEDS */
+       sc->sc_ifuba.ifu_flags = UBA_NEEDBDP | UBA_CANTWAIT;
+       if_attach(&sc->sc_if);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified UBA, reset it's state.
+ */
+dmcreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" dmc%d", unit);
+       dmcinit(unit);
+}
+
+/*
+ * Initialization of interface; reinitialize UNIBUS usage.
+ */
+dmcinit(unit)
+       int unit;
+{
+       register struct dmc_softc *sc = &dmc_softc[unit];
+       register struct uba_device *ui = dmcinfo[unit];
+       register struct dmcdevice *addr;
+       register struct ifnet *ifp = &sc->sc_if;
+       struct sockaddr_in *sin;
+       int base;
+
+       printd("dmcinit\n");
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       if (sin->sin_addr.s_addr == 0)
+               return;
+       if ((ifp->if_flags & IFF_RUNNING) == 0) {
+               if ((sc->sc_flag&DMCBMAPPED) == 0) {
+                       sc->sc_ubinfo = uballoc(ui->ui_ubanum,
+                           (caddr_t)&dmc_base[unit],
+                           sizeof (struct dmc_base), 0);
+                       sc->sc_flag |= DMCBMAPPED;
+               }
+               if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
+                   (int)btoc(DMCMTU)) == 0) {
+                       printf("dmc%d: can't initialize\n", unit);
+                       ifp->if_flags &= ~IFF_UP;
+                       return;
+               }
+               addr = (struct dmcdevice *)ui->ui_addr;
+               addr->bsel2 |= DMC_IEO;
+               base = sc->sc_ubinfo & 0x3ffff;
+               printd("  base 0x%x\n", base);
+               dmcload(sc, DMC_BASEI, base, (base>>2)&DMC_XMEM);
+               dmcload(sc, DMC_CNTLI, 0, DMC_USEMAINT ? DMC_MAINT : 0);
+               base = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
+               dmcload(sc, DMC_READ, base, ((base>>2)&DMC_XMEM)|DMCMTU);
+               printd("  first read queued, addr 0x%x\n", base);
+               ifp->if_flags |= IFF_UP|IFF_RUNNING;
+       }
+       /* set up routing table entry */
+       if ((ifp->if_flags & IFF_ROUTE) == 0) {
+               rtinit((struct sockaddr *)sin, (struct sockaddr *)sin,
+                   RTF_HOST|RTF_UP);
+               ifp->if_flags |= IFF_ROUTE;
+       }
+}
+
+/*
+ * Start output on interface.  Get another datagram
+ * to send from the interface queue and map it to
+ * the interface before starting output.
+ */
+dmcstart(dev)
+       dev_t dev;
+{
+       int unit = minor(dev);
+       register struct dmc_softc *sc = &dmc_softc[unit];
+       int addr, len;
+       struct mbuf *m;
+
+       printd("dmcstart\n");
+       /*
+        * Dequeue a request and map it to the UNIBUS.
+        * If no more requests, just return.
+        */
+       IF_DEQUEUE(&sc->sc_if.if_snd, m);
+       if (m == 0)
+               return;
+       len = if_wubaput(&sc->sc_ifuba, m);
+
+       /*
+        * Have request mapped to UNIBUS for transmission.
+        * Purge any stale data from this BDP and start the output.
+        */
+       if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
+       addr = sc->sc_ifuba.ifu_w.ifrw_info & 0x3ffff;
+       printd("  len %d, addr 0x%x, ", len, addr);
+       printd("mr 0x%x\n", sc->sc_ifuba.ifu_w.ifrw_mr[0]);
+       dmcload(sc, DMC_WRITE, addr, (len&DMC_CCOUNT)|((addr>>2)&DMC_XMEM));
+       sc->sc_oactive = 1;
+}
+
+/*
+ * Utility routine to load the DMC device registers.
+ */
+dmcload(sc, type, w0, w1)
+       register struct dmc_softc *sc;
+       int type, w0, w1;
+{
+       register struct dmcdevice *addr;
+       register int unit, sps, n;
+
+       printd("dmcload: 0x%x 0x%x 0x%x\n", type, w0, w1);
+       unit = sc - dmc_softc;
+       addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
+       sps = spl5();
+       if ((n = sc->sc_que.c_cc) == 0)
+               addr->bsel0 = type | DMC_RQI;
+       else
+               (void) putc(type | DMC_RQI, &sc->sc_que);
+       (void) putw(w0, &sc->sc_que);
+       (void) putw(w1, &sc->sc_que);
+       if (n == 0)
+               dmcrint(unit);
+       splx(sps);
+}
+
+/*
+ * DMC interface receiver interrupt.
+ * Ready to accept another command,
+ * pull one off the command queue.
+ */
+dmcrint(unit)
+       int unit;
+{
+       register struct dmc_softc *sc;
+       register struct dmcdevice *addr;
+       register int n;
+
+       addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
+       sc = &dmc_softc[unit];
+       while (addr->bsel0&DMC_RDYI) {
+               addr->sel4 = getw(&sc->sc_que);
+               addr->sel6 = getw(&sc->sc_que);
+               addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
+               while (addr->bsel0&DMC_RDYI)
+                       ;
+               if (sc->sc_que.c_cc == 0)
+                       goto out;
+               addr->bsel0 = getc(&sc->sc_que);
+               n = RDYSCAN;
+               while (n-- && (addr->bsel0&DMC_RDYI) == 0)
+                       ;
+       }
+       if (sc->sc_que.c_cc)
+               addr->bsel0 |= DMC_IEI;
+out:
+       dmcxint(unit);
+}
+
+/*
+ * DMC interface transmitter interrupt.
+ * A transfer has completed, check for errors.
+ * If it was a read, notify appropriate protocol.
+ * If it was a write, pull the next one off the queue.
+ */
+dmcxint(unit)
+       int unit;
+{
+       register struct dmc_softc *sc;
+       register struct ifnet *ifp;
+       struct uba_device *ui = dmcinfo[unit];
+       struct dmcdevice *addr;
+       struct mbuf *m;
+       register struct ifqueue *inq;
+       int arg, cmd, len;
+
+       addr = (struct dmcdevice *)ui->ui_addr;
+       cmd = addr->bsel2 & 0xff;
+       if ((cmd & DMC_RDYO) == 0)
+               return;
+#ifdef notdef
+       arg2 = addr->sel4;
+#endif
+       arg = addr->sel6;
+       addr->bsel2 &= ~DMC_RDYO;
+       sc = &dmc_softc[unit];
+       ifp = &sc->sc_if;
+       printd("dmcxint\n");
+       switch (cmd & 07) {
+
+       case DMC_OUR:
+               /*
+                * A read has completed.  Purge input buffered
+                * data path.  Pass packet to type specific
+                * higher-level input routine.
+                */
+               ifp->if_ipackets++;
+               if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
+                       UBAPURGE(sc->sc_ifuba.ifu_uba,
+                               sc->sc_ifuba.ifu_r.ifrw_bdp);
+               len = arg & DMC_CCOUNT;
+               printd("  read done, len %d\n", len);
+               switch (ifp->if_addr.sa_family) {
+#ifdef INET
+               case AF_INET:
+                       schednetisr(NETISR_IP);
+                       inq = &ipintrq;
+                       break;
+#endif
+
+               default:
+                       printf("dmc%d: unknown address type %d\n", unit,
+                           ifp->if_addr.sa_family);
+                       goto setup;
+               }
+               m = if_rubaget(&sc->sc_ifuba, len, 0);
+               if (m == 0)
+                       goto setup;
+               if (IF_QFULL(inq)) {
+                       IF_DROP(inq);
+                       m_freem(m);
+               } else
+                       IF_ENQUEUE(inq, m);
+
+setup:
+               arg = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
+               dmcload(sc, DMC_READ, arg, ((arg >> 2) & DMC_XMEM) | DMCMTU);
+               return;
+
+       case DMC_OUX:
+               /*
+                * A write has completed, start another
+                * transfer if there is more data to send.
+                */
+               if (sc->sc_oactive == 0)
+                       return;         /* SHOULD IT BE A FATAL ERROR? */
+               printd("  write done\n");
+               ifp->if_opackets++;
+               sc->sc_oactive = 0;
+               if (sc->sc_ifuba.ifu_xtofree) {
+                       m_freem(sc->sc_ifuba.ifu_xtofree);
+                       sc->sc_ifuba.ifu_xtofree = 0;
+               }
+               if (ifp->if_snd.ifq_head == 0)
+                       return;
+               dmcstart(unit);
+               return;
+
+       case DMC_CNTLO:
+               arg &= DMC_CNTMASK;
+               if (arg&DMC_FATAL) {
+                       addr->bsel1 = DMC_MCLR;
+                       sc->sc_flag &= ~DMCRUN;
+                       /*** DO SOMETHING TO RESTART DEVICE ***/
+                       printf("DMC FATAL ERROR 0%o\n", arg);
+               } else {
+                       /* ACCUMULATE STATISTICS */
+                       printf("DMC SOFT ERROR 0%o\n", arg);
+               }
+               return;
+
+       default:
+               printf("dmc%d: bad control %o\n", unit, cmd);
+       }
+}
+
+/*
+ * DMC output routine.
+ * Just send the data, header was supplied by
+ * upper level protocol routines.
+ */
+dmcoutput(ifp, m, dst)
+       register struct ifnet *ifp;
+       register struct mbuf *m;
+       struct sockaddr *dst;
+{
+       int s;
+
+       printd("dmcoutput\n");
+       if (dst->sa_family != ifp->if_addr.sa_family) {
+               printf("dmc%d: af%d not supported\n", ifp->if_unit,
+                   dst->sa_family);
+               m_freem(m);
+               return (EAFNOSUPPORT);
+       }
+       s = splimp();
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               m_freem(m);
+               splx(s);
+               return (ENOBUFS);
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if (dmc_softc[ifp->if_unit].sc_oactive == 0)
+               dmcstart(ifp->if_unit);
+       splx(s);
+       return (0);
+}
+
+/*
+ * Process an ioctl request.
+ */
+dmcioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       struct sockaddr_in *sin;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               sin = (struct sockaddr_in *)&ifr->ifr_addr;
+               ifp->if_addr = *(struct sockaddr *)sin;
+               ifp->if_net = in_netof(sin->sin_addr);
+               ifp->if_host[0] = in_lnaof(sin->sin_addr);
+               dmcinit(ifp->if_unit);
+               break;
+
+       case SIOCSIFDSTADDR:
+               ifp->if_dstaddr = ifr->ifr_dstaddr;
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_dmc.h b/usr/src/sys/vaxif/if_dmc.h
new file mode 100644 (file)
index 0000000..4129c67
--- /dev/null
@@ -0,0 +1,66 @@
+/*     if_dmc.h        6.1     83/07/29        */
+
+/*
+ * DMC-11 Interface
+ */
+
+struct dmcdevice {
+       union {
+               char    b[8];
+               short   w[4];
+       } un;
+};
+
+#define        bsel0   un.b[0]
+#define        bsel1   un.b[1]
+#define        bsel2   un.b[2]
+#define        bsel3   un.b[3]
+#define        bsel4   un.b[4]
+#define        bsel5   un.b[5]
+#define        bsel6   un.b[6]
+#define        bsel7   un.b[7]
+#define        sel0    un.w[0]
+#define        sel2    un.w[1]
+#define        sel4    un.w[2]
+#define        sel6    un.w[3]
+
+#define        DMCMTU  (2048)
+
+#define        RDYSCAN 16      /* loop delay for RDYI after RQI */
+
+/* defines for bsel0 */
+#define        DMC_BACCI       0
+#define        DMC_CNTLI       1
+#define        DMC_PERR        2
+#define        DMC_BASEI       3
+#define        DMC_WRITE       0               /* transmit block */
+#define        DMC_READ        4               /* read block */
+#define        DMC_RQI         0040            /* port request bit */
+#define        DMC_IEI         0100            /* enable input interrupts */
+#define        DMC_RDYI        0200            /* port ready */
+
+/* defines for bsel1 */
+#define        DMC_MCLR        0100            /* DMC11 Master Clear */
+#define        DMC_RUN         0200            /* clock running */
+
+/* defines for bsel2 */
+#define        DMC_BACCO       0
+#define        DMC_CNTLO       1
+#define        DMC_OUX         0               /* transmit block */
+#define        DMC_OUR         4               /* read block */
+#define        DMC_IEO         0100            /* enable output interrupts */
+#define        DMC_RDYO        0200            /* port available */
+
+/* defines for CNTLI mode */
+#define        DMC_HDPLX       02000           /* half duplex DDCMP operation */
+#define        DMC_SEC         04000           /* half duplex secondary station */
+#define        DMC_MAINT       00400           /* enter maintenance mode */
+
+/* defines for BACCI/O and BASEI mode */
+#define        DMC_XMEM        0140000         /* xmem bit position */
+#define        DMC_CCOUNT      0037777         /* character count mask */
+#define        DMC_RESUME      0002000         /* resume (BASEI only) */
+
+/* defines for CNTLO */
+#define        DMC_CNTMASK     01777
+#define        DMC_FATAL       01620
diff --git a/usr/src/sys/vaxif/if_ec.c b/usr/src/sys/vaxif/if_ec.c
new file mode 100644 (file)
index 0000000..ec444d7
--- /dev/null
@@ -0,0 +1,777 @@
+/*     if_ec.c 6.1     83/07/29        */
+
+#include "ec.h"
+
+/*
+ * 3Com Ethernet Controller interface
+ */
+#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 "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netinet/if_ether.h"
+#include "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_ecreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define        ECMEM   0000000
+
+int    ecprobe(), ecattach(), ecrint(), ecxint(), eccollide();
+struct uba_device *ecinfo[NEC];
+u_short ecstd[] = { 0 };
+struct uba_driver ecdriver =
+       { ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo };
+#define        ECUNIT(x)       minor(x)
+
+int    ecinit(),ecioctl(),ecoutput(),ecreset();
+struct mbuf *ecget();
+
+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, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct ec_softc {
+       struct  arpcom es_ac;           /* common Ethernet structures */
+#define        es_if   es_ac.ac_if             /* network-visible interface */
+#define        es_addr es_ac.ac_enaddr         /* hardware Ethernet address */
+       struct  ifuba es_ifuba;         /* UNIBUS resources */
+       short   es_mask;                /* mask for current output delay */
+       short   es_oactive;             /* is output active? */
+       u_char  *es_buf[16];            /* virtual addresses of buffers */
+} ec_softc[NEC];
+
+/*
+ * Do output DMA to determine interface presence and
+ * interrupt vector.  DMA is too short to disturb other hosts.
+ */
+ecprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct ecdevice *addr = (struct ecdevice *)reg;
+       register caddr_t ecbuf = (caddr_t) &umem[numuba][ECMEM];
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       ecrint(0); ecxint(0); eccollide(0);
+#endif
+       /*
+        * Make sure memory is turned on
+        */
+       addr->ec_rcr = EC_AROM;
+       /*
+        * Disable map registers for ec unibus space,
+        * but don't allocate yet.
+        */
+       (void) ubamem(numuba, ECMEM, 32*2, 0);
+       /*
+        * Check for existence of buffers on Unibus.
+        */
+       if (badaddr((caddr_t)ecbuf, 2)) {
+       bad1:
+               printf("ec: buffer mem not found\n");
+       bad2:
+               (void) ubamem(numuba, 0, 0, 0); /* reenable map (780 only) */
+               addr->ec_rcr = EC_MDISAB;       /* disable memory */
+               return (0);
+       }
+#if VAX780
+       if (cpu == VAX_780 && uba_hd[numuba].uh_uba->uba_sr) {
+               uba_hd[numuba].uh_uba->uba_sr = uba_hd[numuba].uh_uba->uba_sr;
+               goto bad1;
+       }
+#endif
+
+       /*
+        * Tell the system that the board has memory here, so it won't
+        * attempt to allocate the addresses later.
+        */
+       if (ubamem(numuba, ECMEM, 32*2, 1) == 0) {
+               printf("ecprobe: cannot reserve uba addresses\n");
+               goto bad2;
+       }
+
+       /*
+        * Make a one byte packet in what should be buffer #0.
+        * Submit it for sending.  This whould cause an xmit interrupt.
+        * The xmit interrupt vector is 8 bytes after the receive vector,
+        * so adjust for this before returning.
+        */
+       *(u_short *)ecbuf = (u_short) 03777;
+       ecbuf[03777] = '\0';
+       addr->ec_xcr = EC_XINTEN|EC_XWBN;
+       DELAY(100000);
+       addr->ec_xcr = EC_XCLR;
+       if (cvec > 0 && cvec != 0x200) {
+               if (cvec & 04) {        /* collision interrupt */
+                       cvec -= 04;
+                       br += 1;                /* rcv is collision + 1 */
+               } else {                /* xmit interrupt */
+                       cvec -= 010;
+                       br += 2;                /* rcv is xmit + 2 */
+               }
+       }
+       return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+ecattach(ui)
+       struct uba_device *ui;
+{
+       struct ec_softc *es = &ec_softc[ui->ui_unit];
+       register struct ifnet *ifp = &es->es_if;
+       register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
+       struct sockaddr_in *sin;
+       int i, j;
+       u_char *cp;
+
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "ec";
+       ifp->if_mtu = ETHERMTU;
+
+       /*
+        * Read the ethernet address off the board, one nibble at a time.
+        */
+       addr->ec_xcr = EC_UECLR;
+       addr->ec_rcr = EC_AROM;
+       cp = es->es_addr;
+#define        NEXTBIT addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM
+       for (i=0; i<6; i++) {
+               *cp = 0;
+               for (j=0; j<=4; j+=4) {
+                       *cp |= ((addr->ec_rcr >> 8) & 0xf) << j;
+                       NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT;
+               }
+               cp++;
+       }
+       sin = (struct sockaddr_in *)&es->es_if.if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = arpmyaddr((struct arpcom *)0);
+       ifp->if_init = ecinit;
+       ifp->if_ioctl = ecioctl;
+       ifp->if_output = ecoutput;
+       ifp->if_reset = ecreset;
+       for (i=0; i<16; i++)
+               es->es_buf[i] = (u_char *)&umem[ui->ui_ubanum][ECMEM+2048*i];
+       if_attach(ifp);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+ecreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" ec%d", unit);
+       (void) ubamem(uban, ECMEM, 32*2, 0);    /* mr disable (no alloc) */
+       ecinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+ecinit(unit)
+       int unit;
+{
+       struct ec_softc *es = &ec_softc[unit];
+       struct ecdevice *addr;
+       register struct ifnet *ifp = &es->es_if;
+       register struct sockaddr_in *sin;
+       int i, s;
+
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       if (sin->sin_addr.s_addr == 0)          /* address still unknown */
+               return;
+
+       /*
+        * Hang receive buffers and start any pending writes.
+        * Writing into the rcr also makes sure the memory
+        * is turned on.
+        */
+       if ((es->es_if.if_flags & IFF_RUNNING) == 0) {
+               addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
+               s = splimp();
+               for (i = ECRHBF; i >= ECRLBF; i--)
+                       addr->ec_rcr = EC_READ | i;
+               es->es_oactive = 0;
+               es->es_mask = ~0;
+               es->es_if.if_flags |= IFF_UP|IFF_RUNNING;
+               if (es->es_if.if_snd.ifq_head)
+                       ecstart(unit);
+               splx(s);
+       }
+       if_rtinit(&es->es_if, RTF_UP);
+       arpattach(&es->es_ac);
+       arpwhohas(&es->es_ac, &sin->sin_addr);
+}
+
+/*
+ * Start or restart output on interface.
+ * If interface is already active, then this is a retransmit
+ * after a collision, and just restuff registers.
+ * If interface is not already active, get another datagram
+ * to send off of the interface queue, and map it to the interface
+ * before starting the output.
+ */
+ecstart(dev)
+       dev_t dev;
+{
+        int unit = ECUNIT(dev);
+       struct ec_softc *es = &ec_softc[unit];
+       struct ecdevice *addr;
+       struct mbuf *m;
+
+       if (es->es_oactive)
+               goto restart;
+
+       IF_DEQUEUE(&es->es_if.if_snd, m);
+       if (m == 0) {
+               es->es_oactive = 0;
+               return;
+       }
+       ecput(es->es_buf[ECTBF], m);
+
+restart:
+       addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
+       addr->ec_xcr = EC_WRITE|ECTBF;
+       es->es_oactive = 1;
+}
+
+/*
+ * Ethernet interface transmitter interrupt.
+ * Start another output if more data to send.
+ */
+ecxint(unit)
+       int unit;
+{
+       register struct ec_softc *es = &ec_softc[unit];
+       register struct ecdevice *addr =
+               (struct ecdevice *)ecinfo[unit]->ui_addr;
+
+       if (es->es_oactive == 0)
+               return;
+       if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) {
+               printf("ec%d: stray xmit interrupt, xcr=%b\n", unit,
+                       addr->ec_xcr, EC_XBITS);
+               es->es_oactive = 0;
+               addr->ec_xcr = EC_XCLR;
+               return;
+       }
+       es->es_if.if_opackets++;
+       es->es_oactive = 0;
+       es->es_mask = ~0;
+       addr->ec_xcr = EC_XCLR;
+       if (es->es_if.if_snd.ifq_head)
+               ecstart(unit);
+}
+
+/*
+ * Collision on ethernet interface.  Do exponential
+ * backoff, and retransmit.  If have backed off all
+ * the way print warning diagnostic, and drop packet.
+ */
+eccollide(unit)
+       int unit;
+{
+       struct ec_softc *es = &ec_softc[unit];
+
+       es->es_if.if_collisions++;
+       if (es->es_oactive)
+               ecdocoll(unit);
+}
+
+ecdocoll(unit)
+       int unit;
+{
+       register struct ec_softc *es = &ec_softc[unit];
+       register struct ecdevice *addr =
+           (struct ecdevice *)ecinfo[unit]->ui_addr;
+       register i;
+       int delay;
+
+       /*
+        * Es_mask is a 16 bit number with n low zero bits, with
+        * n the number of backoffs.  When es_mask is 0 we have
+        * backed off 16 times, and give up.
+        */
+       if (es->es_mask == 0) {
+               es->es_if.if_oerrors++;
+               printf("ec%d: send error\n", unit);
+               /*
+                * Reset interface, then requeue rcv buffers.
+                * Some incoming packets may be lost, but that
+                * can't be helped.
+                */
+               addr->ec_xcr = EC_UECLR;
+               for (i=ECRHBF; i>=ECRLBF; i--)
+                       addr->ec_rcr = EC_READ|i;
+               /*
+                * Reset and transmit next packet (if any).
+                */
+               es->es_oactive = 0;
+               es->es_mask = ~0;
+               if (es->es_if.if_snd.ifq_head)
+                       ecstart(unit);
+               return;
+       }
+       /*
+        * Do exponential backoff.  Compute delay based on low bits
+        * of the interval timer.  Then delay for that number of
+        * slot times.  A slot time is 51.2 microseconds (rounded to 51).
+        * This does not take into account the time already used to
+        * process the interrupt.
+        */
+       es->es_mask <<= 1;
+       delay = mfpr(ICR) &~ es->es_mask;
+       DELAY(delay * 51);
+       /*
+        * Clear the controller's collision flag, thus enabling retransmit.
+        */
+       addr->ec_xcr = EC_CLEAR;
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  If can't determine length
+ * from type, then have to drop packet.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
+ecrint(unit)
+       int unit;
+{
+       struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
+
+       while (addr->ec_rcr & EC_RDONE)
+               ecread(unit);
+}
+
+ecread(unit)
+       int unit;
+{
+       register struct ec_softc *es = &ec_softc[unit];
+       struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
+       register struct ether_header *ec;
+       struct mbuf *m;
+       int len, off, resid, ecoff, rbuf;
+       register struct ifqueue *inq;
+       u_char *ecbuf;
+
+       es->es_if.if_ipackets++;
+       rbuf = addr->ec_rcr & EC_RBN;
+       if (rbuf < ECRLBF || rbuf > ECRHBF)
+               panic("ecrint");
+       ecbuf = es->es_buf[rbuf];
+       ecoff = *(short *)ecbuf;
+       if (ecoff <= ECRDOFF || ecoff > 2046) {
+               es->es_if.if_ierrors++;
+#ifdef notdef
+               if (es->es_if.if_ierrors % 100 == 0)
+                       printf("ec%d: += 100 input errors\n", unit);
+#endif
+               goto setup;
+       }
+
+       /*
+        * 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 = ecoff - ECRDOFF - sizeof (struct ether_header);
+       ec = (struct ether_header *)(ecbuf + ECRDOFF);
+       ec->ether_type = ntohs((u_short)ec->ether_type);
+#define        ecdataaddr(ec, off, type)       ((type)(((caddr_t)((ec)+1)+(off))))
+       if (ec->ether_type >= ETHERPUP_TRAIL &&
+           ec->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
+               off = (ec->ether_type - ETHERPUP_TRAIL) * 512;
+               if (off >= ETHERMTU)
+                       goto setup;             /* sanity */
+               ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *));
+               resid = ntohs(*(ecdataaddr(ec, off+2, u_short *)));
+               if (off + resid > len)
+                       goto setup;             /* sanity */
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0)
+               goto setup;
+
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; ecget 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 = ecget(ecbuf, len, off);
+       if (m == 0)
+               goto setup;
+       if (off) {
+               m->m_off += 2 * sizeof (u_short);
+               m->m_len -= 2 * sizeof (u_short);
+       }
+       switch (ec->ether_type) {
+
+#ifdef INET
+       case ETHERPUP_IPTYPE:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+
+       case ETHERPUP_ARPTYPE:
+               arpinput(&es->es_ac, m);
+               goto setup;
+#endif
+       default:
+               m_freem(m);
+               goto setup;
+       }
+
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+               goto setup;
+       }
+       IF_ENQUEUE(inq, m);
+
+setup:
+       /*
+        * Reset for next packet.
+        */
+       addr->ec_rcr = EC_READ|EC_RCLR|rbuf;
+}
+
+/*
+ * 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.
+ * 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.
+ */
+ecoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       int type, s, error;
+       u_char edst[6];
+       struct in_addr idst;
+       register struct ec_softc *es = &ec_softc[ifp->if_unit];
+       register struct mbuf *m = m0;
+       register struct ether_header *ec;
+       register int off;
+       struct mbuf *mcopy = (struct mbuf *)0;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               idst = ((struct sockaddr_in *)dst)->sin_addr;
+               if (!arpresolve(&es->es_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)
+               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 *) = ntohs((u_short)ETHERPUP_IPTYPE);
+                       *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
+                       goto gottrailertype;
+               }
+               type = ETHERPUP_IPTYPE;
+               off = 0;
+               goto gottype;
+#endif
+
+       case AF_UNSPEC:
+               ec = (struct ether_header *)dst->sa_data;
+               bcopy((caddr_t)ec->ether_dhost, (caddr_t)edst, sizeof (edst));
+               type = ec->ether_type;
+               goto gottype;
+
+       default:
+               printf("ec%d: can't handle af%d\n", ifp->if_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 (struct ether_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct ether_header);
+       } else {
+               m->m_off -= sizeof (struct ether_header);
+               m->m_len += sizeof (struct ether_header);
+       }
+       ec = mtod(m, struct ether_header *);
+       bcopy((caddr_t)edst, (caddr_t)ec->ether_dhost, sizeof (edst));
+       ec->ether_type = htons((u_short)type);
+       bcopy((caddr_t)es->es_addr, (caddr_t)ec->ether_shost, 6);
+
+       /*
+        * 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);
+       if (es->es_oactive == 0)
+               ecstart(ifp->if_unit);
+       splx(s);
+       return (mcopy ? looutput(&loif, mcopy, dst) : 0);
+
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return (error);
+}
+
+/*
+ * Routine to copy from mbuf chain to transmit
+ * buffer in UNIBUS memory.
+ * 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.
+ */
+ecput(ecbuf, m)
+       u_char *ecbuf;
+       struct mbuf *m;
+{
+       register struct mbuf *mp;
+       register int off;
+       u_char *bp;
+
+       for (off = 2048, mp = m; mp; mp = mp->m_next)
+               off -= mp->m_len;
+       if (2048 - off < ETHERMIN + sizeof (struct ether_header))
+               off = 2048 - ETHERMIN - sizeof (struct ether_header);
+       *(u_short *)ecbuf = off;
+       bp = (u_char *)(ecbuf + off);
+       for (mp = m; mp; mp = mp->m_next) {
+               register unsigned len = mp->m_len;
+               u_char *mcp;
+
+               if (len == 0)
+                       continue;
+               mcp = mtod(mp, u_char *);
+               if ((unsigned)bp & 01) {
+                       *bp++ = *mcp++;
+                       len--;
+               }
+               if (off = (len >> 1)) {
+                       register u_short *to, *from;
+
+                       to = (u_short *)bp;
+                       from = (u_short *)mcp;
+                       do
+                               *to++ = *from++;
+                       while (--off > 0);
+                       bp = (u_char *)to,
+                       mcp = (u_char *)from;
+               }
+               if (len & 01)
+                       *bp++ = *mcp++;
+       }
+       m_freem(m);
+}
+
+/*
+ * Routine to copy from UNIBUS memory into mbufs.
+ * Similar in spirit to if_rubaget.
+ *
+ * Warning: This makes the fairly safe assumption that
+ * mbufs have even lengths.
+ */
+struct mbuf *
+ecget(ecbuf, totlen, off0)
+       u_char *ecbuf;
+       int totlen, off0;
+{
+       register struct mbuf *m;
+       struct mbuf *top = 0, **mp = &top;
+       register int off = off0, len;
+       u_char *cp;
+
+       cp = ecbuf + ECRDOFF + sizeof (struct ether_header);
+       while (totlen > 0) {
+               register int words;
+               u_char *mcp;
+
+               MGET(m, M_DONTWAIT, MT_DATA);
+               if (m == 0)
+                       goto bad;
+               if (off) {
+                       len = totlen - off;
+                       cp = ecbuf + ECRDOFF +
+                               sizeof (struct ether_header) + off;
+               } 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 *);
+               if (words = (len >> 1)) {
+                       register u_short *to, *from;
+
+                       to = (u_short *)mcp;
+                       from = (u_short *)cp;
+                       do
+                               *to++ = *from++;
+                       while (--words > 0);
+                       mcp = (u_char *)to;
+                       cp = (u_char *)from;
+               }
+               if (len & 01)
+                       *mcp++ = *cp++;
+               *mp = m;
+               mp = &m->m_next;
+               if (off == 0) {
+                       totlen -= len;
+                       continue;
+               }
+               off += len;
+               if (off == totlen) {
+                       cp = ecbuf + ECRDOFF + sizeof (struct ether_header);
+                       off = 0;
+                       totlen = off0;
+               }
+       }
+       return (top);
+bad:
+       m_freem(top);
+       return (0);
+}
+
+/*
+ * Process an ioctl request.
+ */
+ecioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       register struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               ecsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               ecinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+ecsetaddr(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;
+}
diff --git a/usr/src/sys/vaxif/if_ecreg.h b/usr/src/sys/vaxif/if_ecreg.h
new file mode 100644 (file)
index 0000000..6c23072
--- /dev/null
@@ -0,0 +1,59 @@
+/*     if_ecreg.h      6.1     83/07/29        */
+
+/*
+ * 3Com Ethernet controller registers.
+ */
+struct ecdevice {
+       short   ec_rcr;         /* Receive Control Register */
+       short   ec_xcr;         /* Transmit Control Register */
+};
+
+/*
+ * Control and status bits -- rcr
+ */
+#define        EC_SPIE         0x8000          /* set parity interrupt enable */
+#define        EC_ASTEP        0x4000          /* increment address counter */
+#define        EC_AROM         0x2000          /* 1: Use address ROM, 0: use RAM */
+#define        EC_PE           0x2000          /* Parity error */
+#define        EC_AWCLK        0x1000          /* address write clock bit */
+#define        EC_PIE          0x1000          /* Parity interrupt enable (read) */
+#define        EC_ADATA        0x0f00          /* address/filtering */
+#define        EC_RDONE        0x0080          /* receive done */
+#define        EC_MDISAB       0x0080          /* memory disable */
+#define        EC_RINTEN       0x0040          /* receive interrupt enable */
+#define        EC_RCLR         0x0020          /* clear RDONE bit */
+#define        EC_RWBN         0x0010          /* submit buffer for receive */
+#define        EC_RBN          0x000f          /* buffer number */
+
+#define        EC_RBITS        "\10\16PE\15PIE\10RDONE\7RINTEN"
+
+/*
+ * Control and status bits -- xcr
+ */
+#define        EC_JAM          0x8000          /* collision dectected */
+#define        EC_JINTEN       0x4000          /* collision interrupt enable */
+#define        EC_JCLR         0x2000          /* clear collision detect */
+#define        EC_UECLR        0x0100          /* reset controller */
+#define        EC_XDONE        0x0080          /* transmit done */
+#define        EC_XINTEN       0x0040          /* transmit interrupt enable */
+#define        EC_XCLR         0x0020          /* clear XDONE bit */
+#define        EC_XWBN         0x0010          /* submit buffer for transmit */
+#define        EC_XBN          0x000f          /* buffer number */
+
+#define        EC_XBITS        "\10\20JAM\17JINTEN\10XDONE\7XINTEN"
+
+/*
+ * Useful combinations
+ */
+#define        EC_READ         (EC_AROM|0x600|EC_RINTEN|EC_RWBN)
+#define        EC_WRITE        (EC_JINTEN|EC_XINTEN|EC_XWBN)
+#define        EC_CLEAR        (EC_JINTEN|EC_XINTEN|EC_JCLR)
+
+/*
+ * Buffer number definitions
+ */
+#define        ECTBF           0               /* Buffer for transmit */
+#define        ECRLBF          1               /* First buffer for receive */
+#define        ECRHBF          15              /* Last buffer for receive */
+
+#define        ECRDOFF         528             /* Packet offset in read buffer */
diff --git a/usr/src/sys/vaxif/if_en.c b/usr/src/sys/vaxif/if_en.c
new file mode 100644 (file)
index 0000000..109e7a1
--- /dev/null
@@ -0,0 +1,661 @@
+/*     if_en.c 6.1     83/07/29        */
+
+#include "en.h"
+
+/*
+ * Xerox prototype (3 Mb) Ethernet interface driver.
+ */
+#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/errno.h"
+#include "../h/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+#include "../netpup/pup.h"
+#include "../netpup/ether.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_en.h"
+#include "../vaxif/if_enreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define        ENMTU   (1024+512)
+#define        ENMRU   (1024+512+16)           /* 16 is enough to receive trailer */
+
+int    enprobe(), enattach(), enrint(), enxint(), encollide();
+struct uba_device *eninfo[NEN];
+u_short enstd[] = { 0 };
+struct uba_driver endriver =
+       { enprobe, 0, enattach, 0, enstd, "en", eninfo };
+#define        ENUNIT(x)       minor(x)
+
+int    eninit(),enoutput(),enreset(),enioctl();
+
+#ifdef notdef
+/*
+ * If you need to byte swap IP's in the system, define
+ * this and do a SIOCSIFFLAGS at boot time.
+ */
+#define        ENF_SWABIPS     0x100
+#endif
+
+/*
+ * 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, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct en_softc {
+       struct  ifnet es_if;            /* network-visible interface */
+       struct  ifuba es_ifuba;         /* UNIBUS resources */
+       short   es_delay;               /* current output delay */
+       short   es_mask;                /* mask for current output delay */
+       short   es_lastx;               /* host last transmitted to */
+       short   es_oactive;             /* is output active? */
+       short   es_olen;                /* length of last output */
+} en_softc[NEN];
+
+/*
+ * Do output DMA to determine interface presence and
+ * interrupt vector.  DMA is too short to disturb other hosts.
+ */
+enprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct endevice *addr = (struct endevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       enrint(0); enxint(0); encollide(0);
+#endif
+       addr->en_istat = 0;
+       addr->en_owc = -1;
+       addr->en_oba = 0;
+       addr->en_ostat = EN_IEN|EN_GO;
+       DELAY(100000);
+       addr->en_ostat = 0;
+       return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+enattach(ui)
+       struct uba_device *ui;
+{
+       register struct en_softc *es = &en_softc[ui->ui_unit];
+
+       es->es_if.if_unit = ui->ui_unit;
+       es->es_if.if_name = "en";
+       es->es_if.if_mtu = ENMTU;
+       es->es_if.if_init = eninit;
+       es->es_if.if_output = enoutput;
+       es->es_if.if_ioctl = enioctl;
+       es->es_if.if_reset = enreset;
+       es->es_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16 | UBA_CANTWAIT;
+#if defined(VAX750)
+       /* don't chew up 750 bdp's */
+       if (cpu == VAX_750 && ui->ui_unit > 0)
+               es->es_ifuba.ifu_flags &= ~UBA_NEEDBDP;
+#endif
+       if_attach(&es->es_if);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+enreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" en%d", unit);
+       eninit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+eninit(unit)
+       int unit;
+{
+       register struct en_softc *es = &en_softc[unit];
+       register struct uba_device *ui = eninfo[unit];
+       register struct endevice *addr;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&es->es_if.if_addr;
+       int s;
+
+       if (in_netof(sin->sin_addr) == 0)
+               return;
+       if (if_ubainit(&es->es_ifuba, ui->ui_ubanum,
+           sizeof (struct en_header), (int)btoc(ENMRU)) == 0) { 
+               printf("en%d: can't initialize\n", unit);
+               es->es_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       addr = (struct endevice *)ui->ui_addr;
+       addr->en_istat = addr->en_ostat = 0;
+
+       /*
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
+        */
+       s = splimp();
+       addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
+       addr->en_istat = EN_IEN|EN_GO;
+       es->es_oactive = 1;
+       es->es_if.if_flags |= IFF_UP|IFF_RUNNING;
+       enxint(unit);
+       splx(s);
+       if_rtinit(&es->es_if, RTF_UP);
+}
+
+int    enalldelay = 0;
+int    enlastdel = 50;
+int    enlastmask = (~0) << 5;
+
+/*
+ * Start or restart output on interface.
+ * If interface is already active, then this is a retransmit
+ * after a collision, and just restuff registers and delay.
+ * If interface is not already active, get another datagram
+ * to send off of the interface queue, and map it to the interface
+ * before starting the output.
+ */
+enstart(dev)
+       dev_t dev;
+{
+        int unit = ENUNIT(dev);
+       struct uba_device *ui = eninfo[unit];
+       register struct en_softc *es = &en_softc[unit];
+       register struct endevice *addr;
+       struct mbuf *m;
+       int dest;
+
+       if (es->es_oactive)
+               goto restart;
+
+       /*
+        * Not already active: dequeue another request
+        * and map it to the UNIBUS.  If no more requests,
+        * just return.
+        */
+       IF_DEQUEUE(&es->es_if.if_snd, m);
+       if (m == 0) {
+               es->es_oactive = 0;
+               return;
+       }
+       dest = mtod(m, struct en_header *)->en_dhost;
+       es->es_olen = if_wubaput(&es->es_ifuba, m);
+#ifdef ENF_SWABIPS
+       /*
+        * The Xerox interface does word at a time DMA, so
+        * someone must do byte swapping of user data if high
+        * and low ender machines are to communicate.  It doesn't
+        * belong here, but certain people depend on it, so...
+        *
+        * Should swab everybody, but this is a kludge anyway.
+        */
+       if (es->es_if.if_flags & ENF_SWABIPS) {
+               register struct en_header *en;
+
+               en = (struct en_header *)es->es_ifuba.ifu_w.ifrw_addr;
+               if (en->en_type == ENTYPE_IP)
+                       enswab((caddr_t)(en + 1), (caddr_t)(en + 1),
+                           es->es_olen - sizeof (struct en_header) + 1);
+       }
+#endif
+
+       /*
+        * Ethernet cannot take back-to-back packets (no
+        * buffering in interface.  To help avoid overrunning
+        * receivers, enforce a small delay (about 1ms) in interface:
+        *      * between all packets when enalldelay
+        *      * whenever last packet was broadcast
+        *      * whenever this packet is to same host as last packet
+        */
+       if (enalldelay || es->es_lastx == 0 || es->es_lastx == dest) {
+               es->es_delay = enlastdel;
+               es->es_mask = enlastmask;
+       }
+       es->es_lastx = dest;
+
+restart:
+       /*
+        * Have request mapped to UNIBUS for transmission.
+        * Purge any stale data from this BDP, and start the otput.
+        */
+       if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_w.ifrw_bdp);
+       addr = (struct endevice *)ui->ui_addr;
+       addr->en_oba = (int)es->es_ifuba.ifu_w.ifrw_info;
+       addr->en_odelay = es->es_delay;
+       addr->en_owc = -((es->es_olen + 1) >> 1);
+       addr->en_ostat = EN_IEN|EN_GO;
+       es->es_oactive = 1;
+}
+
+/*
+ * Ethernet interface transmitter interrupt.
+ * Start another output if more data to send.
+ */
+enxint(unit)
+       int unit;
+{
+       register struct uba_device *ui = eninfo[unit];
+       register struct en_softc *es = &en_softc[unit];
+       register struct endevice *addr = (struct endevice *)ui->ui_addr;
+
+       if (es->es_oactive == 0)
+               return;
+       if (es->es_mask && (addr->en_ostat&EN_OERROR)) {
+               es->es_if.if_oerrors++;
+               endocoll(unit);
+               return;
+       }
+       es->es_if.if_opackets++;
+       es->es_oactive = 0;
+       es->es_delay = 0;
+       es->es_mask = ~0;
+       if (es->es_ifuba.ifu_xtofree) {
+               m_freem(es->es_ifuba.ifu_xtofree);
+               es->es_ifuba.ifu_xtofree = 0;
+       }
+       if (es->es_if.if_snd.ifq_head == 0) {
+               es->es_lastx = 256;             /* putatively illegal */
+               return;
+       }
+       enstart(unit);
+}
+
+/*
+ * Collision on ethernet interface.  Do exponential
+ * backoff, and retransmit.  If have backed off all
+ * the way print warning diagnostic, and drop packet.
+ */
+encollide(unit)
+       int unit;
+{
+       struct en_softc *es = &en_softc[unit];
+
+       es->es_if.if_collisions++;
+       if (es->es_oactive == 0)
+               return;
+       endocoll(unit);
+}
+
+endocoll(unit)
+       int unit;
+{
+       register struct en_softc *es = &en_softc[unit];
+
+       /*
+        * Es_mask is a 16 bit number with n low zero bits, with
+        * n the number of backoffs.  When es_mask is 0 we have
+        * backed off 16 times, and give up.
+        */
+       if (es->es_mask == 0) {
+               printf("en%d: send error\n", unit);
+               enxint(unit);
+               return;
+       }
+       /*
+        * Another backoff.  Restart with delay based on n low bits
+        * of the interval timer.
+        */
+       es->es_mask <<= 1;
+       es->es_delay = mfpr(ICR) &~ es->es_mask;
+       enstart(unit);
+}
+
+#ifdef notdef
+struct sockproto enproto = { AF_ETHERLINK };
+struct sockaddr_en endst = { AF_ETHERLINK };
+struct sockaddr_en ensrc = { AF_ETHERLINK };
+#endif
+/*
+ * Ethernet interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  If can't determine length
+ * from type, then have to drop packet.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
+enrint(unit)
+       int unit;
+{
+       register struct en_softc *es = &en_softc[unit];
+       struct endevice *addr = (struct endevice *)eninfo[unit]->ui_addr;
+       register struct en_header *en;
+       struct mbuf *m;
+       int len; short resid;
+       register struct ifqueue *inq;
+       int off;
+
+       es->es_if.if_ipackets++;
+
+       /*
+        * Purge BDP; drop if input error indicated.
+        */
+       if (es->es_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(es->es_ifuba.ifu_uba, es->es_ifuba.ifu_r.ifrw_bdp);
+       if (addr->en_istat&EN_IERROR) {
+               es->es_if.if_ierrors++;
+               goto setup;
+       }
+
+       /*
+        * Calculate 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.
+        */
+       resid = addr->en_iwc;
+       if (resid)
+               resid |= 0176000;
+       len = (((sizeof (struct en_header) + ENMRU) >> 1) + resid) << 1;
+       len -= sizeof (struct en_header);
+       if (len > ENMRU)
+               goto setup;                     /* sanity */
+       en = (struct en_header *)(es->es_ifuba.ifu_r.ifrw_addr);
+       en->en_type = ntohs(en->en_type);
+#define        endataaddr(en, off, type)       ((type)(((caddr_t)((en)+1)+(off))))
+       if (en->en_type >= ENTYPE_TRAIL &&
+           en->en_type < ENTYPE_TRAIL+ENTYPE_NTRAILER) {
+               off = (en->en_type - ENTYPE_TRAIL) * 512;
+               if (off > ENMTU)
+                       goto setup;             /* sanity */
+               en->en_type = ntohs(*endataaddr(en, off, u_short *));
+               resid = ntohs(*(endataaddr(en, off+2, u_short *)));
+               if (off + resid > len)
+                       goto setup;             /* sanity */
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0)
+               goto setup;
+#ifdef ENF_SWABIPS
+       if (es->es_if.if_flags & ENF_SWABIPS && en->en_type == ENTYPE_IP)
+               enswab((caddr_t)(en + 1), (caddr_t)(en + 1), len);
+#endif
+       /*
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; if_rubaget 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 = if_rubaget(&es->es_ifuba, len, off);
+       if (m == 0)
+               goto setup;
+       if (off) {
+               m->m_off += 2 * sizeof (u_short);
+               m->m_len -= 2 * sizeof (u_short);
+       }
+       switch (en->en_type) {
+
+#ifdef INET
+       case ENTYPE_IP:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+#endif
+#ifdef PUP
+       case ENTYPE_PUP:
+               rpup_input(m);
+               goto setup;
+#endif
+       default:
+#ifdef notdef
+               enproto.sp_protocol = en->en_type;
+               endst.sen_host = en->en_dhost;
+               endst.sen_net = ensrc.sen_net = es->es_if.if_net;
+               ensrc.sen_host = en->en_shost;
+               raw_input(m, &enproto,
+                   (struct sockaddr *)&ensrc, (struct sockaddr *)&endst);
+#else
+               m_freem(m);
+#endif
+               goto setup;
+       }
+
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+
+setup:
+       /*
+        * Reset for next packet.
+        */
+       addr->en_iba = es->es_ifuba.ifu_r.ifrw_info;
+       addr->en_iwc = -(sizeof (struct en_header) + ENMRU) >> 1;
+       addr->en_istat = EN_IEN|EN_GO;
+}
+
+/*
+ * 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.
+ */
+enoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       int type, dest, s, error;
+       register struct mbuf *m = m0;
+       register struct en_header *en;
+       register int off;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+               if (in_lnaof(*((struct in_addr *)&dest)) >= 0x100) {
+                       error = EPERM;          /* ??? */
+                       goto bad;
+               }
+               dest = (dest >> 24) & 0xff;
+               off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
+               /* need per host negotiation */
+               if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
+               if (off > 0 && (off & 0x1ff) == 0 &&
+                   m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
+                       type = ENTYPE_TRAIL + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = htons((u_short)ENTYPE_IP);
+                       *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
+                       goto gottrailertype;
+               }
+               type = ENTYPE_IP;
+               off = 0;
+               goto gottype;
+#endif
+#ifdef PUP
+       case AF_PUP:
+               dest = ((struct sockaddr_pup *)dst)->spup_host;
+               type = ENTYPE_PUP;
+               off = 0;
+               goto gottype;
+#endif
+
+#ifdef notdef
+       case AF_ETHERLINK:
+               goto gotheader;
+#endif
+
+       default:
+               printf("en%d: can't handle af%d\n", ifp->if_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 (struct en_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct en_header);
+       } else {
+               m->m_off -= sizeof (struct en_header);
+               m->m_len += sizeof (struct en_header);
+       }
+       en = mtod(m, struct en_header *);
+       en->en_shost = ifp->if_host[0];
+       en->en_dhost = dest;
+       en->en_type = htons((u_short)type);
+
+gotheader:
+       /*
+        * 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);
+       if (en_softc[ifp->if_unit].es_oactive == 0)
+               enstart(ifp->if_unit);
+       splx(s);
+       return (0);
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return (error);
+}
+
+/*
+ * Process an ioctl request.
+ */
+enioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               ensetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       eninit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+ensetaddr(ifp, sin)
+       register struct ifnet *ifp;
+       register struct sockaddr_in *sin;
+{
+       struct endevice *enaddr;
+
+       ifp->if_net = in_netof(sin->sin_addr);
+       enaddr = (struct endevice *)eninfo[ifp->if_unit]->ui_addr;
+       ifp->if_host[0] = (~enaddr->en_addr) & 0xff;
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
+       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;
+}
+
+#ifdef ENF_SWABIPS
+/*
+ * Swab bytes
+ * Jeffrey Mogul, Stanford
+ */
+enswab(from, to, n)
+       register caddr_t *from, *to;
+       register int n;
+{
+       register unsigned long temp;
+       
+       n >>= 1; n++;
+#define        STEP    temp = *from++,*to++ = *from++,*to++ = temp
+       /* round to multiple of 8 */
+       while ((--n) & 07)
+               STEP;
+       n >>= 3;
+       while (--n >= 0) {
+               STEP; STEP; STEP; STEP;
+               STEP; STEP; STEP; STEP;
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_en.h b/usr/src/sys/vaxif/if_en.h
new file mode 100644 (file)
index 0000000..31e090e
--- /dev/null
@@ -0,0 +1,22 @@
+/*     if_en.h 6.1     83/07/29        */
+
+/*
+ * Structure of a Ethernet header.
+ */
+struct en_header {
+       u_char  en_shost;
+       u_char  en_dhost;
+       u_short en_type;
+};
+
+#define        ENTYPE_PUP      0x0200          /* PUP protocol */
+#define        ENTYPE_IP       0x0201          /* IP protocol */
+
+/*
+ * The ENTYPE_NTRAILER packet types starting at
+ * ENTYPE_TRAIL have (type-ENTYPE_TRAIL)*512 bytes
+ * of data followed by an Ethernet type (as given above)
+ * and then the (variable-length) header.
+ */
+#define        ENTYPE_TRAIL    0x1000          /* Trailer type */
+#define        ENTYPE_NTRAILER 16
diff --git a/usr/src/sys/vaxif/if_enreg.h b/usr/src/sys/vaxif/if_enreg.h
new file mode 100644 (file)
index 0000000..38d1d8d
--- /dev/null
@@ -0,0 +1,32 @@
+/*     if_enreg.h      6.1     83/07/29        */
+
+/*
+ * Xerox experimental ethernet registers.
+ *
+ * N.B.: status register and device address are read/write,
+ * device address is read-only, rest are WRITE ONLY!
+ */
+struct endevice {
+       short   en_owc;         /* output word count (10 bits) */
+       short   en_oba;         /* output buffer address */
+       short   en_ostat;       /* output control and status */
+       short   en_odelay;      /* output start delay, 25usec units  */
+       short   en_iwc;         /* input word count */
+       short   en_iba;         /* input buffer address */
+       short   en_istat;       /* input csr */
+       short   en_addr;        /* ~device address (low 8 bits) */
+};
+
+/*
+ * Control and status bits.
+ */
+#define EN_IERROR      0x8000          /* CRC error, buf ovflo or overrun */
+#define        EN_OERROR       0x8000          /* collision or output underrun */
+#define EN_OPDONE      0x0080          /* previous operation completed */
+#define EN_IEN         0x0040          /* enable interrupt when DONE */
+#define        EN_PROMISCUOUS  0x0002          /* promiscuous, input any packet */
+#define EN_GO          0x0001          /* start op bit */
+
+#define        EN_BITS "\10\20ERR\10OPDONE\7IEN\2PROM\1GO"
+
+#define        spl_enet()      spl5()
diff --git a/usr/src/sys/vaxif/if_ether.h b/usr/src/sys/vaxif/if_ether.h
new file mode 100644 (file)
index 0000000..1289d65
--- /dev/null
@@ -0,0 +1,24 @@
+/*     if_ether.h      4.3     82/12/16        */
+
+/*
+ * Structure of a 10Mb/s Ethernet header.
+ */
+struct ether_header {
+       u_char  ether_dhost[6];
+       u_char  ether_shost[6];
+       u_short ether_type;
+};
+
+#define        ETHERPUP_PUPTYPE        0x0400          /* PUP protocol */
+#define        ETHERPUP_IPTYPE         0x0800          /* IP protocol */
+
+/*
+ * The ETHERPUP_NTRAILER packet types starting at ETHERPUP_TRAIL have
+ * (type-ETHERPUP_TRAIL)*512 bytes of data followed
+ * by a PUP type (as given above) and then the (variable-length) header.
+ */
+#define        ETHERPUP_TRAIL          0x1000          /* Trailer PUP */
+#define        ETHERPUP_NTRAILER       16
+
+#define        ETHERMTU        1500
+#define        ETHERMIN        (60-14)
diff --git a/usr/src/sys/vaxif/if_hy.c b/usr/src/sys/vaxif/if_hy.c
new file mode 100644 (file)
index 0000000..250cd71
--- /dev/null
@@ -0,0 +1,1274 @@
+/*     if_hy.c 6.1     83/07/29        */
+
+#include "hy.h"
+#if NHY > 0
+
+/*
+ * Network Systems Copropration Hyperchanel interface
+ *
+ * UNTESTED WITH 4.2
+ */
+#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/errno.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+#include "../vaxif/if_hy.h"
+#include "../vaxif/if_hyreg.h"
+#include "../vaxif/if_uba.h"
+
+#define HYROUTE
+#define HYELOG
+#define        HYMTU   576
+
+int    hyprobe(), hyattach(), hyinit(), hyioctl();
+int    hyoutput(), hyreset(), hywatch();
+struct uba_device *hyinfo[NHY];
+u_short hystd[] = { 0772410, 0 };
+struct uba_driver hydriver =
+       { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
+
+/*
+ * Hyperchannel software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * hy_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct hy_softc {
+       struct  ifnet hy_if;            /* network-visible interface */
+       struct  ifuba hy_ifuba;         /* UNIBUS resources */
+       short   hy_flags;               /* flags */
+       short   hy_state;               /* driver state */
+       int     hy_ilen;                /* mp length on input */
+       int     hy_olen;                /* packet length on output */
+       int     hy_lastwcr;             /* last command's word count */
+       short   hy_savedstate;          /* saved for reissue after status */
+       short   hy_savedcmd;            /* saved command for reissue */
+       int     hy_savedcount;          /* saved byte count for reissue */
+       int     hy_savedaddr;           /* saved unibus address for reissue */
+       int     hy_ntime;               /* number of timeouts since last cmd */
+       int     hy_retry;               /* retry counter */
+       struct  hy_stat hy_stat;        /* statistics */
+       struct  hy_status hy_status;    /* status */
+} hy_softc[NHY];
+
+#ifdef HYELOG
+#define HYE_MAX        0x18
+u_long hy_elog[(HYE_MAX+1)*4];
+#endif
+
+#ifdef DEBUG
+#define printL lprintf
+#define printD if (hy_debug_flag) lprintf
+int    hy_debug_flag = 0;
+/*
+ * hy_nodebug bit 0x01 set hy_debug_flag on hycancel
+ * hy_nodebug bit 0x02 set hy_debug_flag on command reissue
+ * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt
+ * hy_nodebug bit 0x08 set hy_debug_flag on hyouput
+ * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data
+ */
+int    hy_nodebug = 0x0;
+#else
+#define printD hyvoid
+#endif
+
+/*
+ * Requests for service (in order by descending priority).
+ */
+#define RQ_ENDOP       001     /* end the last adapter function */
+#define RQ_REISSUE     002     /* reissue previous cmd after status */
+#define RQ_STATUS      004     /* get the status of the adapter */
+#define RQ_STATISTICS  010     /* get the statistics of the adapter */
+#define RQ_MARKDOWN    020     /* mark this adapter port down */
+#define RQ_MARKUP      040     /* mark this interface up */
+
+#define RQ_XASSOC      0100    /* associated data to transmit */
+
+/* 
+ * Driver states.
+ */
+#define        STARTUP         0       /* initial state (before fully there) */
+#define        IDLE            1       /* idle state */
+#define        STATSENT        2       /* status cmd sent to adapter */
+#define        ENDOPSENT       3       /* end operation cmd sent */
+#define        RECVSENT        4       /* input message cmd sent */
+#define        RECVDATASENT    5       /* input data cmd sent */
+#define        XMITSENT        6       /* transmit message cmd sent */
+#define        XMITDATASENT    7       /* transmit data cmd sent */
+#define        WAITING         8       /* waiting for messages */
+#define        CLEARSENT       9       /* clear wait for message cmd sent */
+#define MARKPORT       10      /* mark this host's adapter port down issued */
+#define RSTATSENT      11      /* read statistics cmd sent to adapter */
+
+#ifdef DEBUG
+char *hy_state_names[] = {
+       "Startup",
+       "Idle",
+       "Status Sent",
+       "End op Sent",
+       "Recieve Message Proper Sent",
+       "Recieve Data Sent",
+       "Transmit Message Proper Sent",
+       "Transmit Data Sent",
+       "Wait for Message Sent",
+       "Clear Wait for Message Sent",
+       "Mark Port Down Sent",
+       "Read Statistics Sent"
+};
+#endif
+
+#define SCANINTERVAL   10      /* seconds */
+#define MAXINTERVAL    20      /* seconds (max action) */
+
+/*
+ * Cause a device interrupt.  This code uses a buffer starting at
+ * location zero on the unibus (which is already mapped by the
+ * autoconfigure code in the kernel).
+ */
+hyprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct hydevice *addr = (struct hydevice *) reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       hyint(0);
+#endif
+       /*
+        * request adapter status to a buffer starting at unibus location 0
+        */
+       addr->hyd_bar = 0;
+       addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
+       addr->hyd_dbuf = HYF_STATUS;
+#ifdef PI13
+       addr->hyd_csr |= S_GO | S_IE | S_IATTN;
+#else
+       addr->hyd_csr |= S_GO | S_IE;
+#endif
+       DELAY(10000);
+#ifdef PI13
+       addr->hyd_csr |= S_CLRINT;      /* clear any stacked interrupts */
+#endif
+       addr->hyd_csr &= ~(S_IE | S_CLRINT);    /* disable further interrupts */
+       return(1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+hyattach(ui)
+       struct uba_device *ui;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+       register struct ifnet *ifp = &is->hy_if;
+
+       ifp->if_unit = ui->ui_unit;
+       ifp->if_name = "hy";
+       ifp->if_mtu = HYMTU;
+       is->hy_state = STARTUP;         /* don't allow state transitions yet */
+       ifp->if_init = hyinit;
+       ifp->if_ioctl = hyioctl;
+       ifp->if_output = hyoutput;
+       ifp->if_reset = hyreset;
+       ifp->if_watchdog = hywatch;
+       ifp->if_timer = SCANINTERVAL;
+       is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
+#ifdef notdef
+       is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
+#endif
+       if_attach(ifp);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+hyreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui = hyinfo[unit];
+
+       if (unit >= NHY || ui == 0 || ui->ui_alive == 0 ||
+         ui->ui_ubanum != uban)
+               return;
+       printf(" hy%d", unit);
+       hyinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+hyinit(unit)
+       int unit;
+{
+       register struct hy_softc *is = &hy_softc[unit];
+       register struct uba_device *ui = hyinfo[unit];
+       struct sockaddr_in *sin;
+       int s;
+
+       sin = (struct sockaddr_in *)&is->hy_if.if_addr;
+       if (in_netof(sin->sin_addr) == 0)
+               return;
+       if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
+           sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 
+#ifdef DEBUG
+               if (hy_nodebug & 4)
+                       hy_debug_flag = 1;
+#endif
+               printf("hy%d: can't initialize\n", unit);
+               is->hy_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       is->hy_if.if_flags |= IFF_RUNNING;
+       /*
+        * Issue wait for message and start the state machine
+        */
+       s = splimp();
+       is->hy_state = IDLE;
+       is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
+       is->hy_retry = 0;
+       hyact(ui);
+       splx(s);
+}
+
+/*
+ * Issue a command to the adapter
+ */
+hystart(ui, cmd, count, ubaddr)
+       struct uba_device *ui;
+       int cmd, count, ubaddr;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+       register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
+
+#ifdef DEBUG
+       printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
+               ui->ui_unit, cmd, count, ubaddr);
+       printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
+               ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
+               addr->hyd_wcr);
+#endif
+       if (((is->hy_flags & RQ_REISSUE) == 0) &&
+         (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
+               is->hy_savedstate = is->hy_state;
+               is->hy_savedcmd = cmd;
+               is->hy_savedcount = count;
+               is->hy_savedaddr = ubaddr;
+       }
+       addr->hyd_bar = ubaddr & 0xffff;
+       addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
+       addr->hyd_dbuf = cmd;
+#ifdef PI13
+       addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
+#else
+       addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
+#endif
+#ifdef DEBUG
+       printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
+               ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
+               addr->hyd_wcr);
+#endif
+#ifdef HYLOG
+       {
+               struct {
+                       u_char  hcmd;
+                       u_char  hstate;
+                       short   hcount;
+               } hcl;
+
+               hcl.hcmd = cmd;
+               hcl.hstate = is->hy_state;
+               hcl.hcount = count;
+               hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
+       }
+#endif
+       is->hy_ntime = 0;
+}
+
+int hyint_active = 0;          /* set during hy interrupt */
+/*
+ * Hyperchannel interface interrupt.
+ *
+ * An interrupt can occur for many reasons.  Examine the status of
+ * the hyperchannel status bits to determine what to do next.
+ *
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
+hyint(unit)
+       int unit;
+{
+       register struct hy_softc *is = &hy_softc[unit];
+       register struct uba_device *ui = hyinfo[unit];
+       register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
+
+       if (hyint_active)
+               panic("RECURSIVE HYPERCHANNEL INTERRUPT");
+       hyint_active++;
+#ifdef DEBUG
+       printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
+               unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
+#endif
+#ifdef HYLOG
+logit:
+       {
+               struct {
+                       u_char  hstate;
+                       u_char  hflags;
+                       short   hcsr;
+                       short   hwcr;
+               } hil;
+               hil.hstate = is->hy_state;
+               hil.hflags = is->hy_flags;
+               hil.hcsr = addr->hyd_csr;
+               hil.hwcr = addr->hyd_wcr;
+               hylog(HYL_INT, sizeof(hil), (char *)&hil);
+       }
+#endif
+       if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
+               /*
+                * Error bit set, some sort of error in the interface.
+                *
+                * The adapter sets attn on command completion so that's not
+                * a real error even though the interface considers it one.
+                */
+#ifdef DEBUG
+               if (hy_nodebug & 4)
+                       hy_debug_flag = 1;
+#endif
+               printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
+                       addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
+                       addr->hyd_wcr);
+               if (addr->hyd_csr & S_NEX) {
+                       printf("hy%d: NEX - Non Existant Memory\n", unit);
+#ifdef PI13
+                       addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
+#else
+                       addr->hyd_csr &= ~S_NEX;
+#endif
+                       hycancel(ui);
+#ifdef PI13
+               } else if (addr->hyd_csr & S_POWEROFF) {
+                       printf("hy%d: Power Off bit set, trying to reset\n",
+                               unit);
+                       addr->hyd_csr |= S_POWEROFF;
+                       DELAY(100);
+                       if (addr->hyd_csr & S_POWEROFF) {
+                               if_down(&is->hy_if);
+                               is->hy_state = STARTUP;
+                               printf(
+                                 "hy%d: Power Off Error, network shutdown\n",
+                                 unit);
+                       }
+#endif
+               } else {
+                       printf("hy%d:  BAR overflow\n", unit);
+                       hycancel(ui);
+               }
+       } else if (HYS_NORMAL(addr)) {
+               /*
+                * Normal interrupt, bump state machine unless in state
+                * waiting and no data present (assumed to be word count
+                * zero interrupt or other hardware botch).
+                */
+               if (is->hy_state != WAITING || HYS_RECVDATA(addr))
+                       hyact(ui);
+       } else if (HYS_ABNORMAL(addr)) {
+               /*
+                * Abnormal termination.
+                * bump error counts, retry the last function
+                * 'MAXRETRY' times before kicking the bucket.
+                *
+                * Don't reissue the cmd if in certain states, abnormal
+                * on a reissued cmd or max retry exceeded.
+                */
+#ifdef HYLOG
+               if (hy_log.hyl_enable != hy_log.hyl_onerr) {
+                       hy_log.hyl_enable = hy_log.hyl_onerr;
+                       goto logit;
+               }
+#endif
+#ifdef DEBUG
+               if (hy_nodebug & 4)
+                       hy_debug_flag = 1;
+               printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
+                       unit, hy_state_names[is->hy_state], is->hy_state);
+               printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
+                       is->hy_flags, is->hy_ilen, is->hy_olen,
+                       is->hy_lastwcr, is->hy_retry);
+               printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
+                       is->hy_savedstate, is->hy_savedcount,
+                       is->hy_savedaddr, is->hy_savedcmd);
+#endif
+#ifdef PI13
+               addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
+#endif
+               if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
+                       is->hy_if.if_oerrors++;
+               if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
+                       is->hy_if.if_ierrors++;
+               if (is->hy_state == XMITDATASENT ||
+                   is->hy_state == RECVSENT ||
+                   is->hy_state == RECVDATASENT ||
+                   (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
+                       hycancel(ui);
+               else {
+#ifdef DEBUG
+                       if (hy_nodebug & 2)
+                               hy_debug_flag = 1;
+#endif
+                       is->hy_retry++;
+                       is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
+                       is->hy_state = IDLE;
+                       hyact(ui);
+               }
+       } else {
+               /*
+                * Interrupt is neither normal, abnormal, or interface error.
+                * Ignore it. It's either stacked or a word count 0.
+                */
+#ifdef HYLOG
+               if (hy_log.hyl_enable != hy_log.hyl_onerr) {
+                       hy_log.hyl_enable = hy_log.hyl_onerr;
+                       goto logit;
+               }
+#endif
+#ifdef DEBUG
+               printD("hy%d: possible stacked interrupt ignored\n", unit);
+#endif
+       }
+#ifdef DEBUG
+       printD("hy%d: hyint exit\n\n", unit);
+#endif
+       hyint_active = 0;
+
+}
+
+/*
+ * Encapsulate a packet of type family for the local net.
+ */
+hyoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       register struct hym_hdr *hym;
+       register struct mbuf *m;
+#ifdef HYROUTE
+       register struct hyroute *r = &hy_route[ifp->if_unit];
+#endif
+       short dtype;            /* packet type */
+       int dhost;              /* destination adapter address */
+       int dlen;
+       int mplen = 0;          /* message proper length */
+       short loopback = 0;     /* hardware loopback requested */
+       int error = 0;
+       int s;
+
+#ifdef DEBUG
+       if (hy_nodebug & 8)
+               hy_debug_flag = 1;
+#endif
+       dlen = 0;
+       for (m = m0; m; m = m->m_next)
+               dlen += m->m_len;
+       m = m0;
+       switch(dst->sa_family) {
+
+#ifdef INET
+       case AF_INET: {
+               register struct ip *ip = mtod(m, struct ip *);
+               register struct sockaddr_in *sin = (struct sockaddr_in *)dst;
+               register long hostaddr = in_lnaof(sin->sin_addr);
+
+               dhost = hostaddr & 0xffff;
+               dtype = HYLINK_IP;
+#ifdef DEBUG
+               printD("hy%d: output to host %x, dhost %x\n",
+                       ifp->if_unit, sin->sin_addr.s_addr, dhost);
+#endif
+               /*
+                * Debugging loopback support:
+                * upper byte of 24 bit host number interpreted as follows
+                *      0x00 --> no loopback
+                *      0x01 --> hardware loop through remote adapter
+                *      other --> software loop through remote ip layer
+                */
+               if (hostaddr & 0xff0000) {
+                       struct in_addr temp;
+
+                       temp = ip->ip_dst;
+                       ip->ip_dst = ip->ip_src;
+                       ip->ip_src = temp;
+                       if ((hostaddr & 0xff0000) == 0x10000)
+                               loopback = H_LOOPBK;
+               }
+               /*
+                * If entire packet won't fit in message proper, just
+                * send hyperchannel hardware header and ip header in
+                * message proper.  If that won't fit either, just send
+                * the maximum message proper.
+                *
+                * This insures that the associated data is at least a
+                * TCP/UDP header in length and thus prevents potential
+                * problems with very short word counts.
+                */
+               if (dlen > MPSIZE - sizeof (struct hy_hdr)) {
+                       mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2);
+                       if (mplen > MPSIZE)
+                               mplen = MPSIZE;
+               }
+               break;
+       }
+#endif
+
+       default:
+               printf("hy%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+#ifdef DEBUG
+               if (hy_nodebug & 4)
+                       hy_debug_flag = 1;
+#endif
+               error = EAFNOSUPPORT;
+               goto drop;
+       }
+
+       /*
+        * Add the software and hardware hyperchannel headers.
+        * If there's not enough space in the first mbuf, allocate another.
+        * If that should fail, drop this sucker.
+        * No extra space for headers is allocated.
+        */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       m = m0;
+                       error = ENOBUFS;
+                       goto drop;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof(struct hym_hdr);
+       } else {
+               m->m_off -= sizeof(struct hym_hdr);
+               m->m_len += sizeof(struct hym_hdr);
+       }
+       hym = mtod(m, struct hym_hdr *);
+       hym->hym_mplen = mplen;
+       hym->hym_hdr.hyh_type = dtype;
+       hym->hym_hdr.hyh_off = 0;
+       hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]);
+       hym->hym_hdr.hyh_param = loopback;
+#ifdef HYROUTE
+       if (r->hyr_lasttime.tv_sec != 0) {
+               register struct hy_hash *rh;
+               register int i;
+
+               i = HYRHASH(dhost);
+               rh = &r->hyr_hash[i];
+               i = 0;
+               while (rh->hyr_key != dhost) {
+                       rh++; i++;
+                       if (rh > &r->hyr_hash[HYRSIZE])
+                               rh = &r->hyr_hash[0];
+                       if (rh->hyr_flags == 0 || i > HYRSIZE)
+                               goto notfound;
+               }
+               if (rh->hyr_flags & HYR_GATE) {
+                       loopback = 0;   /* no hardware loopback on gateways */
+                       i = rh->hyr_nextgate;
+                       if (i >= rh->hyr_egate)
+                               rh->hyr_nextgate = rh->hyr_pgate;
+                       else
+                               rh->hyr_nextgate++;
+                       rh = &r->hyr_hash[r->hyr_gateway[i]];
+                       if ((rh->hyr_flags & HYR_DIR) == 0)
+                               goto notfound;
+               }
+               hym->hym_hdr.hyh_ctl = rh->hyr_ctl;
+               hym->hym_hdr.hyh_access = rh->hyr_access;
+               hym->hym_hdr.hyh_to = rh->hyr_dst;
+       } else {
+               hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
+               hym->hym_hdr.hyh_access = 0;
+               hym->hym_hdr.hyh_to = htons((u_short)dhost);
+       }
+#else
+       hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
+       hym->hym_hdr.hyh_access = 0;
+       hym->hym_hdr.hyh_to = htons(dhost);
+#endif
+
+       if (hym->hym_mplen) {
+               hym->hym_hdr.hyh_ctl |= H_ASSOC;
+#ifdef DEBUG
+               if (hy_nodebug & 16)
+                       hy_debug_flag = 1;
+#endif
+       } else
+               hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
+#ifdef DEBUG
+       printD("hy%d: output mplen=%x ctl=%x access=%x to=%x",
+               ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
+               hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to);
+       printD(" (adapter %x) from=%x param=%x type=%x off=%x\n",
+               hym->hym_hdr.hyh_to_adapter,
+               hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
+               hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
+#endif
+       s = splimp();
+       if (IF_QFULL(&ifp->if_snd)) {
+               IF_DROP(&ifp->if_snd);
+               error = ENOBUFS;
+               splx(s);
+               goto drop;
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if (hy_softc[ifp->if_unit].hy_state == WAITING)
+               hyact(hyinfo[ifp->if_unit]);
+       splx(s);
+       return (0);
+notfound:
+       error = ENETUNREACH;                    /* XXX */
+drop:
+       m_freem(m);
+       return (error);
+}
+
+hyact(ui)
+       register struct uba_device *ui;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+       register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
+
+actloop:
+#ifdef DEBUG
+       printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
+               hy_state_names[is->hy_state]);
+#endif
+       switch (is->hy_state) {
+
+       case STARTUP:
+               goto endintr;
+
+       case IDLE: {
+               register rq = is->hy_flags;
+
+               if (rq & RQ_STATUS) {
+                       is->hy_flags &= ~RQ_STATUS;
+                       is->hy_state = STATSENT;
+                       hystart(ui, HYF_STATUS, sizeof (is->hy_status),
+                           is->hy_ifuba.ifu_r.ifrw_info);
+               } else if (rq & RQ_ENDOP) {
+                       is->hy_flags &= ~RQ_ENDOP;
+                       is->hy_state = ENDOPSENT;
+                       hystart(ui, HYF_END_OP, 0, 0);
+               } else if (rq & RQ_STATISTICS) {
+                       is->hy_flags &= ~RQ_STATISTICS;
+                       is->hy_state = RSTATSENT;
+                       hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
+                           is->hy_ifuba.ifu_r.ifrw_info);
+               } else if (HYS_RECVDATA(addr)) {
+                       is->hy_state = RECVSENT;
+                       is->hy_retry = 0;
+                       hystart(ui, HYF_INPUTMSG, MPSIZE,
+                           is->hy_ifuba.ifu_r.ifrw_info);
+               } else if (rq & RQ_REISSUE) {
+                       is->hy_flags &= ~RQ_REISSUE;
+                       is->hy_state = is->hy_savedstate;
+#ifdef DEBUG
+                       printD("hy%d: reissue cmd=0x%x count=%d",
+                         ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
+                       printD(" ubaddr=0x%x retry=%d\n",
+                         is->hy_savedaddr, is->hy_retry);
+#endif
+                       hystart(ui, is->hy_savedcmd, is->hy_savedcount,
+                           is->hy_savedaddr);
+               } else {
+                       register struct mbuf *m;
+
+                       IF_DEQUEUE(&is->hy_if.if_snd, m);
+                       if (m != NULL) {
+                               register struct hym_hdr *hym;
+                               register int mplen;
+                               register int cmd;
+
+                               is->hy_state = XMITSENT;
+                               is->hy_retry = 0;
+                               hym = mtod(m, struct hym_hdr *);
+#ifdef HYLOG
+                               hylog(HYL_XMIT, sizeof(struct hym_hdr),
+                                   (char *)hym);
+#endif
+                               mplen = hym->hym_mplen;
+                               if (hym->hym_hdr.hyh_to_adapter ==
+                                   hym->hym_hdr.hyh_from_adapter)
+                                       cmd = HYF_XMITLOCMSG;
+                               else
+                                       cmd = HYF_XMITMSG;
+#ifdef DEBUG
+                               printD("hy%d: hym_hdr = ", ui->ui_unit);
+                               if (hy_debug_flag)
+                                       hyprintdata((char *)hym,
+                                           sizeof (struct hym_hdr));
+#endif
+                               /*
+                                * Strip off the software part of
+                                * the hyperchannel header
+                                */
+                               m->m_off += sizeof(struct hym_data);
+                               m->m_len -= sizeof(struct hym_data);
+                               is->hy_olen = if_wubaput(&is->hy_ifuba, m);
+                               if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
+                                       UBAPURGE(is->hy_ifuba.ifu_uba,
+                                               is->hy_ifuba.ifu_w.ifrw_bdp);
+#ifdef DEBUG
+                               printD(
+               "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
+                                       ui->ui_unit, mplen, is->hy_olen);
+                               if (hy_debug_flag)
+                                       hyprintdata(
+                                           is->hy_ifuba.ifu_w.ifrw_addr,
+                                           is->hy_olen);
+#endif
+                               hystart(ui, cmd,
+                                   (mplen == 0) ? is->hy_olen : mplen,
+                                   is->hy_ifuba.ifu_w.ifrw_info);
+                               if (mplen != 0)
+                                       is->hy_flags |= RQ_XASSOC;
+                       } else if (rq & RQ_MARKDOWN) {
+                               is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
+                               is->hy_state = MARKPORT;
+                               is->hy_retry = 0;
+                               /*
+                                * Port number is taken from status data
+                                */
+                               hystart(ui,
+                                (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
+                                0, 0);
+                       } else if (rq & RQ_MARKUP) {
+                               register struct ifnet *ifp = &is->hy_if;
+                               register struct sockaddr_in *sin =
+                                  (struct sockaddr_in *)&ifp->if_addr;
+
+                               is->hy_flags &= ~RQ_MARKUP;
+                               is->hy_retry = 0;
+                               /*
+                                * Fill in the host number
+                                * from the status buffer
+                                */
+                               printf(
+       "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
+                                       ui->ui_unit,
+                                       is->hy_stat.hyc_uaddr,
+                                       PORTNUM(&is->hy_status),
+                                       (is->hy_stat.hyc_atype[0]<<8) |
+                                               is->hy_stat.hyc_atype[1],
+                                       is->hy_stat.hyc_atype[2]);
+
+                               ifp->if_host[0] =
+                                 (is->hy_stat.hyc_uaddr << 8) |
+                                       PORTNUM(&is->hy_status);
+                               sin->sin_addr =
+                                  if_makeaddr(ifp->if_net, ifp->if_host[0]);
+                               ifp->if_flags |= IFF_UP;
+                               if_rtinit(ifp, RTF_UP);
+#ifdef HYLOG
+                               hylog(HYL_UP, 0, (char *)0);
+#endif
+                       } else {
+                               is->hy_state = WAITING;
+                               is->hy_retry = 0;
+                               hystart(ui, HYF_WAITFORMSG, 0, 0);
+                       }
+               }
+               break;
+       }
+
+       case STATSENT:
+               bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
+                 sizeof (struct hy_status));
+#ifdef DEBUG
+               printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
+                       ui->ui_unit, is->hy_status.hys_gen_status,
+                       is->hy_status.hys_last_fcn,
+                       is->hy_status.hys_resp_trunk,
+                       is->hy_status.hys_status_trunk,
+                       is->hy_status.hys_recd_resp,
+                       is->hy_status.hys_error,
+                       is->hy_status.hys_caddr,
+                       is->hy_status.hys_pad);
+#endif
+               is->hy_state = IDLE;
+#ifdef HYLOG
+               hylog(HYL_STATUS, sizeof (struct hy_status),
+                       (char *)&is->hy_status);
+#endif
+#ifdef HYELOG
+               {
+                       register int i;
+                       
+                       i = is->hy_status.hys_error;
+                       if (i < HYE_MAX)
+                               i = HYE_MAX;
+                       switch (is->hy_status.hys_last_fcn) {
+                               case HYF_XMITLOCMSG:
+                                       i += HYE_MAX+1; /* fall through */
+                               case HYF_XMITLSTDATA:
+                                       i += HYE_MAX+1; /* fall through */
+                               case HYF_XMITMSG:
+                                       i += HYE_MAX+1;
+                       }
+                       hy_elog[i]++;
+               }
+#endif
+               break;
+
+       case RSTATSENT: {
+               register struct hy_stat *p =
+                       (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
+
+               is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
+               is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
+               is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
+               is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
+               is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
+               is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
+               is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
+               is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
+               is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
+               is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
+               is->hy_stat.hyc_uaddr = p->hyc_uaddr;
+#ifdef DEBUG
+               printD(
+       "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
+                       ui->ui_unit,
+                       is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
+                       is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
+                       is->hy_stat.hyc_crcbad);
+               printD("        mcret %d tdabort %d atype %x %x %x uaddr %x\n",
+                       is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
+                       is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
+                       is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
+#endif
+               is->hy_state = IDLE;
+#ifdef HYLOG
+               hylog(HYL_STATISTICS, sizeof (struct hy_stat),
+                       (char *)&is->hy_stat);
+#endif
+               break;
+       }
+
+       case CLEARSENT:
+               is->hy_state = IDLE;
+               break;
+
+       case ENDOPSENT:
+               is->hy_state = IDLE;
+               break;
+
+       case RECVSENT: {
+               register struct hy_hdr *hyh;
+               register unsigned len;
+
+               if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
+                       UBAPURGE(is->hy_ifuba.ifu_uba,
+                           is->hy_ifuba.ifu_r.ifrw_bdp);
+               hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
+               len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
+               if (len > MPSIZE) {
+                       printf("hy%d: RECVD MP > MPSIZE (%d)\n",
+                           ui->ui_unit, len);
+#ifdef DEBUG
+                       hy_debug_flag = 1;
+                       printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
+                               ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
+                               addr->hyd_bar, addr->hyd_wcr);
+#endif
+               }
+#ifdef DEBUG
+               printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
+               if (hy_debug_flag)
+                       hyprintdata((char *)hyh, len);
+#endif
+               if (hyh->hyh_ctl & H_ASSOC) {
+                       is->hy_state = RECVDATASENT;
+                       is->hy_ilen = len;
+                       is->hy_retry = 0;
+                       hystart(ui, HYF_INPUTDATA,
+                           (int)(HYMTU-len+sizeof (struct hy_hdr)),
+                           (int)(is->hy_ifuba.ifu_r.ifrw_info + len));
+               } else {
+                       hyrecvdata(ui, hyh, (int)len);
+                       is->hy_state = IDLE;
+               }
+               break;
+       }
+
+       case RECVDATASENT: {
+               register struct hy_hdr *hyh;
+               register unsigned len;
+
+               if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
+                       UBAPURGE(is->hy_ifuba.ifu_uba,
+                           is->hy_ifuba.ifu_r.ifrw_bdp);
+               hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
+               len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
+#ifdef DEBUG
+               printD("hy%d: recvd assoc data, len = %d, data = ",
+                       ui->ui_unit, len);
+               if (hy_debug_flag)
+                       hyprintdata((char *)hyh + is->hy_ilen, len);
+#endif
+               hyrecvdata(ui, hyh, (int)(len + is->hy_ilen));
+               is->hy_state = IDLE;
+               break;
+       }
+
+       case XMITSENT:
+               if (is->hy_flags & RQ_XASSOC) {
+                       register int len;
+
+                       is->hy_flags &= ~RQ_XASSOC;
+                       is->hy_state = XMITDATASENT;
+                       is->hy_retry = 0;
+                       len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
+                       if (len > is->hy_olen) {
+                               printf(
+                               "hy%d: xmit error - len > hy_olen [%d > %d]\n",
+                               ui->ui_unit, len, is->hy_olen);
+#ifdef DEBUG
+                               hy_debug_flag = 1;
+#endif
+                       }
+                       hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
+                           is->hy_ifuba.ifu_w.ifrw_info + len);
+                       break;
+               }
+               /* fall through to ... */
+               
+       case XMITDATASENT:
+               hyxmitdata(ui);
+               is->hy_state = IDLE;
+               break;
+
+       case WAITING:   /* wait for message complete or output requested */
+               if (HYS_RECVDATA(addr))
+                       is->hy_state = IDLE;
+               else {
+                       is->hy_state = CLEARSENT;
+                       is->hy_retry = 0;
+                       hystart(ui, HYF_CLRWFMSG, 0, 0);
+               }
+               break;
+
+       case MARKPORT:
+               is->hy_state = STARTUP;
+               is->hy_if.if_flags &= ~IFF_UP;
+               goto endintr;
+       
+       default:
+               printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
+                       ui->ui_unit, is->hy_state);
+               panic("HYPERCHANNEL IN INVALID STATE");
+               /*NOTREACHED*/
+       }
+       if (is->hy_state == IDLE)
+               goto actloop;
+endintr:
+       ;
+#ifdef DEBUG
+       printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
+               hy_state_names[is->hy_state]);
+#endif
+}
+
+/*
+ * Called from device interrupt when receiving data.
+ * Examine packet to determine type.  Decapsulate packet
+ * based on type and pass to type specific higher-level
+ * input routine.
+ */
+hyrecvdata(ui, hyh, len)
+       struct uba_device *ui;
+       register struct hy_hdr *hyh;
+       int len;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+       struct mbuf *m;
+       register struct ifqueue *inq;
+
+       is->hy_if.if_ipackets++;
+#ifdef DEBUG
+       printD("hy%d: recieved packet, len = %d (actual %d)\n",
+               ui->ui_unit, len,
+               len - (hyh->hyh_off + sizeof (struct hy_hdr)));
+#endif
+#ifdef HYLOG
+       {
+               struct {
+                       short hlen;
+                       struct hy_hdr hhdr;
+               } hh;
+               hh.hlen = len;
+               hh.hhdr = *hyh;
+               hylog(HYL_RECV, sizeof(hh), (char *)&hh);
+       }
+#endif
+       if (len > HYMTU + MPSIZE || len == 0)
+               return;                 /* sanity */
+       /*
+        * Pull packet off interface.
+        */
+       m = if_rubaget(&is->hy_ifuba, len, 0);
+       if (m == NULL)
+               return;
+       switch (hyh->hyh_type) {
+
+#ifdef INET
+       case HYLINK_IP:
+               /*
+                * Strip the variable portion of the hyperchannel header
+                * (fixed portion stripped in if_rubaget).
+                */
+               m->m_len -= hyh->hyh_off;
+               m->m_off += hyh->hyh_off;
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+#endif
+       default:
+               m_freem(m);
+               return;
+       }
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+}
+
+/*
+ * Transmit done, release resources, bump counters.
+ */
+hyxmitdata(ui)
+       struct uba_device *ui;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+
+       is->hy_if.if_opackets++;
+       if (is->hy_ifuba.ifu_xtofree) {
+               m_freem(is->hy_ifuba.ifu_xtofree);
+               is->hy_ifuba.ifu_xtofree = 0;
+       }
+}
+
+hycancel(ui)
+       register struct uba_device *ui;
+{
+       register struct hy_softc *is = &hy_softc[ui->ui_unit];
+
+       if (is->hy_ifuba.ifu_xtofree) {
+               m_freem(is->hy_ifuba.ifu_xtofree);
+               is->hy_ifuba.ifu_xtofree = 0;
+       }
+#ifdef DEBUG
+       if (hy_nodebug & 1)
+               hy_debug_flag = 1;
+#endif
+#ifdef DEBUG
+       printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
+               ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
+               is->hy_savedcount, is->hy_savedaddr);
+       printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
+               is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr,
+               is->hy_retry);
+       printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
+               is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
+               is->hy_savedcmd);
+#endif
+       is->hy_state = IDLE;
+       is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
+       hyact(ui);
+}
+
+#ifdef DEBUG
+hyprintdata(cp, len)
+       register char *cp;
+       register int len;
+{
+       register int count = 16;
+       register char *fmt;
+       static char regfmt[] = "\n\t %x";
+
+       fmt = &regfmt[2];
+       while (--len >= 0) {
+               printL(fmt, *cp++ & 0xff);
+               fmt = &regfmt[2];
+               if (--count <= 0) {
+                       fmt = &regfmt[0];
+                       count = 16;
+               }
+       }
+       printL("\n");
+}
+#endif
+
+hywatch(unit)
+       int unit;
+{
+       register struct hy_softc *is = &hy_softc[unit];
+       register struct uba_device *ui = hyinfo[unit];
+       register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
+       int s;
+
+       s = splimp();
+       is->hy_if.if_timer = SCANINTERVAL;
+       if (is->hy_ntime > 2 && is->hy_state != WAITING &&
+         is->hy_state != STARTUP && is->hy_state != IDLE) {
+               printf("hy%d: watchdog timer expired\n", unit);
+               hycancel(ui);
+       }
+#ifdef PI13
+       if ((addr->hyd_csr & S_POWEROFF) != 0) {
+               addr->hyd_csr |= S_POWEROFF;
+               DELAY(100);
+               if ((addr->hyd_csr & S_POWEROFF) == 0) {
+                       printf("hy%d: adapter power restored\n", unit);
+                       is->hy_state = IDLE;
+                       is->hy_flags |=
+                         (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
+                       hyact(ui);
+               }
+       }
+#endif
+       splx(s);
+}
+
+#ifdef HYLOG
+hylog(code, len, ptr)
+       int code, len;
+       char *ptr;
+{
+       register unsigned char *p;
+       int s;
+
+       s = splimp();
+       if (hy_log.hyl_self != &hy_log) {
+               hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
+               hy_log.hyl_ptr = &hy_log.hyl_buf[0];
+               hy_log.hyl_self = &hy_log;
+               hy_log.hyl_enable = HYL_DISABLED;
+               hy_log.hyl_onerr = HYL_CATCH1;
+       }
+       if (hy_log.hyl_enable == HYL_DISABLED ||
+         hy_log.hyl_enable == HYL_CAUGHT1 ||
+         hy_log.hyl_enable == HYL_CAUGHTSTATUS ||
+         (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
+               goto out;
+       p = hy_log.hyl_ptr;
+       if (p + len + 2 >= hy_log.hyl_eptr) {
+               bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
+               p = &hy_log.hyl_buf[0];
+               if (hy_log.hyl_enable == HYL_CATCH1) {
+                       hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
+                       goto out;
+               }
+               if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
+                       hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
+                       goto out;
+               }
+       }
+       *p++ = code;
+       *p++ = len;
+       bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
+       hy_log.hyl_ptr = p + len;
+out:
+       splx(s);
+}
+#endif
+
+/*ARGSUSED*/
+hyioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct sockaddr_in *sin;
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch(cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);
+               sin = (struct sockaddr_in *)&ifr->ifr_addr;
+               ifp->if_net = in_netof(sin->sin_addr);
+               sin = (struct sockaddr_in *)&ifp->if_addr;
+               sin->sin_family = AF_INET;
+               sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       hyinit(ifp->if_unit);
+               break;
+
+       case HYSETROUTE:
+               if (!suser()) {
+                       error = EPERM;
+                       goto bad;
+               }
+               hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data;
+               hy_route[ifp->if_unit].hyr_lasttime = time;
+               break;
+
+       case HYGETROUTE:
+               *(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit];
+               break;
+
+       default:
+               error = EINVAL;
+               break;
+       }
+bad:
+       splx(s);
+       return (error);
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_hy.h b/usr/src/sys/vaxif/if_hy.h
new file mode 100644 (file)
index 0000000..cb1f6fe
--- /dev/null
@@ -0,0 +1,54 @@
+/*     if_hy.h 6.1     83/07/29        */
+
+/*
+ * Network Systems Corporation Hyperchannel
+ *     routing database
+ */
+
+#define HYRSIZE  37    /* max number of adapters in routing tables */
+
+struct hyroute {
+       struct  timeval hyr_lasttime;           /* last update time */
+       struct hy_hash {
+               u_short hyr_flags;      /* status flags - see below */
+               u_short hyr_key;                /* desired address */
+               union {
+                       /*
+                        * direct entry (can get there directly)
+                        */
+                       struct {
+                               u_short hyru_dst;               /* adapter number & port */
+                               u_short hyru_ctl;               /* trunks to try */
+                               u_short hyru_access;    /* access code (mostly unused) */
+                       } hyr_d;
+#define        hyr_dst         hyr_u.hyr_d.hyru_dst
+#define        hyr_ctl         hyr_u.hyr_d.hyru_ctl
+#define        hyr_access      hyr_u.hyr_d.hyru_access
+                       /*
+                        * indirect entry (one or more hops required)
+                        */
+                       struct {
+                               u_char hyru_pgate;      /* 1st gateway slot */
+                               u_char hyru_egate;      /* # gateways */
+                               u_char hyru_nextgate;   /* gateway to use next */
+                       } hyr_i;
+#define        hyr_pgate       hyr_u.hyr_i.hyru_pgate
+#define        hyr_egate       hyr_u.hyr_i.hyru_egate
+#define        hyr_nextgate    hyr_u.hyr_i.hyru_nextgate
+               } hyr_u;
+       } hyr_hash[HYRSIZE];
+       u_char hyr_gateway[256];
+};
+
+#ifdef KERNEL
+struct hyroute hy_route[NHY];
+#endif
+
+#define HYR_INUSE      0x01    /* entry in use */
+#define HYR_DIR                0x02    /* direct entry */
+#define HYR_GATE       0x04    /* gateway entry */
+
+#define HYRHASH(x) (((x) ^ ((x) >> 16)) % HYRSIZE)
+
+#define        HYSETROUTE      _IOW(H, 0x80, sizeof (struct hyroute))
+#define        HYGETROUTE      _IOR(H, 0x81, sizeof (struct hyroute))
diff --git a/usr/src/sys/vaxif/if_hyreg.h b/usr/src/sys/vaxif/if_hyreg.h
new file mode 100644 (file)
index 0000000..778feef
--- /dev/null
@@ -0,0 +1,289 @@
+/*     if_hyreg.h      6.1     83/07/29        */
+
+/*
+ * Network Systems Corporation Hyperchannel interface
+ *
+ * supports A410 adapter interfaced via a DEC DR-11B, NSC PI-13 or PI-14
+ *     (PI-14 is a PI-13 with different line drivers, software is
+ *     identical to a PI-13)
+ *
+ * Written by Steve Glaser, Tektronix Inc., July 1982
+ *
+ * NOTE:
+ *
+ * DR11B code has not been fully checked out with 4.1a.
+ * The first adapters at Tek came with DR11Bs, and the code once worked,
+ * but those have been upgraded to PI-13s.
+ */
+#define        PI13    1       /* PI13 vs. DR11B device depandant code */
+#ifndef HYLOG
+#define HYLOG  1       /* enable logging of errors */
+#endif
+
+/*
+ * Structure of a HYPERchannel adapter header
+ */
+struct hy_hdr {
+       short   hyh_ctl;        /* control */
+       short   hyh_access;     /* access code */
+       union {                 /* to/from addresses */
+               short   hyh_addr;       /* full address */
+               char    hyh_baddr[2];   /* adapter/port number from address */
+       } hyhu_to, hyhu_from;
+#define        hyh_to          hyhu_to.hyh_addr
+#define        hyh_from        hyhu_from.hyh_addr
+#define        hyh_to_adapter  hyhu_to.hyh_baddr[0]
+#define        hyh_to_port     hyhu_to.hyh_baddr[1]
+#define        hyh_from_adapter hyhu_from.hyh_baddr[0]
+#define        hyh_from_port   hyhu_from.hyh_baddr[1]
+       short   hyh_param;      /* parameter (for loopback) */
+       char    hyh_type;       /* record type */
+       char    hyh_off;        /* offset from end of hy_hdr to ip data */
+};
+
+/*
+ * Structure of a HYPERchannel message header (from software)
+ */
+struct hym_data {
+       short   hymd_mplen;     /* message proper length, if associated data */
+};
+
+struct hym_hdr {
+       struct  hym_data hym_d;
+#define hym_mplen hym_d.hymd_mplen
+       struct  hy_hdr hym_hdr; /* hardware header, MUST BE LAST */
+};
+
+/*
+ * HYPERchannel header word control bits
+ */
+#define        H_XTRUNKS       0x00F0  /* transmit trunks */
+#define H_RTRUNKS      0x000F  /* remote trunks to transmit on for loopback */
+#define H_ASSOC                0x0100  /* has associated data */
+#define H_LOOPBK       0x00FF  /* loopback command */
+
+/*
+ * Structure of Statistics Record (counters)
+ */
+struct hy_stat {
+       u_long  hyc_msgcnt;             /* # messages transmitted */
+       u_long  hyc_dbcnt;              /* # data buffers transmitted */
+       u_long  hyc_tbusy;              /* # available trunks busy */
+       u_long  hyc_hwret;              /* # hardware retransmits */
+       u_long  hyc_crcbad;             /* # crc errors on trunk */
+       u_long  hyc_mcret;              /* # microcode retransmits */
+       u_long  hyc_tdabort;            /* # trunk driver aborts */
+       u_char  hyc_atype[3];           /* adapter type and revision level */
+       u_char  hyc_uaddr;              /* adapter unit number */
+};
+
+/*
+ * Structure of the Status Record
+ */
+struct hy_status {
+       u_char  hys_gen_status;         /* general status byte */
+       u_char  hys_last_fcn;           /* last function code issued */
+       u_char  hys_resp_trunk;         /* trunk response byte */
+       u_char  hys_status_trunk;       /* trunk status byte */
+       u_char  hys_recd_resp;          /* recieved response byte */
+       u_char  hys_error;              /* error code */
+       u_char  hys_caddr;              /* compressed addr of 1st msg on chain */
+       u_char  hys_pad;                /* not used */
+};
+
+/*
+ * Get port number from status record
+ */
+#define PORTNUM(p)     (((p)->hys_gen_status >> 6) & 0x03)
+
+/*
+ * The HYPERchannel driver sends and receives messages formatted:
+ *
+ *     +---------------------------------------+       ---
+ *     |                                       |       /|\
+ *     |  HYPERchannel adapter header (hy_hdr) |        |
+ *     |                                       |        |
+ *     +---------------------------------------+        |
+ *     |                                       |        |
+ *     |     Internet Protocol header (ip)     |    message proper
+ *     |                                       |    (64 bytes max)
+ *     +---------------------------------------+        |
+ *     |                                       |        |
+ *     |       TCP header + user data          |        |
+ *     |       (if it all fits here)           |        |
+ *     |                                       |       \|/
+ *     +---------------------------------------+       ---
+ *
+ *     +---------------------------------------+       ---
+ *     |                                       |       /|\
+ *     |                                       |        |
+ *     |       TCP header + user data          |  associated data
+ *     |                                       |        |
+ *     |                                       |       \|/
+ *     +---------------------------------------+       ---
+ *
+ * If all of the datagram will fit in the message proper (including
+ * the TCP header and user data) the entire datagram is passed in
+ * the message proper and the associated data feature of the HYPERchannel
+ * is not used.
+ *
+ * The mapping from internet addresses to HYPERchannel addresses is:
+ *
+ *      0       7 8      15 16                   31
+ *     +---------+---------+-----------------------+
+ *     | network | special | HYPERchannel address  |
+ *     +---------+---------+-----------------------+
+ *
+ *     |<------------ internet address ----------->|
+ *
+ * The hyperchannel address is decoded as follows:
+ *
+ *       0                 7 8             13 14  15
+ *     +-------------------+----------------+------+
+ *     |   adapter number  |      zero      | port |
+ *     +-------------------+----------------+------+
+ *
+ * The low 2 bits are port number (interpreted by hyperchannel hardware).
+ *
+ * The encoding of special bits is:
+ *
+ *     00      normal packet
+ *
+ *     01      loop this packet back to the sender at the
+ *             specified adapter (ip header source/destination addresses
+ *             swapped before sending, command bits added to tell the
+ *             remote HYPERchannel adapter debug & performance studies]
+ *             this code acts like 02 (below) if the ip destination (before
+ *             any swapping) and the destination address don't match (e.g.
+ *             this packet is being routed through a gateway)
+ *
+ *     02      loop this packet back to the sender at the
+ *             specified adapter, but go through the specified adapter's
+ *             IP.  This is for testing IP's store and forward mechanism.
+ *
+ *     other   undefined, currently treated as normal packet
+ *
+ */
+#define MPSIZE         64      /* "Message Proper" size */
+#define MAXRETRY       4
+
+/*
+ * Device registers
+ */
+struct hydevice {
+       short   hyd_wcr;        /* word count (negated) */
+       u_short hyd_bar;        /* bus address bits 15-0 */
+       u_short hyd_csr;        /* control and status */
+       u_short hyd_dbuf;       /* data buffer */
+};
+
+/*
+ * CSR bit layout
+ */
+#define        S_ERROR    0100000      /* error */
+#define        S_NEX      0040000      /* non-existent memory error */
+#define        S_ATTN     0020000      /* attn (always zero) */
+#ifdef PI13
+#define S_STKINTR  0010000     /* stacked interrupt */
+#else
+#define        S_MAINT    0010000      /* maintenance (not used) */
+#endif
+#define        S_A        0004000      /* device status A (recieve data available) */
+#define        S_B        0002000      /* device status B (normal termination) */
+#define        S_C        0001000      /* device status C (abnormal termination) */
+#ifdef PI13
+#define S_POWEROFF 0000400     /* power off indicator */
+#else
+#define        S_CYCLE    0000400      /* cycle (not used) */
+#endif
+#define        S_READY    0000200      /* ready */
+#define        S_IE       0000100      /* interrupt enable */
+#define        S_XBA      0000060      /* bus address bit bits 17 and 16 */
+#define S_CLRINT   0000014     /* clear stacked interrupt */
+#define        S_IATTN    0000010      /* interrupt on attention only */
+#define S_WC       0000004     /* interrupt on word count == 0 only */
+#define S_IATTNWC  0000000     /* interrupt on word count == 0 and attention */
+#define        S_BURST    0000002      /* burst mode DMA (not used) */
+#define        S_GO       0000001      /* go */
+
+#define XBASHIFT       12
+
+#define HY_CSR_BITS "\20\20ERROR\17NEX\16ATTN\15STKINTR\14RECV_DATA\13NORMAL\12ABNORMAL\11POWER\10READY\07IENABLE\06XBA17\05XBA16\04IATTN\03IWC\02BURST\01GO"
+
+/*
+ * PI13 status conditions
+ */
+#define        HYS_RECVDATA(x) (((x)->hyd_csr & S_A) != 0)     /* get adapter data */
+#define        HYS_NORMAL(x)   (((x)->hyd_csr & S_B) != 0)     /* done normally */
+#define        HYS_ABNORMAL(x) (((x)->hyd_csr & S_C) != 0)     /* done abnormally */
+#define        HYS_ERROR(x)    (((x)->hyd_csr & S_ERROR) != 0) /* error condition */
+#define        HYS_DONE(x)     (((x)->hyd_csr & (S_ERROR|S_B|S_C)) != 0)
+
+/*
+ * Function Codes for the Hyperchannel Adapter
+ * The codes are offset so they can be "or"ed into
+ * the reg data buffer
+ */
+#define        HYF_XMITMSG     0x04    /* transmit message */
+#define        HYF_XMITDATA    0x08    /* transmit associated data */
+#define        HYF_XMITLSTDATA 0x0C    /* transmit last associated data */
+#define        HYF_XMITLOCMSG  0x10    /* transmit local message */
+#define        HYF_INPUTMSG    0x24    /* input message proper */
+#define        HYF_INPUTDATA   0x28    /* input assiciated data */
+#define        HYF_STATUS      0x40    /* request status */
+#define        HYF_DUMPREGS    0x50    /* dump extention registers */
+#define        HYF_MARKP0      0x60    /* mark down port 0 */
+#define        HYF_MARKP1      0x64    /* mark down port 1 */
+#define        HYF_MARKP2      0x68    /* mark down port 2 */
+#define        HYF_MARKP3      0x6C    /* mark down port 3 */
+#define        HYF_MP0RR       0x70    /* mark down port 0 and reroute messages */
+#define        HYF_MP1RR       0x74    /* mark down port 1 and reroute messages */
+#define        HYF_MP2RR       0x78    /* mark down port 2 and reroute messages */
+#define        HYF_MP3RR       0x7C    /* mark down port 3 and reroute messages */
+#define        HYF_RSTATS      0xA0    /* read statistics */
+#define        HYF_RCSTATS     0xA4    /* read and clear statistics */
+#define        HYF_SETTEST     0xC0    /* enable test operations *set test mode) */
+#define        HYF_SADDR_LEN   0xC4    /* test mode: set address and length */
+#define        HYF_WBUFF       0xC8    /* test mode: write buffer */
+#define        HYF_RBUFF       0xCC    /* test mode: read buffer */
+#define HYF_CLRADAPTER 0xE0    /* clear adapter */
+#define        HYF_END_OP      0xE4    /* end operation */
+#define        HYF_CLRWFMSG    0xE6    /* clear wait for mwssage */
+#define        HYF_WAITFORMSG  0xE8    /* wait for message */
+
+/*
+ * Hyperchannel record types
+ */
+#define        HYLINK_IP       0       /* Internet Protocol Packet */
+
+#ifdef HYLOG
+#define HYL_SIZE 16*1024
+struct hy_log {
+       struct  hy_log *hyl_self;
+       u_char  hyl_enable;             /* logging enabled? */
+       u_char  hyl_onerr;              /* state to enter on error */
+       u_char  *hyl_eptr;              /* &hy_log.hyl_buf[HYL_SIZE] */
+       u_char  *hyl_ptr;               /* pointer into hyl_buf */
+       u_char  hyl_buf[HYL_SIZE];      /* log buffer space */
+};
+
+#define HYL_NOP                0
+#define HYL_UP         1       /* markup */
+#define HYL_STATUS     2       /* status results (struct hy_status) */
+#define HYL_STATISTICS 3       /* statistics (struct hy_stat) */
+#define HYL_XMIT       4       /* packed being send (struct hym_hdr) */
+#define HYL_RECV       5       /* recieved packet (short len; struct hy_hdr) */
+#define HYL_CMD                6       /* cmd issued (uchar cmd, state; short count) */
+#define HYL_INT                7       /* interrupt (short csr, wcr) */
+
+#define HYL_DISABLED   0       /* logging disabled */
+#define HYL_CONTINUOUS 1       /* continuous logging */
+#define HYL_CAUGHT1    2       /* one buffer full captured */
+#define HYL_CATCH1     3       /* one buffer full being captured */
+#define HYL_CAUGHTSTATUS  4    /* one buffer of status captured */
+#define HYL_CATCHSTATUS        5       /* one buffer fill of status being captured */
+
+#ifdef  KERNEL
+struct hy_log hy_log;
+#endif
+#endif
diff --git a/usr/src/sys/vaxif/if_il.h b/usr/src/sys/vaxif/if_il.h
new file mode 100644 (file)
index 0000000..3bd1aac
--- /dev/null
@@ -0,0 +1,46 @@
+/*     if_il.h 6.1     83/07/29        */
+
+/*
+ * Structure of an Ethernet header -- receive format
+ */
+struct il_rheader {
+       u_char  ilr_status;             /* Frame Status */
+       u_char  ilr_fill1;
+       u_short ilr_length;             /* Frame Length */
+       u_char  ilr_dhost[6];           /* Destination Host */
+       u_char  ilr_shost[6];           /* Source Host */
+       u_short ilr_type;               /* Type of packet */
+};
+
+/*
+ * Structure of statistics record
+ */
+struct il_stats {
+       u_short ils_fill1;
+       u_short ils_length;             /* Length (should be 62) */
+       u_char  ils_addr[6];            /* Ethernet Address */
+       u_short ils_frames;             /* Number of Frames Received */
+       u_short ils_rfifo;              /* Number of Frames in Receive FIFO */
+       u_short ils_xmit;               /* Number of Frames Transmitted */
+       u_short ils_xcollis;            /* Number of Excess Collisions */
+       u_short ils_frag;               /* Number of Fragments Received */
+       u_short ils_lost;               /* Number of Times Frames Lost */
+       u_short ils_multi;              /* Number of Multicasts Accepted */
+       u_short ils_rmulti;             /* Number of Multicasts Rejected */
+       u_short ils_crc;                /* Number of CRC Errors */
+       u_short ils_align;              /* Number of Alignment Errors */
+       u_short ils_collis;             /* Number of Collisions */
+       u_short ils_owcollis;           /* Number of Out-of-window Collisions */
+       u_short ils_fill2[8];
+       char    ils_module[8];          /* Module ID */
+       char    ils_firmware[8];        /* Firmware ID */
+};
+
+/*
+ * Structure of Collision Delay Time Record
+ */
+struct il_collis {
+       u_short ilc_fill1;
+       u_short ilc_length;             /* Length (should be 0-32) */
+       u_short ilc_delay[16];          /* Delay Times */
+};
diff --git a/usr/src/sys/vaxif/if_ilreg.h b/usr/src/sys/vaxif/if_ilreg.h
new file mode 100644 (file)
index 0000000..f22c8eb
--- /dev/null
@@ -0,0 +1,116 @@
+/*     if_ilreg.h      6.1     83/07/29        */
+
+/*
+ * Interlan Ethernet Communications Controller interface
+ */
+struct ildevice {
+       short   il_csr;         /* Command and Status Register */
+       short   il_bar;         /* Buffer Address Register */
+       short   il_bcr;         /* Byte Count Register */
+};
+
+/*
+ * Command and status bits
+ */
+#define        IL_EUA          0xc000          /* Extended Unibus Address */
+#define        IL_CMD          0x3f00          /* Command Function Code */
+#define        IL_CDONE        0x0080          /* Command Done */
+#define        IL_CIE          0x0040          /* Command Interrupt Enable */
+#define        IL_RDONE        0x0020          /* Receive DMA Done */
+#define        IL_RIE          0x0010          /* Receive Interrupt Enable */
+#define        IL_STATUS       0x000f          /* Command Status Code */
+
+#define        IL_BITS         "\20\10CDONE\7CIE\6RDONE\5RIE"
+
+/* command definitions */
+#define        ILC_MLPBAK      0x0100          /* Set Module Interface Loopback Mode */
+#define        ILC_ILPBAK      0x0200          /* Set Internal Loopback Mode */
+#define        ILC_CLPBAK      0x0300          /* Clear Loopback Mode */
+#define        ILC_PRMSC       0x0400          /* Set Promiscuous Receive Mode */
+#define        ILC_CLPRMSC     0x0500          /* Clear Promiscuous Receive Mode */
+#define        ILC_RCVERR      0x0600          /* Set Receive-On-Error Bit */
+#define        ILC_CRCVERR     0x0700          /* Clear Receive-On-Error Bit */
+#define        ILC_OFFLINE     0x0800          /* Go Offline */
+#define        ILC_ONLINE      0x0900          /* Go Online */
+#define        ILC_DIAG        0x0a00          /* Run On-board Diagnostics */
+#define        ILC_ISA         0x0d00          /* Set Insert Source Address Mode */
+#define        ILC_CISA        0x0e00          /* Clear Insert Source Address Mode */
+#define        ILC_DEFPA       0x0f00          /* Set Physical Address to Default */
+#define        ILC_ALLMC       0x1000          /* Set Receive All Multicast Packets */
+#define        ILC_CALLMC      0x1100          /* Clear Receive All Multicast */
+#define        ILC_STAT        0x1800          /* Report and Reset Statistics */
+#define        ILC_DELAYS      0x1900          /* Report Collision Delay Times */
+#define        ILC_RCV         0x2000          /* Supply Receive Buffer */
+#define        ILC_LDXMIT      0x2800          /* Load Transmit Data */
+#define        ILC_XMIT        0x2900          /* Load Transmit Data and Send */
+#define        ILC_LDGRPS      0x2a00          /* Load Group Addresses */
+#define        ILC_RMGRPS      0x2b00          /* Delete Group Addresses */
+#define        ILC_LDPA        0x2c00          /* Load Physical Address */
+#define        ILC_FLUSH       0x3000          /* Flush Receive BAR/BCR Queue */
+#define        ILC_RESET       0x3f00          /* Reset */
+
+/*
+ * Error codes found in the status bits of the csr.
+ */
+#define        ILERR_SUCCESS           0       /* command successful */
+#define        ILERR_RETRIES           1       /* " " with retries */
+#define        ILERR_BADCMD            2       /* illegal command */
+#define        ILERR_INVCMD            3       /* invalid command */
+#define        ILERR_RECVERR           4       /* receiver error */
+#define        ILERR_BUFSIZ            5       /* buffer size too big */
+#define        ILERR_FRAMESIZ          6       /* frame size too small */
+#define        ILERR_COLLISIONS        8       /* excessive collisions */
+#define        ILERR_BUFALIGNMENT      10      /* buffer not word aligned */
+#define        ILERR_NXM               15      /* non-existent memory */
+
+#define        NILERRS                 16
+#ifdef ILERRS
+char *ilerrs[NILERRS] = {
+       "success",                      /*  0 */
+       "success with retries",         /*  1 */
+       "illegal command",              /*  2 */
+       "inappropriate command",        /*  3 */
+       "failure",                      /*  4 */
+       "buffer size exceeded",         /*  5 */
+       "frame too small",              /*  6 */
+       0,                              /*  7 */
+       "excessive collisions",         /*  8 */
+       0,                              /*  9 */
+       "buffer alignment error",       /* 10 */
+       0,                              /* 11 */
+       0,                              /* 12 */
+       0,                              /* 13 */
+       0,                              /* 14 */
+       "non-existent memory"           /* 15 */
+};
+#endif
+
+/*
+ * Diagnostics codes.
+ */
+#define        ILDIAG_SUCCESS          0       /* no problems */
+#define        ILDIAG_CHKSUMERR        1       /* ROM/RAM checksum error */
+#define        ILDIAG_DMAERR           2       /* DMA not working */
+#define        ILDIAG_XMITERR          3       /* xmit circuitry failure */
+#define        ILDIAG_RECVERR          4       /* rcvr circuitry failure */
+#define        ILDIAG_LOOPBACK         5       /* loopback test failed */
+
+#define        NILDIAGS                6
+#ifdef ILDIAGS
+char *ildiag[NILDIAGS] = {
+       "success",                      /* 0 */
+       "checksum error",               /* 1 */
+       "NM10 dma error",               /* 2 */
+       "transmitter error",            /* 3 */
+       "receiver error",               /* 4 */
+       "loopback failure",             /* 5 */
+};
+#endif
+
+/*
+ * Frame status bits, returned in frame status byte
+ * at the top of each received packet.
+ */
+#define        ILFSTAT_C       0x1             /* CRC error */
+#define        ILFSTAT_A       0x2             /* alignment error */
+#define        ILFSTAT_L       0x4             /* 1+ frames lost just before */
diff --git a/usr/src/sys/vaxif/if_pcl.c b/usr/src/sys/vaxif/if_pcl.c
new file mode 100644 (file)
index 0000000..c640d1d
--- /dev/null
@@ -0,0 +1,490 @@
+/*     if_pcl.c        6.1     83/07/29        */
+
+#include "pcl.h"
+#if NPCL > 0
+/*
+ * DEC CSS PCL-11B Parallel Communications Interface
+ *
+ * Written by Mike Muuss and Jeff Schwab.
+ */
+#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 "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_pclreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+/* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */
+#define        PCLMTU          (1006)  /* Max transmission unit (bytes) */
+#define        PCLMAXTDM       7       /* Max unit number on TDM bus */
+
+int    pclprobe(), pclattach(), pclrint(), pclxint();
+int    pclinit(), pclioctl(), pcloutput(), pclreset();
+
+struct uba_device      *pclinfo[NPCL];
+u_short pclstd[] = { 0 };
+#define        PCLUNIT(x)      minor(x)
+struct uba_driver pcldriver =
+       { pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo };
+
+/*
+ * PCL software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * sc_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct pcl_softc {
+       struct  ifnet sc_if;            /* network-visible interface */
+       struct  ifuba sc_ifuba;         /* UNIBUS resources */
+       short   sc_oactive;             /* is output active? */
+       short   sc_olen;                /* length of last output */
+       short   sc_lastdest;            /* previous destination */
+       short   sc_odest;               /* current xmit destination */
+       short   sc_bdest;               /* buffer's stated destination */
+       short   sc_pattern;             /* identification pattern */
+} pcl_softc[NPCL];
+
+/*
+ * Structure of "local header", which only goes between
+ * pcloutput and pclstart.
+ */
+struct pcl_header {
+       short   pcl_dest;               /* Destination PCL station */
+};
+
+/*
+ * Do non-DMA output of 1 word to determine presence of interface,
+ * and to find the interupt vector.  1 word messages are a special
+ * case in the receiver routine, and will be discarded.
+ */
+pclprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct pcldevice *addr = (struct pcldevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       pclrint(0); pclxint(0);
+#endif
+       addr->pcl_rcr = PCL_RCINIT;
+       addr->pcl_tcr = PCL_TXINIT;
+       addr->pcl_tsba = 0xFFFE;
+       /* going for 01777776 */
+       addr->pcl_tsbc = -4;            /* really short */
+       addr->pcl_tcr =
+        ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030;
+       DELAY(100000);
+       addr->pcl_tcr = PCL_TXINIT;
+       return (sizeof (struct pcldevice));
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+pclattach(ui)
+       struct uba_device *ui;
+{
+       register struct pcl_softc *sc = &pcl_softc[ui->ui_unit];
+
+       sc->sc_if.if_unit = ui->ui_unit;
+       sc->sc_if.if_name = "pcl";
+       sc->sc_if.if_mtu = PCLMTU;
+       sc->sc_if.if_init = pclinit;
+       sc->sc_if.if_output = pcloutput;
+       sc->sc_if.if_ioctl = pclioctl;
+       sc->sc_if.if_reset = pclreset;
+       sc->sc_ifuba.ifu_flags = UBA_NEEDBDP;
+       if_attach(&sc->sc_if);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+pclreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" pcl%d", unit);
+       pclinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+pclinit(unit)
+       int unit;
+{
+       register struct pcl_softc *sc = &pcl_softc[unit];
+       register struct uba_device *ui = pclinfo[unit];
+       register struct pcldevice *addr;
+       struct sockaddr_in *sin;
+       int s;
+
+       sin = (struct sockaddr_in *)&sc->sc_if.if_addr;
+       if (sin->sin_addr.s_addr == 0)
+               return;
+       if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
+           (int)btoc(PCLMTU)) == 0) { 
+               printf("pcl%d: can't init\n", unit);
+               sc->sc_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       addr = (struct pcldevice *)ui->ui_addr;
+       addr->pcl_rcr = PCL_RCINIT;
+       addr->pcl_tcr = PCL_TXINIT;
+
+       /*
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
+        */
+       s = splimp();
+       addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info;
+       addr->pcl_rdbc = -PCLMTU;
+       addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |
+               PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
+       sc->sc_oactive = 0;
+       sc->sc_if.if_flags |= IFF_UP|IFF_RUNNING;
+       pclstart(unit);
+       splx(s);
+       /* Set up routing table entry */
+       if_rtinit(&sc->sc_if, RTF_UP);
+}
+
+/*
+ * PCL output routine.
+ */
+pcloutput(ifp, m, dst)
+       struct ifnet *ifp;
+       struct mbuf *m;
+       struct sockaddr *dst;
+{
+       int dest, s, error;
+       struct pcl_header *pclp;
+       struct mbuf *m2;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET:
+               dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
+               if (dest > PCLMAXTDM) {
+                       error = EHOSTUNREACH;
+                       goto bad;
+               }
+               break;
+#endif
+       default:
+               printf("pcl%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+               error = EAFNOSUPPORT;
+               goto bad;
+       }
+
+       /*
+        * Add pseudo local net header.
+        * Actually, it does not get transmitted, but merely stripped
+        * off and used by the START routine to route the packet.
+        * If no space in first mbuf, allocate another.
+        */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof (struct pcl_header) > m->m_off) {
+               m2 = m_get(M_DONTWAIT, MT_HEADER);
+               if (m2 == 0) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m2->m_next = m;
+               m2->m_off = MMINOFF;
+               m2->m_len = sizeof (struct pcl_header);
+               m = m2;
+       } else {
+               m->m_off -= sizeof (struct pcl_header);
+               m->m_len += sizeof (struct pcl_header);
+       }
+       pclp = mtod(m, struct pcl_header *);
+       pclp->pcl_dest = dest;
+
+       /*
+        * 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);
+       if (pcl_softc[ifp->if_unit].sc_oactive == 0)
+               pclstart(ifp->if_unit);
+       splx(s);
+       return (0);
+qfull:
+       splx(s);
+bad:
+       m_freem(m);
+       return (error);
+}
+
+/*
+ * Start or restart output on interface.
+ * If interface is already active, then this is a retransmit.
+ * If interface is not already active, get another datagram
+ * to send off of the interface queue, and map it to the interface
+ * before starting the output.
+ */
+pclstart(dev)
+       dev_t dev;
+{
+        int unit = PCLUNIT(dev);
+       struct uba_device *ui = pclinfo[unit];
+       register struct pcl_softc *sc = &pcl_softc[unit];
+       register struct pcldevice *addr;
+       struct mbuf *m;
+
+       if (sc->sc_oactive)
+               goto restart;
+
+       /*
+        * Not already active: dequeue another request
+        * and map it to the UNIBUS.  If no more requests,
+        * just return.
+        */
+       IF_DEQUEUE(&sc->sc_if.if_snd, m);
+       if (m == 0) {
+               sc->sc_oactive = 0;
+               return;
+       }
+
+       /*
+        * Pull destination node out of pseudo-local net header.
+        * remove it from outbound data.
+        * Note that if_wubaput calls m_bcopy, which is prepared for
+        * m_len to be 0 in the first mbuf in the chain.
+        */
+       sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest;
+       sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1;
+       m->m_off += sizeof (struct pcl_header);
+       m->m_len -= sizeof (struct pcl_header);
+
+       /* Map out to the DMA area */
+       sc->sc_olen = if_wubaput(&sc->sc_ifuba, m);
+
+restart:
+       /*
+        * Have request mapped to UNIBUS for transmission.
+        * Purge any stale data from this BDP, and start the output.
+        */
+       if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
+       addr = (struct pcldevice *)ui->ui_addr;
+       addr->pcl_tcr = PCL_TXINIT;
+       addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info;
+       addr->pcl_tsbc = -sc->sc_olen;
+
+       /*
+        * RIB (retry if busy) is used on the second and subsequent packets
+        * to a single host, because TCP often wants to transmit multiple
+        * buffers in a row,
+        * and if they are all going to the same place, the second and
+        * subsequent ones may be lost due to receiver not ready again yet.
+        * This can cause serious problems, because the TCP will resend the
+        * whole window, which just repeats the problem.  The result is that
+        * a perfectly good link appears not to work unless we take steps here.
+        */
+       addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
+               ((sc->sc_odest & 0xF)<<8) |
+               PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE |
+               (sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0);
+       sc->sc_lastdest = sc->sc_odest;
+       sc->sc_oactive = 1;
+}
+
+/*
+ * PCL transmitter interrupt.
+ * Start another output if more data to send.
+ */
+pclxint(unit)
+       int unit;
+{
+       register struct uba_device *ui = pclinfo[unit];
+       register struct pcl_softc *sc = &pcl_softc[unit];
+       register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr;
+
+       if (sc->sc_oactive == 0) {
+               printf ("pcl%d: stray interrupt\n", unit);
+               return;
+       }
+       if (addr->pcl_tsr & PCL_ERR) {
+               sc->sc_lastdest = 0;            /* don't bother with RIB */
+               if (addr->pcl_tsr & PCL_MSTDWN) {
+                       addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR;
+                       pclstart(unit); /* Retry */
+                       printf("pcl%d: master\n", unit );
+                       return;
+               }
+#ifndef PCL_TESTING
+               if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0))  {
+                       ;       /* Receiver Offline -- not exactly an error */
+               }  else  {
+#else
+               {
+#endif
+                       /* Log as an error */
+                       printf("pcl%d: send error, tcr=%b tsr=%b\n",
+                               unit, addr->pcl_tcr, PCL_TCSRBITS,
+                               addr->pcl_tsr, PCL_TERRBITS);
+                       sc->sc_if.if_oerrors++;
+               }
+       } else
+               sc->sc_if.if_opackets++;
+       if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) {
+               sc->sc_odest++;         /* do next host (broadcast) */
+       } else {
+               sc->sc_oactive = 0;
+               if (sc->sc_ifuba.ifu_xtofree) {
+                       m_freem(sc->sc_ifuba.ifu_xtofree);
+                       sc->sc_ifuba.ifu_xtofree = 0;
+               }
+       }
+       pclstart(unit);
+}
+
+/*
+ * PCL interface receiver interrupt.
+ * If input error just drop packet.
+ */
+pclrint(unit)
+       int unit;
+{
+       register struct pcl_softc *sc = &pcl_softc[unit];
+       struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr;
+       struct mbuf *m;
+       int len;
+       register struct ifqueue *inq;
+
+       sc->sc_if.if_ipackets++;
+       /*
+        * Purge BDP; drop if input error indicated.
+        */
+       if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp);
+       if (addr->pcl_rsr & PCL_ERR) {
+               printf("pcl%d: rcv error, rcr=%b rsr=%b\n",
+                       unit, addr->pcl_rcr, PCL_RCSRBITS,
+                       addr->pcl_rsr, PCL_RERRBITS);
+               sc->sc_if.if_ierrors++;
+               goto setup;
+       }
+       len = PCLMTU + addr->pcl_rdbc;
+       if (len <= 0 || len > PCLMTU) {
+               printf("pcl%d: bad len=%d.\n", unit, len);
+               sc->sc_if.if_ierrors++;
+               goto setup;
+       }
+
+       /* Really short packets will be part of the startup sequence */
+       if (len <= 4) {
+               /* Later, do comming-up processing here */
+               goto setup;     /* drop packet */
+       }
+
+       /*
+        * Pull packet off interface.
+        */
+       m = if_rubaget(&sc->sc_ifuba, len, 0);
+       if (m == 0)
+               goto setup;
+
+       schednetisr(NETISR_IP);
+       inq = &ipintrq;
+
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+setup:
+       /*
+        * Reset for next packet.
+        */
+       addr->pcl_rcr = PCL_RCINIT;
+       addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info;
+       addr->pcl_rdbc = -PCLMTU;
+       addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
+               PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
+}
+
+/*
+ * Process an ioctl request.
+ */
+pclioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       struct sockaddr_in *sin;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               sin = (struct sockaddr_in *)&ifr->ifr_addr;
+               ifp->if_addr = *(struct sockaddr *)sin;
+               ifp->if_net = in_netof(sin->sin_addr);
+               ifp->if_host[0] = in_lnaof(sin->sin_addr);
+               ifp->if_broadaddr = *(struct sockaddr *)sin;
+               sin = (struct sockaddr_in *)&ifp->if_broadaddr;
+               sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+               ifp->if_flags |= IFF_BROADCAST;
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       pclinit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_pclreg.h b/usr/src/sys/vaxif/if_pclreg.h
new file mode 100644 (file)
index 0000000..0ed54ee
--- /dev/null
@@ -0,0 +1,53 @@
+/*     if_pclreg.h     6.1     83/07/29        */
+
+/*
+ * DEC CSS PCL-11B Parallel Communications Interface
+ */
+
+struct pcldevice  {
+       u_short pcl_tcr;        /* Transmitter Command Register */
+       u_short pcl_tsr;        /* Transmitter Status Register */
+       u_short pcl_tsdb;       /* Transmitter Source Data Buffer */
+       short   pcl_tsbc;       /* Transmitter Source Byte Count */
+       u_short pcl_tsba;       /* Transmitter Source Bus Address */
+       u_short pcl_tmmr;       /* Transmitter Master/Maint Regs */
+       u_short pcl_tscrc;      /* Transmitter Source CRC */
+       u_short pcl_spare;
+       u_short pcl_rcr;        /* Receiver Command Register */
+       u_short pcl_rsr;        /* Receiver Status Register */
+       u_short pcl_rddb;       /* Receiver Destination Data Buffer */
+       short   pcl_rdbc;       /* Receiver Destination Byte Count */
+       u_short pcl_rdba;       /* Receiver Destination Bus Address */
+       u_short pcl_rdcrc;      /* Receiver Destination CRC */
+};
+
+/* Transmitter Command and Status Bits */
+#define PCL_STTXM      (1<<0)          /* Start transmission */
+#define PCL_TXINIT     (1<<1)          /* Transmitter Initialize */
+#define PCL_IE         (1<<6)          /* Interrupt Enable */
+#define PCL_SNDWD      (1<<13)         /* Send word */
+#define PCL_TXNPR      (1<<14)         /* Transmitter NPR */
+#define PCL_RIB                (1<<15)         /* Retry if busy */
+
+#define PCL_RESPA      (3<<0)          /* Response A bits (tsr & rsr) */
+#define PCL_RESPB      (3<<2)          /* Response B bits (tsr & rsr) */
+#define PCL_MSTDWN     (1<<11)         /* Master down */
+#define PCL_ERR                (1<<15)         /* Error summary */
+
+#define PCL_MASTER     (1<<8)          /* Set MASTER status */
+#define PCL_AUTOADDR   (1<<12)         /* Auto time slicing */
+
+/* Receiver Command and Status Bits */
+#define PCL_RCVDAT     (1<<0)          /* Receive data */
+#define PCL_RCINIT     (1<<1)          /* Receiver Initialize */
+#define PCL_RCVWD      (1<<13)         /* Receive word */
+#define PCL_RCNPR      (1<<14)         /* Receive NRP */
+#define PCL_REJ                (1<<15)         /* Reject transmission */
+
+#define PCL_BCOFL      (1<<9)          /* Byte Counter Overflow */
+
+#define PCL_TERRBITS   "\20\20ERR\17NXL\16MEM_OFL\15TXM_ERR\14MST_DWN\13TIM_OUT\12OVERRUN\11DTI_RDY\10SUC_TXF\07BUSY\06SOREJ\05TBS_BUSY"
+#define PCL_TCSRBITS   "\20\20RIB\17TX_NPR\16SND_WD\10RD_SILO\07IE\04DTO_RDY\03INH_ADI\02TX_INIT\01START_TXM"
+
+#define PCL_RERRBITS   "\20\20ERR\17NXL\16MEM_OFL\15TXM_ERR\14PARITY\13TIM_OUT\12BC_OFL\11DTO_RDY\10SUC_TXF\07BUSY\06REJ_COMP\05CHN_OPN"
+#define PCL_RCSRBITS   "\20\20REJ\17RC_NPR\16RCV_WD\10LD_SILO\07IE\04DTI_RDY\03INH_ADI\02RC_INIT\01RCV_DAT"
diff --git a/usr/src/sys/vaxif/if_uba.c b/usr/src/sys/vaxif/if_uba.c
new file mode 100644 (file)
index 0000000..0ed765c
--- /dev/null
@@ -0,0 +1,251 @@
+/*     if_uba.c        6.1     83/07/29        */
+
+#include "../machine/pte.h"
+
+#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/mbuf.h"
+#include "../h/map.h"
+#include "../h/buf.h"
+#include "../h/cmap.h"
+#include "../h/vmmac.h"
+#include "../h/socket.h"
+
+#include "../net/if.h"
+
+#include "../vax/mtpr.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+/*
+ * Routines supporting UNIBUS network interfaces.
+ *
+ * TODO:
+ *     Support interfaces using only one BDP statically.
+ */
+
+/*
+ * Init UNIBUS for interface on uban whose headers of size hlen are to
+ * end on a page boundary.  We allocate a UNIBUS map register for the page
+ * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
+ * doing this twice: once for reading and once for writing.  We also
+ * allocate page frames in the mbuffer pool for these pages.
+ */
+if_ubainit(ifu, uban, hlen, nmr)
+       register struct ifuba *ifu;
+       int uban, hlen, nmr;
+{
+       register caddr_t cp;
+       int i, ncl;
+
+       ncl = clrnd(nmr + CLSIZE) / CLSIZE;
+       if (ifu->ifu_r.ifrw_addr)
+               cp = ifu->ifu_r.ifrw_addr - (CLBYTES - hlen);
+       else {
+               cp = m_clalloc(2 * ncl, MPG_SPACE);
+               if (cp == 0)
+                       return (0);
+               ifu->ifu_r.ifrw_addr = cp + CLBYTES - hlen;
+               ifu->ifu_w.ifrw_addr = ifu->ifu_r.ifrw_addr + ncl * CLBYTES;
+               ifu->ifu_hlen = hlen;
+               ifu->ifu_uban = uban;
+               ifu->ifu_uba = uba_hd[uban].uh_uba;
+       }
+       if (if_ubaalloc(ifu, &ifu->ifu_r, nmr) == 0)
+               goto bad;
+       if (if_ubaalloc(ifu, &ifu->ifu_w, nmr) == 0)
+               goto bad2;
+       for (i = 0; i < nmr; i++)
+               ifu->ifu_wmap[i] = ifu->ifu_w.ifrw_mr[i];
+       ifu->ifu_xswapd = 0;
+       return (1);
+bad2:
+       ubarelse(ifu->ifu_uban, &ifu->ifu_r.ifrw_info);
+bad:
+       m_pgfree(cp, 2 * ncl);
+       ifu->ifu_r.ifrw_addr = 0;
+       return (0);
+}
+
+/*
+ * Setup either a ifrw structure by allocating UNIBUS map registers,
+ * possibly a buffered data path, and initializing the fields of
+ * the ifrw structure to minimize run-time overhead.
+ */
+static
+if_ubaalloc(ifu, ifrw, nmr)
+       struct ifuba *ifu;
+       register struct ifrw *ifrw;
+       int nmr;
+{
+       register int info;
+
+       info =
+           uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
+               ifu->ifu_flags);
+       if (info == 0)
+               return (0);
+       ifrw->ifrw_info = info;
+       ifrw->ifrw_bdp = UBAI_BDP(info);
+       ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
+       ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
+       return (1);
+}
+
+/*
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs.  When full cluster sized units are present
+ * on the interface on cluster boundaries we can get them more
+ * easily by remapping, and take advantage of this here.
+ */
+struct mbuf *
+if_rubaget(ifu, totlen, off0)
+       register struct ifuba *ifu;
+       int totlen, off0;
+{
+       struct mbuf *top, **mp, *m;
+       int off = off0, len;
+       register caddr_t cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen;
+
+
+       top = 0;
+       mp = &top;
+       while (totlen > 0) {
+               MGET(m, M_DONTWAIT, MT_DATA);
+               if (m == 0)
+                       goto bad;
+               if (off) {
+                       len = totlen - off;
+                       cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen + off;
+               } else
+                       len = totlen;
+               if (len >= CLBYTES) {
+                       struct mbuf *p;
+                       struct pte *cpte, *ppte;
+                       int x, *ip, i;
+
+                       MCLGET(p, 1);
+                       if (p == 0)
+                               goto nopage;
+                       len = m->m_len = CLBYTES;
+                       m->m_off = (int)p - (int)m;
+                       if (!claligned(cp))
+                               goto copy;
+
+                       /*
+                        * Switch pages mapped to UNIBUS with new page p,
+                        * as quick form of copy.  Remap UNIBUS and invalidate.
+                        */
+                       cpte = &Mbmap[mtocl(cp)*CLSIZE];
+                       ppte = &Mbmap[mtocl(p)*CLSIZE];
+                       x = btop(cp - ifu->ifu_r.ifrw_addr);
+                       ip = (int *)&ifu->ifu_r.ifrw_mr[x];
+                       for (i = 0; i < CLSIZE; i++) {
+                               struct pte t;
+                               t = *ppte; *ppte++ = *cpte; *cpte = t;
+                               *ip++ =
+                                   cpte++->pg_pfnum|ifu->ifu_r.ifrw_proto;
+                               mtpr(TBIS, cp);
+                               cp += NBPG;
+                               mtpr(TBIS, (caddr_t)p);
+                               p += NBPG / sizeof (*p);
+                       }
+                       goto nocopy;
+               }
+nopage:
+               m->m_len = MIN(MLEN, len);
+               m->m_off = MMINOFF;
+copy:
+               bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
+               cp += m->m_len;
+nocopy:
+               *mp = m;
+               mp = &m->m_next;
+               if (off) {
+                       /* sort of an ALGOL-W style for statement... */
+                       off += m->m_len;
+                       if (off == totlen) {
+                               cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen;
+                               off = 0;
+                               totlen = off0;
+                       }
+               } else
+                       totlen -= m->m_len;
+       }
+       return (top);
+bad:
+       m_freem(top);
+       return (0);
+}
+
+/*
+ * Map a chain of mbufs onto a network interface
+ * in preparation for an i/o operation.
+ * The argument chain of mbufs includes the local network
+ * header which is copied to be in the mapped, aligned
+ * i/o space.
+ */
+if_wubaput(ifu, m)
+       register struct ifuba *ifu;
+       register struct mbuf *m;
+{
+       register struct mbuf *mp;
+       register caddr_t cp, dp;
+       register int i;
+       int xswapd = 0;
+       int x, cc;
+
+       cp = ifu->ifu_w.ifrw_addr;
+       while (m) {
+               dp = mtod(m, char *);
+               if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
+                       struct pte *pte; int *ip;
+                       pte = &Mbmap[mtocl(dp)*CLSIZE];
+                       x = btop(cp - ifu->ifu_w.ifrw_addr);
+                       ip = (int *)&ifu->ifu_w.ifrw_mr[x];
+                       for (i = 0; i < CLSIZE; i++)
+                               *ip++ =
+                                   ifu->ifu_w.ifrw_proto | pte++->pg_pfnum;
+                       xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
+                       mp = m->m_next;
+                       m->m_next = ifu->ifu_xtofree;
+                       ifu->ifu_xtofree = m;
+                       cp += m->m_len;
+               } else {
+                       bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
+                       cp += m->m_len;
+                       MFREE(m, mp);
+               }
+               m = mp;
+       }
+
+       /*
+        * Xswapd is the set of clusters we just mapped out.  Ifu->ifu_xswapd
+        * is the set of clusters mapped out from before.  We compute
+        * the number of clusters involved in this operation in x.
+        * Clusters mapped out before and involved in this operation
+        * should be unmapped so original pages will be accessed by the device.
+        */
+       cc = cp - ifu->ifu_w.ifrw_addr;
+       x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT;
+       ifu->ifu_xswapd &= ~xswapd;
+       xswapd &= ~ifu->ifu_xswapd;
+       while (i = ffs(ifu->ifu_xswapd)) {
+               i--;
+               if (i >= x)
+                       break;
+               ifu->ifu_xswapd &= ~(1<<i);
+               i *= CLSIZE;
+               for (x = 0; x < CLSIZE; x++) {
+                       ifu->ifu_w.ifrw_mr[i] = ifu->ifu_wmap[i];
+                       i++;
+               }
+       }
+       ifu->ifu_xswapd |= xswapd;
+       return (cc);
+}
diff --git a/usr/src/sys/vaxif/if_uba.h b/usr/src/sys/vaxif/if_uba.h
new file mode 100644 (file)
index 0000000..3a79999
--- /dev/null
@@ -0,0 +1,49 @@
+/*     if_uba.h        6.1     83/07/29        */
+
+/*
+ * Structure and routine definitions
+ * for UNIBUS network interfaces.
+ */
+
+#define        IF_MAXNUBAMR    10
+/*
+ * Each interface has one of these structures giving information
+ * about UNIBUS resources held by the interface.
+ *
+ * We hold IF_NUBAMR map registers for datagram data, starting
+ * at ifr_mr.  Map register ifr_mr[-1] maps the local network header
+ * ending on the page boundary.  Bdp's are reserved for read and for
+ * write, given by ifr_bdp.  The prototype of the map register for
+ * read and for write is saved in ifr_proto.
+ *
+ * When write transfers are not full pages on page boundaries we just
+ * copy the data into the pages mapped on the UNIBUS and start the
+ * transfer.  If a write transfer is of a (1024 byte) page on a page
+ * boundary, we swap in UNIBUS pte's to reference the pages, and then
+ * remap the initial pages (from ifu_wmap) when the transfer completes.
+ *
+ * When read transfers give whole pages of data to be input, we
+ * allocate page frames from a network page list and trade them
+ * with the pages already containing the data, mapping the allocated
+ * pages to replace the input pages for the next UNIBUS data input.
+ */
+struct ifuba {
+       short   ifu_uban;                       /* uba number */
+       short   ifu_hlen;                       /* local net header length */
+       struct  uba_regs *ifu_uba;              /* uba regs, in vm */
+       struct ifrw {
+               caddr_t ifrw_addr;              /* virt addr of header */
+               int     ifrw_bdp;               /* unibus bdp */
+               int     ifrw_info;              /* value from ubaalloc */
+               int     ifrw_proto;             /* map register prototype */
+               struct  pte *ifrw_mr;           /* base of map registers */
+       } ifu_r, ifu_w;
+       struct  pte ifu_wmap[IF_MAXNUBAMR];     /* base pages for output */
+       short   ifu_xswapd;                     /* mask of clusters swapped */
+       short   ifu_flags;                      /* used during uballoc's */
+       struct  mbuf *ifu_xtofree;              /* pages being dma'd out */
+};
+
+#ifdef         KERNEL
+struct mbuf *if_rubaget();
+#endif
diff --git a/usr/src/sys/vaxif/if_un.c b/usr/src/sys/vaxif/if_un.c
new file mode 100644 (file)
index 0000000..f5adeed
--- /dev/null
@@ -0,0 +1,556 @@
+/*     if_un.c 6.1     83/07/29        */
+
+#include "un.h"
+#if NUN > 0
+/*
+ * Ungermann-Bass network/DR11-W interface driver
+ */
+#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/errno.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_un.h"
+#include "../vaxif/if_unreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#define        UNMTU           (600-sizeof (struct un_header))
+
+#define        US_NULL         0       /* not doing anything state */
+#define        US_IDLE         1       /* waiting to transfer state */
+#define        US_READ         2       /* reading state */
+#define        US_WRITE        3       /* writing state */
+#define        US_RESET        4       /* waiting for reset state */
+
+int    unprobe(), unattach(), unintr();
+struct uba_device *uninfo[NUN];
+u_short        unstd[] = { 0 };
+struct uba_driver undriver =
+       { unprobe, 0, unattach, 0, unstd, "un", uninfo };
+#define        UNUNIT(dev)     (minor(dev))
+
+int    uninit(), unioctl(), unoutput(), unreset();
+int    unrestart();
+
+/*
+ * Ungermann-Bass software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * us_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address,
+ * etc.  We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct un_softc {
+       struct  ifnet us_if;            /* network-visible interface */
+       struct  ifuba us_ifuba;         /* UNIBUS resources */
+       short   us_state;               /* device state */
+       short   us_errcnt;              /* number of errors since time set */
+       short   us_restart;             /* restart interval */
+       u_char  us_maxtime;             /* interval for error counting */
+       u_char  us_maxerr;              /* errors allowed in interval */
+       time_t  us_errtime;             /* time for error counting */
+} un_softc[NUN];
+
+/*
+ * Cause an interrupt to determine interface presence and
+ * interrupt vector.
+ */
+unprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;          /* r11, r10 value-result */
+       register struct undevice *addr = (struct undevice *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec;
+       unintr(0);
+#endif
+       addr->csr = IE|UNRESET;
+       addr->csr = IE|UNRESET|GO;
+       DELAY(100000);
+       addr->csr = 0;
+       return (1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+unattach(ui)
+       struct uba_device *ui;
+{
+       register struct un_softc *us = &un_softc[ui->ui_unit];
+
+       us->us_if.if_unit = ui->ui_unit;
+       us->us_if.if_name = "un";
+       us->us_if.if_mtu = UNMTU;
+       us->us_if.if_init = uninit;
+       us->us_if.if_ioctl = unioctl;
+       us->us_if.if_output = unoutput;
+       us->us_if.if_reset = unreset;
+       us->us_if.if_watchdog = unrestart;
+       us->us_maxtime = 3;
+       us->us_maxerr = 10;
+       us->us_restart = 5 * 60;
+       us->us_ifuba.ifu_flags = UBA_CANTWAIT;
+#ifdef notdef
+       us->us_ifuba.ifu_flags |= UBA_NEEDBDP;
+#endif
+       if_attach(&us->us_if);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+unreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NUN || (ui = uninfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" un%d", unit);
+       uninit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+uninit(unit)
+       int unit;
+{
+       register struct un_softc *us = &un_softc[unit];
+       register struct uba_device *ui = uninfo[unit];
+       register struct undevice *addr;
+       struct sockaddr_in *sin;
+       int s;
+
+       sin = (struct sockaddr_in *)&us->us_if.if_addr;
+       if (in_netof(sin->sin_addr) == 0)
+               return;
+       if (if_ubainit(&us->us_ifuba, ui->ui_ubanum,
+           sizeof (struct un_header), (int)btoc(UNMTU)) == 0) {
+               printf("un%d: can't initialize\n", unit);
+               us->us_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       us->us_if.if_flags |= IFF_RUNNING;
+       us->us_errcnt = 0;
+       us->us_errtime = time.tv_sec;
+       unwhoami(unit);
+
+       /*
+        * Reset U-B interface, thus causing an interrupt which
+        * will start things going.
+        */
+       addr = (struct undevice *)ui->ui_addr;
+       s = splimp();
+       addr->csr = IE|UNRESET;
+       addr->csr = IE|UNRESET|GO;
+       us->us_state = US_RESET;
+       splx(s);
+}
+
+/*
+ * Try to start a write operation.
+ * If interface is busy, it must be in idle state, so issue a reset.
+ * Otherwise, get the datagram from the output queue, map it onto
+ * the UNIBUS, and start the write.  This routine should not be
+ * called if the output queue is empty.
+ */
+unstart(dev)
+       dev_t dev;
+{
+       int unit = UNUNIT(dev);
+       struct uba_device *ui = uninfo[unit];
+       register struct un_softc *us = &un_softc[unit];
+       register struct undevice *addr = (struct undevice *)ui->ui_addr;
+       struct mbuf *m;
+       int dataaddr, datalen;
+       register short cmdcsr;
+
+       if (us->us_state != US_NULL) {
+               addr->csr = IE|UNRESET;
+               addr->csr = IE|UNRESET|GO;
+               us->us_state = US_RESET;
+       } else {
+               IF_DEQUEUE(&us->us_if.if_snd, m);
+               if (m == 0)
+                       return;
+               us->us_state = US_WRITE;
+               datalen = if_wubaput(&us->us_ifuba, m);
+               if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
+                       UBAPURGE(us->us_ifuba.ifu_uba,
+                               us->us_ifuba.ifu_w.ifrw_bdp);
+               dataaddr = us->us_ifuba.ifu_w.ifrw_info;
+               addr->bar = dataaddr & 0xffff;
+               addr->wcr = -(((datalen + 1) >> 1) + 1);
+               cmdcsr = ((dataaddr >> 12) & 0x30) | IE | UNOUT;
+               addr->csr = cmdcsr;
+               addr->csr = cmdcsr | GO;
+       }
+}
+
+/*
+ * Ungermann-Bass interface interrupt handler.
+ * Determines reason for interrupt and acts accordingly.
+ */
+unintr(unit)
+       int unit;
+{
+       register struct un_softc *us = &un_softc[unit];
+       struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
+       register struct un_header *un;
+       struct mbuf *m;
+       int len;
+       register struct ifqueue *inq;
+       int cmdcsr;
+
+       if ((addr->dar & RESETACK) && us->us_state != US_RESET) {
+               if ((us->us_if.if_flags & IFF_UP) == 0)
+                       return;
+               printf("un%d: unexpected reset\n", unit);
+               unerror(unit);
+       }
+               
+       switch (us->us_state) {
+
+       case US_NULL:
+               printf("un%d: stray interrupt\n", unit);
+               break;
+
+       case US_RESET:
+               if (!(addr->dar & RESETACK)) {
+                       addr->csr = IE|UNRESET;
+                       addr->csr = IE|UNRESET|GO;
+                       return;
+               }
+               break;
+
+       case US_IDLE:
+               break;
+
+       case US_READ:
+               us->us_if.if_ipackets++;
+               if (us->us_ifuba.ifu_flags & UBA_NEEDBDP)
+                       UBAPURGE(us->us_ifuba.ifu_uba,
+                               us->us_ifuba.ifu_r.ifrw_bdp);
+               if (addr->csr & STATA) {
+                       if ((us->us_if.if_flags & IFF_UP) == 0)
+                               return;
+                       printf("un%d: input error csr=%b\n", unit,
+                               addr->csr&0xffff, UNBITS);
+                       us->us_if.if_ierrors++;
+                       unerror(unit);
+                       break;
+               }
+               un = (struct un_header *)(us->us_ifuba.ifu_r.ifrw_addr);
+               switch (un->un_ptype) {
+#ifdef INET
+               case UNTYPE_IP:
+                       len = htons((u_short)((struct ip *) (un+1))->ip_len);
+                       schednetisr(NETISR_IP);
+                       inq = &ipintrq;
+                       break;
+#endif
+               case UNTYPE_INQUIRE: {
+                       struct sockaddr_in *sin;
+
+                       us->us_if.if_host[0] =
+                           un->un_dport << 16 | htons(un->un_dniu);
+                       sin = (struct sockaddr_in *)&us->us_if.if_addr;
+                       sin->sin_addr = if_makeaddr(us->us_if.if_net,
+                               us->us_if.if_host[0]);
+                       us->us_if.if_flags |= IFF_UP;
+                       if_rtinit(&us->us_if, RTF_UP);
+                       goto setup;
+               }
+
+               default:
+                       printf("un%d: bad packet type %d\n", un->un_ptype);
+                       goto setup;
+               }
+
+               m = if_rubaget(&us->us_ifuba, len, 0);
+               if (m != 0)
+                       if (IF_QFULL(inq)) {
+                               IF_DROP(inq);
+                               m_freem(m);
+                       } else
+                               IF_ENQUEUE(inq, m);
+               break;
+
+       case US_WRITE:
+               us->us_if.if_opackets++;
+               if (addr->csr & STATA) {
+                       if ((us->us_if.if_flags & IFF_UP) == 0)
+                               return;
+                       printf("un%d: output error csr=%b\n",
+                           unit, addr->csr, UNBITS);
+                       us->us_if.if_oerrors++;
+                       unerror(unit);
+               }
+               if (us->us_ifuba.ifu_xtofree) {
+                       m_freem(us->us_ifuba.ifu_xtofree);
+                       us->us_ifuba.ifu_xtofree = 0;
+               }
+               break;
+
+       default:
+               printf("un%d: invalid state %d csr=%b\n",
+                   us->us_state, addr->csr, UNBITS);
+       }
+
+setup:
+       us->us_state = US_NULL;
+       if (addr->csr & STATB) {
+               us->us_state = US_READ;
+               addr->wcr = -((sizeof (struct un_header) + UNMTU + 1)/2+1);
+               addr->bar = us->us_ifuba.ifu_r.ifrw_info & 0xffff;
+               cmdcsr = ((us->us_ifuba.ifu_r.ifrw_info >> 12) & 0x30);
+               cmdcsr |= IE|UNRDDG;
+               addr->csr = cmdcsr;
+               addr->csr = cmdcsr | GO;
+       } else if (us->us_if.if_snd.ifq_head != 0 && (addr->csr & STATC))
+               unstart(unit);
+       
+       if (us->us_state == US_NULL) {
+               us->us_state = US_IDLE;
+               addr->csr = IE|UNIDLE;
+               addr->csr = IE|UNIDLE|GO;
+       }
+}
+
+/*
+ * Ungermann-Bass output routine.
+ * Encapsulate a packet destined for dst for the local net.
+ */
+unoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       int type, destniu, destport, len;
+       register struct mbuf *m = m0;
+       register struct un_header *un;
+       register struct un_softc *us = &un_softc[ifp->if_unit];
+       int s;
+
+       if ((us->us_if.if_flags & IFF_UP) == 0)
+               return (ENETDOWN);
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET: {
+               struct sockaddr_in *sin = (struct sockaddr_in *)dst;
+               struct ip *ip = mtod(m, struct ip *);
+
+               if (sin->sin_addr.s_addr & 0xffffff00) {
+                       destniu = sin->sin_addr.s_addr >> 24;
+                       destport = (sin->sin_addr.s_addr >> 8) & 0xff;
+               } else {
+                       destniu = 0xffff;
+                       destport = 0xff;
+               }
+               len = htons((u_short) ip->ip_len);
+               type = UNTYPE_IP;
+               break;
+       }
+#endif
+       default:
+               printf("un%d: can't handle af%d\n", ifp->if_unit,
+                       dst->sa_family);
+               m_freem(m0);
+               return (EAFNOSUPPORT);
+       }
+       
+       /*
+        * Add local net header.  If no space in first mbuf,
+        * allocate another.
+        */
+       if (m->m_off > MMAXOFF ||
+           MMINOFF + sizeof (struct un_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       m_freem(m0);
+                       return (ENOBUFS);
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct un_header);
+       } else {
+               m->m_off -= sizeof (struct un_header);
+               m->m_len += sizeof (struct un_header);
+       }
+       un = mtod(m, struct un_header *);
+       bzero((caddr_t)un, sizeof (struct un_header));
+       un->un_length = htons((u_short)(len + sizeof (struct un_header)));
+       un->un_dniu = htons((u_short)destniu);
+       un->un_dport = destport;
+       un->un_dtype = 5;
+       un->un_sniu = htons((u_short)(ifp->if_host[0] >> 24));
+       un->un_sport = (ifp->if_host[0] >> 8) & 0xff;
+       un->un_stype = 5;
+       un->un_ptype = 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);
+               m_freem(m);
+               splx(s);
+               return (ENOBUFS);
+       }
+       IF_ENQUEUE(&ifp->if_snd, m);
+       if (us->us_state == US_IDLE)
+               unstart(ifp->if_unit);
+       splx(s);
+       return (0);
+}
+
+/*
+ * U-B error handler, if maxerr errors have occured
+ * in maxtime seconds, disable the interface.
+ */
+unerror(unit)
+       int unit;
+{
+       register struct un_softc *us = &un_softc[unit];
+       struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
+
+       if (time.tv_sec - us->us_errtime > us->us_maxtime) {
+               us->us_errtime = time.tv_sec;
+               us->us_errcnt = 1;
+       } else if (++us->us_errcnt >= us->us_maxerr) {
+               printf("un%d: error limit exceeded\n", unit);
+               us->us_if.if_flags &= ~IFF_UP;
+               addr->csr = 0;
+               us->us_if.if_timer = us->us_restart;
+       }
+}
+
+unrestart(unit)
+       int unit;
+{
+       register struct un_softc *us = &un_softc[unit];
+       struct undevice *addr = (struct undevice *)uninfo[unit]->ui_addr;
+       int s;
+
+       us->us_if.if_flags |= IFF_UP;
+       printf("un%d: restarting\n", unit);
+       unwhoami(unit);
+       s = splimp();
+       addr->csr = IE|UNRESET;
+       addr->csr = IE|UNRESET|GO;
+       us->us_state = US_RESET;
+       splx(s);
+}
+
+/*
+ * Send a "Who am I?" message to the interface. 
+ * Interface should respond with an copy of the
+ * packet with its real address filled in.  The
+ * message is placed at the head of the output queue.
+ * An interface reset should be done next to start
+ * things rolling.
+ */
+unwhoami(unit)             
+       int unit;
+{
+       register struct mbuf *m;
+       register struct un_softc *us = &un_softc[unit];
+       register struct un_header *un;
+       int s;
+
+       if ((m = m_get(M_DONTWAIT, MT_HEADER)) == 0) 
+               return;
+       m->m_off = MMINOFF;
+       m->m_len = sizeof(struct un_header);
+       un = mtod(m, struct un_header *);
+       bzero((caddr_t)un, sizeof (struct un_header));
+       un->un_length = htons(sizeof (struct un_header));
+       un->un_dtype = un->un_stype = 5;
+       un->un_ptype = UNTYPE_INQUIRE;
+       s = splimp();
+       IF_PREPEND(&us->us_if.if_snd, m);
+       splx(s);
+}
+
+/*
+ * Process an ioctl request.
+ */
+unioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, -1);     /* delete previous route */
+               unsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+               if (ifp->if_flags & IFF_RUNNING)
+                       if_rtinit(ifp, RTF_UP);
+               else
+                       uninit(ifp->if_unit);
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+unsetaddr(ifp, sin)
+       register struct ifnet *ifp;
+       register struct sockaddr_in *sin;
+{
+
+       ifp->if_net = in_netof(sin->sin_addr);
+       sin = (struct sockaddr_in *)&ifp->if_addr;
+       sin->sin_family = AF_INET;
+       /* host number filled in already, or filled in later */
+       sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
+       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;
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_un.h b/usr/src/sys/vaxif/if_un.h
new file mode 100644 (file)
index 0000000..4703b66
--- /dev/null
@@ -0,0 +1,29 @@
+/*     if_un.h 6.1     83/07/29        */
+
+/*
+ * Structure of a Ungermann-Bass datagram header.
+ */
+
+struct un_header {
+       u_short un_length;
+       u_char  un_type;
+       u_char  un_control;
+       u_short un_dnet;
+       u_short un_dniu;
+       u_char  un_dport;
+       u_char  un_dtype;
+       u_short un_snet;
+       u_short un_sniu;
+       u_char  un_sport;
+       u_char  un_stype;
+       u_char  un_option;
+       u_char  un_bcc;
+       u_short un_ptype;       /* protocol type */
+};
+
+/*
+ * Protocol types
+ */
+
+#define        UNTYPE_INQUIRE          1       /* inquire - "Who am I?" */
+#define        UNTYPE_IP               2       /* Internet Protocol */
diff --git a/usr/src/sys/vaxif/if_unreg.h b/usr/src/sys/vaxif/if_unreg.h
new file mode 100644 (file)
index 0000000..2c7e19e
--- /dev/null
@@ -0,0 +1,55 @@
+/*     if_unreg.h      6.1     83/07/29        */
+
+/*
+ * Device registers and bit meanings
+ */
+
+struct undevice {
+       short   wcr;    /* word count */
+       short   bar;    /* bus address */
+       short   csr;    /* control & status (also error & info) */
+       short   dar;    /* input and output data register */
+};
+
+/* CSR bits */
+#define GO     0000001
+#define FCN1   0000002         /* three function bits */
+#define FCN2   0000004 
+#define FCN3   0000010 
+#define XBA    0000060         /* extended bus address (16&17) */
+#define IE     0000100         /* interrupt enable */
+#define RDY    0000200         /* ready */
+#define CYCL   0000400         /* cycle */
+#define        STATC   0001000         /* Status bit C */
+#define        STATB   0002000         /* Status bit B */
+#define        STATA   0004000         /* Status bit A */
+#define MNT    0010000         /* maintenance */
+#define ATTN   0020000         /* attention (from device) */
+#define NEX    0040000         /* non-existent memory */
+#define ERR    0100000
+#define XADD   4
+
+#define        UNBITS  "\10\20ERR\17NEX\16ATTN\15MNT\14STATA\13STATB\12STATC\
+\11CYCL\10RDY\7IE\6XBA17\5XBA16\4FCN3\3FCN2\2FCN1\1GO"
+
+/* EIR bits */
+#define RF     0000001         /* register flag 1 - verifies EIR */
+#define NBST   0000400         /* N - cycle burst */
+#define BDLT   0001000         /* burst data late */
+#define PERR   0002000         /* parity error */
+#define ACLO   0004000         /* power fail */
+#define MCYC   0010000         /* multicycle request */
+#define ATTN   0020000         /* attention (from device) */
+#define NEX    0040000         /* non-existent memory */
+#define ERR    0100000
+
+/* Network interface commands */
+#define        UNRESET 0
+#define        UNRDHDR FCN1
+#define        UNOUT   FCN2
+#define        UNRDDG  (FCN2|FCN1)
+#define        UNFLUSH FCN3
+#define        UNIDLE  (FCN3|FCN2)
+
+/* Extended status bits (in dar) */
+#define RESETACK       1       /* Reset cmd acknowledged */
diff --git a/usr/src/sys/vaxif/if_vv.c b/usr/src/sys/vaxif/if_vv.c
new file mode 100644 (file)
index 0000000..edde2c4
--- /dev/null
@@ -0,0 +1,928 @@
+/*     if_vv.c 6.1     83/07/29        */
+
+#include "vv.h"
+
+/*
+ * Proteon 10 Meg Ring Driver.
+ * This device is called "vv" because its "real name",
+ * V2LNI won't work if shortened to the obvious "v2".
+ * Hence the subterfuge.
+ *
+ */
+#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/errno.h"
+#include "../h/time.h"
+#include "../h/kernel.h"
+#include "../h/ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#include "../vax/mtpr.h"
+#include "../vax/cpu.h"
+
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
+
+#include "../vaxif/if_vv.h"
+#include "../vaxif/if_uba.h"
+
+/*
+ * N.B. - if WIRECENTER is defined wrong, it can well break
+ * the hardware!!
+ */
+#define        WIRECENTER
+
+#ifdef WIRECENTER
+#define        VV_CONF VV_HEN          /* drive wire center relay */
+#else
+#define        VV_CONF VV_STE          /* allow operation without wire center */
+#endif
+
+#define        VVMTU   (1024+512)
+#define VVMRU  (1024+512+16)   /* space for trailer */
+
+int vv_tracehdr = 0,           /* 1 => trace headers (slowly!!) */
+    vv_tracetimeout = 1;       /* 1 => trace input error-rate limiting */
+    vv_logreaderrors = 0;      /* 1 => log all read errors */
+
+#define vvtracehdr     if (vv_tracehdr) vvprt_hdr
+#define        vvtrprintf      if (vv_tracetimeout) printf
+
+int vv_ticking = 0;            /* error flywheel is running */
+
+/*
+ * Interval in HZ - 50 msec.
+ * N.B. all times below are in units of flywheel ticks
+ */
+#define VV_FLYWHEEL            3
+#define        VV_ERRORTHRESHOLD       100     /* errors/flywheel-interval */
+#define        VV_MODE1ATTEMPTS        10      /* number mode 1 retries */
+#define        VV_MODE1DELAY           2       /* period interface is PAUSEd - 100ms */
+#define VV_MODE2DELAY          4       /* base interval host relay is off - 200ms */
+#define        VV_MAXDELAY             6400    /* max interval host relay is off - 2 minutes */
+
+int    vvprobe(), vvattach(), vvrint(), vvxint();
+struct uba_device *vvinfo[NVV];
+u_short vvstd[] = { 0 };
+struct uba_driver vvdriver =
+       { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
+#define        VVUNIT(x)       minor(x)
+int    vvinit(),vvioctl(),vvoutput(),vvreset();
+
+/*
+ * Software status of each interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * vs_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ * We also have, for each interface, a UBA interface structure, which
+ * contains information about the UNIBUS resources held by the interface:
+ * map registers, buffered data paths, etc.  Information is cached in this
+ * structure for use by the if_uba.c routines in running the interface
+ * efficiently.
+ */
+struct vv_softc {
+       struct  ifnet vs_if;            /* network-visible interface */
+       struct  ifuba vs_ifuba;         /* UNIBUS resources */
+       short   vs_oactive;             /* is output active */
+       short   vs_iactive;             /* is input active */
+       short   vs_olen;                /* length of last output */
+       u_short vs_lastx;               /* last destination address */
+       short   vs_tries;               /* transmit current retry count */
+       short   vs_init;                /* number of ring inits */
+       short   vs_nottaken;            /* number of packets refused */
+       /* input error rate limiting state */
+       short   vs_major;               /* recovery major state */
+       short   vs_minor;               /* recovery minor state */
+       short   vs_retry;               /* recovery retry count */
+       short   vs_delayclock;          /* recovery delay clock */
+       short   vs_delayrange;          /* increasing delay interval */
+       short   vs_dropped;             /* number of packes tossed in last dt */
+} vv_softc[NVV];
+
+/*
+ * States of vs_iactive.
+ */
+#define        ACTIVE  1               /* interface should post new receives */
+#define        PAUSE   0               /* interface should NOT post new receives */
+#define        OPEN    -1              /* PAUSE and open host relay */
+
+/*
+ * Recovery major states.
+ */
+#define        MODE0   0               /* everything is wonderful */
+#define        MODE1   1               /* hopefully whatever will go away */
+#define        MODE2   2               /* drastic measures - open host relay for increasing intervals */
+
+vvprobe(reg)
+       caddr_t reg;
+{
+       register int br, cvec;
+       register struct vvreg *addr = (struct vvreg *)reg;
+
+#ifdef lint
+       br = 0; cvec = br; br = cvec; vvrint(0);
+#endif
+       /* reset interface, enable, and wait till dust settles */
+       addr->vvicsr = VV_RST;
+       addr->vvocsr = VV_RST;
+       DELAY(10000);
+       /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
+       addr->vvocsr = VV_IEN;          /* enable interrupt */
+       addr->vvoba = 0;                /* low 16 bits */
+       addr->vvoea = 0;                /* extended bits */
+       addr->vvowc = -1;               /* for 1 word */
+       addr->vvocsr |= VV_DEN;         /* start the DMA */
+       DELAY(100000);
+       addr->vvocsr = 0;
+       if (cvec && cvec != 0x200)
+               cvec -= 4;              /* backup so vector => recieve */
+       return(1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record.  System will initialize the interface when it is ready
+ * to accept packets.
+ */
+vvattach(ui)
+       struct uba_device *ui;
+{
+       register struct vv_softc *vs = &vv_softc[ui->ui_unit];
+
+       vs->vs_if.if_unit = ui->ui_unit;
+       vs->vs_if.if_name = "vv";
+       vs->vs_if.if_mtu = VVMTU;
+       vs->vs_if.if_init = vvinit;
+       vs->vs_if.if_ioctl = vvioctl;
+       vs->vs_if.if_output = vvoutput;
+       vs->vs_if.if_reset = vvreset;
+       vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
+#if defined(VAX750)
+       /* don't chew up 750 bdp's */
+       if (cpu == VAX_750 && ui->ui_unit > 0)
+               vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
+#endif
+       if_attach(&vs->vs_if);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+vvreset(unit, uban)
+       int unit, uban;
+{
+       register struct uba_device *ui;
+
+       if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
+           ui->ui_ubanum != uban)
+               return;
+       printf(" vv%d", unit);
+       vvinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+vvinit(unit)
+       int unit;
+{
+       register struct vv_softc *vs = &vv_softc[unit];
+       register struct uba_device *ui = vvinfo[unit];
+       register struct vvreg *addr;
+       struct sockaddr_in *sin;
+       int ubainfo, s;
+       int vvtimeout();
+
+       if (vs->vs_if.if_net == 0)
+               return;
+       addr = (struct vvreg *)ui->ui_addr;
+       if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
+           sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 
+               printf("vv%d: can't initialize\n", unit);
+               vs->vs_if.if_flags &= ~IFF_UP;
+               return;
+       }
+       if (vv_ticking++ == 0)
+               timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
+       /*
+        * Discover our host address and post it
+        */
+       vs->vs_if.if_host[0] = vvidentify(unit);
+       printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
+       sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
+       sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
+       sin->sin_family = AF_INET;
+       sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
+
+       /*
+        * Reset the interface, and join the ring
+        */
+       addr->vvocsr = VV_RST | VV_CPB;         /* clear packet buffer */
+       addr->vvicsr = VV_RST | VV_CONF;        /* close logical relay */
+       DELAY(500000);                          /* let contacts settle */
+       vs->vs_init = 0;
+       vs->vs_dropped = 0;
+       vs->vs_nottaken = 0;
+
+       /*
+        * Hang a receive and start any
+        * pending writes by faking a transmit complete.
+        */
+       s = splimp();
+       ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+       addr->vviba = (u_short)ubainfo;
+       addr->vviea = (u_short)(ubainfo >> 16);
+       addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
+       addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
+       vs->vs_iactive = ACTIVE;
+       vs->vs_oactive = 1;
+       vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
+       vvxint(unit);
+       splx(s);
+       if_rtinit(&vs->vs_if, RTF_UP);
+}
+
+/*
+ * vvidentify() - return our host address
+ */
+vvidentify(unit)
+       int unit;
+{
+       register struct vv_softc *vs = &vv_softc[unit];
+       register struct uba_device *ui = vvinfo[unit];
+       register struct vvreg *addr;
+       struct mbuf *m;
+       struct vv_header *v;
+       int ubainfo, attempts, waitcount;
+
+       /*
+        * Build a multicast message to identify our address
+        */
+       addr = (struct vvreg *)ui->ui_addr;
+       attempts = 0;           /* total attempts, including bad msg type */
+       m = m_get(M_DONTWAIT, MT_HEADER);
+       if (m == NULL)
+               return (0);
+       m->m_next = 0;
+       m->m_off = MMINOFF;
+       m->m_len = sizeof(struct vv_header);
+       v = mtod(m, struct vv_header *);
+       v->vh_dhost = VV_BROADCAST;     /* multicast destination address */
+       v->vh_shost = 0;                /* will be overwritten with ours */
+       v->vh_version = RING_VERSION;
+       v->vh_type = RING_WHOAMI;
+       v->vh_info = 0;
+       /* map xmit message into uba */
+       vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
+       /*
+        * Reset interface, establish Digital Loopback Mode, and
+        * send the multicast (to myself) with Input Copy enabled.
+        */
+retry:
+       ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+       addr->vvicsr = VV_RST;
+       addr->vviba = (u_short) ubainfo;
+       addr->vviea = (u_short) (ubainfo >> 16);
+       addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
+       addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
+
+       /* let flag timers fire so ring will initialize */
+       DELAY(2000000);
+
+       addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
+       ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
+       addr->vvoba = (u_short) ubainfo;
+       addr->vvoea = (u_short) (ubainfo >> 16);
+       addr->vvowc = -((vs->vs_olen + 1) >> 1);
+       addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
+       /*
+        * Wait for receive side to finish.
+        * Extract source address (which will our own),
+        * and post to interface structure.
+        */
+       DELAY(1000);
+       for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
+               if (waitcount < 10) {
+                       DELAY(1000);
+                       continue;
+               }
+               if (attempts++ >= 10) {
+                       printf("vv%d: can't initialize\n", unit);
+                       printf("vvinit loopwait: icsr = %b\n",
+                               0xffff&(addr->vvicsr), VV_IBITS);
+                       vs->vs_if.if_flags &= ~IFF_UP;
+                       return (0);
+               }
+               goto retry;
+       }
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
+       if (vs->vs_ifuba.ifu_xtofree)
+               m_freem(vs->vs_ifuba.ifu_xtofree);
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
+       m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
+       if (m != NULL)
+               m_freem(m);
+       /*
+        * Check message type before we believe the source host address
+        */
+       v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
+       if (v->vh_type != RING_WHOAMI)
+               goto retry;
+       return(v->vh_shost);
+}
+
+/*
+ * vvtimeout() - called by timer flywheel to monitor input packet
+ * discard rate.  Interfaces getting too many errors are shut
+ * down for a while.  If the condition persists, the interface
+ * is marked down.
+ */
+/*ARGSUSED*/
+vvtimeout(junk)
+       int junk;
+{
+       register struct vv_softc *vs;
+       register int i;
+       register struct vvreg *addr;
+       int ubainfo;
+
+       timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
+       for (i = 0; i < NVV; i++) {
+               vs = &vv_softc[i];
+               addr = (struct vvreg *)vvinfo[i]->ui_addr;
+               if ((vs->vs_if.if_flags & IFF_UP) == 0)
+                       continue;
+               switch (vs->vs_major) {
+
+               /*
+                * MODE0: generally OK, just check error rate 
+                */
+               case MODE0:
+                       if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+                               vs->vs_dropped = 0;
+                               continue;
+                       }
+                       /* suspend reads for a while */
+                       vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
+                       vs->vs_major = MODE1;
+                       vs->vs_iactive = PAUSE; /* no new reads */
+                       vs->vs_retry = VV_MODE1ATTEMPTS;
+                       vs->vs_delayclock = VV_MODE1DELAY;
+                       vs->vs_minor = 0;
+                       continue;
+
+               /*
+                * MODE1: excessive error rate observed
+                * Scheme: try simply suspending reads for a
+                * short while a small number of times
+                */
+               case MODE1:
+                       if (vs->vs_delayclock > 0) {
+                               vs->vs_delayclock--;
+                               continue;
+                       }
+                       switch (vs->vs_minor) {
+
+                       case 0:                         /* reenable reads */
+                               vvtrprintf("vv%d M1m0\n",i);
+                               vs->vs_dropped = 0;
+                               vs->vs_iactive = ACTIVE;
+                               vs->vs_minor = 1;       /* next state */
+                               ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+                               addr->vviba = (u_short) ubainfo;
+                               addr->vviea = (u_short) (ubainfo >> 16);
+                               addr->vviwc =
+                                 -(sizeof (struct vv_header) + VVMTU) >> 1;
+                               addr->vvicsr = VV_RST | VV_CONF;
+                               addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
+                               continue;
+
+                       case 1:                         /* see if it worked */
+                               vvtrprintf("vv%d M1m1\n",i);
+                               if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+                                       vs->vs_dropped = 0;
+                                       vs->vs_major = MODE0;   /* yeah!! */
+                                       continue;
+                               }
+                               if (vs->vs_retry -- > 0) {
+                                       vs->vs_dropped = 0;
+                                       vs->vs_iactive = PAUSE;
+                                       vs->vs_delayclock = VV_MODE1DELAY;
+                                       vs->vs_minor = 0; /* recheck */
+                                       continue;
+                               }
+                               vs->vs_major = MODE2;
+                               vs->vs_minor = 0;
+                               vs->vs_dropped = 0;
+                               vs->vs_iactive = OPEN;
+                               vs->vs_delayrange = VV_MODE2DELAY;
+                               vs->vs_delayclock = VV_MODE2DELAY;
+                               /* fall thru ... */
+                       }
+
+               /*
+                * MODE2: simply ignoring traffic didn't relieve condition
+                * Scheme: open host relay for intervals linearly
+                * increasing up to some maximum of a several minutes.
+                * This allows broken networks to return to operation
+                * without rebooting.
+                */
+               case MODE2:
+                       if (vs->vs_delayclock > 0) {
+                               vs->vs_delayclock--;
+                               continue;
+                       }
+                       switch (vs->vs_minor) {
+
+                       case 0:         /* close relay and reenable reads */
+                               vvtrprintf("vv%d M2m0\n",i);
+                               vs->vs_dropped = 0;
+                               vs->vs_iactive = ACTIVE;
+                               vs->vs_minor = 1;       /* next state */
+                               ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+                               addr->vviba = (u_short) ubainfo;
+                               addr->vviea = (u_short) (ubainfo >> 16);
+                               addr->vviwc =
+                                 -(sizeof (struct vv_header) + VVMTU) >> 1;
+                               addr->vvicsr = VV_RST | VV_CONF;
+                               addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
+                               continue;
+
+                       case 1:                         /* see if it worked */
+                               vvtrprintf("vv%d M2m1\n",i);
+                               if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
+                                       vs->vs_dropped = 0;
+                                       vs->vs_major = MODE0;   /* yeah!! */
+                                       continue;
+                               }
+                               vvtrprintf("vv%d M2m1 ++ delay\n",i);
+                               vs->vs_dropped = 0;
+                               vs->vs_iactive = OPEN;
+                               vs->vs_minor = 0;
+                               if (vs->vs_delayrange < VV_MAXDELAY)
+                                       vs->vs_delayrange +=
+                                         (vs->vs_delayrange/2);
+                               vs->vs_delayclock = vs->vs_delayrange;
+                               continue;
+                       }
+
+               default:
+                       printf("vv%d: major state screwed\n", i);
+                       vs->vs_if.if_flags &= ~IFF_UP;
+               }
+       }
+}
+
+/*
+ * Start or restart output on interface.
+ * If interface is active, this is a retransmit, so just
+ * restuff registers and go.
+ * If interface is not already active, get another datagram
+ * to send off of the interface queue, and map it to the interface
+ * before starting the output.
+ */
+vvstart(dev)
+       dev_t dev;
+{
+        int unit = VVUNIT(dev);
+       struct uba_device *ui = vvinfo[unit];
+       register struct vv_softc *vs = &vv_softc[unit];
+       register struct vvreg *addr;
+       struct mbuf *m;
+       int ubainfo;
+       int dest;
+
+       if (vs->vs_oactive)
+               goto restart;
+       /*
+        * Not already active: dequeue another request
+        * and map it to the UNIBUS.  If no more requests,
+        * just return.
+        */
+       IF_DEQUEUE(&vs->vs_if.if_snd, m);
+       if (m == NULL) {
+               vs->vs_oactive = 0;
+               return;
+       }
+       dest = mtod(m, struct vv_header *)->vh_dhost;
+       vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
+       vs->vs_lastx = dest;
+restart:
+       /*
+        * Have request mapped to UNIBUS for transmission.
+        * Purge any stale data from this BDP, and start the otput.
+        */
+       if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
+               printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
+               panic("vvdriver vs_olen botch");
+       }
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
+       addr = (struct vvreg *)ui->ui_addr;
+       ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
+       addr->vvoba = (u_short) ubainfo;
+       addr->vvoea = (u_short) (ubainfo >> 16);
+       addr->vvowc = -((vs->vs_olen + 1) >> 1);
+       addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
+       vs->vs_oactive = 1;
+}
+
+/*
+ * VVLNI transmit interrupt
+ * Start another output if more data to send.
+ */
+vvxint(unit)
+       int unit;
+{
+       register struct uba_device *ui = vvinfo[unit];
+       register struct vv_softc *vs = &vv_softc[unit];
+       register struct vvreg *addr;
+       register int oc;
+
+       addr = (struct vvreg *)ui->ui_addr;
+       oc = 0xffff & (addr->vvocsr);
+       if (vs->vs_oactive == 0) {
+               printf("vv%d: stray interrupt vvocsr = %b\n", unit,
+                       oc, VV_OBITS);
+               return;
+       }
+       if (oc &  (VV_OPT | VV_RFS)) {
+               vs->vs_if.if_collisions++;
+               if (vs->vs_tries++ < VVRETRY) {
+                       if (oc & VV_OPT)
+                               vs->vs_init++;
+                       if (oc & VV_RFS)
+                               vs->vs_nottaken++;
+                       vvstart(unit);          /* restart this message */
+                       return;
+               }
+               if (oc & VV_OPT)
+                       printf("vv%d: output timeout\n");
+       }
+       vs->vs_if.if_opackets++;
+       vs->vs_oactive = 0;
+       vs->vs_tries = 0;
+       if (oc & VVXERR) {
+               vs->vs_if.if_oerrors++;
+               printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
+                       VV_OBITS);
+       }
+       if (vs->vs_ifuba.ifu_xtofree) {
+               m_freem(vs->vs_ifuba.ifu_xtofree);
+               vs->vs_ifuba.ifu_xtofree = 0;
+       }
+       if (vs->vs_if.if_snd.ifq_head == 0) {
+               vs->vs_lastx = 256;             /* an invalid address */
+               return;
+       }
+       vvstart(unit);
+}
+
+/*
+ * V2lni interface receiver interrupt.
+ * If input error just drop packet.
+ * Otherwise purge input buffered data path and examine 
+ * packet to determine type.  If can't determine length
+ * from type, then have to drop packet.  Othewise decapsulate
+ * packet based on type and pass to type specific higher-level
+ * input routine.
+ */
+vvrint(unit)
+       int unit;
+{
+       register struct vv_softc *vs = &vv_softc[unit];
+       struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
+       register struct vv_header *vv;
+       register struct ifqueue *inq;
+       struct mbuf *m;
+       int ubainfo, len, off;
+       short resid;
+
+       vs->vs_if.if_ipackets++;
+       /*
+        * Purge BDP; drop if input error indicated.
+        */
+       if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
+               UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
+       if (addr->vvicsr & VVRERR) {
+               if (vv_logreaderrors)
+                       printf("vv%d: error vvicsr = %b\n", unit,
+                               0xffff&(addr->vvicsr), VV_IBITS);
+               goto dropit;
+       }
+
+       /*
+        * Get packet length from word count residue
+        *
+        * Compute header offset if trailer protocol
+        *
+        * Pull packet off interface.  Off is nonzero if packet
+        * has trailing header; if_rubaget will then force this header
+        * information to be at the front.  The vh_info field
+        * carries the offset to the trailer data in trailer
+        * format packets.
+        */
+       vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
+       vvtracehdr("vi", vv);
+       resid = addr->vviwc;
+       if (resid)
+               resid |= 0176000;               /* ugly!!!! */
+       len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
+       len -= sizeof(struct vv_header);
+       if (len > VVMRU || len <= 0)
+               goto dropit;
+#define        vvdataaddr(vv, off, type)       ((type)(((caddr_t)((vv)+1)+(off))))
+       if (vv->vh_type >= RING_IPTrailer &&
+            vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
+               off = (vv->vh_type - RING_IPTrailer) * 512;
+               if (off > VVMTU)
+                       goto dropit;
+               vv->vh_type = *vvdataaddr(vv, off, u_short *);
+               resid = *(vvdataaddr(vv, off+2, u_short *));
+               if (off + resid > len)
+                       goto dropit;
+               len = off + resid;
+       } else
+               off = 0;
+       if (len == 0)
+               goto dropit;
+       m = if_rubaget(&vs->vs_ifuba, len, off);
+       if (m == NULL)
+               goto dropit;
+       if (off) {
+               m->m_off += 2 * sizeof(u_short);
+               m->m_len -= 2 * sizeof(u_short);
+       }
+
+       /*
+        * Demultiplex on packet type 
+        */
+       switch (vv->vh_type) {
+
+#ifdef INET
+       case RING_IP:
+               schednetisr(NETISR_IP);
+               inq = &ipintrq;
+               break;
+#endif
+       default:
+               printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
+               m_freem(m);
+               goto setup;
+       }
+       if (IF_QFULL(inq)) {
+               IF_DROP(inq);
+               m_freem(m);
+       } else
+               IF_ENQUEUE(inq, m);
+setup:
+       /*
+        * Check the error rate and start recovery if needed
+        * this has to go here since the timer flywheel runs at
+        * a lower ipl and never gets a chance to change the mode
+        */
+       if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
+               vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
+               vs->vs_major = MODE1;
+               vs->vs_iactive = PAUSE;         /* no new reads */
+               vs->vs_retry = VV_MODE1ATTEMPTS;
+               vs->vs_delayclock = VV_MODE1DELAY;
+               vs->vs_minor = 0;
+               vs->vs_dropped = 0;
+       }
+       switch (vs->vs_iactive) {
+
+       case ACTIVE:            /* Restart the read for next packet */
+               ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
+               addr->vviba = (u_short) ubainfo;
+               addr->vviea = (u_short) (ubainfo >> 16);
+               addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
+               addr->vvicsr = VV_RST | VV_CONF;
+               addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
+               return;
+
+       case PAUSE:             /* requested to not start any new reads */
+               vs->vs_dropped = 0;
+               return;
+
+       case OPEN:              /* request to open host relay */
+               vs->vs_dropped = 0;
+               addr->vvicsr = 0;
+               return;
+
+       default:
+               printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
+               return;
+       }
+       /*
+        * Drop packet on floor -- count them!!
+        */
+dropit:
+       vs->vs_if.if_ierrors++;
+       vs->vs_dropped++;
+       /*
+       printf("vv%d: error vvicsr = %b\n", unit,
+               0xffff&(addr->vvicsr), VV_IBITS);
+       */
+       goto setup;
+}
+
+/*
+ * V2lni 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.
+ */
+vvoutput(ifp, m0, dst)
+       struct ifnet *ifp;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+       register struct mbuf *m = m0;
+       register struct vv_header *vv;
+       register int off;
+       int type, dest, s, error;
+
+       switch (dst->sa_family) {
+
+#ifdef INET
+       case AF_INET: {
+               dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
+               if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
+                       error = EPERM;
+                       goto bad;
+               }
+               off = ntohs((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 = RING_IPTrailer + (off>>9);
+                       m->m_off -= 2 * sizeof (u_short);
+                       m->m_len += 2 * sizeof (u_short);
+                       *mtod(m, u_short *) = RING_IP;
+                       *(mtod(m, u_short *) + 1) = m->m_len;
+                       goto gottrailertype;
+               }
+               type = RING_IP;
+               off = 0;
+               goto gottype;
+               }
+#endif
+       default:
+               printf("vv%d: can't handle af%d\n", ifp->if_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 (struct vv_header) > m->m_off) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == NULL) {
+                       error = ENOBUFS;
+                       goto bad;
+               }
+               m->m_next = m0;
+               m->m_off = MMINOFF;
+               m->m_len = sizeof (struct vv_header);
+       } else {
+               m->m_off -= sizeof (struct vv_header);
+               m->m_len += sizeof (struct vv_header);
+       }
+       vv = mtod(m, struct vv_header *);
+       vv->vh_shost = ifp->if_host[0];
+       vv->vh_dhost = dest;
+       vv->vh_version = RING_VERSION;
+       vv->vh_type = type;
+       vv->vh_info = off;
+       vvtracehdr("vo", vv);
+
+       /*
+        * 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);
+       if (vv_softc[ifp->if_unit].vs_oactive == 0)
+               vvstart(ifp->if_unit);
+       splx(s);
+       return (0);
+qfull:
+       m0 = m;
+       splx(s);
+bad:
+       m_freem(m0);
+       return(error);
+}
+
+/*
+ * Process an ioctl request.
+ */
+vvioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       struct ifreq *ifr = (struct ifreq *)data;
+       int s = splimp(), error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               /* too difficult to change addr while running */
+               if ((ifp->if_flags & IFF_RUNNING) == 0) {
+                       struct sockaddr_in *sin =
+                           (struct sockaddr_in *)&ifr->ifr_addr;
+                       ifp->if_net = in_netof(sin->sin_addr);
+                       vvinit(ifp->if_unit);
+               } else
+                       error = EINVAL;
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       splx(s);
+       return (error);
+}
+
+/*
+ * vvprt_hdr(s, v) print the local net header in "v"
+ *     with title is "s"
+ */
+vvprt_hdr(s, v)
+       char *s;
+       register struct vv_header *v;
+{
+       printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+               s,
+               0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
+               0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
+               0xffff & (int)(v->vh_info));
+}
+
+#ifdef notdef
+/*
+ * print "l" hex bytes starting at "s"
+ */
+vvprt_hex(s, l) 
+       char *s;
+       int l;
+{
+       register int i;
+       register int z;
+
+       for (i=0 ; i < l; i++) {
+               z = 0xff & (int)(*(s + i));
+               printf("%c%c ",
+               "0123456789abcdef"[(z >> 4) & 0x0f],
+               "0123456789abcdef"[z & 0x0f]
+               );
+       }
+}
+#endif
diff --git a/usr/src/sys/vaxif/if_vv.h b/usr/src/sys/vaxif/if_vv.h
new file mode 100644 (file)
index 0000000..438db97
--- /dev/null
@@ -0,0 +1,85 @@
+/*     if_vv.h 4.5     83/07/29        */
+/*
+ * Local network header for V2LNI Ring
+ * This is arbitrated by "V2LNI-PEOPLE@MIT-MC"
+ * (aka Joel N. Chiappa)
+ */
+
+#define        NEW_BROADCAST           /* new plas for broadcast problem */
+
+struct vv_header {
+        /* the first two fields are required by the hardware */
+       u_char  vh_dhost;       /* destination address */
+       u_char  vh_shost;       /* source address */
+       /* the next three fields are the local network header */
+       u_char  vh_version;     /* header version */
+       u_char  vh_type;        /* packet type => protocol number */
+       short   vh_info;        /* protocol-specific information */
+};
+
+#define        RING_VERSION    2       /* current version of v2lni header */
+
+/*
+ * Packet types (protocol numbers) in v2lni header
+ */
+#define        RING_IP         1
+#define        RING_IPTrailer  2
+#define        RING_IPNTrailer 16
+#define        RING_WHOAMI     0xa5    /* insure some bit transitions */
+
+#ifdef NEW_BROADCAST
+#define        VV_BROADCAST    0xff    /* hardware-defined broadcast address */
+#else
+#define        VV_BROADCAST    0x00    /* hardware-defined broadcast address */
+#endif
+
+/*
+ * Proteon V2LNI Hardware definitions
+ * register bit definitions - new style
+ */
+#define        VV_ENB  01              /* Enable Operation */
+#define        VV_DEN  02              /* Enable DMA */
+#define        VV_HEN  04              /* Host Relay Enable (Rcv) */
+#define        VV_CPB  04              /* Clear Packet Buffer (Xmit) */
+#define        VV_STE  010             /* Self Test Enable (Rcv) */
+#define        VV_UT1  010             /* Unused (Xmit) */
+#define        VV_LPB  020             /* Modem Disable (Rcv) */
+#define        VV_INR  020             /* Initialize Ring (Xmit) */
+#define        VV_RST  040             /* Reset */
+#define        VV_IEN  0100            /* Interrupt Enable */
+#define        VV_RDY  0200            /* Done */
+#define        VV_DPR  0400            /* Data Present (Rcv) */
+#define        VV_RFS  0400            /* Refused (Xmit) */
+#define        VV_NXM  01000           /* Non Existent Memory */
+#define        VV_OVR  02000           /* Overrun */
+#define        VV_ODB  04000           /* Odd Byte (Achtung, mein Fuehrer) (Rcv) */
+#define        VV_UT2  04000           /* Unused (Xmit) */
+#define        VV_LDE  010000          /* Link Data Error (Rcv) */
+#define        VV_OPT  010000          /* Output Timeout (Xmit) */
+#define        VV_NOK  020000          /* Ring Not OK */
+#define        VV_BDF  040000          /* Bad Format in Operation */
+#define        VV_NIR  0100000         /* Not in Ring */
+
+#define        VVXERR  (VV_NXM|VV_OVR|VV_OPT|VV_BDF)   /* Xmit errs */
+#define        VVRERR  (VV_NXM|VV_OVR|VV_ODB|VV_BDF)   /* Rcv errs */
+#define        VVFE    (VV_NXM|VV_OVR)                 /* Fatal errors */
+
+#define VV_IBITS \
+"\10\20NIR\17BDF\16NOK\15LDE\14ODB\13OVR\12NXM\11DPR\10RDY\7IEN\6RST\5LPB\4STE\3HEN\2DEN\1ENB"
+
+#define VV_OBITS \
+"\10\20NIR\17BDF\16NOK\15OPT\13OVR\12NXM\11RFS\10RDY\7IEN\6RST\5INR\3HEN\2DEN\1ENB"
+
+/* device registers */
+struct vvreg {
+       short   vvicsr;         /* input csr */
+       u_short vviwc;          /* input word count */
+       u_short vviba;          /* input addr lo */
+       u_short vviea;          /* input addr hi */
+       short   vvocsr;         /* output csr */
+       u_short vvowc;          /* output word count */
+       u_short vvoba;          /* output addr lo */
+       u_short vvoea;          /* output addr hi */
+};
+
+#define        VVRETRY 7