4.2BSD driver for DEC Deuna Ethernet board
From Computer History Wiki
A 4.2 BSD device driver for DEC DEUNA Ethernet board; back in the Usenet days, this driver was posted there.
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/5/84; site green.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!teddy!panda!talcott!harvard!seismo!umcp-cs!aplvax!green!bill From: bill@green.UUCP (bill) Newsgroups: net.unix,net.sources Subject: 4.2BSD driver for DEC Deuna Ethernet board Message-ID: <145@green.UUCP> Date: Sat, 12-Jan-85 16:20:51 EST Article-I.D.: green.145 Posted: Sat Jan 12 16:20:51 1985 Date-Received: Mon, 14-Jan-85 03:14:02 EST Distribution: net Organization: JHU/Biophysics Dept., Baltimore, MD Lines: 1195 Xref: watmath net.unix:3306 net.sources:2364 # Here is a driver for a DEC Deuna Ethernet driver. # We have had it installed on two 11/750's here for about four months # now without any problems which can be attributed to the # driver. # # I'm not sure who we got it from, but the comments attribute it # to Lou Salkind of New York University. # # Bill Bogstad # green!bill #---CUT HERE--- #!/bin/sh : This is a shar archieve. Extract with sh, not csh. : The rest of this file will extract: : if_de.c if_dereg.h echo extracting - if_de.c sed 's/^X//' > if_de.c << '~FUNKY STUFF~' X#ifdef RCSIDENT Xstatic char *rcsident = "$Header: if_de.c,v 1.1 84/02/01 17:18:51 mike Exp $"; X#endif X X#include "de.h" X#if NDE > 0 X X/* X * DEC DEUNA interface X * X * Lou Salkind X * New York University X * X * TODO: X * timeout routine (get statistics) X */ X#include "../machine/pte.h" X X#include "../h/param.h" X#include "../h/systm.h" X#include "../h/mbuf.h" X#include "../h/buf.h" X#include "../h/protosw.h" X#include "../h/socket.h" X#include "../h/vmmac.h" X#include "../h/ioctl.h" X#include "../h/errno.h" X X#include "../net/if.h" X#include "../net/netisr.h" X#include "../net/route.h" X#include "../netinet/in.h" X#include "../netinet/in_systm.h" X#include "../netinet/ip.h" X#include "../netinet/ip_var.h" X#include "../netinet/if_ether.h" X#include "../netpup/pup.h" X X#include "../vax/cpu.h" X#include "../vax/mtpr.h" X#include "../vaxif/if_dereg.h" X#include "../vaxif/if_uba.h" X#include "../vaxuba/ubareg.h" X#include "../vaxuba/ubavar.h" X X#define NXMT 2 /* number of transmit buffers */ X#define NRCV 4 /* number of receive buffers (must be > 1) */ X#define NTOT (NXMT + NRCV) X Xint dedebug = 0; X Xint deprobe(), deattach(), deintr(); Xstruct uba_device *deinfo[NDE]; Xu_short destd[] = { 0 }; Xstruct uba_driver dedriver = X { deprobe, 0, deattach, 0, destd, "de", deinfo }; X#define DEUNIT(x) minor(x) Xint deinit(),deoutput(),deioctl(),dereset(); Xstruct mbuf *deget(); X X X/* X * The following generalizes the ifuba structure X * to an arbitrary number of receive and transmit X * buffers. X */ Xstruct deuba { X short ifu_uban; /* uba number */ X short ifu_hlen; /* local net header length */ X struct uba_regs *ifu_uba; /* uba regs, in vm */ X struct ifrw ifu_r[NRCV]; /* receive information */ X struct ifrw ifu_w[NXMT]; /* transmit information */ X /* these should only be pointers */ X short ifu_flags; /* used during uballoc's */ X}; X X/* X * Ethernet software status per interface. X * X * Each interface is referenced by a network interface structure, X * ds_if, which the routing code uses to locate the interface. X * This structure contains the output queue for the interface, its address, ... X * We also have, for each interface, a UBA interface structure, which X * contains information about the UNIBUS resources held by the interface: X * map registers, buffered data paths, etc. Information is cached in this X * structure for use by the if_uba.c routines in running the interface X * efficiently. X */ Xstruct de_softc { X struct arpcom ds_ac; /* Ethernet common part */ X#define ds_if ds_ac.ac_if /* network-visible interface */ X#define ds_addr ds_ac.ac_enaddr /* hardware Ethernet address */ X int ds_flags; X#define DSF_LOCK 1 /* lock out destart */ X#define DSF_RUNNING 2 X int ds_ubaddr; /* map info for incore structs */ X struct deuba ds_deuba; /* unibus resource structure */ X /* the following structures are always mapped in */ X struct de_pcbb ds_pcbb; /* port control block */ X struct de_ring ds_xrent[NXMT]; /* transmit ring entrys */ X struct de_ring ds_rrent[NRCV]; /* receive ring entrys */ X struct de_udbbuf ds_udbbuf; /* UNIBUS data buffer */ X /* end mapped area */ X#define INCORE_BASE(p) ((char *)&(p)->ds_pcbb) X#define RVAL_OFF(n) ((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0])) X#define LVAL_OFF(n) ((char *)de_softc[0].n - INCORE_BASE(&de_softc[0])) X#define PCBB_OFFSET RVAL_OFF(ds_pcbb) X#define XRENT_OFFSET LVAL_OFF(ds_xrent) X#define RRENT_OFFSET LVAL_OFF(ds_rrent) X#define UDBBUF_OFFSET RVAL_OFF(ds_udbbuf) X#define INCORE_SIZE RVAL_OFF(ds_xindex) X int ds_xindex; /* UNA index into transmit chain */ X int ds_rindex; /* UNA index into receive chain */ X int ds_xfree; /* index for next transmit buffer */ X int ds_nxmit; /* # of transmits in progress */ X} de_softc[NDE]; X Xdeprobe(reg) X caddr_t reg; X{ X register int br, cvec; /* r11, r10 value-result */ X register struct dedevice *addr = (struct dedevice *)reg; X register i; X X#ifdef lint X br = 0; cvec = br; br = cvec; X i = 0; derint(i); deintr(i); X#endif X X addr->pcsr0 = PCSR0_RSET; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X /* make board interrupt by executing a GETPCBB command */ X addr->pcsr0 = PCSR0_INTE; X addr->pcsr2 = 0; X addr->pcsr3 = 0; X addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB; X DELAY(100000); X return(1); X} X X/* X * Interface exists: make available by filling in network interface X * record. System will initialize the interface when it is ready X * to accept packets. We get the ethernet address here. X */ Xdeattach(ui) X struct uba_device *ui; X{ X register struct de_softc *ds = &de_softc[ui->ui_unit]; X register struct ifnet *ifp = &ds->ds_if; X register struct dedevice *addr = (struct dedevice *)ui->ui_addr; X struct sockaddr_in *sin; X int csr0; X X ifp->if_unit = ui->ui_unit; X ifp->if_name = "de"; X ifp->if_mtu = ETHERMTU; X X /* X * Reset the board and temporarily map X * the pcbb buffer onto the Unibus. X */ X addr->pcsr0 = PCSR0_RSET; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb, X sizeof (struct de_pcbb), 0); X addr->pcsr2 = ds->ds_ubaddr & 0xffff; X addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3; X addr->pclow = CMD_GETPCBB; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X ds->ds_pcbb.pcbb0 = FC_RDPHYAD; X addr->pclow = CMD_GETCMD; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X ubarelse(ui->ui_ubanum, &ds->ds_ubaddr); X if (dedebug) X printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit, X ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff, X ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff, X ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff); X bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr, X sizeof (ds->ds_addr)); X sin = (struct sockaddr_in *)&ifp->if_addr; X sin->sin_family = AF_INET; X sin->sin_addr = arpmyaddr((struct arpcom *)0); X ifp->if_init = deinit; X ifp->if_output = deoutput; X ifp->if_ioctl = deioctl; X ifp->if_reset = dereset; X ds->ds_deuba.ifu_flags = UBA_CANTWAIT; X#ifdef notdef X /* CAN WE USE BDP's ??? */ X ds->ds_deuba.ifu_flags |= UBA_NEEDBDP; X#endif X if_attach(ifp); X} X X/* X * Reset of interface after UNIBUS reset. X * If interface is on specified uba, reset its state. X */ Xdereset(unit, uban) X int unit, uban; X{ X register struct uba_device *ui; X X if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 || X ui->ui_ubanum != uban) X return; X printf(" de%d", unit); X deinit(unit); X} X X/* X * Initialization of interface; clear recorded pending X * operations, and reinitialize UNIBUS usage. X */ Xdeinit(unit) X int unit; X{ X register struct de_softc *ds = &de_softc[unit]; X register struct uba_device *ui = deinfo[unit]; X register struct dedevice *addr; X register struct ifrw *ifrw; X int s; X register struct ifnet *ifp = &ds->ds_if; X register struct sockaddr_in *sin; X struct de_ring *rp; X int incaddr; X int csr0; X X sin = (struct sockaddr_in *)&ifp->if_addr; X if (sin->sin_addr.s_addr == 0) /* if address still unknown */ X return; X X if (ifp->if_flags & IFF_RUNNING) X goto justarp; X if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum, X sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) { X printf("de%d: can't initialize\n", unit); X ds->ds_if.if_flags &= ~IFF_UP; X return; X } X ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0); X addr = (struct dedevice *)ui->ui_addr; X X /* set the pcbb block address */ X incaddr = ds->ds_ubaddr + PCBB_OFFSET; X addr->pcsr2 = incaddr & 0xffff; X addr->pcsr3 = (incaddr >> 16) & 0x3; X addr->pclow = CMD_GETPCBB; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X X /* set the transmit and receive ring header addresses */ X incaddr = ds->ds_ubaddr + UDBBUF_OFFSET; X ds->ds_pcbb.pcbb0 = FC_WTRING; X ds->ds_pcbb.pcbb2 = incaddr & 0xffff; X ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3; X X incaddr = ds->ds_ubaddr + XRENT_OFFSET; X ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff; X ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3; X ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short); X ds->ds_udbbuf.b_trlen = NXMT; X incaddr = ds->ds_ubaddr + RRENT_OFFSET; X ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff; X ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3; X ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short); X ds->ds_udbbuf.b_rrlen = NRCV; X X addr->pclow = CMD_GETCMD; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X X /* initialize the mode - enable hardware padding */ X ds->ds_pcbb.pcbb0 = FC_WTMODE; X /* let hardware do padding - set MTCH bit on broadcast */ X ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX; X addr->pclow = CMD_GETCMD; X while ((addr->pcsr0 & PCSR0_INTR) == 0) X ; X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X if (csr0 & PCSR0_PCEI) X printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit, X csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS); X X /* set up the receive and transmit ring entries */ X ifrw = &ds->ds_deuba.ifu_w[0]; X for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) { X rp->r_segbl = ifrw->ifrw_info & 0xffff; X rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; X rp->r_flags = 0; X ifrw++; X } X ifrw = &ds->ds_deuba.ifu_r[0]; X for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) { X rp->r_slen = sizeof (struct de_buf); X rp->r_segbl = ifrw->ifrw_info & 0xffff; X rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3; X rp->r_flags = RFLG_OWN; /* hang receive */ X ifrw++; X } X X /* start up the board (rah rah) */ X s = splimp(); X ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0; X ds->ds_if.if_flags |= IFF_UP|IFF_RUNNING; X destart(unit); /* queue output packets */ X addr->pclow = PCSR0_INTE; /* avoid interlock */ X addr->pclow = CMD_START | PCSR0_INTE; X ds->ds_flags |= DSF_RUNNING; X splx(s); Xjustarp: X if_rtinit(&ds->ds_if, RTF_UP); X arpattach(&ds->ds_ac); X arpwhohas(&ds->ds_ac, &sin->sin_addr); X} X X/* X * Setup output on interface. X * Get another datagram to send off of the interface queue, X * and map it to the interface before starting the output. X */ Xdestart(unit) X int unit; X{ X int len; X struct uba_device *ui = deinfo[unit]; X struct dedevice *addr = (struct dedevice *)ui->ui_addr; X register struct de_softc *ds = &de_softc[unit]; X register struct de_ring *rp; X struct mbuf *m; X register int nxmit; X X /* X * the following test is necessary, since X * the code is not reentrant and we have X * multiple transmission buffers. X */ X if (ds->ds_flags & DSF_LOCK) X return; X for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) { X IF_DEQUEUE(&ds->ds_if.if_snd, m); X if (m == 0) X break; X rp = &ds->ds_xrent[ds->ds_xfree]; X if (rp->r_flags & XFLG_OWN) X panic("deuna xmit in progress"); X len = deput(&ds->ds_deuba.ifu_w[ds->ds_xfree], m); X if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP) X UBAPURGE(ds->ds_deuba.ifu_uba, X ds->ds_deuba.ifu_w[ds->ds_xfree].ifrw_bdp); X rp->r_slen = len; X rp->r_tdrerr = 0; X rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN; X X ds->ds_xfree++; X if (ds->ds_xfree == NXMT) X ds->ds_xfree = 0; X } X if (ds->ds_nxmit != nxmit) { X ds->ds_nxmit = nxmit; X if (ds->ds_flags & DSF_RUNNING) X addr->pclow = PCSR0_INTE|CMD_PDMD; X } X} X X/* X * Command done interrupt. X */ Xdeintr(unit) X int unit; X{ X struct uba_device *ui = deinfo[unit]; X register struct dedevice *addr = (struct dedevice *)ui->ui_addr; X register struct de_softc *ds = &de_softc[unit]; X register struct de_ring *rp; X short csr0; X X /* save flags right away - clear out interrupt bits */ X csr0 = addr->pcsr0; X addr->pchigh = csr0 >> 8; X X X ds->ds_flags |= DSF_LOCK; /* prevent entering destart */ X /* X * if receive, put receive buffer on mbuf X * and hang the request again X */ X derecv(unit); X X /* X * Poll transmit ring and check status. X * Be careful about loopback requests. X * Then free buffer space and check for X * more transmit requests. X */ X for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) { X rp = &ds->ds_xrent[ds->ds_xindex]; X if (rp->r_flags & XFLG_OWN) X break; X ds->ds_if.if_opackets++; X /* check for unusual conditions */ X if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) { X if (rp->r_flags & XFLG_ERRS) { X /* output error */ X ds->ds_if.if_oerrors++; X if (dedebug) X printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n", X unit, rp->r_flags, XFLG_BITS, X rp->r_tdrerr, XERR_BITS, rp->r_slen); X } else if (rp->r_flags & XFLG_ONE) { X /* one collision */ X ds->ds_if.if_collisions++; X } else if (rp->r_flags & XFLG_MORE) { X /* more than one collision */ X ds->ds_if.if_collisions += 2; /* guess */ X } else if (rp->r_flags & XFLG_MTCH) { X /* received our own packet */ X ds->ds_if.if_ipackets++; X deread(ds, &ds->ds_deuba.ifu_w[ds->ds_xindex], X rp->r_slen - sizeof (struct ether_header)); X } X } X /* check if next transmit buffer also finished */ X ds->ds_xindex++; X if (ds->ds_xindex == NXMT) X ds->ds_xindex = 0; X } X ds->ds_flags &= ~DSF_LOCK; X destart(unit); X X if (csr0 & PCSR0_RCBI) { X printf("de%d: buffer unavailable\n", unit); X addr->pclow = PCSR0_INTE|CMD_PDMD; X } X} X X/* X * Ethernet interface receiver interface. X * If input error just drop packet. X * Otherwise purge input buffered data path and examine X * packet to determine type. If can't determine length X * from type, then have to drop packet. Othewise decapsulate X * packet based on type and pass to type specific higher-level X * input routine. X */ Xderecv(unit) X int unit; X{ X register struct de_softc *ds = &de_softc[unit]; X register struct de_ring *rp; X int len; X X rp = &ds->ds_rrent[ds->ds_rindex]; X while ((rp->r_flags & RFLG_OWN) == 0) { X ds->ds_if.if_ipackets++; X if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP) X UBAPURGE(ds->ds_deuba.ifu_uba, X ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp); X len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header) X - 4; /* don't forget checksum! */ X /* check for errors */ X if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) || X (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) || X (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) || X len < ETHERMIN || len > ETHERMTU) { X ds->ds_if.if_ierrors++; X if (dedebug) X printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n", X unit, rp->r_flags, RFLG_BITS, rp->r_lenerr, X RERR_BITS, len); X } else X deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len); X X /* hang the receive buffer again */ X rp->r_lenerr = 0; X rp->r_flags = RFLG_OWN; X X /* check next receive buffer */ X ds->ds_rindex++; X if (ds->ds_rindex == NRCV) X ds->ds_rindex = 0; X rp = &ds->ds_rrent[ds->ds_rindex]; X } X} X X/* X * Pass a packet to the higher levels. X * We deal with the trailer protocol here. X */ Xderead(ds, ifrw, len) X register struct de_softc *ds; X struct ifrw *ifrw; X int len; X{ X struct ether_header *eh; X struct mbuf *m; X int off, resid; X register struct ifqueue *inq; X X /* X * Deal with trailer protocol: if type is PUP trailer X * get true type from first 16-bit word past data. X * Remember that type was trailer by setting off. X */ X eh = (struct ether_header *)ifrw->ifrw_addr; X eh->ether_type = ntohs((u_short)eh->ether_type); X#define dedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) X if (eh->ether_type >= ETHERPUP_TRAIL && X eh->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) { X off = (eh->ether_type - ETHERPUP_TRAIL) * 512; X if (off >= ETHERMTU) X return; /* sanity */ X eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *)); X resid = ntohs(*(dedataaddr(eh, off+2, u_short *))); X if (off + resid > len) X return; /* sanity */ X len = off + resid; X } else X off = 0; X if (len == 0) X return; X X /* X * Pull packet off interface. Off is nonzero if packet X * has trailing header; deget will then force this header X * information to be at the front, but we still have to drop X * the type and length which are at the front of any trailer data. X */ X m = deget(&ds->ds_deuba, ifrw, len, off); X if (m == 0) X return; X if (off) { X m->m_off += 2 * sizeof (u_short); X m->m_len -= 2 * sizeof (u_short); X } X switch (eh->ether_type) { X X#ifdef INET X case ETHERPUP_IPTYPE: X schednetisr(NETISR_IP); X inq = &ipintrq; X break; X X case ETHERPUP_ARPTYPE: X arpinput(&ds->ds_ac, m); X return; X#endif X default: X m_freem(m); X return; X } X X if (IF_QFULL(inq)) { X IF_DROP(inq); X m_freem(m); X return; X } X IF_ENQUEUE(inq, m); X} X X/* X * Ethernet output routine. X * Encapsulate a packet of type family for the local net. X * Use trailer local net encapsulation if enough data in first X * packet leaves a multiple of 512 bytes of data in remainder. X */ Xdeoutput(ifp, m0, dst) X struct ifnet *ifp; X struct mbuf *m0; X struct sockaddr *dst; X{ X int type, s, error; X u_char edst[6]; X struct in_addr idst; X register struct de_softc *ds = &de_softc[ifp->if_unit]; X register struct mbuf *m = m0; X register struct ether_header *eh; X register int off; X X switch (dst->sa_family) { X X#ifdef INET X case AF_INET: X idst = ((struct sockaddr_in *)dst)->sin_addr; X if (!arpresolve(&ds->ds_ac, m, &idst, edst)) X return (0); /* if not yet resolved */ X off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; X /* need per host negotiation */ X if ((ifp->if_flags & IFF_NOTRAILERS) == 0) X if (off > 0 && (off & 0x1ff) == 0 && X m->m_off >= MMINOFF + 2 * sizeof (u_short)) { X type = ETHERPUP_TRAIL + (off>>9); X m->m_off -= 2 * sizeof (u_short); X m->m_len += 2 * sizeof (u_short); X *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE); X *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); X goto gottrailertype; X } X type = ETHERPUP_IPTYPE; X off = 0; X goto gottype; X#endif X X case AF_UNSPEC: X eh = (struct ether_header *)dst->sa_data; X bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); X type = eh->ether_type; X goto gottype; X X default: X printf("de%d: can't handle af%d\n", ifp->if_unit, X dst->sa_family); X error = EAFNOSUPPORT; X goto bad; X } X Xgottrailertype: X /* X * Packet to be sent as trailer: move first packet X * (control information) to end of chain. X */ X while (m->m_next) X m = m->m_next; X m->m_next = m0; X m = m0->m_next; X m0->m_next = 0; X m0 = m; X Xgottype: X /* X * Add local net header. If no space in first mbuf, X * allocate another. X */ X if (m->m_off > MMAXOFF || X MMINOFF + sizeof (struct ether_header) > m->m_off) { X m = m_get(M_DONTWAIT, MT_HEADER); X if (m == 0) { X error = ENOBUFS; X goto bad; X } X m->m_next = m0; X m->m_off = MMINOFF; X m->m_len = sizeof (struct ether_header); X } else { X m->m_off -= sizeof (struct ether_header); X m->m_len += sizeof (struct ether_header); X } X eh = mtod(m, struct ether_header *); X eh->ether_type = htons((u_short)type); X bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); X /* DEUNA fills in source address */ X X /* X * Queue message on interface, and start output if interface X * not yet active. X */ X s = splimp(); X if (IF_QFULL(&ifp->if_snd)) { X IF_DROP(&ifp->if_snd); X splx(s); X m_freem(m); X return (ENOBUFS); X } X IF_ENQUEUE(&ifp->if_snd, m); X destart(ifp->if_unit); X splx(s); X return (0); X Xbad: X m_freem(m0); X return (error); X} X X/* X * Routines supporting UNIBUS network interfaces. X */ X X/* X * Init UNIBUS for interface on uban whose headers of size hlen are to X * end on a page boundary. We allocate a UNIBUS map register for the page X * with the header, and nmr more UNIBUS map registers for i/o on the adapter, X * doing this for each receive and transmit buffer. We also X * allocate page frames in the mbuffer pool for these pages. X */ Xde_ubainit(ifu, uban, hlen, nmr) X register struct deuba *ifu; X int uban, hlen, nmr; X{ X register caddr_t cp, dp; X register struct ifrw *ifrw; X int ncl; X X ncl = clrnd(nmr + CLSIZE) / CLSIZE; X if (ifu->ifu_r[0].ifrw_addr) X /* X * If the first read buffer has a non-zero X * address, it means we have already allocated core X */ X cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen); X else { X cp = m_clalloc(NTOT * ncl, MPG_SPACE); X if (cp == 0) X return (0); X ifu->ifu_hlen = hlen; X ifu->ifu_uban = uban; X ifu->ifu_uba = uba_hd[uban].uh_uba; X dp = cp + CLBYTES - hlen; X for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { X ifrw->ifrw_addr = dp; X dp += ncl * CLBYTES; X } X for (ifrw = ifu->ifu_w; ifrw < &ifu->ifu_w[NXMT]; ifrw++) { X ifrw->ifrw_addr = dp; X dp += ncl * CLBYTES; X } X } X /* allocate for receive ring */ X for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { X if (de_ubaalloc(ifu, ifrw, nmr) == 0) { X struct ifrw *if2; X X for (if2 = ifu->ifu_r; if2 < ifrw; if2++) X ubarelse(ifu->ifu_uban, &if2->ifrw_info); X goto bad; X } X } X /* and now transmit ring */ X for (ifrw = ifu->ifu_w; ifrw < &ifu->ifu_w[NXMT]; ifrw++) { X if (de_ubaalloc(ifu, ifrw, nmr) == 0) { X struct ifrw *if2; X X for (if2 = ifu->ifu_w; if2 < ifrw; if2++) X ubarelse(ifu->ifu_uban, &if2->ifrw_info); X for (if2 = ifu->ifu_r; if2 < &ifu->ifu_r[NRCV]; if2++) X ubarelse(ifu->ifu_uban, &if2->ifrw_info); X goto bad; X } X } X return (1); Xbad: X m_pgfree(cp, NTOT * ncl); X ifu->ifu_r[0].ifrw_addr = 0; X return(0); X} X X/* X * Setup either a ifrw structure by allocating UNIBUS map registers, X * possibly a buffered data path, and initializing the fields of X * the ifrw structure to minimize run-time overhead. X */ Xstatic Xde_ubaalloc(ifu, ifrw, nmr) X struct deuba *ifu; X register struct ifrw *ifrw; X int nmr; X{ X register int info; X X info = X uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, X ifu->ifu_flags); X if (info == 0) X return (0); X ifrw->ifrw_info = info; X ifrw->ifrw_bdp = UBAI_BDP(info); X ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); X ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; X return (1); X} X X/* X * Pull read data off a interface. X * Len is length of data, with local net header stripped. X * Off is non-zero if a trailer protocol was used, and X * gives the offset of the trailer information. X * We copy the trailer information and then all the normal X * data into mbufs. When full cluster sized units are present X * on the interface on cluster boundaries we can get them more X * easily by remapping, and take advantage of this here. X */ Xstruct mbuf * Xdeget(ifu, ifrw, totlen, off0) X register struct deuba *ifu; X register struct ifrw *ifrw; X int totlen, off0; X{ X struct mbuf *top, **mp, *m; X int off = off0, len; X register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen; X X top = 0; X mp = ⊤ X while (totlen > 0) { X MGET(m, M_DONTWAIT, MT_DATA); X if (m == 0) X goto bad; X if (off) { X len = totlen - off; X cp = ifrw->ifrw_addr + ifu->ifu_hlen + off; X } else X len = totlen; X if (len >= CLBYTES) { X struct mbuf *p; X struct pte *cpte, *ppte; X int x, *ip, i; X X MCLGET(p, 1); X if (p == 0) X goto nopage; X len = m->m_len = CLBYTES; X m->m_off = (int)p - (int)m; X if (!claligned(cp)) X goto copy; X X /* X * Switch pages mapped to UNIBUS with new page p, X * as quick form of copy. Remap UNIBUS and invalidate. X */ X cpte = &Mbmap[mtocl(cp)*CLSIZE]; X ppte = &Mbmap[mtocl(p)*CLSIZE]; X x = btop(cp - ifrw->ifrw_addr); X ip = (int *)&ifrw->ifrw_mr[x]; X for (i = 0; i < CLSIZE; i++) { X struct pte t; X t = *ppte; *ppte++ = *cpte; *cpte = t; X *ip++ = X cpte++->pg_pfnum|ifrw->ifrw_proto; X mtpr(TBIS, cp); X cp += NBPG; X mtpr(TBIS, (caddr_t)p); X p += NBPG / sizeof (*p); X } X goto nocopy; X } Xnopage: X m->m_len = MIN(MLEN, len); X m->m_off = MMINOFF; Xcopy: X bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); X cp += m->m_len; Xnocopy: X *mp = m; X mp = &m->m_next; X if (off) { X /* sort of an ALGOL-W style for statement... */ X off += m->m_len; X if (off == totlen) { X cp = ifrw->ifrw_addr + ifu->ifu_hlen; X off = 0; X totlen = off0; X } X } else X totlen -= m->m_len; X } X return (top); Xbad: X m_freem(top); X return (0); X} X X/* X * Map a chain of mbufs onto a network interface X * in preparation for an i/o operation. X * The argument chain of mbufs includes the local network X * header which is copied to be in the mapped, aligned X * i/o space. X * X * This routine is unlike if_wubaput in that pages are X * actually switched, rather than the UNIBUS maps temporarily X * remapped. X */ Xdeput(ifrw, m) X register struct ifrw *ifrw; X register struct mbuf *m; X{ X register struct mbuf *mp; X register caddr_t cp; X int cc; X register caddr_t dp; X register int i; X int x; X X cp = ifrw->ifrw_addr; X while (m) { X dp = mtod(m, char *); X if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { X struct pte *cpte, *ppte; X int *ip; X X cpte = &Mbmap[mtocl(cp)*CLSIZE]; X ppte = &Mbmap[mtocl(dp)*CLSIZE]; X x = btop(cp - ifrw->ifrw_addr); X ip = (int *)&ifrw->ifrw_mr[x]; X for (i = 0; i < CLSIZE; i++) { X struct pte t; X t = *ppte; *ppte++ = *cpte; *cpte = t; X *ip++ = X cpte++->pg_pfnum|ifrw->ifrw_proto; X mtpr(TBIS, cp); X cp += NBPG; X mtpr(TBIS, dp); X dp += NBPG; X } X } else { X bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); X cp += m->m_len; X } X MFREE(m, mp); X m = mp; X } X X cc = cp - ifrw->ifrw_addr; X return (cc); X} X#endif X X/* X * Process an ioctl request. X */ Xdeioctl(ifp, cmd, data) X register struct ifnet *ifp; X int cmd; X caddr_t data; X{ X register struct ifreq *ifr = (struct ifreq *)data; X int s = splimp(), error = 0; X X switch (cmd) { X X case SIOCSIFADDR: X if (ifp->if_flags & IFF_RUNNING) X if_rtinit(ifp, -1); /* delete previous route */ X desetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); X deinit(ifp->if_unit); X break; X X default: X error = EINVAL; X } X splx(s); X return (error); X} X Xdesetaddr(ifp, sin) X register struct ifnet *ifp; X register struct sockaddr_in *sin; X{ X X ifp->if_addr = *(struct sockaddr *)sin; X ifp->if_net = in_netof(sin->sin_addr); X ifp->if_host[0] = in_lnaof(sin->sin_addr); X sin = (struct sockaddr_in *)&ifp->if_broadaddr; X sin->sin_family = AF_INET; X sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); X ifp->if_flags |= IFF_BROADCAST; X} ~FUNKY STUFF~ echo extracting - if_dereg.h sed 's/^X//' > if_dereg.h << '~FUNKY STUFF~' X/* X * DEC DEUNA interface X */ Xstruct dedevice { X union { X short p0_w; X char p0_b[2]; X } u_p0; X#define pcsr0 u_p0.p0_w X#define pclow u_p0.p0_b[0] X#define pchigh u_p0.p0_b[1] X short pcsr1; X short pcsr2; X short pcsr3; X}; X X/* X * PCSR 0 bit descriptions X */ X#define PCSR0_SERI 0x8000 /* Status error interrupt */ X#define PCSR0_PCEI 0x4000 /* Port command error interrupt */ X#define PCSR0_RXI 0x2000 /* Receive done interrupt */ X#define PCSR0_TXI 0x1000 /* Transmit done interrupt */ X#define PCSR0_DNI 0x0800 /* Done interrupt */ X#define PCSR0_RCBI 0x0400 /* Receive buffer unavail intrpt */ X#define PCSR0_FATI 0x0100 /* Fatal error interrupt */ X#define PCSR0_INTR 0x0080 /* Interrupt summary */ X#define PCSR0_INTE 0x0040 /* Interrupt enable */ X#define PCSR0_RSET 0x0020 /* DEUNA reset */ X#define PCSR0_CMASK 0x000f /* command mask */ X X#define PCSR0_BITS "\20\20SERI\17PCEI\16RXI\15TXI\14DNI\13RCBI\11FATI\10INTR\7INTE\6RSET" X X/* bits 0-3 are for the PORT_COMMAND */ X#define CMD_NOOP 0x0 X#define CMD_GETPCBB 0x1 /* Get PCB Block */ X#define CMD_GETCMD 0x2 /* Execute command in PCB */ X#define CMD_STEST 0x3 /* Self test mode */ X#define CMD_START 0x4 /* Reset xmit and receive ring ptrs */ X#define CMD_BOOT 0x5 /* Boot DEUNA */ X#define CMD_PDMD 0x8 /* Polling demand */ X#define CMD_TMRO 0x9 /* Sanity timer on */ X#define CMD_TMRF 0xa /* Sanity timer off */ X#define CMD_RSTT 0xb /* Reset sanity timer */ X#define CMD_STOP 0xf /* Suspend operation */ X X/* X * PCSR 1 bit descriptions X */ X#define PCSR1_XPWR 0x8000 /* Transceiver power BAD */ X#define PCSR1_ICAB 0x4000 /* Interconnect cabling BAD */ X#define PCSR1_STCODE 0x3f00 /* Self test error code */ X#define PCSR1_PCTO 0x0080 /* Port command timed out */ X#define PCSR1_ILLINT 0x0040 /* Illegal interrupt */ X#define PCSR1_TIMEOUT 0x0020 /* Timeout */ X#define PCSR1_POWER 0x0010 /* Power fail */ X#define PCSR1_RMTC 0x0008 /* Remote console reserved */ X#define PCSR1_STMASK 0x0007 /* State */ X X/* bit 0-3 are for STATE */ X#define STAT_RESET 0x0 X#define STAT_PRIMLD 0x1 /* Primary load */ X#define STAT_READY 0x2 X#define STAT_RUN 0x3 X#define STAT_UHALT 0x5 /* UNIBUS halted */ X#define STAT_NIHALT 0x6 /* NI halted */ X#define STAT_NIUHALT 0x7 /* NI and UNIBUS Halted */ X X#define PCSR1_BITS "\20\20XPWR\17ICAB\10PCTO\7ILLINT\6TIMEOUT\5POWER\4RMTC" X X/* X * Port Control Block Base X */ Xstruct de_pcbb { X short pcbb0; /* function */ X short pcbb2; /* command specific */ X short pcbb4; X short pcbb6; X}; X X/* PCBB function codes */ X#define FC_NOOP 0x00 /* NO-OP */ X#define FC_LSUADDR 0x01 /* Load and start microaddress */ X#define FC_RDDEFAULT 0x02 /* Read default physical address */ X#define FC_RDPHYAD 0x04 /* Read physical address */ X#define FC_WTPHYAD 0x05 /* Write physical address */ X#define FC_RDMULTI 0x06 /* Read multicast address list */ X#define FC_WTMULTI 0x07 /* Read multicast address list */ X#define FC_RDRING 0x08 /* Read ring format */ X#define FC_WTRING 0x09 /* Write ring format */ X#define FC_RDCNTS 0x0a /* Read counters */ X#define FC_RCCNTS 0x0b /* Read and clear counters */ X#define FC_RDMODE 0x0c /* Read mode */ X#define FC_WTMODE 0x0d /* Write mode */ X#define FC_RDSTATUS 0x0e /* Read port status */ X#define FC_RCSTATUS 0x0f /* Read and clear port status */ X#define FC_DUMPMEM 0x10 /* Dump internal memory */ X#define FC_LOADMEM 0x11 /* Load internal memory */ X#define FC_RDSYSID 0x12 /* Read system ID parameters */ X#define FC_WTSYSID 0x13 /* Write system ID parameters */ X#define FC_RDSERAD 0x14 /* Read load server address */ X#define FC_WTSERAD 0x15 /* Write load server address */ X X/* X * Unibus Data Block Base (UDBB) for ring buffers X */ Xstruct de_udbbuf { X short b_tdrbl; /* Transmit desc ring base low 16 bits */ X char b_tdrbh; /* Transmit desc ring base high 2 bits */ X char b_telen; /* Length of each transmit entry */ X short b_trlen; /* Number of entries in the XMIT desc ring */ X short b_rdrbl; /* Receive desc ring base low 16 bits */ X char b_rdrbh; /* Receive desc ring base high 2 bits */ X char b_relen; /* Length of each receive entry */ X short b_rrlen; /* Number of entries in the RECV desc ring */ X}; X X/* X * Transmit/Receive Ring Entry X */ Xstruct de_ring { X short r_slen; /* Segment length */ X short r_segbl; /* Segment address (low 16 bits) */ X char r_segbh; /* Segment address (hi 2 bits) */ X u_char r_flags; /* Status flags */ X u_short r_tdrerr; /* Errors */ X#define r_lenerr r_tdrerr X short r_rid; /* Request ID */ X}; X X#define XFLG_OWN 0x80 /* If 0 then owned by driver */ X#define XFLG_ERRS 0x40 /* Error summary */ X#define XFLG_MTCH 0x20 /* Address match on xmit request */ X#define XFLG_MORE 0x10 /* More than one entry required */ X#define XFLG_ONE 0x08 /* One collision encountered */ X#define XFLG_DEF 0x04 /* Transmit deferred */ X#define XFLG_STP 0x02 /* Start of packet */ X#define XFLG_ENP 0x01 /* End of packet */ X X#define XFLG_BITS "\10\10OWN\7ERRS\6MTCH\5MORE\4ONE\3DEF\2STP\1ENP" X X#define XERR_BUFL 0x8000 /* Buffer length error */ X#define XERR_UBTO 0x4000 /* UNIBUS tiemout X#define XERR_LCOL 0x1000 /* Late collision */ X#define XERR_LCAR 0x0800 /* Loss of carrier */ X#define XERR_RTRY 0x0400 /* Failed after 16 retries */ X#define XERR_TDR 0x03ff /* TDR value */ X X#define XERR_BITS "\20\20BUFL\17UBTO\15LCOL\14LCAR\13RTRY" X X#define RFLG_OWN 0x80 /* If 0 then owned by driver */ X#define RFLG_ERRS 0x40 /* Error summary */ X#define RFLG_FRAM 0x20 /* Framing error */ X#define RFLG_OFLO 0x10 /* Message overflow */ X#define RFLG_CRC 0x08 /* CRC error */ X#define RFLG_STP 0x02 /* Start of packet */ X#define RFLG_ENP 0x01 /* End of packet */ X X#define RFLG_BITS "\10\10OWN\7ERRS\6FRAM\5OFLO\4CRC\2STP\1ENP" X X#define RERR_BUFL 0x8000 /* Buffer length error */ X#define RERR_UBTO 0x4000 /* UNIBUS tiemout */ X#define RERR_NCHN 0x2000 /* No data chaining */ X#define RERR_MLEN 0x0fff /* Message length */ X X#define RERR_BITS "\20\20BUFL\17UBTO\16NCHN" X X/* mode description bits */ X#define MOD_HDX 0x0001 /* Half duplex mode */ X#define MOD_LOOP 0x0004 /* Enable internal loopback */ X#define MOD_DTCR 0x0008 /* Disables CRC generation */ X#define MOD_DMNT 0x0200 /* Disable maintenance features */ X#define MOD_ECT 0x0400 /* Enable collision test */ X#define MOD_TPAD 0x1000 /* Transmit message pad enable */ X#define MOD_DRDC 0x2000 /* Disable data chaining */ X#define MOD_ENAL 0x4000 /* Enable all multicast */ X#define MOD_PROM 0x8000 /* Enable promiscuous mode */ X Xstruct de_buf { X struct ether_header db_head; /* header */ X char db_data[ETHERMTU]; /* packet data */ X int db_crc; /* CRC - on receive only */ X}; ~FUNKY STUFF~ exit