summaryrefslogtreecommitdiff
path: root/sys/arch/vax/if
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /sys/arch/vax/if
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/vax/if')
-rw-r--r--sys/arch/vax/if/if_de.c723
-rw-r--r--sys/arch/vax/if/if_dereg.h220
-rw-r--r--sys/arch/vax/if/if_qe.c975
-rw-r--r--sys/arch/vax/if/if_qereg.h172
-rw-r--r--sys/arch/vax/if/if_uba.c390
-rw-r--r--sys/arch/vax/if/if_uba.h136
6 files changed, 2616 insertions, 0 deletions
diff --git a/sys/arch/vax/if/if_de.c b/sys/arch/vax/if/if_de.c
new file mode 100644
index 00000000000..18f01217787
--- /dev/null
+++ b/sys/arch/vax/if/if_de.c
@@ -0,0 +1,723 @@
+/* $NetBSD: if_de.c,v 1.7.2.1 1995/10/15 13:56:24 ragge Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_de.c 7.12 (Berkeley) 12/16/90
+ */
+
+#include "de.h"
+#if NDE > 0
+
+/*
+ * DEC DEUNA interface
+ *
+ * Lou Salkind
+ * New York University
+ *
+ * TODO:
+ * timeout routine (get statistics)
+ */
+
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/mbuf.h"
+#include "sys/buf.h"
+#include "sys/protosw.h"
+#include "sys/socket.h"
+/* #include "sys/vmmac.h" */
+#include "sys/ioctl.h"
+#include "sys/errno.h"
+#include "sys/syslog.h"
+#include "sys/device.h"
+
+#include "vax/include/pte.h"
+#include "vax/include/sid.h"
+
+#include "net/if.h"
+#include "net/netisr.h"
+#include "net/route.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#ifdef ISO
+#include "netiso/iso.h"
+#include "netiso/iso_var.h"
+extern char all_es_snpa[], all_is_snpa[];
+#endif
+
+#include "../include/cpu.h"
+#include "../include/mtpr.h"
+#include "if_dereg.h"
+#include "if_uba.h"
+#include "../uba/ubareg.h"
+#include "../uba/ubavar.h"
+
+#define NXMT 3 /* number of transmit buffers */
+#define NRCV 7 /* number of receive buffers (must be > 1) */
+
+int dedebug = 0;
+
+
+int deprobe(), deattach(), deintr();
+struct uba_device *deinfo[NDE];
+u_short destd[] = { 0 };
+struct uba_driver dedriver =
+ { deprobe, 0, deattach, 0, destd, "de", deinfo };
+int deinit(),deioctl(),dereset();
+void destart();
+
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * ds_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 de_softc {
+ struct arpcom ds_ac; /* Ethernet common part */
+#define ds_if ds_ac.ac_if /* network-visible interface */
+#define ds_addr ds_ac.ac_enaddr /* hardware Ethernet address */
+ int ds_flags;
+#define DSF_RUNNING 2 /* board is enabled */
+#define DSF_SETADDR 4 /* physical address is changed */
+ int ds_ubaddr; /* map info for incore structs */
+ struct ifubinfo ds_deuba; /* unibus resource structure */
+ struct ifrw ds_ifr[NRCV]; /* unibus receive maps */
+ struct ifxmt ds_ifw[NXMT]; /* unibus xmt maps */
+ /* the following structures are always mapped in */
+ struct de_pcbb ds_pcbb; /* port control block */
+ struct de_ring ds_xrent[NXMT]; /* transmit ring entrys */
+ struct de_ring ds_rrent[NRCV]; /* receive ring entrys */
+ struct de_udbbuf ds_udbbuf; /* UNIBUS data buffer */
+ /* end mapped area */
+#define INCORE_BASE(p) ((char *)&(p)->ds_pcbb)
+#define RVAL_OFF(n) ((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0]))
+#define LVAL_OFF(n) ((char *)de_softc[0].n - INCORE_BASE(&de_softc[0]))
+#define PCBB_OFFSET RVAL_OFF(ds_pcbb)
+#define XRENT_OFFSET LVAL_OFF(ds_xrent)
+#define RRENT_OFFSET LVAL_OFF(ds_rrent)
+#define UDBBUF_OFFSET RVAL_OFF(ds_udbbuf)
+#define INCORE_SIZE RVAL_OFF(ds_xindex)
+ int ds_xindex; /* UNA index into transmit chain */
+ int ds_rindex; /* UNA index into receive chain */
+ int ds_xfree; /* index for next transmit buffer */
+ int ds_nxmit; /* # of transmits in progress */
+} de_softc[NDE];
+
+deprobe(reg)
+ caddr_t reg;
+{
+ register int br, cvec; /* r11, r10 value-result */
+ volatile struct dedevice *addr = (struct dedevice *)reg;
+ register i;
+
+#ifdef lint
+ br = 0; cvec = br; br = cvec;
+ i = 0; derint(i); deintr(i);
+#endif
+
+ /*
+ * Make sure self-test is finished before we screw with the board.
+ * Self-test on a DELUA can take 15 seconds (argh).
+ */
+ for (i = 0;
+ i < 160 &&
+ (addr->pcsr0 & PCSR0_FATI) == 0 &&
+ (addr->pcsr1 & PCSR1_STMASK) == STAT_RESET;
+ ++i)
+ waitabit(10);
+ if ((addr->pcsr0 & PCSR0_FATI) != 0 ||
+ (addr->pcsr1 & PCSR1_STMASK) != STAT_READY &&
+ (addr->pcsr1 & PCSR1_STMASK) != STAT_RUN)
+ return(0);
+
+ addr->pcsr0 = 0;
+ waitabit(1);
+ addr->pcsr0 = PCSR0_RSET;
+ while ((addr->pcsr0 & PCSR0_INTR) == 0)
+ ;
+ /* make board interrupt by executing a GETPCBB command */
+ addr->pcsr0 = PCSR0_INTE;
+ addr->pcsr2 = 0;
+ addr->pcsr3 = 0;
+ addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB;
+ waitabit(10);
+ return(1);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets. We get the ethernet address here.
+ */
+deattach(ui)
+ struct uba_device *ui;
+{
+ register struct de_softc *ds = &de_softc[ui->ui_unit];
+ register struct ifnet *ifp = &ds->ds_if;
+ volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr;
+ int csr1;
+
+ ifp->if_unit = ui->ui_unit;
+ ifp->if_name = "de";
+ ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
+
+ /*
+ * What kind of a board is this?
+ * The error bits 4-6 in pcsr1 are a device id as long as
+ * the high byte is zero.
+ */
+ csr1 = addr->pcsr1;
+ if (csr1 & 0xff60)
+ printf("de%d: broken\n", ui->ui_unit);
+ else if (csr1 & 0x10)
+ printf("de%d: delua\n", ui->ui_unit);
+ else
+ printf("de%d: deuna\n", ui->ui_unit);
+
+ /*
+ * Reset the board and temporarily map
+ * the pcbb buffer onto the Unibus.
+ */
+ addr->pcsr0 = 0; /* reset INTE */
+ waitabit(1);
+ addr->pcsr0 = PCSR0_RSET;
+ (void)dewait(ui, "reset");
+
+ ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb,
+ sizeof (struct de_pcbb), 0);
+ addr->pcsr2 = ds->ds_ubaddr & 0xffff;
+ addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3;
+ addr->pclow = CMD_GETPCBB;
+ (void)dewait(ui, "pcbb");
+
+ ds->ds_pcbb.pcbb0 = FC_RDPHYAD;
+ addr->pclow = CMD_GETCMD;
+ (void)dewait(ui, "read addr ");
+
+ ubarelse(ui->ui_ubanum, &ds->ds_ubaddr);
+ bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr,
+ sizeof (ds->ds_addr));
+ printf("de%d: hardware address %s\n", ui->ui_unit,
+ ether_sprintf(ds->ds_addr));
+ ifp->if_ioctl = deioctl;
+ ifp->if_reset = dereset;
+ ifp->if_start = destart;
+ ds->ds_deuba.iff_flags = UBA_CANTWAIT;
+#ifdef notdef
+ /* CAN WE USE BDP's ??? */
+ ds->ds_deuba.iff_flags |= UBA_NEEDBDP;
+#endif
+ if_attach(ifp);
+ ether_ifattach(ifp);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+dereset(unit, uban)
+ int unit, uban;
+{
+ register struct uba_device *ui;
+
+ if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 ||
+ ui->ui_ubanum != uban)
+ return;
+ printf(" de%d", unit);
+ de_softc[unit].ds_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ de_softc[unit].ds_flags &= ~DSF_RUNNING;
+ ((struct dedevice *)ui->ui_addr)->pcsr0 = PCSR0_RSET;
+ (void)dewait(ui, "reset");
+ deinit(unit);
+}
+
+/*
+ * Initialization of interface; clear recorded pending
+ * operations, and reinitialize UNIBUS usage.
+ */
+deinit(unit)
+ int unit;
+{
+ struct de_softc *ds;
+ struct uba_device *ui;
+ volatile struct dedevice *addr;
+ struct ifrw *ifrw;
+ struct ifxmt *ifxp;
+ struct ifnet *ifp;
+ struct de_ring *rp;
+ int s,incaddr;
+
+ ds = &de_softc[unit];
+ ui = deinfo[unit];
+ ifp = &ds->ds_if;
+
+ /* not yet, if address still unknown */
+ if (ifp->if_addrlist.tqh_first == (struct ifaddr *)0)
+ return;
+
+ if (ds->ds_flags & DSF_RUNNING)
+ return;
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ if (if_ubaminit(&ds->ds_deuba, ui->ui_ubanum,
+ sizeof (struct ether_header), (int)btoc(ETHERMTU),
+ ds->ds_ifr, NRCV, ds->ds_ifw, NXMT) == 0) {
+ printf("de%d: can't initialize\n", unit);
+ ds->ds_if.if_flags &= ~IFF_UP;
+ return;
+ }
+ ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds),
+ INCORE_SIZE, 0);
+ }
+ addr = (struct dedevice *)ui->ui_addr;
+
+ /* set the pcbb block address */
+ incaddr = ds->ds_ubaddr + PCBB_OFFSET;
+ addr->pcsr2 = incaddr & 0xffff;
+ addr->pcsr3 = (incaddr >> 16) & 0x3;
+ addr->pclow = 0; /* reset INTE */
+ waitabit(1);
+ addr->pclow = CMD_GETPCBB;
+ (void)dewait(ui, "pcbb");
+
+ /* set the transmit and receive ring header addresses */
+ incaddr = ds->ds_ubaddr + UDBBUF_OFFSET;
+ ds->ds_pcbb.pcbb0 = FC_WTRING;
+ ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
+ ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
+
+ incaddr = ds->ds_ubaddr + XRENT_OFFSET;
+ ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
+ ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
+ ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
+ ds->ds_udbbuf.b_trlen = NXMT;
+ incaddr = ds->ds_ubaddr + RRENT_OFFSET;
+ ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
+ ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
+ ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
+ ds->ds_udbbuf.b_rrlen = NRCV;
+
+ addr->pclow = CMD_GETCMD;
+ (void)dewait(ui, "wtring");
+
+ /* initialize the mode - enable hardware padding */
+ ds->ds_pcbb.pcbb0 = FC_WTMODE;
+ /* let hardware do padding - set MTCH bit on broadcast */
+ ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
+ addr->pclow = CMD_GETCMD;
+ (void)dewait(ui, "wtmode");
+
+ /* set up the receive and transmit ring entries */
+ ifxp = &ds->ds_ifw[0];
+ for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
+ rp->r_segbl = ifxp->ifw_info & 0xffff;
+ rp->r_segbh = (ifxp->ifw_info >> 16) & 0x3;
+ rp->r_flags = 0;
+ ifxp++;
+ }
+ ifrw = &ds->ds_ifr[0];
+ for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
+ rp->r_slen = sizeof (struct de_buf);
+ rp->r_segbl = ifrw->ifrw_info & 0xffff;
+ rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
+ rp->r_flags = RFLG_OWN; /* hang receive */
+ ifrw++;
+ }
+
+ /* start up the board (rah rah) */
+ s = splimp();
+ ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = ds->ds_nxmit = 0;
+ ds->ds_if.if_flags |= IFF_RUNNING;
+ addr->pclow = PCSR0_INTE; /* avoid interlock */
+ destart(&ds->ds_if); /* queue output packets */
+ ds->ds_flags |= DSF_RUNNING; /* need before de_setaddr */
+ if (ds->ds_flags & DSF_SETADDR)
+ de_setaddr(ds->ds_addr, unit);
+ addr->pclow = CMD_START | PCSR0_INTE;
+ splx(s);
+}
+
+/*
+ * Setup output on interface.
+ * Get another datagram to send off of the interface queue,
+ * and map it to the interface before starting the output.
+ * Must be called from ipl >= our interrupt level.
+ */
+void
+destart(ifp)
+ struct ifnet *ifp;
+{
+ int len;
+ int unit = ifp->if_unit;
+ struct uba_device *ui = deinfo[unit];
+ volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr;
+ register struct de_softc *ds = &de_softc[unit];
+ register struct de_ring *rp;
+ struct mbuf *m;
+ register int nxmit;
+
+ /*
+ * the following test is necessary, since
+ * the code is not reentrant and we have
+ * multiple transmission buffers.
+ */
+ if (ds->ds_if.if_flags & IFF_OACTIVE)
+ return;
+ for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
+ IF_DEQUEUE(&ds->ds_if.if_snd, m);
+ if (m == 0)
+ break;
+ rp = &ds->ds_xrent[ds->ds_xfree];
+ if (rp->r_flags & XFLG_OWN)
+ panic("deuna xmit in progress");
+ len = if_ubaput(&ds->ds_deuba, &ds->ds_ifw[ds->ds_xfree], m);
+ if (ds->ds_deuba.iff_flags & UBA_NEEDBDP)
+ UBAPURGE(ds->ds_deuba.iff_uba,
+ ds->ds_ifw[ds->ds_xfree].ifw_bdp);
+ rp->r_slen = len;
+ rp->r_tdrerr = 0;
+ rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
+
+ ds->ds_xfree++;
+ if (ds->ds_xfree == NXMT)
+ ds->ds_xfree = 0;
+ }
+ if (ds->ds_nxmit != nxmit) {
+ ds->ds_nxmit = nxmit;
+ if (ds->ds_flags & DSF_RUNNING)
+ addr->pclow = PCSR0_INTE|CMD_PDMD;
+ }
+}
+
+/*
+ * Command done interrupt.
+ */
+deintr(uba,vector,level,unit)
+{
+ struct uba_device *ui;
+ volatile struct dedevice *addr;
+ register struct de_softc *ds;
+ register struct de_ring *rp;
+ register struct ifxmt *ifxp;
+ short csr0;
+
+ ui = deinfo[unit];
+ addr = (struct dedevice *)ui->ui_addr;
+ ds = &de_softc[unit];
+
+
+ /* save flags right away - clear out interrupt bits */
+ csr0 = addr->pcsr0;
+ addr->pchigh = csr0 >> 8;
+
+
+ ds->ds_if.if_flags |= IFF_OACTIVE; /* prevent entering destart */
+ /*
+ * if receive, put receive buffer on mbuf
+ * and hang the request again
+ */
+ derecv(unit);
+
+ /*
+ * Poll transmit ring and check status.
+ * Be careful about loopback requests.
+ * Then free buffer space and check for
+ * more transmit requests.
+ */
+ for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
+ rp = &ds->ds_xrent[ds->ds_xindex];
+ if (rp->r_flags & XFLG_OWN)
+ break;
+ ds->ds_if.if_opackets++;
+ ifxp = &ds->ds_ifw[ds->ds_xindex];
+ /* check for unusual conditions */
+ if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
+ if (rp->r_flags & XFLG_ERRS) {
+ /* output error */
+ ds->ds_if.if_oerrors++;
+ if (dedebug)
+ printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n",
+ unit, rp->r_flags, XFLG_BITS,
+ rp->r_tdrerr, XERR_BITS, rp->r_slen);
+ } else if (rp->r_flags & XFLG_ONE) {
+ /* one collision */
+ ds->ds_if.if_collisions++;
+ } else if (rp->r_flags & XFLG_MORE) {
+ /* more than one collision */
+ ds->ds_if.if_collisions += 2; /* guess */
+ } else if (rp->r_flags & XFLG_MTCH) {
+ /* received our own packet */
+ ds->ds_if.if_ipackets++;
+ deread(ds, &ifxp->ifrw,
+ rp->r_slen - sizeof (struct ether_header));
+ }
+ }
+ if (ifxp->ifw_xtofree) {
+ m_freem(ifxp->ifw_xtofree);
+ ifxp->ifw_xtofree = 0;
+ }
+ /* check if next transmit buffer also finished */
+ ds->ds_xindex++;
+ if (ds->ds_xindex == NXMT)
+ ds->ds_xindex = 0;
+ }
+ ds->ds_if.if_flags &= ~IFF_OACTIVE;
+ destart(&ds->ds_if);
+
+ if (csr0 & PCSR0_RCBI) {
+ if (dedebug)
+ log(LOG_WARNING, "de%d: buffer unavailable\n", unit);
+ addr->pclow = PCSR0_INTE|CMD_PDMD;
+ }
+}
+
+/*
+ * Ethernet interface receiver interface.
+ * 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.
+ */
+derecv(unit)
+ int unit;
+{
+ register struct de_softc *ds = &de_softc[unit];
+ register struct de_ring *rp;
+ int len;
+
+ rp = &ds->ds_rrent[ds->ds_rindex];
+ while ((rp->r_flags & RFLG_OWN) == 0) {
+ ds->ds_if.if_ipackets++;
+ if (ds->ds_deuba.iff_flags & UBA_NEEDBDP)
+ UBAPURGE(ds->ds_deuba.iff_uba,
+ ds->ds_ifr[ds->ds_rindex].ifrw_bdp);
+ len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
+ - 4; /* don't forget checksum! */
+ /* check for errors */
+ if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
+ (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
+ (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
+ len < ETHERMIN || len > ETHERMTU) {
+ ds->ds_if.if_ierrors++;
+ if (dedebug)
+ printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n",
+ unit, rp->r_flags, RFLG_BITS, rp->r_lenerr,
+ RERR_BITS, len);
+ } else
+ deread(ds, &ds->ds_ifr[ds->ds_rindex], len);
+
+ /* hang the receive buffer again */
+ rp->r_lenerr = 0;
+ rp->r_flags = RFLG_OWN;
+
+ /* check next receive buffer */
+ ds->ds_rindex++;
+ if (ds->ds_rindex == NRCV)
+ ds->ds_rindex = 0;
+ rp = &ds->ds_rrent[ds->ds_rindex];
+ }
+}
+
+/*
+ * Pass a packet to the higher levels.
+ * We deal with the trailer protocol here.
+ */
+deread(ds, ifrw, len)
+ register struct de_softc *ds;
+ struct ifrw *ifrw;
+ int len;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ int s;
+ register struct ifqueue *inq;
+
+ /*
+ * Deal with trailer protocol: if type is trailer type
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+ eh = (struct ether_header *)ifrw->ifrw_addr;
+/* eh->ether_type = ntohs((u_short)eh->ether_type); */
+ if (len == 0)
+ return;
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; if_ubaget will then force this header
+ * information to be at the front.
+ */
+ m = if_ubaget(&ds->ds_deuba, ifrw, len, &ds->ds_if);
+ if (m)
+ ether_input(&ds->ds_if, eh, m);
+}
+/*
+ * Process an ioctl request.
+ */
+deioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ register struct de_softc *ds = &de_softc[ifp->if_unit];
+ int s = splimp(), error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ deinit(ifp->if_unit);
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ arp_ifinit(&ds->ds_ac, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)(ds->ds_addr);
+ else
+ de_setaddr(ina->x_host.c_host,ifp->if_unit);
+ break;
+ }
+#endif
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ ds->ds_flags & DSF_RUNNING) {
+ ((struct dedevice *)
+ (deinfo[ifp->if_unit]->ui_addr))->pclow = 0;
+ waitabit(1);
+ ((struct dedevice *)
+ (deinfo[ifp->if_unit]->ui_addr))->pclow = PCSR0_RSET;
+ ds->ds_flags &= ~DSF_RUNNING;
+ ds->ds_if.if_flags &= ~IFF_OACTIVE;
+ } else if (ifp->if_flags & IFF_UP &&
+ (ds->ds_flags & DSF_RUNNING) == 0)
+ deinit(ifp->if_unit);
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return (error);
+}
+
+/*
+ * set ethernet address for unit
+ */
+de_setaddr(physaddr, unit)
+ u_char *physaddr;
+ int unit;
+{
+ register struct de_softc *ds = &de_softc[unit];
+ struct uba_device *ui = deinfo[unit];
+ volatile struct dedevice *addr= (struct dedevice *)ui->ui_addr;
+
+ if (! (ds->ds_flags & DSF_RUNNING))
+ return;
+
+ bcopy((caddr_t) physaddr, (caddr_t) &ds->ds_pcbb.pcbb2, 6);
+ ds->ds_pcbb.pcbb0 = FC_WTPHYAD;
+ addr->pclow = PCSR0_INTE|CMD_GETCMD;
+ if (dewait(ui, "address change") == 0) {
+ ds->ds_flags |= DSF_SETADDR;
+ bcopy((caddr_t) physaddr, (caddr_t) ds->ds_addr, 6);
+ }
+}
+
+/*
+ * Await completion of the named function
+ * and check for errors.
+ */
+dewait(ui, fn)
+ register struct uba_device *ui;
+ char *fn;
+{
+ volatile struct dedevice *addr = (struct dedevice *)ui->ui_addr;
+ register csr0;
+
+ while ((addr->pcsr0 & PCSR0_INTR) == 0)
+ ;
+ csr0 = addr->pcsr0;
+ addr->pchigh = csr0 >> 8;
+ if (csr0 & PCSR0_PCEI)
+ printf("de%d: %s failed, csr0=%b csr1=%b\n",
+ ui->ui_unit, fn, csr0, PCSR0_BITS,
+ addr->pcsr1, PCSR1_BITS);
+ return (csr0 & PCSR0_PCEI);
+}
+
+de_match(){
+ printf("de_match\n");
+ return 0;
+}
+
+void
+de_attach(){
+ printf("de_attach\n");
+}
+
+struct cfdriver decd =
+ { NULL,"de",de_match, de_attach, DV_IFNET, sizeof(struct uba_driver) };
+
+
+#endif
diff --git a/sys/arch/vax/if/if_dereg.h b/sys/arch/vax/if/if_dereg.h
new file mode 100644
index 00000000000..2f2b48c9796
--- /dev/null
+++ b/sys/arch/vax/if/if_dereg.h
@@ -0,0 +1,220 @@
+/* $NetBSD: if_dereg.h,v 1.2 1994/10/26 08:01:51 cgd Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_dereg.h 7.3 (Berkeley) 6/28/90
+ */
+
+/*
+ * DEC DEUNA interface
+ */
+struct dedevice {
+ union {
+ short p0_w;
+ char p0_b[2];
+ } u_p0;
+#define pcsr0 u_p0.p0_w
+#define pclow u_p0.p0_b[0]
+#define pchigh u_p0.p0_b[1]
+ short pcsr1;
+ short pcsr2;
+ short pcsr3;
+};
+
+/*
+ * PCSR 0 bit descriptions
+ */
+#define PCSR0_SERI 0x8000 /* Status error interrupt */
+#define PCSR0_PCEI 0x4000 /* Port command error interrupt */
+#define PCSR0_RXI 0x2000 /* Receive done interrupt */
+#define PCSR0_TXI 0x1000 /* Transmit done interrupt */
+#define PCSR0_DNI 0x0800 /* Done interrupt */
+#define PCSR0_RCBI 0x0400 /* Receive buffer unavail intrpt */
+#define PCSR0_FATI 0x0100 /* Fatal error interrupt */
+#define PCSR0_INTR 0x0080 /* Interrupt summary */
+#define PCSR0_INTE 0x0040 /* Interrupt enable */
+#define PCSR0_RSET 0x0020 /* DEUNA reset */
+#define PCSR0_CMASK 0x000f /* command mask */
+
+#define PCSR0_BITS "\20\20SERI\17PCEI\16RXI\15TXI\14DNI\13RCBI\11FATI\10INTR\7INTE\6RSET"
+
+/* bits 0-3 are for the PORT_COMMAND */
+#define CMD_NOOP 0x0
+#define CMD_GETPCBB 0x1 /* Get PCB Block */
+#define CMD_GETCMD 0x2 /* Execute command in PCB */
+#define CMD_STEST 0x3 /* Self test mode */
+#define CMD_START 0x4 /* Reset xmit and receive ring ptrs */
+#define CMD_BOOT 0x5 /* Boot DEUNA */
+#define CMD_PDMD 0x8 /* Polling demand */
+#define CMD_TMRO 0x9 /* Sanity timer on */
+#define CMD_TMRF 0xa /* Sanity timer off */
+#define CMD_RSTT 0xb /* Reset sanity timer */
+#define CMD_STOP 0xf /* Suspend operation */
+
+/*
+ * PCSR 1 bit descriptions
+ */
+#define PCSR1_XPWR 0x8000 /* Transceiver power BAD */
+#define PCSR1_ICAB 0x4000 /* Interconnect cabling BAD */
+#define PCSR1_STCODE 0x3f00 /* Self test error code */
+#define PCSR1_PCTO 0x0080 /* Port command timed out */
+#define PCSR1_ILLINT 0x0040 /* Illegal interrupt */
+#define PCSR1_TIMEOUT 0x0020 /* Timeout */
+#define PCSR1_POWER 0x0010 /* Power fail */
+#define PCSR1_RMTC 0x0008 /* Remote console reserved */
+#define PCSR1_STMASK 0x0007 /* State */
+
+/* bit 0-3 are for STATE */
+#define STAT_RESET 0x0
+#define STAT_PRIMLD 0x1 /* Primary load */
+#define STAT_READY 0x2
+#define STAT_RUN 0x3
+#define STAT_UHALT 0x5 /* UNIBUS halted */
+#define STAT_NIHALT 0x6 /* NI halted */
+#define STAT_NIUHALT 0x7 /* NI and UNIBUS Halted */
+
+#define PCSR1_BITS "\20\20XPWR\17ICAB\10PCTO\7ILLINT\6TIMEOUT\5POWER\4RMTC"
+
+/*
+ * Port Control Block Base
+ */
+struct de_pcbb {
+ short pcbb0; /* function */
+ short pcbb2; /* command specific */
+ short pcbb4;
+ short pcbb6;
+};
+
+/* PCBB function codes */
+#define FC_NOOP 0x00 /* NO-OP */
+#define FC_LSUADDR 0x01 /* Load and start microaddress */
+#define FC_RDDEFAULT 0x02 /* Read default physical address */
+#define FC_RDPHYAD 0x04 /* Read physical address */
+#define FC_WTPHYAD 0x05 /* Write physical address */
+#define FC_RDMULTI 0x06 /* Read multicast address list */
+#define FC_WTMULTI 0x07 /* Read multicast address list */
+#define FC_RDRING 0x08 /* Read ring format */
+#define FC_WTRING 0x09 /* Write ring format */
+#define FC_RDCNTS 0x0a /* Read counters */
+#define FC_RCCNTS 0x0b /* Read and clear counters */
+#define FC_RDMODE 0x0c /* Read mode */
+#define FC_WTMODE 0x0d /* Write mode */
+#define FC_RDSTATUS 0x0e /* Read port status */
+#define FC_RCSTATUS 0x0f /* Read and clear port status */
+#define FC_DUMPMEM 0x10 /* Dump internal memory */
+#define FC_LOADMEM 0x11 /* Load internal memory */
+#define FC_RDSYSID 0x12 /* Read system ID parameters */
+#define FC_WTSYSID 0x13 /* Write system ID parameters */
+#define FC_RDSERAD 0x14 /* Read load server address */
+#define FC_WTSERAD 0x15 /* Write load server address */
+
+/*
+ * Unibus Data Block Base (UDBB) for ring buffers
+ */
+struct de_udbbuf {
+ short b_tdrbl; /* Transmit desc ring base low 16 bits */
+ char b_tdrbh; /* Transmit desc ring base high 2 bits */
+ char b_telen; /* Length of each transmit entry */
+ short b_trlen; /* Number of entries in the XMIT desc ring */
+ short b_rdrbl; /* Receive desc ring base low 16 bits */
+ char b_rdrbh; /* Receive desc ring base high 2 bits */
+ char b_relen; /* Length of each receive entry */
+ short b_rrlen; /* Number of entries in the RECV desc ring */
+};
+
+/*
+ * Transmit/Receive Ring Entry
+ */
+struct de_ring {
+ short r_slen; /* Segment length */
+ short r_segbl; /* Segment address (low 16 bits) */
+ char r_segbh; /* Segment address (hi 2 bits) */
+ u_char r_flags; /* Status flags */
+ u_short r_tdrerr; /* Errors */
+#define r_lenerr r_tdrerr
+ short r_rid; /* Request ID */
+};
+
+#define XFLG_OWN 0x80 /* If 0 then owned by driver */
+#define XFLG_ERRS 0x40 /* Error summary */
+#define XFLG_MTCH 0x20 /* Address match on xmit request */
+#define XFLG_MORE 0x10 /* More than one entry required */
+#define XFLG_ONE 0x08 /* One collision encountered */
+#define XFLG_DEF 0x04 /* Transmit deferred */
+#define XFLG_STP 0x02 /* Start of packet */
+#define XFLG_ENP 0x01 /* End of packet */
+
+#define XFLG_BITS "\10\10OWN\7ERRS\6MTCH\5MORE\4ONE\3DEF\2STP\1ENP"
+
+#define XERR_BUFL 0x8000 /* Buffer length error */
+#define XERR_UBTO 0x4000 /* UNIBUS tiemout
+#define XERR_LCOL 0x1000 /* Late collision */
+#define XERR_LCAR 0x0800 /* Loss of carrier */
+#define XERR_RTRY 0x0400 /* Failed after 16 retries */
+#define XERR_TDR 0x03ff /* TDR value */
+
+#define XERR_BITS "\20\20BUFL\17UBTO\15LCOL\14LCAR\13RTRY"
+
+#define RFLG_OWN 0x80 /* If 0 then owned by driver */
+#define RFLG_ERRS 0x40 /* Error summary */
+#define RFLG_FRAM 0x20 /* Framing error */
+#define RFLG_OFLO 0x10 /* Message overflow */
+#define RFLG_CRC 0x08 /* CRC error */
+#define RFLG_STP 0x02 /* Start of packet */
+#define RFLG_ENP 0x01 /* End of packet */
+
+#define RFLG_BITS "\10\10OWN\7ERRS\6FRAM\5OFLO\4CRC\2STP\1ENP"
+
+#define RERR_BUFL 0x8000 /* Buffer length error */
+#define RERR_UBTO 0x4000 /* UNIBUS tiemout */
+#define RERR_NCHN 0x2000 /* No data chaining */
+#define RERR_MLEN 0x0fff /* Message length */
+
+#define RERR_BITS "\20\20BUFL\17UBTO\16NCHN"
+
+/* mode description bits */
+#define MOD_HDX 0x0001 /* Half duplex mode */
+#define MOD_LOOP 0x0004 /* Enable internal loopback */
+#define MOD_DTCR 0x0008 /* Disables CRC generation */
+#define MOD_DMNT 0x0200 /* Disable maintenance features */
+#define MOD_ECT 0x0400 /* Enable collision test */
+#define MOD_TPAD 0x1000 /* Transmit message pad enable */
+#define MOD_DRDC 0x2000 /* Disable data chaining */
+#define MOD_ENAL 0x4000 /* Enable all multicast */
+#define MOD_PROM 0x8000 /* Enable promiscuous mode */
+
+struct de_buf {
+ struct ether_header db_head; /* header */
+ char db_data[ETHERMTU]; /* packet data */
+ int db_crc; /* CRC - on receive only */
+};
diff --git a/sys/arch/vax/if/if_qe.c b/sys/arch/vax/if/if_qe.c
new file mode 100644
index 00000000000..fbf584fd09e
--- /dev/null
+++ b/sys/arch/vax/if/if_qe.c
@@ -0,0 +1,975 @@
+/* $NetBSD: if_qe.c,v 1.4.2.1 1995/10/15 13:56:26 ragge Exp $ */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Digital Equipment Corp.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_qe.c 7.20 (Berkeley) 3/28/91
+ */
+
+/* from @(#)if_qe.c 1.15 (ULTRIX) 4/16/86 */
+
+/****************************************************************
+ * *
+ * Licensed from Digital Equipment Corporation *
+ * Copyright (c) *
+ * Digital Equipment Corporation *
+ * Maynard, Massachusetts *
+ * 1985, 1986 *
+ * All rights reserved. *
+ * *
+ * The Information in this software is subject to change *
+ * without notice and should not be construed as a commitment *
+ * by Digital Equipment Corporation. Digital makes no *
+ * representations about the suitability of this software for *
+ * any purpose. It is supplied "As Is" without expressed or *
+ * implied warranty. *
+ * *
+ * If the Regents of the University of California or its *
+ * licensees modify the software in a manner creating *
+ * derivative copyright rights, appropriate copyright *
+ * legends may be placed on the derivative work in addition *
+ * to that set forth above. *
+ * *
+ ****************************************************************/
+/* ---------------------------------------------------------------------
+ * Modification History
+ *
+ * 15-Apr-86 -- afd
+ * Rename "unused_multi" to "qunused_multi" for extending Generic
+ * kernel to MicroVAXen.
+ *
+ * 18-mar-86 -- jaw br/cvec changed to NOT use registers.
+ *
+ * 12 March 86 -- Jeff Chase
+ * Modified to handle the new MCLGET macro
+ * Changed if_qe_data.c to use more receive buffers
+ * Added a flag to poke with adb to log qe_restarts on console
+ *
+ * 19 Oct 85 -- rjl
+ * Changed the watch dog timer from 30 seconds to 3. VMS is using
+ * less than 1 second in their's. Also turned the printf into an
+ * mprintf.
+ *
+ * 09/16/85 -- Larry Cohen
+ * Add 43bsd alpha tape changes for subnet routing
+ *
+ * 1 Aug 85 -- rjl
+ * Panic on a non-existent memory interrupt and the case where a packet
+ * was chained. The first should never happen because non-existant
+ * memory interrupts cause a bus reset. The second should never happen
+ * because we hang 2k input buffers on the device.
+ *
+ * 1 Aug 85 -- rich
+ * Fixed the broadcast loopback code to handle Clusters without
+ * wedging the system.
+ *
+ * 27 Feb. 85 -- ejf
+ * Return default hardware address on ioctl request.
+ *
+ * 12 Feb. 85 -- ejf
+ * Added internal extended loopback capability.
+ *
+ * 27 Dec. 84 -- rjl
+ * Fixed bug that caused every other transmit descriptor to be used
+ * instead of every descriptor.
+ *
+ * 21 Dec. 84 -- rjl
+ * Added watchdog timer to mask hardware bug that causes device lockup.
+ *
+ * 18 Dec. 84 -- rjl
+ * Reworked driver to use q-bus mapping routines. MicroVAX-I now does
+ * copying instead of m-buf shuffleing.
+ * A number of deficencies in the hardware/firmware were compensated
+ * for. See comments in qestart and qerint.
+ *
+ * 14 Nov. 84 -- jf
+ * Added usage counts for multicast addresses.
+ * Updated general protocol support to allow access to the Ethernet
+ * header.
+ *
+ * 04 Oct. 84 -- jf
+ * Added support for new ioctls to add and delete multicast addresses
+ * and set the physical address.
+ * Add support for general protocols.
+ *
+ * 14 Aug. 84 -- rjl
+ * Integrated Shannon changes. (allow arp above 1024 and ? )
+ *
+ * 13 Feb. 84 -- rjl
+ *
+ * Initial version of driver. derived from IL driver.
+ *
+ * ---------------------------------------------------------------------
+ */
+
+#include "qe.h"
+#if NQE > 0
+/*
+ * Digital Q-BUS to NI Adapter
+ */
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/mbuf.h"
+#include "sys/buf.h"
+#include "sys/protosw.h"
+#include "sys/socket.h"
+#include "sys/ioctl.h"
+#include "sys/errno.h"
+#include "sys/syslog.h"
+#include "sys/device.h"
+#include "sys/time.h"
+#include "sys/kernel.h"
+
+#include "net/if.h"
+#include "net/netisr.h"
+#include "net/route.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#ifdef ISO
+#include "netiso/iso.h"
+#include "netiso/iso_var.h"
+extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
+#endif
+
+#include "vax/include/pte.h"
+#include "vax/include/cpu.h"
+#include "vax/include/mtpr.h"
+#include "if_qereg.h"
+#include "if_uba.h"
+#include "vax/uba/ubareg.h"
+#include "vax/uba/ubavar.h"
+
+#if NQE == 1 && !defined(QNIVERT)
+#define NRCV 15 /* Receive descriptors */
+#else
+#define NRCV 10 /* Receive descriptors */
+#endif
+#define NXMT 5 /* Transmit descriptors */
+#define NTOT (NXMT + NRCV)
+
+#define QETIMEOUT 2 /* transmit timeout, must be > 1 */
+#define QESLOWTIMEOUT 40 /* timeout when no xmits in progress */
+
+#define MINDATA 60
+
+void qetimeout(int);
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * qe_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+struct qe_softc {
+ struct arpcom qe_ac; /* Ethernet common part */
+#define qe_if qe_ac.ac_if /* network-visible interface */
+#define qe_addr qe_ac.ac_enaddr /* hardware Ethernet address */
+ struct ifubinfo qe_uba; /* Q-bus resources */
+ volatile struct ifrw qe_ifr[NRCV]; /* for receive buffers; */
+ volatile struct ifxmt qe_ifw[NXMT]; /* for xmit buffers; */
+ int qe_flags; /* software state */
+#define QEF_RUNNING 0x01
+#define QEF_SETADDR 0x02
+#define QEF_FASTTIMEO 0x04
+ int setupaddr; /* mapping info for setup pkts */
+ int ipl; /* interrupt priority */
+ struct qe_ring *rringaddr; /* mapping info for rings */
+ struct qe_ring *tringaddr; /* "" */
+ volatile struct qe_ring rring[NRCV+1]; /* Receive ring descriptors */
+ volatile struct qe_ring tring[NXMT+1]; /* Xmit ring descriptors */
+ u_char setup_pkt[16][8]; /* Setup packet */
+ int rindex; /* Receive index */
+ int tindex; /* Transmit index */
+ int otindex; /* Old transmit index */
+ int qe_intvec; /* Interrupt vector */
+ volatile struct qedevice *addr; /* device addr */
+ int setupqueued; /* setup packet queued */
+ int nxmit; /* Transmits in progress */
+ int qe_restarts; /* timeouts */
+} qe_softc[NQE];
+
+struct uba_device *qeinfo[NQE];
+
+extern struct timeval time;
+
+int qeprobe(), qeattach(), qeintr();
+int qeinit(), qeioctl(), qereset();
+void qestart();
+
+u_short qestd[] = { 0 };
+struct uba_driver qedriver =
+ { qeprobe, 0, qeattach, 0, qestd, "qe", qeinfo };
+
+#define QEUNIT(x) minor(x)
+/*
+ * The deqna shouldn't receive more than ETHERMTU + sizeof(struct ether_header)
+ * but will actually take in up to 2048 bytes. To guard against the receiver
+ * chaining buffers (which we aren't prepared to handle) we allocate 2kb
+ * size buffers.
+ */
+#define MAXPACKETSIZE 2048 /* Should really be ETHERMTU */
+/*
+ * Probe the QNA to see if it's there
+ */
+qeprobe(reg, ui)
+ caddr_t reg;
+ struct uba_device *ui;
+{
+ /* register int br, cvec; r11, r10 value-result */
+ register volatile struct qedevice *addr = (struct qedevice *)reg;
+ register volatile struct qe_ring *rp;
+ register struct qe_ring *prp; /* physical rp */
+ register int i;
+ register volatile struct qe_softc *sc = &qe_softc[ui->ui_unit];
+
+#ifdef lint
+ br = 0; cvec = br; br = cvec;
+ qeintr(0);
+#endif
+
+ /*
+ * The QNA interrupts on i/o operations. To do an I/O operation
+ * we have to setup the interface by transmitting a setup packet.
+ */
+ addr->qe_csr = QE_RESET;
+ addr->qe_csr &= ~QE_RESET;
+ addr->qe_vector = (uba_hd[numuba].uh_lastiv -= 4);
+
+ /*
+ * Map the communications area and the setup packet.
+ */
+ sc->setupaddr =
+ uballoc(0, (caddr_t)sc->setup_pkt, sizeof(sc->setup_pkt), 0);
+ sc->rringaddr = (struct qe_ring *) uballoc(0, (caddr_t)sc->rring,
+ sizeof(struct qe_ring) * (NTOT+2), 0);
+ prp = (struct qe_ring *)UBAI_ADDR((int)sc->rringaddr);
+
+ /*
+ * The QNA will loop the setup packet back to the receive ring
+ * for verification, therefore we initialize the first
+ * receive & transmit ring descriptors and link the setup packet
+ * to them.
+ */
+ qeinitdesc(sc->tring, (caddr_t)UBAI_ADDR(sc->setupaddr),
+ sizeof(sc->setup_pkt));
+ qeinitdesc(sc->rring, (caddr_t)UBAI_ADDR(sc->setupaddr),
+ sizeof(sc->setup_pkt));
+
+ rp = (struct qe_ring *)sc->tring;
+ rp->qe_setup = 1;
+ rp->qe_eomsg = 1;
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_valid = 1;
+
+ rp = (struct qe_ring *)sc->rring;
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_valid = 1;
+
+ /*
+ * Get the addr off of the interface and place it into the setup
+ * packet. This code looks strange due to the fact that the address
+ * is placed in the setup packet in col. major order.
+ */
+ for( i = 0 ; i < 6 ; i++ )
+ sc->setup_pkt[i][1] = addr->qe_sta_addr[i];
+
+ qesetup( sc );
+ /*
+ * Start the interface and wait for the packet.
+ */
+ addr->qe_csr = QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT;
+ addr->qe_rcvlist_lo = (short)((int)prp);
+ addr->qe_rcvlist_hi = (short)((int)prp >> 16);
+ prp += NRCV+1;
+ addr->qe_xmtlist_lo = (short)((int)prp);
+ addr->qe_xmtlist_hi = (short)((int)prp >> 16);
+ DELAY(10000);
+ /*
+ * All done with the bus resources.
+ */
+ ubarelse(0, &sc->setupaddr);
+ ubarelse(0, (int *)&sc->rringaddr);
+ sc->ipl = 0x15;
+ return( sizeof(struct qedevice) );
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets.
+ */
+qeattach(ui)
+ struct uba_device *ui;
+{
+ struct qe_softc *sc = &qe_softc[ui->ui_unit];
+ struct ifnet *ifp = (struct ifnet *)&sc->qe_if;
+ volatile struct qedevice *addr=(struct qedevice *)ui->ui_addr;
+ int i;
+
+ ifp->if_unit = ui->ui_unit;
+ ifp->if_name = "qe";
+ /*
+ * The Deqna is cable of transmitting broadcasts, but
+ * doesn't listen to its own.
+ */
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+
+ /*
+ * Read the address from the prom and save it.
+ */
+ for( i=0 ; i<6 ; i++ )
+ sc->setup_pkt[i][1] = sc->qe_addr[i] = addr->qe_sta_addr[i] & 0xff;
+ addr->qe_vector |= 1;
+ printf("qe%d: %s, hardware address %s\n", ui->ui_unit,
+ addr->qe_vector&01 ? "delqa":"deqna",
+ ether_sprintf(sc->qe_addr));
+ addr->qe_vector &= ~1;
+
+ /*
+ * Save the vector for initialization at reset time.
+ */
+ sc->qe_intvec = addr->qe_vector;
+
+ ifp->if_start = qestart;
+ ifp->if_ioctl = qeioctl;
+ ifp->if_reset = qereset;
+ ifp->if_watchdog = qetimeout;
+ sc->qe_uba.iff_flags = UBA_CANTWAIT;
+ if_attach(ifp);
+ ether_ifattach(ifp);
+}
+
+/*
+ * Reset of interface after UNIBUS reset.
+ * If interface is on specified uba, reset its state.
+ */
+qereset(unit, uban)
+ int unit, uban;
+{
+ register struct uba_device *ui;
+
+ if (unit >= NQE || (ui = qeinfo[unit]) == 0 || ui->ui_alive == 0 ||
+ ui->ui_ubanum != uban)
+ return;
+ printf(" qe%d", unit);
+ qe_softc[unit].qe_if.if_flags &= ~IFF_RUNNING;
+ qeinit(unit);
+}
+
+/*
+ * Initialization of interface.
+ */
+qeinit(unit)
+ int unit;
+{
+ volatile struct qe_softc *sc = &qe_softc[unit];
+ struct uba_device *ui = qeinfo[unit];
+ volatile struct qedevice *addr=(struct qedevice *)ui->ui_addr;
+ struct ifnet *ifp = (struct ifnet *)&sc->qe_if;
+ int i;
+ int s;
+
+ /* address not known */
+ if (ifp->if_addrlist.tqh_first == (struct ifaddr *)0)
+ return;
+ if (sc->qe_flags & QEF_RUNNING)
+ return;
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * map the communications area onto the device
+ */
+ i = uballoc(0, (caddr_t)sc->rring,
+ sizeof(struct qe_ring) * (NTOT+2), 0);
+ if (i == 0)
+ goto fail;
+ sc->rringaddr = (struct qe_ring *)UBAI_ADDR(i);
+ sc->tringaddr = sc->rringaddr + NRCV + 1;
+ i = uballoc(0, (caddr_t)sc->setup_pkt,
+ sizeof(sc->setup_pkt), 0);
+ if (i == 0)
+ goto fail;
+ sc->setupaddr = UBAI_ADDR(i);
+ /*
+ * init buffers and maps
+ */
+ if (if_ubaminit(&sc->qe_uba, ui->ui_ubanum,
+ sizeof (struct ether_header), (int)btoc(MAXPACKETSIZE),
+ sc->qe_ifr, NRCV, sc->qe_ifw, NXMT) == 0) {
+ fail:
+ printf("qe%d: can't allocate uba resources\n", unit);
+ sc->qe_if.if_flags &= ~IFF_UP;
+ return;
+ }
+ }
+ /*
+ * Init the buffer descriptors and indexes for each of the lists and
+ * loop them back to form a ring.
+ */
+ for (i = 0; i < NRCV; i++) {
+ qeinitdesc( &sc->rring[i],
+ (caddr_t)UBAI_ADDR(sc->qe_ifr[i].ifrw_info), MAXPACKETSIZE);
+ sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET;
+ sc->rring[i].qe_valid = 1;
+ }
+ qeinitdesc(&sc->rring[i], (caddr_t)NULL, 0);
+
+ sc->rring[i].qe_addr_lo = (short)((int)sc->rringaddr);
+ sc->rring[i].qe_addr_hi = (short)((int)sc->rringaddr >> 16);
+ sc->rring[i].qe_chain = 1;
+ sc->rring[i].qe_flag = sc->rring[i].qe_status1 = QE_NOTYET;
+ sc->rring[i].qe_valid = 1;
+
+ for( i = 0 ; i <= NXMT ; i++ )
+ qeinitdesc(&sc->tring[i], (caddr_t)NULL, 0);
+ i--;
+
+ sc->tring[i].qe_addr_lo = (short)((int)sc->tringaddr);
+ sc->tring[i].qe_addr_hi = (short)((int)sc->tringaddr >> 16);
+ sc->tring[i].qe_chain = 1;
+ sc->tring[i].qe_flag = sc->tring[i].qe_status1 = QE_NOTYET;
+ sc->tring[i].qe_valid = 1;
+
+ sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0;
+
+ /*
+ * Take the interface out of reset, program the vector,
+ * enable interrupts, and tell the world we are up.
+ */
+ s = splimp();
+ addr->qe_vector = sc->qe_intvec;
+ sc->addr = addr;
+ addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
+ QE_RCV_INT | QE_ILOOP;
+ addr->qe_rcvlist_lo = (short)((int)sc->rringaddr);
+ addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16);
+ ifp->if_flags |= IFF_UP | IFF_RUNNING;
+ sc->qe_flags |= QEF_RUNNING;
+ qesetup( sc );
+ qestart( ifp );
+ sc->qe_if.if_timer = QESLOWTIMEOUT; /* Start watchdog */
+ splx( s );
+}
+
+/*
+ * Start output on interface.
+ *
+ */
+void
+qestart(ifp)
+ struct ifnet *ifp;
+{
+ int unit = ifp->if_unit;
+ struct uba_device *ui = qeinfo[unit];
+ register volatile struct qe_softc *sc = &qe_softc[unit];
+ register volatile struct qedevice *addr;
+ register volatile struct qe_ring *rp;
+ register index;
+ struct mbuf *m;
+ int buf_addr, len, s;
+
+
+ s = splimp();
+ addr = (struct qedevice *)ui->ui_addr;
+ /*
+ * The deqna doesn't look at anything but the valid bit
+ * to determine if it should transmit this packet. If you have
+ * a ring and fill it the device will loop indefinately on the
+ * packet and continue to flood the net with packets until you
+ * break the ring. For this reason we never queue more than n-1
+ * packets in the transmit ring.
+ *
+ * The microcoders should have obeyed their own defination of the
+ * flag and status words, but instead we have to compensate.
+ */
+ for( index = sc->tindex;
+ sc->tring[index].qe_valid == 0 && sc->nxmit < (NXMT-1) ;
+ sc->tindex = index = ++index % NXMT){
+ rp = &sc->tring[index];
+ if( sc->setupqueued ) {
+ buf_addr = sc->setupaddr;
+ len = 128;
+ rp->qe_setup = 1;
+ sc->setupqueued = 0;
+ } else {
+ IF_DEQUEUE(&sc->qe_if.if_snd, m);
+ if( m == 0 ){
+ splx(s);
+ return;
+ }
+ buf_addr = sc->qe_ifw[index].ifw_info;
+ len = if_ubaput(&sc->qe_uba, &sc->qe_ifw[index], m);
+ }
+ if( len < MINDATA )
+ len = MINDATA;
+ /*
+ * Does buffer end on odd byte ?
+ */
+ if( len & 1 ) {
+ len++;
+ rp->qe_odd_end = 1;
+ }
+ rp->qe_buf_len = -(len/2);
+ buf_addr = UBAI_ADDR(buf_addr);
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_addr_lo = (short)buf_addr;
+ rp->qe_addr_hi = (short)(buf_addr >> 16);
+ rp->qe_eomsg = 1;
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_valid = 1;
+ if (sc->nxmit++ == 0) {
+ sc->qe_flags |= QEF_FASTTIMEO;
+ sc->qe_if.if_timer = QETIMEOUT;
+ }
+
+ /*
+ * See if the xmit list is invalid.
+ */
+ if( addr->qe_csr & QE_XL_INVALID ) {
+ buf_addr = (int)(sc->tringaddr+index);
+ addr->qe_xmtlist_lo = (short)buf_addr;
+ addr->qe_xmtlist_hi = (short)(buf_addr >> 16);
+ }
+ }
+ splx(s);
+ return;
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+qeintr(uba, vector, level, unit)
+{
+ register volatile struct qe_softc *sc = &qe_softc[unit];
+ volatile struct qedevice *addr =
+ (struct qedevice *)qeinfo[unit]->ui_addr;
+ int buf_addr, csr;
+
+ splx(sc->ipl);
+ if (!(sc->qe_flags & QEF_FASTTIMEO))
+ sc->qe_if.if_timer = QESLOWTIMEOUT; /* Restart timer clock */
+ csr = addr->qe_csr;
+ addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP;
+ if( csr & QE_RCV_INT )
+ qerint( unit );
+ if( csr & QE_XMIT_INT )
+ qetint( unit );
+ if( csr & QE_NEX_MEM_INT )
+ printf("qe%d: Nonexistent memory interrupt\n", unit);
+
+ if( addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET ) {
+ buf_addr = (int)&sc->rringaddr[sc->rindex];
+ addr->qe_rcvlist_lo = (short)buf_addr;
+ addr->qe_rcvlist_hi = (short)(buf_addr >> 16);
+ }
+}
+
+/*
+ * Ethernet interface transmit interrupt.
+ */
+
+qetint(unit)
+ int unit;
+{
+ register volatile struct qe_softc *sc = &qe_softc[unit];
+ register volatile struct qe_ring *rp;
+ register volatile struct ifxmt *ifxp;
+ int status1, setupflag;
+ short len;
+
+
+ while( sc->otindex != sc->tindex && sc->tring[sc->otindex].qe_status1 != QE_NOTYET && sc->nxmit > 0 ) {
+ /*
+ * Save the status words from the descriptor so that it can
+ * be released.
+ */
+ rp = &sc->tring[sc->otindex];
+ status1 = rp->qe_status1;
+ setupflag = rp->qe_setup;
+ len = (-rp->qe_buf_len) * 2;
+ if( rp->qe_odd_end )
+ len++;
+ /*
+ * Init the buffer descriptor
+ */
+ bzero((caddr_t)rp, sizeof(struct qe_ring));
+ if( --sc->nxmit == 0 ) {
+ sc->qe_flags &= ~QEF_FASTTIMEO;
+ sc->qe_if.if_timer = QESLOWTIMEOUT;
+ }
+ if( !setupflag ) {
+ /*
+ * Do some statistics.
+ */
+ sc->qe_if.if_opackets++;
+ sc->qe_if.if_collisions += ( status1 & QE_CCNT ) >> 4;
+ if (status1 & QE_ERROR)
+ sc->qe_if.if_oerrors++;
+ ifxp = &sc->qe_ifw[sc->otindex];
+ if (ifxp->ifw_xtofree) {
+ m_freem(ifxp->ifw_xtofree);
+ ifxp->ifw_xtofree = 0;
+ }
+ }
+ sc->otindex = ++sc->otindex % NXMT;
+ }
+ qestart( &sc->qe_if );
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ * 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.
+ */
+qerint(unit)
+ int unit;
+{
+ register volatile struct qe_softc *sc = &qe_softc[unit];
+ register volatile struct qe_ring *rp;
+ register int nrcv = 0;
+ int len, status1, status2;
+ int bufaddr;
+
+ /*
+ * Traverse the receive ring looking for packets to pass back.
+ * The search is complete when we find a descriptor not in use.
+ *
+ * As in the transmit case the deqna doesn't honor it's own protocols
+ * so there exists the possibility that the device can beat us around
+ * the ring. The proper way to guard against this is to insure that
+ * there is always at least one invalid descriptor. We chose instead
+ * to make the ring large enough to minimize the problem. With a ring
+ * size of 4 we haven't been able to see the problem. To be safe we
+ * doubled that to 8.
+ *
+ */
+ while (sc->rring[sc->rindex].qe_status1 == QE_NOTYET && nrcv < NRCV) {
+ /*
+ * We got an interrupt but did not find an input packet
+ * where we expected one to be, probably because the ring
+ * was overrun.
+ * We search forward to find a valid packet and start
+ * processing from there. If no valid packet is found it
+ * means we processed all the packets during a previous
+ * interrupt and that the QE_RCV_INT bit was set while
+ * we were processing one of these earlier packets. In
+ * this case we can safely ignore the interrupt (by dropping
+ * through the code below).
+ */
+ sc->rindex = (sc->rindex + 1) % NRCV;
+ nrcv++;
+ }
+ if (nrcv && nrcv < NRCV)
+ log(LOG_ERR, "qe%d: ring overrun, resync'd by skipping %d\n",
+ unit, nrcv);
+
+ for( ; sc->rring[sc->rindex].qe_status1 != QE_NOTYET ; sc->rindex = ++sc->rindex % NRCV ){
+ rp = &sc->rring[sc->rindex];
+ status1 = rp->qe_status1;
+ status2 = rp->qe_status2;
+ bzero((caddr_t)rp, sizeof(struct qe_ring));
+ if( (status1 & QE_MASK) == QE_MASK )
+ panic("qe: chained packet");
+ len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60;
+ sc->qe_if.if_ipackets++;
+
+ if (status1 & QE_ERROR) {
+ if ((status1 & QE_RUNT) == 0)
+ sc->qe_if.if_ierrors++;
+ } else {
+ /*
+ * We don't process setup packets.
+ */
+ if( !(status1 & QE_ESETUP) )
+ qeread(sc, &sc->qe_ifr[sc->rindex],
+ len - sizeof(struct ether_header));
+ }
+ /*
+ * Return the buffer to the ring
+ */
+ bufaddr = (int)UBAI_ADDR(sc->qe_ifr[sc->rindex].ifrw_info);
+ rp->qe_buf_len = -((MAXPACKETSIZE)/2);
+ rp->qe_addr_lo = (short)bufaddr;
+ rp->qe_addr_hi = (short)((int)bufaddr >> 16);
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_valid = 1;
+ }
+}
+
+/*
+ * Process an ioctl request.
+ */
+qeioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ struct qe_softc *sc = &qe_softc[ifp->if_unit];
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s = splimp(), error = 0;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ qeinit(ifp->if_unit);
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ arp_ifinit(&sc->qe_ac, ifa);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)(sc->qe_addr);
+ else
+ qe_setaddr(ina->x_host.c_host, ifp->if_unit);
+ break;
+ }
+#endif
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ sc->qe_flags & QEF_RUNNING) {
+ ((volatile struct qedevice *)
+ (qeinfo[ifp->if_unit]->ui_addr))->qe_csr = QE_RESET;
+ sc->qe_flags &= ~QEF_RUNNING;
+ } else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
+ IFF_RUNNING && (sc->qe_flags & QEF_RUNNING) == 0)
+ qerestart(sc);
+ break;
+
+ default:
+ error = EINVAL;
+
+ }
+ splx(s);
+ return (error);
+}
+
+/*
+ * set ethernet address for unit
+ */
+qe_setaddr(physaddr, unit)
+ u_char *physaddr;
+ int unit;
+{
+ register volatile struct qe_softc *sc = &qe_softc[unit];
+ register int i;
+
+ for (i = 0; i < 6; i++)
+ sc->setup_pkt[i][1] = sc->qe_addr[i] = physaddr[i];
+ sc->qe_flags |= QEF_SETADDR;
+ if (sc->qe_if.if_flags & IFF_RUNNING)
+ qesetup(sc);
+ qeinit(unit);
+}
+
+
+/*
+ * Initialize a ring descriptor with mbuf allocation side effects
+ */
+qeinitdesc(rp, addr, len)
+ register volatile struct qe_ring *rp;
+ caddr_t addr; /* mapped address */
+ int len;
+{
+ /*
+ * clear the entire descriptor
+ */
+ bzero((caddr_t)rp, sizeof(struct qe_ring));
+
+ if( len ) {
+ rp->qe_buf_len = -(len/2);
+ rp->qe_addr_lo = (short)((int)addr);
+ rp->qe_addr_hi = (short)((int)addr >> 16);
+ }
+}
+/*
+ * Build a setup packet - the physical address will already be present
+ * in first column.
+ */
+qesetup( sc )
+ volatile struct qe_softc *sc;
+{
+ register i, j;
+
+ /*
+ * Copy the target address to the rest of the entries in this row.
+ */
+ for ( j = 0; j < 6 ; j++ )
+ for ( i = 2 ; i < 8 ; i++ )
+ sc->setup_pkt[j][i] = sc->setup_pkt[j][1];
+ /*
+ * Duplicate the first half.
+ */
+ bcopy((caddr_t)sc->setup_pkt[0], (caddr_t)sc->setup_pkt[8], 64);
+ /*
+ * Fill in the broadcast (and ISO multicast) address(es).
+ */
+ for ( i = 0; i < 6 ; i++ ) {
+ sc->setup_pkt[i][2] = 0xff;
+#ifdef ISO
+ sc->setup_pkt[i][3] = all_es_snpa[i];
+ sc->setup_pkt[i][4] = all_is_snpa[i];
+ sc->setup_pkt[i][5] = all_l1is_snpa[i];
+ sc->setup_pkt[i][6] = all_l2is_snpa[i];
+#endif
+ }
+ sc->setupqueued++;
+}
+
+/*
+ * Pass a packet to the higher levels.
+ * We deal with the trailer protocol here.
+ */
+qeread(sc, ifrw, len)
+ register volatile struct qe_softc *sc;
+ volatile struct ifrw *ifrw;
+ int len;
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ int s;
+ struct ifqueue *inq;
+
+ /*
+ * Deal with trailer protocol: if type is INET trailer
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+
+ eh = (struct ether_header *)ifrw->ifrw_addr;
+ if (len == 0)
+ return;
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; qeget 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_ubaget(&sc->qe_uba, ifrw, len, &sc->qe_if);
+#ifdef notdef
+if (m) {
+*(((u_long *)m->m_data)+0),
+*(((u_long *)m->m_data)+1),
+*(((u_long *)m->m_data)+2),
+*(((u_long *)m->m_data)+3)
+); }
+#endif
+
+ if (m)
+ ether_input((struct ifnet *)&sc->qe_if, eh, m);
+}
+
+/*
+ * Watchdog timeout routine. There is a condition in the hardware that
+ * causes the board to lock up under heavy load. This routine detects
+ * the hang up and restarts the device.
+ */
+void
+qetimeout(unit)
+ int unit;
+{
+ register volatile struct qe_softc *sc;
+
+ sc = &qe_softc[unit];
+#ifdef notdef
+ log(LOG_ERR, "qe%d: transmit timeout, restarted %d\n",
+ unit, sc->qe_restarts++);
+#endif
+ qerestart(sc);
+}
+/*
+ * Restart for board lockup problem.
+ */
+qerestart(sc)
+ register volatile struct qe_softc *sc;
+{
+ register struct ifnet *ifp = (struct ifnet *)&sc->qe_if;
+ register volatile struct qedevice *addr = sc->addr;
+ register volatile struct qe_ring *rp;
+ register i;
+
+ addr->qe_csr = QE_RESET;
+ addr->qe_csr &= ~QE_RESET;
+ qesetup( sc );
+ for (i = 0, rp = sc->tring; i < NXMT; rp++, i++) {
+ rp->qe_flag = rp->qe_status1 = QE_NOTYET;
+ rp->qe_valid = 0;
+ }
+ sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0;
+ addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
+ QE_RCV_INT | QE_ILOOP;
+ addr->qe_rcvlist_lo = (short)((int)sc->rringaddr);
+ addr->qe_rcvlist_hi = (short)((int)sc->rringaddr >> 16);
+ sc->qe_flags |= QEF_RUNNING;
+ qestart(ifp);
+}
+
+qe_match(){
+ printf("qe_match\n");
+ return 0;
+}
+
+void
+qe_attach(){
+ printf("qe_attach\n");
+}
+
+struct cfdriver qecd =
+ { 0,"qe",qe_match, qe_attach, DV_IFNET, sizeof(struct uba_driver) };
+
+#endif
diff --git a/sys/arch/vax/if/if_qereg.h b/sys/arch/vax/if/if_qereg.h
new file mode 100644
index 00000000000..fe608daa42a
--- /dev/null
+++ b/sys/arch/vax/if/if_qereg.h
@@ -0,0 +1,172 @@
+/* $NetBSD: if_qereg.h,v 1.1 1995/03/30 20:26:41 ragge Exp $ */
+/*
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Digital Equipment Corp.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_qereg.h 7.3 (Berkeley) 6/28/90
+ */
+
+/* @(#)if_qereg.h 1.2 (ULTRIX) 1/3/85 */
+
+/****************************************************************
+ * *
+ * Licensed from Digital Equipment Corporation *
+ * Copyright (c) *
+ * Digital Equipment Corporation *
+ * Maynard, Massachusetts *
+ * 1985, 1986 *
+ * All rights reserved. *
+ * *
+ * The Information in this software is subject to change *
+ * without notice and should not be construed as a commitment *
+ * by Digital Equipment Corporation. Digital makes no *
+ * representations about the suitability of this software for *
+ * any purpose. It is supplied "As Is" without expressed or *
+ * implied warranty. *
+ * *
+ * If the Regents of the University of California or its *
+ * licensees modify the software in a manner creating *
+ * diriviative copyright rights, appropriate copyright *
+ * legends may be placed on the drivative work in addition *
+ * to that set forth above. *
+ * *
+ ****************************************************************/
+/* ---------------------------------------------------------------------
+ * Modification History
+ *
+ * 13 Feb. 84 -- rjl
+ *
+ * Initial version of driver. derived from IL driver.
+ *
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * Digital Q-BUS to NI Adapter
+ */
+struct qedevice {
+ u_short qe_sta_addr[2]; /* Station address (actually 6 */
+ u_short qe_rcvlist_lo; /* Receive list lo address */
+ u_short qe_rcvlist_hi; /* Receive list hi address */
+ u_short qe_xmtlist_lo; /* Transmit list lo address */
+ u_short qe_xmtlist_hi; /* Transmit list hi address */
+ u_short qe_vector; /* Interrupt vector */
+ u_short qe_csr; /* Command and Status Register */
+};
+
+/*
+ * Command and status bits (csr)
+ */
+#define QE_RCV_ENABLE 0x0001 /* Receiver enable */
+#define QE_RESET 0x0002 /* Software reset */
+#define QE_NEX_MEM_INT 0x0004 /* Non existant mem interrupt */
+#define QE_LOAD_ROM 0x0008 /* Load boot/diag from rom */
+#define QE_XL_INVALID 0x0010 /* Transmit list invalid */
+#define QE_RL_INVALID 0x0020 /* Receive list invalid */
+#define QE_INT_ENABLE 0x0040 /* Interrupt enable */
+#define QE_XMIT_INT 0x0080 /* Transmit interrupt */
+#define QE_ILOOP 0x0100 /* Internal loopback */
+#define QE_ELOOP 0x0200 /* External loopback */
+#define QE_STIM_ENABLE 0x0400 /* Sanity timer enable */
+#define QE_POWERUP 0x1000 /* Tranceiver power on */
+#define QE_CARRIER 0x2000 /* Carrier detect */
+#define QE_RCV_INT 0x8000 /* Receiver interrupt */
+
+/*
+ * Transmit and receive ring discriptor ---------------------------
+ *
+ * The QNA uses the flag, status1 and the valid bit as a handshake/semiphore
+ * mechinism.
+ *
+ * The flag word is written on ( bits 15,15 set to 1 ) when it reads the
+ * descriptor. If the valid bit is set it considers the address to be valid.
+ * When it uses the buffer pointed to by the valid address it sets status word
+ * one.
+ */
+struct qe_ring {
+ u_short qe_flag; /* Buffer utilization flags */
+ u_short qe_addr_hi:6, /* Hi order bits of buffer addr */
+ qe_odd_begin:1, /* Odd byte begin and end (xmit)*/
+ qe_odd_end:1,
+ qe_fill1:4,
+ qe_setup:1, /* Setup packet */
+ qe_eomsg:1, /* End of message flag */
+ qe_chain:1, /* Chain address instead of buf */
+ qe_valid:1; /* Address field is valid */
+ u_short qe_addr_lo; /* Low order bits of address */
+ short qe_buf_len; /* Negative buffer length */
+ u_short qe_status1; /* Status word one */
+ u_short qe_status2; /* Status word two */
+};
+
+/*
+ * Status word definations (receive)
+ * word1
+ */
+#define QE_OVF 0x0001 /* Receiver overflow */
+#define QE_CRCERR 0x0002 /* CRC error */
+#define QE_FRAME 0x0004 /* Framing alignment error */
+#define QE_SHORT 0x0008 /* Packet size < 10 bytes */
+#define QE_RBL_HI 0x0700 /* Hi bits of receive len */
+#define QE_RUNT 0x0800 /* Runt packet */
+#define QE_DISCARD 0x1000 /* Discard the packet */
+#define QE_ESETUP 0x2000 /* Looped back setup or eloop */
+#define QE_ERROR 0x4000 /* Receiver error */
+#define QE_LASTNOT 0x8000 /* Not the last in the packet */
+/* word2 */
+#define QE_RBL_LO 0x00ff /* Low bits of receive len */
+
+/*
+ * Status word definations (transmit)
+ * word1
+ */
+#define QE_CCNT 0x00f0 /* Collision count this packet */
+#define QE_FAIL 0x0100 /* Heart beat check failure */
+#define QE_ABORT 0x0200 /* Transmission abort */
+#define QE_STE16 0x0400 /* Sanity timer default on */
+#define QE_NOCAR 0x0800 /* No carrier */
+#define QE_LOSS 0x1000 /* Loss of carrier while xmit */
+/* word2 */
+#define QE_TDR 0x3fff /* Time domain reflectometry */
+
+/*
+ * General constant definations
+ */
+#define QEALLOC 0 /* Allocate an mbuf */
+#define QENOALLOC 1 /* No mbuf allocation */
+#define QEDEALLOC 2 /* Release an mbuf chain */
+
+#define QE_NOTYET 0x8000 /* Descriptor not in use yet */
+#define QE_INUSE 0x4000 /* Descriptor being used by QNA */
+#define QE_MASK 0xc000 /* Lastnot/error/used mask */
diff --git a/sys/arch/vax/if/if_uba.c b/sys/arch/vax/if/if_uba.c
new file mode 100644
index 00000000000..1ef5b3f8179
--- /dev/null
+++ b/sys/arch/vax/if/if_uba.c
@@ -0,0 +1,390 @@
+/* $NetBSD: if_uba.c,v 1.6 1995/04/11 06:19:09 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_uba.c 7.16 (Berkeley) 12/16/90
+ */
+
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/malloc.h"
+#include "sys/mbuf.h"
+#include "sys/map.h"
+#include "sys/buf.h"
+#include "sys/socket.h"
+#include "sys/syslog.h"
+
+#include "net/if.h"
+
+#include "vax/include/pte.h"
+#include "vax/include/mtpr.h"
+#include "if_uba.h"
+#include "vax/include/vmparam.h"
+#include "vax/uba/ubareg.h"
+#include "vax/uba/ubavar.h"
+#include "machine/macros.h"
+
+static if_ubaalloc(struct ifubinfo *, struct ifrw *, int);
+static rcv_xmtbuf(struct ifxmt *);
+static restor_xmtbuf(struct ifxmt *);
+
+/*
+ * 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 once for each read and once for each write buffer. We also
+ * allocate page frames in the mbuffer pool for these pages.
+ */
+if_ubaminit(ifu, uban, hlen, nmr, ifr, nr, ifw, nw)
+ register struct ifubinfo *ifu;
+ int uban, hlen, nmr, nr, nw;
+ register struct ifrw *ifr;
+ register struct ifxmt *ifw;
+{
+ register caddr_t p;
+ caddr_t cp;
+ int i, nclbytes, off;
+
+ if (hlen)
+ off = MCLBYTES - hlen;
+ else
+ off = 0;
+ nclbytes = roundup(nmr * NBPG, MCLBYTES);
+ if (hlen)
+ nclbytes += MCLBYTES;
+ if (ifr[0].ifrw_addr)
+ cp = ifr[0].ifrw_addr - off;
+ else {
+ cp = (caddr_t)malloc((u_long)((nr + nw) * nclbytes), M_DEVBUF,
+ M_NOWAIT);
+ if (cp == 0)
+ return (0);
+ p = cp;
+ for (i = 0; i < nr; i++) {
+ ifr[i].ifrw_addr = p + off;
+ p += nclbytes;
+ }
+ for (i = 0; i < nw; i++) {
+ ifw[i].ifw_base = p;
+ ifw[i].ifw_addr = p + off;
+ p += nclbytes;
+ }
+ ifu->iff_hlen = hlen;
+ ifu->iff_uban = uban;
+ ifu->iff_uba = uba_hd[uban].uh_uba;
+ ifu->iff_ubamr = uba_hd[uban].uh_mr;
+ }
+ for (i = 0; i < nr; i++)
+ if (if_ubaalloc(ifu, &ifr[i], nmr) == 0) {
+ nr = i;
+ nw = 0;
+ goto bad;
+ }
+ for (i = 0; i < nw; i++)
+ if (if_ubaalloc(ifu, &ifw[i].ifrw, nmr) == 0) {
+ nw = i;
+ goto bad;
+ }
+ while (--nw >= 0) {
+ for (i = 0; i < nmr; i++)
+ ifw[nw].ifw_wmap[i] = ifw[nw].ifw_mr[i];
+ ifw[nw].ifw_xswapd = 0;
+ ifw[nw].ifw_flags = IFRW_W;
+ ifw[nw].ifw_nmr = nmr;
+ }
+ return (1);
+bad:
+ while (--nw >= 0)
+ ubarelse(ifu->iff_uban, &ifw[nw].ifw_info);
+ while (--nr >= 0)
+ ubarelse(ifu->iff_uban, &ifr[nr].ifrw_info);
+ free(cp, M_DEVBUF);
+ ifr[0].ifrw_addr = 0;
+ return (0);
+}
+
+/*
+ * Setup an 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 ifubinfo *ifu;
+ register struct ifrw *ifrw;
+ int nmr;
+{
+ register int info;
+
+ info =
+ uballoc(ifu->iff_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->iff_hlen,
+ ifu->iff_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->iff_ubamr[UBAI_MR(info) + (ifu->iff_hlen? 1 : 0)];
+ return (1);
+}
+
+/*
+ * Pull read data off a interface.
+ * Totlen is length of data, with local net header stripped.
+ * 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.
+ * Save a pointer to the interface structure and the total length,
+ * so that protocols can determine where incoming packets arrived.
+ * Note: we may be called to receive from a transmit buffer by some
+ * devices. In that case, we must force normal mapping of the buffer,
+ * so that the correct data will appear (only unibus maps are
+ * changed when remapping the transmit buffers).
+ */
+struct mbuf *
+if_ubaget(ifu, ifr, totlen, ifp)
+ struct ifubinfo *ifu;
+ register struct ifrw *ifr;
+ register int totlen;
+ struct ifnet *ifp;
+{
+ struct mbuf *top, **mp;
+ register struct mbuf *m;
+ register caddr_t cp = ifr->ifrw_addr + ifu->iff_hlen, pp;
+ register int len;
+ top = 0;
+ mp = &top;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0){
+ return ((struct mbuf *)NULL);
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ m->m_len = MHLEN;
+
+ if (ifr->ifrw_flags & IFRW_W){
+ rcv_xmtbuf((struct ifxmt *)ifr);
+ }
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ top = 0;
+ goto out;
+ }
+ m->m_len = MLEN;
+ }
+ len = totlen;
+ if (len >= MINCLSIZE) {
+ struct pte *cpte, *ppte;
+ int x, *ip, i;
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0){
+ goto nopage;
+ }
+ len = min(len, MCLBYTES);
+ m->m_len = len;
+ if (!claligned(cp)){
+ goto copy;
+ }
+ /*
+ * Switch pages mapped to UNIBUS with new page pp,
+ * as quick form of copy. Remap UNIBUS and invalidate.
+ */
+ pp = mtod(m, char *);
+ cpte = (struct pte *)kvtopte(cp);
+ ppte = (struct pte *)kvtopte(pp);
+ x = vax_btop(cp - ifr->ifrw_addr);
+ ip = (int *)&ifr->ifrw_mr[x];
+ for (i = 0; i < MCLBYTES/NBPG; i++) {
+ struct pte t;
+ t = *ppte; *ppte++ = *cpte; *cpte = t;
+ *ip++ = cpte++->pg_pfn|ifr->ifrw_proto;
+ mtpr(cp,PR_TBIS);
+ cp += NBPG;
+ mtpr((caddr_t)pp,PR_TBIS);
+ pp += NBPG;
+ }
+ goto nocopy;
+ }
+nopage:
+ if (len < m->m_len) {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+copy:
+ bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+ cp += len;
+nocopy:
+ *mp = m;
+ mp = &m->m_next;
+ totlen -= len;
+ }
+out:
+ if (ifr->ifrw_flags & IFRW_W){
+ restor_xmtbuf((struct ifxmt *)ifr);
+ }
+ return (top);
+}
+
+/*
+ * Change the mapping on a transmit buffer so that if_ubaget may
+ * receive from that buffer. Copy data from any pages mapped to Unibus
+ * into the pages mapped to normal kernel virtual memory, so that
+ * they can be accessed and swapped as usual. We take advantage
+ * of the fact that clusters are placed on the xtofree list
+ * in inverse order, finding the last one.
+ */
+static
+rcv_xmtbuf(ifw)
+ register struct ifxmt *ifw;
+{
+ register struct mbuf *m;
+ struct mbuf **mprev;
+ register i;
+ char *cp;
+
+ while (i = ffs((long)ifw->ifw_xswapd)) {
+ cp = ifw->ifw_base + i * MCLBYTES;
+ i--;
+ ifw->ifw_xswapd &= ~(1<<i);
+ mprev = &ifw->ifw_xtofree;
+ for (m = ifw->ifw_xtofree; m && m->m_next; m = m->m_next)
+ mprev = &m->m_next;
+ if (m == NULL)
+ break;
+ bcopy(mtod(m, caddr_t), cp, MCLBYTES);
+ (void) m_free(m);
+ *mprev = NULL;
+ }
+ ifw->ifw_xswapd = 0;
+ for (i = 0; i < ifw->ifw_nmr; i++)
+ ifw->ifw_mr[i] = ifw->ifw_wmap[i];
+}
+
+/*
+ * Put a transmit buffer back together after doing an if_ubaget on it,
+ * which may have swapped pages.
+ */
+static
+restor_xmtbuf(ifw)
+ register struct ifxmt *ifw;
+{
+ register i;
+
+ for (i = 0; i < ifw->ifw_nmr; i++)
+ ifw->ifw_wmap[i] = ifw->ifw_mr[i];
+}
+
+/*
+ * 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_ubaput(ifu, ifw, m)
+ struct ifubinfo *ifu;
+ register struct ifxmt *ifw;
+ register struct mbuf *m;
+{
+ register struct mbuf *mp;
+ register caddr_t cp, dp;
+ register int i;
+ int xswapd = 0;
+ int x, cc, t;
+
+ cp = ifw->ifw_addr;
+ while (m) {
+ dp = mtod(m, char *);
+ if (claligned(cp) && claligned(dp) &&
+ (m->m_len == MCLBYTES || m->m_next == (struct mbuf *)0)) {
+ struct pte *pte;
+ int *ip;
+
+ pte = (struct pte *)kvtopte(dp);
+ x = vax_btop(cp - ifw->ifw_addr);
+ ip = (int *)&ifw->ifw_mr[x];
+ for (i = 0; i < MCLBYTES/NBPG; i++)
+ *ip++ = ifw->ifw_proto | pte++->pg_pfn;
+ xswapd |= 1 << (x>>(MCLSHIFT-PGSHIFT));
+ mp = m->m_next;
+ m->m_next = ifw->ifw_xtofree;
+ ifw->ifw_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->iff_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 - ifw->ifw_addr;
+ x = ((cc - ifu->iff_hlen) + MCLBYTES - 1) >> MCLSHIFT;
+ ifw->ifw_xswapd &= ~xswapd;
+ while (i = ffs((long)ifw->ifw_xswapd)) {
+ i--;
+ if (i >= x)
+ break;
+ ifw->ifw_xswapd &= ~(1<<i);
+ i *= MCLBYTES/NBPG;
+ for (t = 0; t < MCLBYTES/NBPG; t++) {
+ ifw->ifw_mr[i] = ifw->ifw_wmap[i];
+ i++;
+ }
+ }
+ ifw->ifw_xswapd |= xswapd;
+ return (cc);
+}
diff --git a/sys/arch/vax/if/if_uba.h b/sys/arch/vax/if/if_uba.h
new file mode 100644
index 00000000000..b1d6a2a203f
--- /dev/null
+++ b/sys/arch/vax/if/if_uba.h
@@ -0,0 +1,136 @@
+/* $NetBSD: if_uba.h,v 1.3 1995/05/11 16:53:12 jtc Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_uba.h 7.4 (Berkeley) 6/28/90
+ */
+
+/*
+ * Structure and routine definitions
+ * for UNIBUS network interfaces.
+ */
+
+#define IF_MAXNUBAMR 10
+/*
+ * Each interface has structures giving information
+ * about UNIBUS resources held by the interface
+ * for each send and receive buffer.
+ *
+ * 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.
+ */
+
+/*
+ * Information per interface.
+ */
+struct ifubinfo {
+ short iff_uban; /* uba number */
+ short iff_hlen; /* local net header length */
+ struct uba_regs *iff_uba; /* uba adaptor regs, in vm */
+ struct pte *iff_ubamr; /* uba map regs, in vm */
+ short iff_flags; /* used during uballoc's */
+};
+
+/*
+ * Information per buffer.
+ */
+struct ifrw {
+ caddr_t ifrw_addr; /* virt addr of header */
+ short ifrw_bdp; /* unibus bdp */
+ short ifrw_flags; /* type, etc. */
+#define IFRW_W 0x01 /* is a transmit buffer */
+ int ifrw_info; /* value from ubaalloc */
+ int ifrw_proto; /* map register prototype */
+ struct pte *ifrw_mr; /* base of map registers */
+};
+
+/*
+ * Information per transmit buffer, including the above.
+ */
+struct ifxmt {
+ struct ifrw ifrw;
+ caddr_t ifw_base; /* virt addr of buffer */
+ struct pte ifw_wmap[IF_MAXNUBAMR]; /* base pages for output */
+ struct mbuf *ifw_xtofree; /* pages being dma'd out */
+ short ifw_xswapd; /* mask of clusters swapped */
+ short ifw_nmr; /* number of entries in wmap */
+};
+#define ifw_addr ifrw.ifrw_addr
+#define ifw_bdp ifrw.ifrw_bdp
+#define ifw_flags ifrw.ifrw_flags
+#define ifw_info ifrw.ifrw_info
+#define ifw_proto ifrw.ifrw_proto
+#define ifw_mr ifrw.ifrw_mr
+
+/*
+ * Most interfaces have a single receive and a single transmit buffer,
+ * and use struct ifuba to store all of the unibus information.
+ */
+struct ifuba {
+ struct ifubinfo ifu_info;
+ struct ifrw ifu_r;
+ struct ifxmt ifu_xmt;
+};
+
+#define ifu_uban ifu_info.iff_uban
+#define ifu_hlen ifu_info.iff_hlen
+#define ifu_uba ifu_info.iff_uba
+#define ifu_ubamr ifu_info.iff_ubamr
+#define ifu_flags ifu_info.iff_flags
+#define ifu_w ifu_xmt.ifrw
+#define ifu_xtofree ifu_xmt.ifw_xtofree
+
+#ifdef _KERNEL
+#define if_ubainit(ifuba, uban, hlen, nmr) \
+ if_ubaminit(&(ifuba)->ifu_info, uban, hlen, nmr, \
+ &(ifuba)->ifu_r, 1, &(ifuba)->ifu_xmt, 1)
+#define if_rubaget(ifu, totlen, off0, ifp) \
+ if_ubaget(&(ifu)->ifu_info, &(ifu)->ifu_r, totlen, off0, ifp)
+#define if_wubaput(ifu, m) \
+ if_ubaput(&(ifu)->ifu_info, &(ifu)->ifu_xmt, m)
+struct mbuf *if_ubaget();
+#endif