Subject: working DELQA-YM etherboard driver (#121) Index: pdpif/if_qt.c,if_qtreg.h 2.11BSD Description: The DELQA-YM driver is now operational and being released for more widespread testing. The earlier version (in update #98) was known not to work and was released as a "place holder" only (the various Makefiles needed to be updated, etc). Repeat-By: Have a DELQA-YM (M7516-YM) in the system. Configure a kernel with 'NQT 1' in the config file. Notice that after a few packets the system no longer communicates on the network. This is due to the ring buffers not being properly recycled by the old driver. Next, install the driver below and see that the problem is fixed. Fix: Remove any existing 'pdpif/if_qt.c' and 'pdpif/if_qtreg.h' files that are present on the system. Save the remainder of this file (below the 'cut here' line) to /tmp/qt and unshar it. cd /sys/pdpif rm -f if_qt.c if_qtreg.h sh /tmp/qt To use this driver you must have a DELQA-YM (the driver detects if this is not the case so you won't crash the system). The device is specified as 'QT' (right below the 'QE' for the DEQNA in the config files) in the kernel config file. Many thanks to Terry Kennedy for the loan of the board (and the RG-58 used to hook the systems together) used for development of the driver. ==============================cut here===================================== #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # if_qt.c # if_qtreg.h # This archive created: Thu Mar 4 10:52:22 1993 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'if_qt.c' then echo shar: "will not over-write existing file 'if_qt.c'" else sed 's/^X//' << \SHAR_EOF > 'if_qt.c' X/* @(#)if_qt.c 1.2 (2.11BSD) 2/20/93 X * X * Modification History X * 23-Feb-92 -- sms X * Rewrite the buffer handling so that fewer than the maximum number of X * buffers may be used (32 receive and 12 transmit buffers consume 66+kb X * of main system memory in addition to the internal structures in the X * networking code). A freelist of available buffers is maintained now. X * When I/O operations complete the associated buffer is placed on the X * freelist (a single linked list for simplicity) and when an I/O is X * started a buffer is pulled off the list. X * X * 20-Feb-92 -- sms X * It works! Darned board couldn't handle "short" rings - those rings X * where only half the entries were made available to the board (the X * ring descriptors were the full size, merely half the entries were X * flagged as belonging always to the driver). Grrrr. Would have thought X * the board could skip over those entries reserved by the driver. X * Now to find a way not to have to allocated 32+12 times 1.5kb worth of X * buffers... X * X * 03-Feb-92 -- sms X * Released but still not working. The driver now responds to arp and X * ping requests. The board is apparently not returning ring descriptors X * to the driver so eventually we run out of buffers. Back to the X * drawing board. X * X * 28-Dec-92 -- sms X * Still not released. Hiatus in finding free time and thin-netting X * the systems (many thanks Terry!). X * Added logic to dynamically allocate a vector and initialize it. X * X * 23-Oct-92 -- sms X * The INIT block must (apparently) be quadword aligned [no thanks to X * the manual for not mentioning that fact]. The necessary alignment X * is achieved by allocating the INIT block from main memory ('malloc' X * guarantees click alignment) and mapping it as needed (which is _very_ X * infrequently). A check for quadword alignment of the ring descriptors X * was added - at present the descriptors are properly aligned, if this X * should change then something will have to be done (like do it "right"). X * Darned alignment restrictions! X * X * A couple of typos were corrected (missing parentheses, reversed X * arguments to printf calls, etc). X * X * 13-Oct-92 -- sms@wlv.iipo.gtegsc.com X * Created based on the DELQA-PLUS addendum to DELQA User's Guide. X * This driver ('qt') is selected at system configuration time. If the X * board * is not a DELQA-YM an error message will be printed and the X * interface will not be attached. X*/ X X#include "qt.h" X#if NQT > 0 X X#include "param.h" X#include "pdp/psl.h" X#include "pdp/seg.h" X#include "map.h" X#include "systm.h" X#include "mbuf.h" X#include "buf.h" X#include "protosw.h" X#include "socket.h" X#include "ioctl.h" X#include "errno.h" X#include "syslog.h" X#include "time.h" X#include "kernel.h" X X#include "../net/if.h" X#include "../net/netisr.h" X#include "../net/route.h" X X#ifdef INET X#include "domain.h" X#include "../netinet/in.h" X#include "../netinet/in_systm.h" X#include "../netinet/in_var.h" X#include "../netinet/ip.h" X#include "../netinet/if_ether.h" X#endif X X#ifdef NS X#include "../netns/ns.h" X#include "../netns/ns_if.h" X#endif X X#include "if_qtreg.h" X#include "if_uba.h" X#include "../pdpuba/ubavar.h" X X#define NRCV 16 /* Receive descriptors (must be <= 32) */ X#define NXMT 6 /* Transmit descriptors (must be <= 12) */ X#if NRCV > 32 || NXMT > 12 X generate an error X#endif X X struct qt_uba X { X struct qt_uba *next; /* link to next buffer in list or X * NULL if the last buffer X */ X struct ifuba ubabuf; /* buffer descriptor */ X }; X Xstruct qt_softc { X struct arpcom is_ac; /* common part - must be first */ X#define is_if is_ac.ac_if /* network-visible interface */ X#define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ X struct qt_uba *freelist; /* list of available buffers */ X struct qt_uba ifrw[NRCV + NXMT]; X u_short initclick; /* click addr of the INIT block */ X struct qt_rring *rring; /* Receive ring address */ X struct qt_tring *tring; /* Transmit ring address */ X char r_align[QT_MAX_RCV * sizeof (struct qt_rring) + 8]; X char t_align[QT_MAX_XMT * sizeof (struct qt_tring) + 8]; X short qt_flags; /* software state */ X#define QTF_RUNNING 0x1 X#define QTF_STARTUP 0x2 /* Waiting for start interrupt */ X char rindex; /* Receive Completed Index */ X char nxtrcv; /* Next Receive Index */ X char nrcv; /* Number of Receives active */ X char tindex; /* Transmit index */ X char otindex; /* Old transmit index */ X char nxmit; /* # of xmits in progress */ X struct qtdevice *addr; /* device CSR addr */ X} qt_softc[NQT]; X Xstruct uba_device *qtinfo[NQT]; X Xint qtattach(), qtintr(), qtinit(), qtoutput(), qtioctl(); X Xextern struct ifnet loif; X Xu_short qtstd[] = { 0 }; X Xstruct uba_driver qtdriver = X { 0, 0, qtattach, 0, qtstd, "qe", qtinfo }; X X/* X * Maximum packet size needs to include 4 bytes for the CRC X * on received packets. X*/ X#define MAXPACKETSIZE (ETHERMTU + sizeof (struct ether_header) + 4) X#define MINPACKETSIZE 64 X X/* X * The C compiler's propensity for prepending '_'s to names is the reason X * for the hack below. We need the "handler" address (the code which X * sets up the interrupt stack frame) in order to initialize the vector. X*/ X Xstatic int qtfoo() X { X asm("mov $qtintr, r0"); /* return value is in r0 */ X } X X/* X * Interface exists. More accurately, something exists at the CSR (see X * sys/sys_net.c) -- there's no guarantee it's a DELQA-YM. X * X * The ring descriptors are initialized, the buffers allocated using first the X * DMA region allocated at network load time and then later main memory. The X * INIT block is filled in and the device is poked/probed to see if it really X * is a DELQA-YM. If the device is not a -YM then a message is printed and X * the 'if_attach' call is skipped. For a -YM the START command is issued, X * but the device is not marked as running|up - that happens at interrupt level X * when the device interrupts to say it has started. X*/ X Xqtattach(ui) X struct uba_device *ui; X { X register struct qt_softc *sc = &qt_softc[ui->ui_unit]; X register struct ifnet *ifp = &sc->is_if; X register struct qt_init *iniblk = (struct qt_init *)SEG5; X segm seg5; X long bufaddr; X extern int nextiv(); X X ifp->if_unit = ui->ui_unit; X ifp->if_name = "qe"; X ifp->if_mtu = ETHERMTU; X ifp->if_flags = IFF_BROADCAST; X X/* X * Fill in most of the INIT block: vector, options (interrupt enable), ring X * locations. The physical address is copied from the ROMs as part of the X * -YM testing proceedure. The CSR is saved here rather than in qtinit() X * because the qtturbo() routine needs it. X * X * The INIT block must be quadword aligned. Using malloc() guarantees click X * (64 byte) alignment. Since the only time the INIT block is referenced is X * at 'startup' or 'reset' time there is really no time penalty (and a modest X * D space savings) involved. X*/ X sc->addr = (struct qtdevice *)ui->ui_addr; X sc->initclick = MALLOC(coremap, btoc(sizeof (struct qt_init))); X saveseg5(seg5); X mapseg5(sc->initclick, 077406); X bzero(iniblk, sizeof (struct qt_init)); X sc->rring = (struct qt_rring *)(((int)sc->r_align + 7) & ~7); X sc->tring = (struct qt_tring *)(((int)sc->t_align + 7) & ~7); X X/* X * Fetch the next available interrupt vector. The routine is in the kernel X * (for several reasons) so use SKcall. Then initialize the vector with X * the address of our 'handler' and PSW of supervisor, priority 4 and unit X*/ X iniblk->vector = SKcall(nextiv, 0); X mtkd(iniblk->vector, qtfoo()); X mtkd(iniblk->vector + 2, PSL_CURSUP | PSL_BR4 | ifp->if_unit); X X iniblk->options = INIT_OPTIONS_INT; X bufaddr = startnet + (long)sc->rring; X iniblk->rx_lo = loint(bufaddr); X iniblk->rx_hi = hiint(bufaddr); X bufaddr = startnet + (long)sc->tring; X iniblk->tx_lo = loint(bufaddr); X iniblk->tx_hi = hiint(bufaddr); X restorseg5(seg5); X X/* X * Now allocate the buffers and initialize the buffers. This should _never_ X * fail because main memory is allocated after the DMA pool is used up. X*/ X X if (!qbaini(sc, NRCV + NXMT)) X return; /* XXX */ X X ifp->if_init = qtinit; X ifp->if_output = qtoutput; X ifp->if_ioctl = qtioctl; X ifp->if_reset = 0; X if (qtturbo(sc)) X if_attach(ifp); X } X Xqtturbo(sc) X register struct qt_softc *sc; X { X register int i; X register struct qtdevice *addr = sc->addr; X struct qt_init *iniblk = (struct qt_init *)SEG5; X segm seg5; X X/* X * Issue the software reset. Delay 150us. The board should now be in X * DELQA-Normal mode. Set ITB and DEQTA select. If both bits do not X * stay turned on then the board is not a DELQA-YM. X*/ X addr->arqr = ARQR_SR; X addr->arqr = 0; X delay(150L); X X addr->srr = 0x8001; /* MS | ITB */ X i = addr->srr; X addr->srr = 0x8000; /* Turn off ITB, set DELQA select */ X if (i != 0x8001) X { X printf("qt@%o !-YM\n", addr); X return(0); X } X/* X * Board is a DELQA-YM. Send the commands to enable Turbo mode. Delay X * 1 second, testing the SRR register every millisecond to see if the X * board has shifted to Turbo mode. X*/ X addr->xcr0 = 0x0baf; X addr->xcr1 = 0xff00; X for (i = 0; i < 1000; i++) X { X if ((addr->srr & SRR_RESP) == 1) X break; X delay(1000L); X } X if (i >= 1000) X { X printf("qt@%o !Turbo\n", addr); X return(0); X } X/* X * Board has entered Turbo mode. Now copy the physical address from the X * ROMs to the INIT block. Fill in the address in the part of the structure X * "visible" to the rest of the system. X*/ X saveseg5(seg5); X mapseg5(sc->initclick, 077406); X sc->is_addr[0] = addr->sarom[0]; X sc->is_addr[1] = addr->sarom[2]; X sc->is_addr[2] = addr->sarom[4]; X sc->is_addr[3] = addr->sarom[6]; X sc->is_addr[4] = addr->sarom[8]; X sc->is_addr[5] = addr->sarom[10]; X bcopy(sc->is_addr, iniblk->paddr, 6); X restorseg5(seg5); X return(1); X } X Xqtinit(unit) X int unit; X { X int s; X register struct qt_softc *sc = &qt_softc[unit]; X struct qtdevice *addr = sc->addr; X struct ifnet *ifp = &sc->is_if; X struct qt_rring *rp; X struct qt_tring *tp; X register struct qt_uba *xp; X register int i; X long buf_adr; X X if (!ifp->if_addrlist) /* oops! */ X return; X/* X * Now initialize the receive ring descriptors. Because this routine can be X * called with outstanding I/O operations we check the ring descriptors for X * a non-zero 'rhost0' (or 'thost0') word and place those buffers back on X * the free list. X*/ X for (i = 0, rp = sc->rring; i < QT_MAX_RCV; i++, rp++) X { X rp->rmd3 = RMD3_OWN; X if (xp = rp->rhost0) X { X rp->rhost0 = 0; X xp->next = sc->freelist; X sc->freelist = xp; X } X } X for (i = 0, tp = sc->tring ; i < QT_MAX_XMT; i++, tp++) X { X sc->tring[i].tmd3 = TMD3_OWN; X if (xp = tp->thost0) X { X tp->thost0 = 0; X xp->next = sc->freelist; X sc->freelist = xp; X } X } X X sc->nxmit = 0; X sc->otindex = 0; X sc->tindex = 0; X sc->rindex = 0; X sc->nxtrcv = 0; X sc->nrcv = 0; X X s = splimp(); X/* X * Now we tell the device the address of the INIT block. The device X * _must_ be in the Turbo mode at this time. The "START" command is X * then issued to the device. A 1 second timeout is then started. X * When the interrupt occurs the IFF_UP|IFF_RUNNING state is entered and X * full operations will proceed. If the timeout expires without an interrupt X * being received an error is printed, the flags cleared and the device left X * marked down. X*/ X buf_adr = ctob((long)sc->initclick); X addr->ibal = loint(buf_adr); X addr->ibah = hiint(buf_adr); X addr->srqr = 2; X/* X * set internal state to 'startup' and start a one second timer. the interrupt X * service routine will be entered either 1) when the device posts the 'start' X * interrupt or 2) when the timer expires. The interrupt routine will fill X * the receive rings, etc. X*/ X sc->qt_flags = QTF_STARTUP; X TIMEOUT(qtintr, unit, 60); X splx(s); X } X X/* X * Start output on interface. X */ X Xqtstart(unit) X int unit; X { X int len, s; X register struct qt_softc *sc = &qt_softc[unit]; X register struct qt_tring *rp; X struct mbuf *m; X long buf_addr; X register struct qt_uba *xp; X X s = splimp(); X while (sc->nxmit < NXMT) X { X IF_DEQUEUE(&sc->is_if.if_snd, m); X if (m == 0) X break; X rp = &sc->tring[sc->tindex]; X#ifdef QTDEBUG X if ((rp->tmd3 & TMD3_OWN) == 0) X printf("qt xmit in progress\n"); X#endif X/* X * Now pull a buffer off of the freelist. Guaranteed to be a buffer X * because both the receive and transmit sides limit themselves to X * NRCV and NXMT buffers respectively. X*/ X xp = sc->freelist; X sc->freelist = xp->next; X X buf_addr = xp->ubabuf.ifu_w.ifrw_info; X len = if_wubaput(&xp->ubabuf, m); X if (len < MINPACKETSIZE) X len = MINPACKETSIZE; X rp->tmd4 = loint(buf_addr); X rp->tmd5 = hiint(buf_addr) & TMD5_HADR; X rp->tmd3 = len & TMD3_BCT; /* set length,clear ownership */ X rp->thost0 = xp; /* set entry active */ X sc->addr->arqr = ARQR_TRQ; /* tell device it has buffer */ X sc->nxmit++; X if (++sc->tindex >= QT_MAX_XMT) X sc->tindex = 0; X } X splx(s); X } X X/* X * General interrupt service routine. Receive, transmit, device start X * interrupts and timeouts come here. Check for hard device errors and print a X * message if any errors are found. If we are waiting for the device to X * START then check if the device is now running. X*/ X Xqtintr(unit) X int unit; X { X register struct qt_softc *sc = &qt_softc[unit]; X register int status; X int s; X X status = sc->addr->srr; X if (status < 0) X /* should we reset the device after a bunch of these errs? */ X qtsrr(unit, status); X if (sc->qt_flags == QTF_STARTUP) X { X if ((status & SRR_RESP) == 2) X { X sc->qt_flags = QTF_RUNNING; X sc->is_if.if_flags |= (IFF_UP | IFF_RUNNING); X } X else X printf("qt%d !start\n", unit); X } X s = splimp(); X qtrint(unit); X if (sc->nxmit) X qttint(unit); X qtstart(unit); X splx(s); X } X X/* X * Transmit interrupt service. Only called if there are outstanding transmit X * requests which could have completed. The DELQA-YM doesn't provide the X * status bits telling the kind (receive, transmit) of interrupt. X*/ X X#define BBLMIS (TMD2_BBL|TMD2_MIS) X Xqttint(unit) X int unit; X { X register struct qt_softc *sc = &qt_softc[unit]; X register struct qt_tring *rp; X register struct qt_uba *xp; X X while (sc->nxmit > 0) X { X rp = &sc->tring[sc->otindex]; X if ((rp->tmd3 & TMD3_OWN) == 0) X break; X/* X * Now check the buffer address (the first word in the ring descriptor X * available for the host's use). If it is NULL then we have already seen X * and processed (or never presented to the board in the first place) this X * entry and the ring descriptor should not be counted. X*/ X xp = rp->thost0; X if (xp == 0) X break; X/* X * Clear the buffer address from the ring descriptor and put the X * buffer back on the freelist for future use. X*/ X rp->thost0 = 0; X xp->next = sc->freelist; X sc->freelist = xp; X X sc->nxmit--; X sc->is_if.if_opackets++; X/* X * Collisions don't count as output errors, but babbling and missing packets X * do count as output errors. X*/ X if (rp->tmd2 & TMD2_CER) X sc->is_if.if_collisions++; X if ((rp->tmd0 & TMD0_ERR1) || X ((rp->tmd2 & TMD2_ERR2) && (rp->tmd2 & BBLMIS))) X { X#ifdef QTDEBUG X printf("qt%d tmd2 %b\n", unit, rp->tmd2, TMD2_BITS); X#endif X sc->is_if.if_oerrors++; X } X if (++sc->otindex >= QT_MAX_XMT) X sc->otindex = 0; X } X } X X/* X * Receive interrupt service. Pull packet off the interface and put into X * a mbuf chain for processing later. X*/ X Xqtrint(unit) X int unit; X { X register struct qt_softc *sc = &qt_softc[unit]; X register struct qt_rring *rp; X register struct qt_uba *xp; X int len; X long bufaddr; X X while (sc->rring[sc->rindex].rmd3 & RMD3_OWN) X { X rp = &sc->rring[sc->rindex]; X/* X * If the host word is 0 then this is a buffer either already seen or not X * presented to the device in the first place. X*/ X xp = rp->rhost0; X if (xp == 0) X break; X X if ((rp->rmd0 & (RMD0_STP|RMD0_ENP)) != (RMD0_STP|RMD0_ENP)) X { X printf("qt%d chained packet\n", unit); X sc->is_if.if_ierrors++; X goto rnext; X } X len = (rp->rmd1 & RMD1_MCNT) - 4; /* -4 for CRC */ X sc->is_if.if_ipackets++; X X if ((rp->rmd0 & RMD0_ERR3) || (rp->rmd2 & RMD2_ERR4)) X { X sc->is_if.if_ierrors++; X#ifdef QTDEBUG X printf("qt%d rmd0 %b\n", unit, rp->rmd0, RMD0_BITS); X printf("qt%d rmd2 %b\n", unit, rp->rmd2, RMD2_BITS); X#endif X } X else X qtread(sc, &xp->ubabuf, X len - sizeof (struct ether_header)); Xrnext: X --sc->nrcv; X if (++sc->rindex >= QT_MAX_RCV) X sc->rindex = 0; X/* X * put the buffer back on the free list and clear the first host word X * in the ring descriptor so we don't process this one again. X*/ X xp->next = sc->freelist; X sc->freelist = xp; X rp->rhost0 = 0; X } X while (sc->nrcv < NRCV) X { X rp = &sc->rring[sc->nxtrcv]; X#ifdef QTDEBUG X if ((rp->rmd3 & RMD3_OWN) == 0) X printf("qtrint: !OWN\n"); X#endif X xp = sc->freelist; X sc->freelist = xp->next; X bufaddr = xp->ubabuf.ifu_r.ifrw_info; X rp->rmd1 = MAXPACKETSIZE; X rp->rmd4 = loint(bufaddr); X rp->rmd5 = hiint(bufaddr); X rp->rhost0 = xp; X rp->rmd3 = 0; /* clear RMD3_OWN */ X ++sc->nrcv; X sc->addr->arqr = ARQR_RRQ; /* tell device it has buffer */ X if (++sc->nxtrcv >= QT_MAX_RCV) X sc->nxtrcv = 0; X } X } X X/* X * Place data on the appropriate queue and call the start routine to X * send the data to the device. X*/ X Xqtoutput(ifp, m0, dst) X struct ifnet *ifp; X struct mbuf *m0; X struct sockaddr *dst; X { X int type, s, trail; X u_char edst[6]; X struct in_addr idst; X register struct ether_header *eh; X register struct qt_softc *is = &qt_softc[ifp->if_unit]; X register struct mbuf *m = m0; X struct mbuf *mcopy = (struct mbuf *)0; X X if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) X { X m_freem(m0); X return(ENETDOWN); 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(&is->is_ac, m, &idst, edst,&trail)) X return(0); /* wait for arp to finish */ X if (!bcmp(edst, etherbroadcastaddr,sizeof (edst))) X mcopy = m_copy(m, 0, (int)M_COPYALL); X type = ETHERTYPE_IP; X break; X#endif X#ifdef NS X case AF_NS: X type = ETHERTYPE_NS; X bcopy(&(((struct sockaddr_ns *)dst)->sns_addr.x_host), X edst, sizeof (edst)); X if (!bcmp(edst, &ns_broadcast, sizeof (edst))) X return(looutput(&loif, m, dst)); X break; X#endif X case AF_UNSPEC: X eh = (struct ether_header *)dst->sa_data; X bcopy(eh->ether_dhost, (caddr_t)edst, sizeof (edst)); X type = eh->ether_type; X break; X default: X printf("qt%d can't handle af%d\n", ifp->if_unit, X dst->sa_family); X m_freem(m); X return(EAFNOSUPPORT); X } X/* X * Add local net header. If no space in first mbuf, allocate another. X*/ X if (m->m_off > MMAXOFF || X MMINOFF + sizeof (struct ether_header) > m->m_off) X { X m = m_get(M_DONTWAIT, MT_HEADER); X if (m == 0) X { X m_freem(m0); Xnobufs: if (mcopy) X m_freem(mcopy); X return(ENOBUFS); X } X m->m_next = m0; X m->m_off = MMINOFF; X m->m_len = sizeof (struct ether_header); X } X else X { 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(edst, (caddr_t)eh->ether_dhost, sizeof (edst)); X bcopy(is->is_addr, (caddr_t)eh->ether_shost, sizeof (is->is_addr)); X X s = splimp(); X if (IF_QFULL(&ifp->if_snd)) X { X IF_DROP(&ifp->if_snd); X m_freem(m); X splx(s); X goto nobufs; X } X IF_ENQUEUE(&ifp->if_snd, m); X qtstart(ifp->if_unit); X splx(s); X return(mcopy ? looutput(&loif, mcopy, dst) : 0); X } X Xqtioctl(ifp, cmd, data) X register struct ifnet *ifp; X int cmd; X caddr_t data; X { X struct qt_softc *sc = &qt_softc[ifp->if_unit]; X struct ifaddr *ifa = (struct ifaddr *)data; X int s = splimp(), error = 0; X#ifdef NS X register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); X#endif X X switch (cmd) X { X case SIOCSIFADDR: X/* X * Resetting the board is probably overkill, but then again this is only X * done when the system comes up or possibly when a reset is needed after a X * major network fault (open wire, etc). X*/ X qtrestart(sc); X switch (ifa->ifa_addr.sa_family) X { X#ifdef INET X case AF_INET: X ((struct arpcom *)ifp)->ac_ipaddr = X IA_SIN(ifa)->sin_addr; X arpwhohas(ifp, &IA_SIN(ifa)->sin_addr); X break; X#endif X#ifdef NS X case AF_NS: X if (ns_nullhost(*ina)) X ina->x_host = X *(union ns_host *)(sc->is_addr); X else X { X qt_ns(ina->x_host.c_host); X qtrestart(sc); X } X break; X#endif X } X break; X case SIOCSIFFLAGS: X if ((ifp->if_flags & IFF_UP) == 0 && X sc->qt_flags & QTF_RUNNING) X { X/* X * We've been asked to stop the board and leave it that way. qtturbo() X * does this with the side effect of placing the device back in Turbo mode. X*/ X qtturbo(sc); X sc->qt_flags &= ~QTF_RUNNING; X } X else if (ifp->if_flags & IFF_UP && X !(sc->qt_flags & QTF_RUNNING)) X qtrestart(sc); X break; X default: X error = EINVAL; X } X splx(s); X return(error); X } X X#ifdef NS Xqt_ns(cp) X register char *cp; X { X segm seg5; X register struct qt_init *iniblk = (struct qt_init *)SEG5; X X saveseg5(seg5); X mapseg5(sc->initclick, 077406); X bcopy(cp, sc->is_addr, 6); X bcopy(cp, iniblk->paddr, 6); X restorseg5(seg5); X } X#endif X X/* X * Pull the data off of the board and pass back to the upper layers of X * the networking code. Trailers are counted as errors and the packet X * dropped. SEG5 is saved and restored (used to peek at the packet type). X*/ X Xqtread(sc, ifuba, len) X register struct qt_softc *sc; X struct ifuba *ifuba; X int len; X { X struct ether_header *eh; X register struct mbuf *m; X struct ifqueue *inq; X int type; X segm seg5; X X saveseg5(seg5); X mapseg5(ifuba->ifu_r.ifrw_click, 077406); X eh = (struct ether_header *)SEG5; X eh->ether_type = ntohs((u_short)eh->ether_type); X type = eh->ether_type; X restorseg5(seg5); X if (len == 0 || type >= ETHERTYPE_TRAIL && X type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) X { X sc->is_if.if_ierrors++; X return; X } X X m = if_rubaget(ifuba, len, 0, &sc->is_if); X if (m == 0) X return; X X switch (type) X { X#ifdef INET X case ETHERTYPE_IP: X schednetisr(NETISR_IP); X inq = &ipintrq; X break; X case ETHERTYPE_ARP: X arpinput(&sc->is_ac, m); X return; X#endif X#ifdef NS X case ETHERTYPE_NS: X schednetisr(NETISR_NS); X inq = &nsintrq; X break; X#endif X default: X m_freem(m); X return; X } X X if (IF_QFULL(inq)) X { X IF_DROP(inq); X m_freem(m); X return; X } X IF_ENQUEUE(inq, m); X } X X Xqtsrr(unit, srrbits) X int unit, srrbits; X { X printf("qt%d srr=%b\n", unit, srrbits, SRR_BITS); X } X X/* X * Reset the device. This moves it from DELQA-T mode to DELQA-Normal mode. X * After the reset put the device back in -T mode. Then call qtinit() to X * reinitialize the ring structures and issue the 'timeout' for the "device X * started interrupt". X*/ X Xqtrestart(sc) X register struct qt_softc *sc; X { X X qtturbo(sc); X qtinit(sc - qt_softc); X } X Xqbaini(sc, num) X struct qt_softc *sc; X int num; X { X register int i; X register memaddr click; X struct qt_uba *xp; X register struct ifuba *ifuba; X X for (i = 0; i < num; i++) X { X xp = &sc->ifrw[i]; X ifuba = &xp->ubabuf; X click = m_ioget(MAXPACKETSIZE); X if (click == 0) X { X click = MALLOC(coremap, btoc(MAXPACKETSIZE)); X if (click == 0) X return(0); /* _can't_ happen */ X } X ifuba->ifu_hlen = sizeof (struct ether_header); X ifuba->ifu_w.ifrw_click = ifuba->ifu_r.ifrw_click = click; X ifuba->ifu_w.ifrw_info = ifuba->ifu_r.ifrw_info = X ctob((long)click); X xp->next = sc->freelist; X sc->freelist = xp; X } X return(1); X } X#endif SHAR_EOF fi if test -f 'if_qtreg.h' then echo shar: "will not over-write existing file 'if_qtreg.h'" else sed 's/^X//' << \SHAR_EOF > 'if_qtreg.h' X/* @(#)if_qtreg.h 1.0 (GTE) 10/12/92 */ X X/* X * Modification History X * 26 Feb 93 -- sms X * Add defines for number of receive and transmit ring descriptors. X * X * 12 Oct 92 -- Steven M. Schultz (sms) X * Created from the DELQA-PLUS Addendum to the DELQA User's Guide. X*/ X X#define QT_MAX_RCV 32 X#define QT_MAX_XMT 12 X X/* Receive ring descriptor and bit/field definitions */ X X struct qt_rring X { X short rmd0; X short rmd1; X short rmd2; X short rmd3; X short rmd4; X short rmd5; X struct qt_uba *rhost0; X short rhost1; X }; X X#define RMD0_ERR3 0x4000 /* Error summary. FRA|CRC|OFL|BUF */ X#define RMD0_FRA 0x2000 /* Framing error */ X#define RMD0_OFL 0x1000 /* Overflow error. Oversized packet */ X#define RMD0_CRC 0x0800 /* CRC error */ X#define RMD0_BUF 0x0400 /* Internal device buffer error */ X#define RMD0_STP 0x0200 /* Start of packet */ X#define RMD0_ENP 0x0100 /* End of packet */ X X#define RMD1_MCNT 0x0fff /* Message byte count */ X X#define RMD2_ERR4 0x8000 /* Error summary. BBL|CER|MIS */ X#define RMD2_BBL 0x4000 /* Babble error on transmit */ X#define RMD2_CER 0x2000 /* Collision error on transmit */ X#define RMD2_MIS 0x1000 /* Packet lost on receive */ X#define RMD2_EOR 0x0800 /* End of receive ring */ X#define RMD2_RON 0x0020 /* Receiver on */ X#define RMD2_TON 0x0010 /* Transmitter on */ X X#define RMD3_OWN 0x8000 /* Ownership field. */ X X#define RMD4_LADR 0xfff8 /* Octabyte aligned low address bits */ X X#define RMD5_HADR 0x003f /* High 6 bits of buffer address */ X X#define RMD0_BITS "\010\016FRA\015OFL\014CRC\013BUF\012STP\011ENP" X#define RMD2_BITS "\010\017BBL\014CER\013MIS\012EOR\06RON\05TON" X X/* Transmit ring descriptor and bit/field definitions */ X X struct qt_tring X { X short tmd0; X short tmd1; X short tmd2; X short tmd3; X short tmd4; X short tmd5; X struct qt_uba *thost0; X short thost1; X }; X X#define TMD0_ERR1 0x4000 /* Error summary. LCO|LCA|RTR */ X#define TMD0_MOR 0x1000 /* More than one retry on transmit */ X#define TMD0_ONE 0x0800 /* One retry on transmit */ X#define TMD0_DEF 0x0400 /* Deferral during transmit */ X X#define TMD1_LCO 0x1000 /* Late collision on transmit */ X#define TMD1_LCA 0x0800 /* Loss of carrier on transmit */ X#define TMD1_RTR 0x0400 /* Retry error on transmit */ X#define TMD1_TDR 0x03ff /* Time Domain Reflectometry value */ X X#define TMD2_ERR2 0x8000 /* Error summary. BBL|CER|MIS */ X#define TMD2_BBL 0x4000 /* Babble error on transmit */ X#define TMD2_CER 0x2000 /* Collision error on transmit */ X#define TMD2_MIS 0x1000 /* Packet lost on receive */ X#define TMD2_EOR 0x0800 /* Endof Receive ring reached */ X#define TMD2_RON 0x0020 /* Receiver on */ X#define TMD2_TON 0x0010 /* Transmitter on */ X X#define TMD3_OWN 0x8000 /* Ownership field */ X#define TMD3_FOT 0x4000 /* First of two flag */ X#define TMD3_BCT 0x0fff /* Byte count */ X X#define TMD4_LADR 0xfff8 /* Octabyte aligned low address bits */ X X#define TMD5_HADR 0x003f /* High 6 bits of buffer address */ X X#define TMD1_BITS "\010\015LCO\014LCA\013RTR" X#define TMD2_BITS "\010\017BBL\016CER\015MIS\014EOR\06RON\05TON" X X/* DELQA-YM CSR layout */ X X struct qtcsr0 X { X short Ibal; X short Ibah; X short Icr; X short pad0; X short Srqr; X short pad1; X }; X X struct qtdevice X { X union { X u_char Sarom[12]; X struct qtcsr0 csr0; X } qt_un0; X short srr; X short arqr; X }; X X#define ibal qt_un0.csr0.Ibal X#define ibah qt_un0.csr0.Ibah X#define srqr qt_un0.csr0.Srqr X#define icr qt_un0.csr0.Icr X#define sarom qt_un0.Sarom X X/* SRR definitions */ X X#define SRR_FES 0x8000 X#define SRR_CHN 0x4000 X#define SRR_NXM 0x1000 X#define SRR_PER 0x0800 X#define SRR_IME 0x0400 X#define SRR_TBL 0x0200 X#define SRR_RESP 0x0003 X#define SRR_BITS "\010\017CHN\015NXM\014PER\013IME\012TBL" X X/* SRQR definitions */ X X#define SRQR_REQ 0x0003 X X/* ARQR definitions */ X X#define ARQR_TRQ 0x8000 X#define ARQR_RRQ 0x0080 X#define ARQR_SR 0x0002 X X/* define ICR definitions */ X X#define ICR_CMD 0x0001 X X/* DELQA registers used to shift into -T mode */ X X#define xcr0 qt_un0.csr0.Ibal X#define xcr1 qt_un0.csr0.Ibah X X/* INIT block structure and definitions */ X X struct qt_init X { X short mode; X u_char paddr[6]; /* 48 bit physical address */ X u_char laddr[8]; /* 64 bit logical address filter */ X u_short rx_lo; /* low 16 bits of receive ring addr */ X u_short rx_hi; /* high 6 bits of receive ring addr */ X u_short tx_lo; /* low 16 bits of transmit ring addr */ X u_short tx_hi; /* high 6 bits of transmit ring addr */ X u_short options; X u_short vector; X u_short hit; X char passwd[6]; X }; X X#define INIT_MODE_PRO 0x8000 /* Promiscuous mode */ X#define INIT_MODE_INT 0x0040 /* Internal Loopback */ X#define INIT_MODE_DRT 0x0020 /* Disable Retry */ X#define INIT_MODE_DTC 0x0008 /* Disable Transmit CRC */ X#define INIT_MODE_LOP 0x0004 /* Loopback */ X X#define INIT_OPTIONS_HIT 0x0002 /* Host Inactivity Timeout Flag */ X#define INIT_OPTIONS_INT 0x0001 /* Interrupt Enable Flag */ SHAR_EOF fi exit 0 # End of shell archive