home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / vax / if / if_dmv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  27.1 KB  |  1,088 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)if_dmv.c    7.12 (Berkeley) 12/16/90
  34.  */
  35.  
  36. /*
  37.  * DMV-11 Driver
  38.  *
  39.  * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode
  40.  *
  41.  * Written by Bob Kridle of Mt Xinu
  42.  * starting from if_dmc.c version 6.12 dated 4/23/86
  43.  */
  44.  
  45. #include "dmv.h"
  46. #if NDMV > 0
  47.  
  48. #include "sys/param.h"
  49. #include "sys/systm.h"
  50. #include "sys/mbuf.h"
  51. #include "sys/buf.h"
  52. #include "sys/ioctl.h"        /* must precede tty.h */
  53. #include "sys/tty.h"
  54. #include "sys/protosw.h"
  55. #include "sys/socket.h"
  56. #include "sys/syslog.h"
  57. #include "sys/vmmac.h"
  58. #include "sys/errno.h"
  59. #include "sys/time.h"
  60. #include "sys/kernel.h"
  61.  
  62. #include "net/if.h"
  63. #include "net/netisr.h"
  64. #include "net/route.h"
  65.  
  66. #ifdef    INET
  67. #include "netinet/in.h"
  68. #include "netinet/in_systm.h"
  69. #include "netinet/in_var.h"
  70. #include "netinet/ip.h"
  71. #endif
  72.  
  73. #include "../include/cpu.h"
  74. #include "../include/mtpr.h"
  75. #include "../include/pte.h"
  76. #include "../uba/ubareg.h"
  77. #include "../uba/ubavar.h"
  78. #include "if_uba.h"
  79. #include "if_dmv.h"
  80.  
  81. int    dmv_timeout = 8;        /* timeout value */
  82.  
  83. /*
  84.  * Driver information for auto-configuration stuff.
  85.  */
  86. int    dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
  87. int    dmvoutput(), dmvreset(), dmvtimeout();
  88. struct    uba_device *dmvinfo[NDMV];
  89. u_short    dmvstd[] = { 0 };
  90. struct    uba_driver dmvdriver =
  91.     { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo };
  92.  
  93. /*
  94.  * Don't really know how many buffers/commands can be queued to a DMV-11.
  95.  * Manual doesn't say... Perhaps we can look at a DEC driver some day.
  96.  * These numbers ame from DMC/DMR driver.
  97.  */
  98. #define NRCV 5
  99. #define NXMT 3 
  100. #define NCMDS    (NRCV+NXMT+4)    /* size of command queue */
  101.  
  102. #ifdef DEBUG
  103. #define printd(f)   if (sc->sc_if.if_flags & IFF_DEBUG) \
  104.     printf("DMVDEBUG: dmv%d: ", unit), printf(f)
  105. #else
  106. #define    printd(f)    /* nil */
  107. #endif
  108.  
  109. /* error reporting intervals */
  110.  
  111. #define    DMV_RPRTE     1
  112. #define    DMV_RPTTE        1
  113. #define    DMV_RPSTE     1
  114. #define DMV_RPNXM        1
  115. #define DMV_RPMODD       1
  116. #define DMV_RPQOVF     1
  117. #define DMV_RPCXRL     1
  118.  
  119. /* number of errors to accept before trying a reset */
  120. #define DMV_RPUNKNOWN     10
  121.  
  122. struct  dmv_command {
  123.     u_char    qp_mask;    /* Which registers to set up */
  124. #define    QP_TRIB        0x01
  125. #define    QP_SEL4        0x02
  126. #define    QP_SEL6        0x04
  127. #define    QP_SEL10    0x08
  128.     u_char    qp_cmd;
  129.     u_char    qp_tributary;
  130.     u_short    qp_sel4;
  131.     u_short    qp_sel6;
  132.     u_short    qp_sel10;
  133.     struct    dmv_command *qp_next;    /* next command on queue */
  134. };
  135.  
  136. #define    qp_lowbufaddr    qp_
  137.  
  138. struct dmvbufs {
  139.     int    ubinfo;        /* from uballoc */
  140.     short    cc;        /* buffer size */
  141.     short    flags;        /* access control */
  142. };
  143.  
  144. #define    DBUF_OURS    0    /* buffer is available */
  145. #define    DBUF_DMVS    1    /* buffer claimed by somebody */
  146. #define    DBUF_XMIT    4    /* transmit buffer */
  147. #define    DBUF_RCV    8    /* receive buffer */
  148.  
  149.  
  150. /*
  151.  * DMV software status per interface.
  152.  *
  153.  * Each interface is referenced by a network interface structure,
  154.  * sc_if, which the routing code uses to locate the interface.
  155.  * This structure contains the output queue for the interface, its address, ...
  156.  * We also have, for each interface, a  set of 7 UBA interface structures
  157.  * for each, which
  158.  * contain information about the UNIBUS resources held by the interface:
  159.  * map registers, buffered data paths, etc.  Information is cached in this
  160.  * structure for use by the if_uba.c routines in running the interface
  161.  * efficiently.
  162.  */
  163. struct dmv_softc {
  164.     struct    ifnet sc_if;        /* network-visible interface */
  165.     short    sc_oused;        /* output buffers currently in use */
  166.     short    sc_iused;        /* input buffers given to DMV */
  167.     short    sc_flag;        /* flags */
  168.     short    sc_ipl;            /* interrupt priority */
  169.     int    sc_ubinfo;        /* UBA mapping info for base table */
  170.     int    sc_errors[8];        /* error counters */
  171. #define    sc_rte    sc_errors[0]        /* receive threshhold error */
  172. #define    sc_xte    sc_errors[1]        /* xmit threshhold error */
  173. #define    sc_ste    sc_errors[2]        /* select threshhold error */
  174. #define    sc_nxm    sc_errors[3]        /* non-existant memory */
  175. #define    sc_modd    sc_errors[4]        /* modem disconnect */
  176. #define    sc_qovf    sc_errors[5]        /* command/response queue overflow */
  177. #define    sc_cxrl    sc_errors[6]        /* carrier loss */
  178. #define sc_unknown sc_errors[7]        /* other errors - look in DMV manual */
  179.     struct    dmvbufs sc_rbufs[NRCV];    /* receive buffer info */
  180.     struct    dmvbufs sc_xbufs[NXMT];    /* transmit buffer info */
  181.     struct    ifubinfo sc_ifuba;    /* UNIBUS resources */
  182.     struct    ifrw sc_ifr[NRCV];    /* UNIBUS receive buffer maps */
  183.     struct    ifxmt sc_ifw[NXMT];    /* UNIBUS receive buffer maps */
  184.     /* command queue stuff */
  185.     struct    dmv_command sc_cmdbuf[NCMDS];
  186.     struct    dmv_command *sc_qhead;    /* head of command queue */
  187.     struct    dmv_command *sc_qtail;    /* tail of command queue */
  188.     struct    dmv_command *sc_qactive;    /* command in progress */
  189.     struct    dmv_command *sc_qfreeh;    /* head of list of free cmd buffers */
  190.     struct    dmv_command *sc_qfreet;    /* tail of list of free cmd buffers */
  191.     /* end command queue stuff */
  192. } dmv_softc[NDMV];
  193.  
  194. /* flags */
  195. #define DMV_RESTART    0x01        /* software restart in progress */
  196. #define DMV_ONLINE    0x02        /* device managed to transmit */
  197. #define DMV_RUNNING    0x04        /* device initialized */
  198.  
  199.  
  200. /* queue manipulation macros */
  201. #define    QUEUE_AT_HEAD(qp, head, tail) \
  202.     (qp)->qp_next = (head); \
  203.     (head) = (qp); \
  204.     if ((tail) == (struct dmv_command *) 0) \
  205.         (tail) = (head) 
  206.  
  207. #define QUEUE_AT_TAIL(qp, head, tail) \
  208.     if ((tail)) \
  209.         (tail)->qp_next = (qp); \
  210.     else \
  211.         (head) = (qp); \
  212.     (qp)->qp_next = (struct dmv_command *) 0; \
  213.     (tail) = (qp)
  214.  
  215. #define DEQUEUE(head, tail) \
  216.     (head) = (head)->qp_next;\
  217.     if ((head) == (struct dmv_command *) 0)\
  218.         (tail) = (head)
  219.  
  220. dmvprobe(reg, ui)
  221.     caddr_t reg;
  222.     struct uba_device *ui;
  223. {
  224.     register int br, cvec;
  225.     register struct dmvdevice *addr = (struct dmvdevice *)reg;
  226.     register int i;
  227.  
  228. #ifdef lint
  229.     br = 0; cvec = br; br = cvec;
  230.     dmvrint(0); dmvxint(0);
  231. #endif
  232.     addr->bsel1 = DMV_MCLR;
  233.     for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
  234.         ;
  235.     if ((addr->bsel1 & DMV_RUN) == 0) {
  236.         printf("dmvprobe: can't start device\n" );
  237.         return (0);
  238.     }
  239.     if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
  240.     {
  241.         printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n",
  242.             addr->bsel4, addr->bsel6);
  243.         return (0);
  244.     }
  245.     (void) spl6();
  246.     addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO;
  247.     DELAY(1000000);
  248.     dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri();
  249.     addr->bsel1 = DMV_MCLR;
  250.     for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
  251.         ;
  252.     return (sizeof(struct dmvdevice));
  253. }
  254.  
  255. /*
  256.  * Interface exists: make available by filling in network interface
  257.  * record.  System will initialize the interface when it is ready
  258.  * to accept packets.
  259.  */
  260. dmvattach(ui)
  261.     register struct uba_device *ui;
  262. {
  263.     register struct dmv_softc *sc = &dmv_softc[ui->ui_unit];
  264.  
  265.     sc->sc_if.if_unit = ui->ui_unit;
  266.     sc->sc_if.if_name = "dmv";
  267.     sc->sc_if.if_mtu = DMVMTU;
  268.     sc->sc_if.if_init = dmvinit;
  269.     sc->sc_if.if_output = dmvoutput;
  270.     sc->sc_if.if_ioctl = dmvioctl;
  271.     sc->sc_if.if_reset = dmvreset;
  272.     sc->sc_if.if_watchdog = dmvtimeout;
  273.     sc->sc_if.if_flags = IFF_POINTOPOINT;
  274.     sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
  275.  
  276.     if_attach(&sc->sc_if);
  277. }
  278.  
  279. /*
  280.  * Reset of interface after UNIBUS reset.
  281.  * If interface is on specified UBA, reset its state.
  282.  */
  283. dmvreset(unit, uban)
  284.     int unit, uban;
  285. {
  286.     register struct uba_device *ui;
  287.     register struct dmv_softc *sc = &dmv_softc[unit];
  288.  
  289.     if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 ||
  290.         ui->ui_ubanum != uban)
  291.         return;
  292.     printf(" dmv%d", unit);
  293.     sc->sc_flag = 0;
  294.     sc->sc_if.if_flags &= ~IFF_RUNNING;
  295.     dmvinit(unit);
  296. }
  297.  
  298. /*
  299.  * Initialization of interface; reinitialize UNIBUS usage.
  300.  */
  301. dmvinit(unit)
  302.     int unit;
  303. {
  304.     register struct dmv_softc *sc = &dmv_softc[unit];
  305.     register struct uba_device *ui = dmvinfo[unit];
  306.     register struct dmvdevice *addr;
  307.     register struct ifnet *ifp = &sc->sc_if;
  308.     register struct ifrw *ifrw;
  309.     register struct ifxmt *ifxp;
  310.     register struct dmvbufs *rp;
  311.     register struct dmv_command *qp;
  312.     struct ifaddr *ifa;
  313.     int base;
  314.     int s;
  315.  
  316.     addr = (struct dmvdevice *)ui->ui_addr;
  317.  
  318.     /*
  319.      * Check to see that an address has been set
  320.      * (both local and destination for an address family).
  321.      */
  322.     for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
  323.         if (ifa->ifa_addr->sa_family &&
  324.             ifa->ifa_addr->sa_family != AF_LINK &&
  325.             ifa->ifa_dstaddr && ifa->ifa_dstaddr->sa_family)
  326.             break;
  327.     if (ifa == (struct ifaddr *) 0)
  328.         return;
  329.  
  330.     if ((addr->bsel1&DMV_RUN) == 0) {
  331.         log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit);
  332.         ifp->if_flags &= ~IFF_UP;
  333.         return;
  334.     }
  335.     printd(("dmvinit\n"));
  336.     /* initialize UNIBUS resources */
  337.     sc->sc_iused = sc->sc_oused = 0;
  338.     if ((ifp->if_flags & IFF_RUNNING) == 0) {
  339.         if (if_ubaminit(
  340.             &sc->sc_ifuba,
  341.             ui->ui_ubanum,
  342.                 sizeof(struct dmv_header),
  343.             (int)btoc(DMVMTU),
  344.             sc->sc_ifr,
  345.             NRCV,
  346.             sc->sc_ifw,
  347.             NXMT
  348.               ) == 0) {
  349.             log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit);
  350.             ifp->if_flags &= ~IFF_UP;
  351.             return;
  352.         }
  353.         ifp->if_flags |= IFF_RUNNING;
  354.     }
  355.     /*
  356.      * Limit packets enqueued until we see if we're on the air.
  357.      */
  358.     ifp->if_snd.ifq_maxlen = 3;
  359.  
  360.  
  361.     /* initialize buffer pool */
  362.     /* receives */
  363.     ifrw = &sc->sc_ifr[0];
  364.     for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
  365.         rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
  366.         rp->cc = DMVMTU + sizeof (struct dmv_header);
  367.         rp->flags = DBUF_OURS|DBUF_RCV;
  368.         ifrw++; 
  369.     }
  370.     /* transmits */
  371.     ifxp = &sc->sc_ifw[0];
  372.     for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
  373.         rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
  374.         rp->cc = 0;
  375.         rp->flags = DBUF_OURS|DBUF_XMIT;
  376.         ifxp++; 
  377.     }
  378.  
  379.     /* set up command queues */
  380.     sc->sc_qfreeh = sc->sc_qfreet
  381.          = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
  382.         (struct dmv_command *)0;
  383.     /* set up free command buffer list */
  384.     for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
  385.         QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
  386.     }
  387.     if(sc->sc_flag & DMV_RUNNING)
  388.         dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0);
  389.     else
  390.         dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0);
  391.     dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0);
  392.     sc->sc_flag |= (DMV_RESTART|DMV_RUNNING);
  393.     sc->sc_flag &= ~DMV_ONLINE;
  394.     addr->bsel0 |= DMV_IEO;
  395. }
  396.  
  397. /*
  398.  * Start output on interface.  Get another datagram
  399.  * to send from the interface queue and map it to
  400.  * the interface before starting output.
  401.  *
  402.  * Must be called at spl 5
  403.  */
  404. dmvstart(dev)
  405.     dev_t dev;
  406. {
  407.     int unit = minor(dev);
  408.     register struct dmv_softc *sc = &dmv_softc[unit];
  409.     struct mbuf *m;
  410.     register struct dmvbufs *rp;
  411.     register int n;
  412.  
  413.     /*
  414.      * Dequeue up to NXMT requests and map them to the UNIBUS.
  415.      * If no more requests, or no dmv buffers available, just return.
  416.      */
  417.     printd(("dmvstart\n"));
  418.     n = 0;
  419.     for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
  420.         /* find an available buffer */
  421.         if ((rp->flags & DBUF_DMVS) == 0) {
  422.             IF_DEQUEUE(&sc->sc_if.if_snd, m);
  423.             if (m == 0)
  424.                 return;
  425.             /* mark it dmvs */
  426.             rp->flags |= (DBUF_DMVS);
  427.             /*
  428.              * Have request mapped to UNIBUS for transmission
  429.              * and start the output.
  430.              */
  431.             rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
  432.             if (++sc->sc_oused == 1)
  433.                 sc->sc_if.if_timer = dmv_timeout;
  434.             dmvload(
  435.                 sc,
  436.                 DMV_BACCX,
  437.                 QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
  438.                 1,
  439.                 rp->ubinfo,
  440.                 (rp->ubinfo>>16)&0x3f,
  441.                 rp->cc
  442.             );
  443.         }
  444.         n++;
  445.     }
  446. }
  447.  
  448. /*
  449.  * Utility routine to load the DMV device registers.
  450.  */
  451. dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10)
  452.     register struct dmv_softc *sc;
  453.     u_char cmd, tributary, mask;
  454.     u_short sel4, sel6, sel10;
  455. {
  456.     register struct dmvdevice *addr;
  457.     register int unit, sps;
  458.     register struct dmv_command *qp;
  459.  
  460.     unit = sc - dmv_softc;
  461.     printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
  462.         (unsigned) cmd,
  463.         (unsigned) mask,
  464.         (unsigned) tributary,
  465.         (unsigned) sel4,
  466.         (unsigned) sel6,
  467.         (unsigned) sel10
  468.     ));
  469.     addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
  470.     sps = spl5();
  471.  
  472.     /* grab a command buffer from the free list */
  473.     if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0)
  474.         panic("dmv command queue overflow");
  475.     DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
  476.  
  477.     /* fill in requested info */
  478.     qp->qp_cmd = cmd;
  479.     qp->qp_mask = mask;
  480.     qp->qp_tributary = tributary;
  481.     qp->qp_sel4 = sel4;
  482.     qp->qp_sel6 = sel6;
  483.     qp->qp_sel10 = sel10;
  484.     
  485.     if (sc->sc_qactive) {    /* command in progress */
  486.         if (cmd == DMV_BACCR) {  /* supply read buffers first */
  487.             QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
  488.         } else {
  489.             QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
  490.         }
  491.     } else {    /* command port free */
  492.         sc->sc_qactive = qp;
  493.         addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
  494.     }
  495.     splx(sps);
  496. }
  497. /*
  498.  * DMV interface input interrupt.
  499.  * Ready to accept another command,
  500.  * pull one off the command queue.
  501.  */
  502. dmvrint(unit)
  503.     int unit;
  504. {
  505.     register struct dmv_softc *sc;
  506.     register struct dmvdevice *addr;
  507.     register struct dmv_command *qp;
  508.     register int n;
  509.  
  510.     addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
  511.     sc = &dmv_softc[unit];
  512.     splx(sc->sc_ipl);
  513.     printd(("dmvrint\n"));
  514.     if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) {
  515.         log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit);
  516.         return;
  517.     }
  518.     while (addr->bsel2&DMV_RDI) {
  519.         if(qp->qp_mask&QP_SEL4)
  520.             addr->wsel4 = qp->qp_sel4;
  521.         if(qp->qp_mask&QP_SEL6)
  522.             addr->wsel6 = qp->qp_sel6;
  523.         if(qp->qp_mask&QP_SEL10) {
  524.             addr->wsel10 = qp->qp_sel10;
  525.             qp->qp_cmd |= DMV_22BIT;
  526.         }
  527.         if(qp->qp_mask&QP_TRIB)
  528.             addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8);
  529.         else
  530.             addr->bsel2 = qp->qp_cmd;
  531.         QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
  532.         if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0)
  533.             break;
  534.         qp = sc->sc_qactive;
  535.         DEQUEUE(sc->sc_qhead, sc->sc_qtail);
  536.         if (addr->bsel2&DMV_RDO)
  537.                 break;
  538.     }
  539.     if (!sc->sc_qactive) {
  540.         if(addr->bsel2&DMV_RDI) {
  541.             /* clear RQI prior to last command per DMV manual */
  542.             addr->bsel0 &= ~DMV_RQI;
  543.             addr->wsel6 = DMV_NOP;
  544.             addr->bsel2 = DMV_CNTRLI;
  545.         }
  546.         addr->bsel0 = DMV_IEO;
  547.     }
  548.     else /* RDO set or DMV still holding CSR */
  549.         addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
  550.  
  551. }
  552.  
  553. /*
  554.  * DMV interface output interrupt.
  555.  * A transfer may have completed, check for errors.
  556.  * If it was a read, notify appropriate protocol.
  557.  * If it was a write, pull the next one off the queue.
  558.  */
  559. dmvxint(unit)
  560.     int unit;
  561. {
  562.     register struct dmv_softc *sc;
  563.     register struct ifnet *ifp;
  564.     struct uba_device *ui = dmvinfo[unit];
  565.     struct dmvdevice *addr;
  566.     struct mbuf *m;
  567.     struct ifqueue *inq;
  568.     int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s;
  569.     register struct ifrw *ifrw;
  570.     register struct dmvbufs *rp;
  571.     register struct ifxmt *ifxp;
  572.     struct dmv_header *dh;
  573.     int off, resid;
  574.  
  575.     addr = (struct dmvdevice *)ui->ui_addr;
  576.     sc = &dmv_softc[unit];
  577.     splx(sc->sc_ipl);
  578.     ifp = &sc->sc_if;
  579.  
  580.     while (addr->bsel2 & DMV_RDO) {
  581.  
  582.         sel2 = addr->bsel2;
  583.         sel3 = addr->bsel3;
  584.         sel4 = addr->wsel4;        /* release port */
  585.         sel6 = addr->wsel6;
  586.         if(sel2 & DMV_22BIT)
  587.             sel10 = addr->wsel10;
  588.         addr->bsel2 &= ~DMV_RDO;
  589.         pkaddr =  sel4 | ((sel6 & 0x3f) << 16);
  590.         printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
  591.             (unsigned) sel2,
  592.             (unsigned) sel4,
  593.             (unsigned) sel6,
  594.             (unsigned) sel10,
  595.             (unsigned) pkaddr
  596.         ));
  597.         if((sc->sc_flag & DMV_RUNNING)==0) {
  598.                 log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit);
  599.                 return;
  600.         }
  601.         switch (sel2 & 07) {
  602.         case DMV_BDRUS:
  603.             /*
  604.              * A read has completed.  
  605.              * Pass packet to type specific
  606.              * higher-level input routine.
  607.              */
  608.             ifp->if_ipackets++;
  609.             /* find location in dmvuba struct */
  610.             ifrw= &sc->sc_ifr[0];
  611.             for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
  612.                 if(rp->ubinfo == pkaddr)
  613.                     break;
  614.                 ifrw++;
  615.             }
  616.             if (rp >= &sc->sc_rbufs[NRCV])
  617.                 panic("dmv rcv");
  618.             if ((rp->flags & DBUF_DMVS) == 0)
  619.                 log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit);
  620.  
  621.             len = (sel10&0x3fff) - sizeof (struct dmv_header);
  622.             if (len < 0 || len > DMVMTU) {
  623.                 ifp->if_ierrors++;
  624.                 log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n",
  625.                     unit, pkaddr, len);
  626.                 goto setup;
  627.             }
  628.             /*
  629.              * Deal with trailer protocol: if type is trailer
  630.              * get true type from first 16-bit word past data.
  631.              * Remember that type was trailer by setting off.
  632.              */
  633.             dh = (struct dmv_header *)ifrw->ifrw_addr;
  634.             dh->dmv_type = ntohs((u_short)dh->dmv_type);
  635. #define dmvdataaddr(dh, off, type)    ((type)(((caddr_t)((dh)+1)+(off))))
  636.             if (dh->dmv_type >= DMV_TRAILER &&
  637.                 dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) {
  638.                 off = (dh->dmv_type - DMV_TRAILER) * 512;
  639.                 if (off >= DMVMTU)
  640.                     goto setup;        /* sanity */
  641.                 dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *));
  642.                 resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *)));
  643.                 if (off + resid > len)
  644.                     goto setup;        /* sanity */
  645.                 len = off + resid;
  646.             } else
  647.                 off = 0;
  648.             if (len == 0)
  649.                 goto setup;
  650.  
  651.             /*
  652.              * Pull packet off interface.  Off is nonzero if
  653.              * packet has trailing header; dmv_get will then
  654.              * force this header information to be at the front,
  655.              * but we still have to drop the type and length
  656.              * which are at the front of any trailer data.
  657.              */
  658.             m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
  659.             if (m == 0)
  660.                 goto setup;
  661.             switch (dh->dmv_type) {
  662. #ifdef INET
  663.             case DMV_IPTYPE:
  664.                 schednetisr(NETISR_IP);
  665.                 inq = &ipintrq;
  666.                 break;
  667. #endif
  668.             default:
  669.                 m_freem(m);
  670.                 goto setup;
  671.             }
  672.  
  673.             s = splimp();
  674.             if (IF_QFULL(inq)) {
  675.                 IF_DROP(inq);
  676.                 m_freem(m);
  677.             } else
  678.                 IF_ENQUEUE(inq, m);
  679.             splx(s);
  680.     setup:
  681.             /* is this needed? */
  682.             rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
  683.             dmvload(
  684.                 sc,
  685.                 DMV_BACCR,
  686.                 QP_SEL4|QP_SEL6|QP_SEL10,
  687.                 0,
  688.                 (u_short) rp->ubinfo,
  689.                 (rp->ubinfo>>16)&0x3f,
  690.                 rp->cc
  691.             );
  692.             break;
  693.         case DMV_BDXSA:
  694.             /*
  695.              * A write has completed, start another
  696.              * transfer if there is more data to send.
  697.              */
  698.             ifp->if_opackets++;
  699.             /* find associated dmvbuf structure */
  700.             ifxp = &sc->sc_ifw[0];
  701.             for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
  702.                 if(rp->ubinfo == pkaddr)
  703.                     break;
  704.                 ifxp++;
  705.             }
  706.             if (rp >= &sc->sc_xbufs[NXMT]) {
  707.                 log(LOG_ERR, "dmv%d: bad packet address 0x%x\n",
  708.                     unit, pkaddr);
  709.                 break;
  710.             }
  711.             if ((rp->flags & DBUF_DMVS) == 0)
  712.                 log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n",
  713.                     unit, pkaddr);
  714.             /* mark buffer free */
  715.             if (ifxp->ifw_xtofree) {
  716.                 (void)m_freem(ifxp->ifw_xtofree);
  717.                 ifxp->ifw_xtofree = 0;
  718.             }
  719.             rp->flags &= ~DBUF_DMVS;
  720.             if (--sc->sc_oused == 0)
  721.                 sc->sc_if.if_timer = 0;
  722.             else
  723.                 sc->sc_if.if_timer = dmv_timeout;
  724.             if ((sc->sc_flag & DMV_ONLINE) == 0) {
  725.                 extern int ifqmaxlen;
  726.  
  727.                 /*
  728.                  * We're on the air.
  729.                  * Open the queue to the usual value.
  730.                  */
  731.                 sc->sc_flag |= DMV_ONLINE;
  732.                 ifp->if_snd.ifq_maxlen = ifqmaxlen;
  733.             }
  734.             break;
  735.  
  736.         case DMV_CNTRLO:
  737.             /* ACCUMULATE STATISTICS */
  738.             switch(sel6&DMV_EEC) {
  739.             case DMV_ORUN:
  740.                 if(sc->sc_flag & DMV_RESTART) {
  741.                     load_rec_bufs(sc);
  742.                     sc->sc_flag &= ~DMV_RESTART;
  743.                     log(LOG_INFO,
  744.                         "dmv%d: far end on-line\n", unit);
  745.                 } else {
  746.                     log(LOG_WARNING,
  747.                         "dmv%d: far end restart\n", unit);
  748.                     goto restart;
  749.                 }
  750.                 break;
  751.             case DMV_RTE:
  752.                 ifp->if_ierrors++;
  753.                 if ((sc->sc_rte++ % DMV_RPRTE) == 0)
  754.                     log(LOG_WARNING,
  755.                     "dmv%d: receive threshold error\n",
  756.                         unit);
  757.                 break;
  758.             case DMV_TTE:
  759.                 ifp->if_oerrors++;
  760.                 if ((sc->sc_xte++ % DMV_RPTTE) == 0)
  761.                     log(LOG_WARNING,
  762.                     "dmv%d: transmit threshold error\n",
  763.                         unit);
  764.                 break;
  765.             case DMV_STE:
  766.                 if ((sc->sc_ste++ % DMV_RPSTE) == 0)
  767.                     log(LOG_WARNING,
  768.                     "dmv%d: select threshold error\n",
  769.                         unit);
  770.                 break;
  771.             case DMV_NXM:
  772.                 if ((sc->sc_nxm++ % DMV_RPNXM) == 0)
  773.                     log(LOG_WARNING,
  774.                     "dmv%d: nonexistent memory error\n",
  775.                         unit);
  776.                 break;
  777.             case DMV_MODD:
  778.                 if ((sc->sc_modd++ % DMV_RPMODD) == 0) {
  779.                     log(LOG_WARNING,
  780.                     "dmv%d: modem disconnected error\n",
  781.                         unit);
  782.                     goto restart;
  783.                 }
  784.                 break;
  785.             case DMV_CXRL:
  786.                 if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)
  787.                     log(LOG_WARNING,
  788.                     "dmv%d: carrier loss error\n",
  789.                         unit);
  790.                 break;
  791.             case DMV_QOVF:
  792.                 log(LOG_WARNING,
  793.                     "dmv%d: response queue overflow\n",
  794.                     unit);
  795.                 sc->sc_qovf++;
  796.                 goto restart;
  797.  
  798.             default:
  799.                 log(LOG_WARNING,
  800.                     "dmv%d: unknown error %o\n",
  801.                     unit, sel6&DMV_EEC);
  802.                 if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)
  803.                     goto restart;
  804.                 break;
  805.             }
  806.             break;
  807.  
  808.         case DMV_BDRUNUS:
  809.         case DMV_BDXSN:
  810.         case DMV_BDXNS:
  811.             log(LOG_INFO,
  812.                "dmv%d: buffer disp for halted trib %o\n",
  813.                unit, sel2&0x7
  814.                 );
  815.             break;
  816.  
  817.         case DMV_MDEFO:
  818.             if((sel6&0x1f) == 020) {
  819.                 log(LOG_INFO,
  820.                        "dmv%d: buffer return complete sel3=%x\n",
  821.                        unit, sel3);
  822.             } else {
  823.                 log(LOG_INFO,
  824.                    "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",
  825.                    unit, sel3, sel4, sel6
  826.                     );
  827.             }
  828.             break;
  829.             
  830.         default:
  831.             log(LOG_WARNING, "dmv%d: bad control %o\n",
  832.                unit, sel2&0x7
  833.                 );
  834.             break;
  835.         }
  836.     }
  837.     dmvstart(unit);
  838.     return;
  839. restart:
  840.     dmvrestart(unit);
  841. }
  842.  
  843. load_rec_bufs(sc)
  844. register struct dmv_softc *sc;
  845. {
  846.     register struct dmvbufs *rp;
  847.  
  848.     /* queue first NRCV buffers for DMV to fill */
  849.     for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
  850.         rp->flags |= DBUF_DMVS;
  851.         dmvload(
  852.             sc,
  853.             DMV_BACCR,
  854.             QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
  855.             1,
  856.             rp->ubinfo,
  857.             (rp->ubinfo>>16)&0x3f,
  858.             rp->cc
  859.         );
  860.         sc->sc_iused++;
  861.     }
  862. }
  863.  
  864. /*
  865.  * DMV output routine.
  866.  * Encapsulate a packet of type family for the dmv.
  867.  * Use trailer local net encapsulation if enough data in first
  868.  * packet leaves a multiple of 512 bytes of data in remainder.
  869.  */
  870. dmvoutput(ifp, m0, dst)
  871.     register struct ifnet *ifp;
  872.     register struct mbuf *m0;
  873.     struct sockaddr *dst;
  874. {
  875.     int type, error, s;
  876.     register struct mbuf *m = m0;
  877.     register struct dmv_header *dh;
  878.     register int off;
  879.  
  880.     if ((ifp->if_flags & IFF_UP) == 0) {
  881.         error = ENETDOWN;
  882.         goto bad;
  883.     }
  884.  
  885.     switch (dst->sa_family) {
  886. #ifdef    INET
  887.     case AF_INET:
  888.         off = m->m_pkthdr.len - m->m_len;
  889.         if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
  890.         if (off > 0 && (off & 0x1ff) == 0 &&
  891.             (m->m_flags & M_EXT) == 0 &&
  892.             m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
  893.             type = DMV_TRAILER + (off>>9);
  894.             m->m_data -= 2 * sizeof (u_short);
  895.             m->m_len += 2 * sizeof (u_short);
  896.             *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE);
  897.             *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
  898.             goto gottrailertype;
  899.         }
  900.         type = DMV_IPTYPE;
  901.         off = 0;
  902.         goto gottype;
  903. #endif
  904.  
  905.     case AF_UNSPEC:
  906.         dh = (struct dmv_header *)dst->sa_data;
  907.         type = dh->dmv_type;
  908.         goto gottype;
  909.  
  910.     default:
  911.         log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n",
  912.             ifp->if_unit, dst->sa_family);
  913.         error = EAFNOSUPPORT;
  914.         goto bad;
  915.     }
  916.  
  917. gottrailertype:
  918.     /*
  919.      * Packet to be sent as a trailer; move first packet
  920.      * (control information) to end of chain.
  921.      */
  922.     while (m->m_next)
  923.         m = m->m_next;
  924.     m->m_next = m0;
  925.     m = m0->m_next;
  926.     m0->m_next = 0;
  927.     m0 = m;
  928.  
  929. gottype:
  930.     /*
  931.      * Add local network header
  932.      * (there is space for a uba on a vax to step on)
  933.      */
  934.     M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT);
  935.     if (m == 0) {
  936.         error = ENOBUFS;
  937.         goto bad;
  938.     }
  939.     dh = mtod(m, struct dmv_header *);
  940.     dh->dmv_type = htons((u_short)type);
  941.  
  942.     /*
  943.      * Queue message on interface, and start output if interface
  944.      * not yet active.
  945.      */
  946.     s = splimp();
  947.     if (IF_QFULL(&ifp->if_snd)) {
  948.         IF_DROP(&ifp->if_snd);
  949.         m_freem(m);
  950.         splx(s);
  951.         return (ENOBUFS);
  952.     }
  953.     IF_ENQUEUE(&ifp->if_snd, m);
  954.     dmvstart(ifp->if_unit);
  955.     splx(s);
  956.     return (0);
  957.  
  958. bad:
  959.     m_freem(m0);
  960.     return (error);
  961. }
  962.  
  963.  
  964. /*
  965.  * Process an ioctl request.
  966.  */
  967. /* ARGSUSED */
  968. dmvioctl(ifp, cmd, data)
  969.     register struct ifnet *ifp;
  970.     int cmd;
  971.     caddr_t data;
  972. {
  973.     int s = splimp(), error = 0;
  974.     struct mbuf *m;
  975.     register struct dmv_softc *sc = &dmv_softc[ifp->if_unit];
  976.  
  977.     switch (cmd) {
  978.  
  979.     case SIOCSIFADDR:
  980.         ifp->if_flags |= IFF_UP;
  981.         if ((ifp->if_flags & IFF_RUNNING) == 0)
  982.             dmvinit(ifp->if_unit); 
  983.         break;
  984.  
  985.     case SIOCSIFDSTADDR:
  986.         if ((ifp->if_flags & IFF_RUNNING) == 0)
  987.             dmvinit(ifp->if_unit); 
  988.         break;
  989.         
  990.     case SIOCSIFFLAGS:
  991.         if ((ifp->if_flags & IFF_UP) == 0 &&
  992.             sc->sc_flag & DMV_RUNNING)
  993.             dmvdown(ifp->if_unit);
  994.         else if (ifp->if_flags & IFF_UP &&
  995.             (sc->sc_flag & DMV_RUNNING) == 0)
  996.             dmvrestart(ifp->if_unit);
  997.         break;
  998.  
  999.     default:
  1000.         error = EINVAL;
  1001.     }
  1002.     splx(s);
  1003.     return (error);
  1004. }
  1005.  
  1006. /*
  1007.  * Restart after a fatal error.
  1008.  * Clear device and reinitialize.
  1009.  */
  1010. dmvrestart(unit)
  1011.     int unit;
  1012. {
  1013.     register struct dmvdevice *addr;
  1014.     register int i;
  1015.  
  1016.     dmvdown(unit);
  1017.  
  1018.     addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
  1019.     /*
  1020.      * Let the DMV finish the MCLR.
  1021.      */
  1022.     for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
  1023.         ;
  1024.     if ((addr->bsel1 & DMV_RUN) == 0) {
  1025.         log(LOG_ERR, "dmvrestart: can't start device\n" );
  1026.         return (0);
  1027.     }
  1028.     if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
  1029.     {
  1030.         log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",
  1031.             unit, addr->bsel4, addr->bsel6);
  1032.         return (0);
  1033.     }
  1034.  
  1035.     /* restart DMV */
  1036.     dmvinit(unit);
  1037.     dmv_softc[unit].sc_if.if_collisions++;    /* why not? */
  1038. }
  1039.     
  1040. /*
  1041.  * Reset a device and mark down.
  1042.  * Flush output queue and drop queue limit.
  1043.  */
  1044. dmvdown(unit)
  1045.     int unit;
  1046. {
  1047.     struct dmv_softc *sc = &dmv_softc[unit];
  1048.     register struct ifxmt *ifxp;
  1049.  
  1050.     ((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR;
  1051.     sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE);
  1052.  
  1053.     for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
  1054.         if (ifxp->ifw_xtofree) {
  1055.             (void) m_freem(ifxp->ifw_xtofree);
  1056.             ifxp->ifw_xtofree = 0;
  1057.         }
  1058.     }
  1059.     sc->sc_oused = 0;
  1060.     if_qflush(&sc->sc_if.if_snd);
  1061.  
  1062.     /*
  1063.      * Limit packets enqueued until we're back on the air.
  1064.      */
  1065.     sc->sc_if.if_snd.ifq_maxlen = 3;
  1066. }
  1067.  
  1068. /*
  1069.  * Watchdog timeout to see that transmitted packets don't
  1070.  * lose interrupts.  The device has to be online.
  1071.  */
  1072. dmvtimeout(unit)
  1073.     int unit;
  1074. {
  1075.     register struct dmv_softc *sc;
  1076.     struct dmvdevice *addr;
  1077.  
  1078.     sc = &dmv_softc[unit];
  1079.     if (sc->sc_flag & DMV_ONLINE) {
  1080.         addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
  1081.         log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n",
  1082.             unit, addr->bsel0 & 0xff, DMV0BITS,
  1083.             addr->bsel2 & 0xff, DMV2BITS);
  1084.         dmvrestart(unit);
  1085.     }
  1086. }
  1087. #endif
  1088.