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

  1. /*
  2.  * Copyright (c) 1982, 1986, 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_vv.c    7.10 (Berkeley) 12/16/90
  34.  */
  35.  
  36. #include "vv.h"
  37. #if NVV > 0
  38.  
  39. /*
  40.  * Proteon ProNET-10 and ProNET-80 token ring driver.
  41.  * The name of this device driver derives from the old MIT
  42.  * name of V2LNI for the proNET hardware, would would abbreviate
  43.  * to "v2", but this won't work right in config. Thus the name is "vv".
  44.  *
  45.  * This driver is compatible with the Unibus ProNET 10 megabit and
  46.  * 80 megabit token ring interfaces (models p1000 and p1080).
  47.  * A unit may be marked as 80 megabit using "flags 1" in the
  48.  * config file.
  49.  *
  50.  * This driver is also compatible with the Q-bus ProNET 10 megabit and
  51.  * 80 megabit token ring interfaces (models p1100 and p1180), but
  52.  * only on a MicroVAX-II or MicroVAX-III.  No attempt is made to
  53.  * support the MicroVAX-I.
  54.  *
  55.  * TRAILERS: This driver has a new implementation of trailers that
  56.  * is at least a tolerable neighbor on the ring. The offset is not
  57.  * stored in the protocol type, but instead only in the vh_info
  58.  * field. Also, the vh_info field, and the two shorts before the
  59.  * trailing header, are in network byte order, not VAX byte order.
  60.  *
  61.  * Of course, nothing but BSD UNIX supports trailers on ProNET.
  62.  * If you need interoperability with anything else (like the p4200),
  63.  * turn off trailers using the -trailers option to /etc/ifconfig!
  64.  *
  65.  * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
  66.  * have a serial number >= 040, which is about March, 1982. Older
  67.  * HSBUs do not carry across 64kbyte boundaries. They can be supported
  68.  * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization
  69.  * in vvattach().
  70.  *
  71.  * The old warning about use without Wire Centers applies only to CTL
  72.  * (p1002) cards with serial <= 057, which have not received ECO 176-743,
  73.  * which was implemented in March, 1982. Most such CTLs have received
  74.  * this ECO.
  75.  */
  76. #include "sys/param.h"
  77. #include "sys/systm.h"
  78. #include "sys/mbuf.h"
  79. #include "sys/buf.h"
  80. #include "sys/time.h"
  81. #include "sys/kernel.h"
  82. #include "sys/protosw.h"
  83. #include "sys/socket.h"
  84. #include "sys/syslog.h"
  85. #include "sys/vmmac.h"
  86. #include "sys/errno.h"
  87. #include "sys/ioctl.h"
  88.  
  89. #include "net/if.h"
  90. #include "net/if_types.h"
  91. #include "net/netisr.h"
  92. #include "net/route.h"
  93.  
  94. #ifdef    INET
  95. #include "netinet/in.h"
  96. #include "netinet/in_systm.h"
  97. #include "netinet/in_var.h"
  98. #include "netinet/ip.h"
  99. #endif
  100.  
  101. #include "../include/pte.h"
  102. #include "../include/cpu.h"
  103. #include "../include/mtpr.h"
  104. #include "if_vv.h"
  105. #include "if_uba.h"
  106. #include "../uba/ubareg.h"
  107. #include "../uba/ubavar.h"
  108.  
  109. /*
  110.  *    maximum transmission unit definition --
  111.  *        you can set VVMTU at anything from 576 to 2036.
  112.  *        1536 is a popular "large" value, because it is a multiple
  113.  *      of 512, which the trailer scheme likes.
  114.  *        The absolute maximum size is 2036, which is enforced.
  115.  */
  116.  
  117. #define VVMTU (2036)
  118.  
  119. #define VVMRU (VVMTU + (2 * sizeof(u_short)))
  120. #define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
  121. #if VVMTU>2036
  122. #undef VVMTU
  123. #undef VVMRU
  124. #undef VVBUFSIZE
  125. #define VVBUFSIZE (2046)
  126. #define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
  127. #define VVMTU (VVMRU - (2 * sizeof(u_short)))
  128. #endif
  129.  
  130. /*
  131.  *   debugging and tracing stuff
  132.  */
  133. int    vv_tracehdr = 0;    /* 1 => trace headers (slowly!!) */
  134.  
  135. #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
  136. #define vvlog    if (vs->vs_if.if_flags & IFF_DEBUG) log
  137.  
  138. /*
  139.  * externals, types, etc.
  140.  */
  141. int    vvprobe(), vvattach(), vvreset(), vvinit();
  142. int    vvidentify(), vvstart(), vvxint(), vvwatchdog();
  143. int    vvrint(), vvoutput(), vvioctl();
  144. struct    uba_device *vvinfo[NVV];
  145. u_short vvstd[] = { 0 };
  146. struct    uba_driver vvdriver =
  147.     { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
  148. #define    VVUNIT(x)    minor(x)
  149.  
  150. #define LOOPBACK        /* use loopback for packets meant for us */
  151. #ifdef    LOOPBACK
  152. extern struct ifnet loif;
  153. #endif
  154.  
  155. extern wakeup();
  156.  
  157. /*
  158.  * Software status of each interface.
  159.  *
  160.  * Each interface is referenced by a network interface structure,
  161.  * vs_if, which the routing code uses to locate the interface.
  162.  * This structure contains the output queue for the interface, its address, ...
  163.  * We also have, for each interface, a UBA interface structure, which
  164.  * contains information about the UNIBUS resources held by the interface:
  165.  * map registers, buffered data paths, etc.  Information is cached in this
  166.  * structure for use by the if_uba.c routines in running the interface
  167.  * efficiently.
  168.  */
  169. struct    vv_softc {
  170.     struct    ifnet vs_if;        /* network-visible interface */
  171.     struct    ifuba vs_ifuba;        /* UNIBUS resources */
  172.     u_short    vs_host;        /* this interface address */
  173.     short    vs_oactive;        /* is output active */
  174.     short    vs_is80;        /* is 80 megabit version */
  175.     short    vs_olen;        /* length of last output */
  176.     u_short    vs_lastx;        /* address of last packet sent */
  177.     u_short    vs_lastr;        /* address of last packet received */
  178.     short    vs_tries;        /* transmit current retry count */
  179.     short    vs_init;        /* number of ring inits */
  180.     short    vs_refused;        /* number of packets refused */
  181.     short    vs_timeouts;        /* number of transmit timeouts */
  182.     short    vs_otimeout;        /* number of output timeouts */
  183.     short    vs_ibadf;        /* number of input bad formats */
  184.     short    vs_parity;        /* number of parity errors on 10 meg, */
  185.                     /* link data errors on 80 meg */
  186.     short    vs_ipl;            /* interrupt priority on Q-bus */
  187.     short    vs_flags;        /* board state: */
  188. #define    VS_RUNNING    0x01        /* board has been initialized */
  189. #define    VS_INIT        0x02        /* board being initialized */
  190. } vv_softc[NVV];
  191.  
  192. #define    NOHOST    0xff            /* illegal host number */
  193.  
  194. /*
  195.  * probe the interface to see that the registers exist, and then
  196.  * cause an interrupt to find its vector
  197.  */
  198. vvprobe(reg, ui)
  199.     caddr_t reg;
  200.     struct uba_device *ui;
  201. {
  202.     register int br, cvec;
  203.     register struct vvreg *addr;
  204.  
  205. #ifdef lint
  206.     br = 0; cvec = br; br = cvec;
  207. #endif
  208.     addr = (struct vvreg *)reg;
  209.  
  210.     /* reset interface, enable, and wait till dust settles */
  211. #ifdef QBA
  212.     (void) spl6();
  213. #endif
  214.     addr->vvicsr = VV_RST;
  215.     addr->vvocsr = VV_RST;
  216.     DELAY(100000);
  217.  
  218.     /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
  219.     addr->vvoba = 0;        /* low 16 bits */
  220.     addr->vvoea = 0;        /* extended bits */
  221.     addr->vvowc = -1;        /* for 1 word */
  222.     addr->vvocsr = VV_IEN | VV_DEN;    /* start the DMA, with interrupt */
  223.     DELAY(100000);
  224. #ifdef QBA
  225.     vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri();
  226. #endif
  227.     addr->vvocsr = VV_RST;        /* clear out the CSR */
  228.     if (cvec && cvec != 0x200)
  229.         cvec -= 4;        /* backup so vector => receive */
  230.     return (sizeof(struct vvreg));
  231. }
  232.  
  233. /*
  234.  * Interface exists: make available by filling in network interface
  235.  * record.  System will initialize the interface when it is ready
  236.  * to accept packets.
  237.  */
  238. vvattach(ui)
  239.     struct uba_device *ui;
  240. {
  241.     register struct vv_softc *vs;
  242.  
  243.     vs = &vv_softc[ui->ui_unit];
  244.     vs->vs_if.if_unit = ui->ui_unit;
  245.     vs->vs_if.if_name = "vv";
  246.     vs->vs_if.if_mtu = VVMTU;
  247.     vs->vs_if.if_flags = IFF_BROADCAST;
  248.     vs->vs_if.if_init = vvinit;
  249.     vs->vs_if.if_ioctl = vvioctl;
  250.     vs->vs_if.if_output = vvoutput;
  251.     vs->vs_if.if_reset = vvreset;
  252.     vs->vs_if.if_timer = 0;
  253.     vs->vs_if.if_watchdog = vvwatchdog;
  254.     vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
  255.  
  256.     /* use flag to determine if this is proNET-80 */
  257.     if (vs->vs_is80 = (short)(ui->ui_flags & 01)) {
  258.         vs->vs_if.if_type = IFT_P80;
  259.         vs->vs_if.if_baudrate = 80 * 1024 * 1024;
  260.     } else {
  261.         vs->vs_if.if_type = IFT_P10;
  262.         vs->vs_if.if_baudrate = 10 * 1024 * 1024;
  263.     }
  264.     vs->vs_host = NOHOST;
  265.  
  266. #if defined(VAX750)
  267.     /* don't chew up 750 bdp's */
  268.     if (cpu == VAX_750 && ui->ui_unit > 0)
  269.         vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
  270. #endif
  271.     if_attach(&vs->vs_if);
  272. }
  273.  
  274. /*
  275.  * Reset of interface after UNIBUS reset.
  276.  * If interface is on specified uba, reset its state.
  277.  */
  278. vvreset(unit, uban)
  279.     int unit, uban;
  280. {
  281.     register struct uba_device *ui;
  282.  
  283.     if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
  284.         ui->ui_ubanum != uban)
  285.         return;
  286.     printf(" vv%d", unit);
  287.     vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING;
  288.     vv_softc[unit].vs_flags &= ~VS_RUNNING;
  289.     vvinit(unit, 0);
  290. }
  291.  
  292. /*
  293.  * Initialization of interface; clear recorded pending
  294.  * operations, and reinitialize UNIBUS usage.
  295.  */
  296. vvinit(unit, cansleep)
  297.     int unit, cansleep;
  298. {
  299.     register struct vv_softc *vs;
  300.     register struct uba_device *ui;
  301.     register struct vvreg *addr;
  302.     register int ubaaddr, s;
  303.  
  304.     vs = &vv_softc[unit];
  305.     ui = vvinfo[unit];
  306.  
  307.     if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
  308.         return;
  309.  
  310.     /*
  311.      * Prevent multiple instances of vvinit
  312.      * from trying simultaneously.
  313.      */
  314.     while (vs->vs_flags & VS_INIT) {
  315.         if (cansleep)
  316.             sleep((caddr_t)vs, PZERO);
  317.         else
  318.             return;
  319.     }
  320.     if (vs->vs_flags & VS_RUNNING)
  321.         return;
  322.     vs->vs_flags = VS_INIT;
  323.  
  324.     addr = (struct vvreg *)ui->ui_addr;
  325.     if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 &&
  326.         if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
  327.           sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) {
  328.         printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
  329.         vs->vs_if.if_flags &= ~IFF_UP;
  330.         vs->vs_flags = 0;
  331.         return;
  332.     }
  333.     vs->vs_if.if_flags |= IFF_RUNNING;
  334.  
  335.     /*
  336.      * Now that the uba is set up, figure out our address and
  337.      * update complete our host address.
  338.      */
  339.     if (cansleep)
  340.         vs->vs_host = vvidentify(unit);
  341.     if (vs->vs_host == NOHOST) {
  342.         vs->vs_if.if_flags &= ~IFF_UP;
  343.         vs->vs_flags = 0;
  344.         return;
  345.     }
  346.     vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host);
  347.  
  348.     /*
  349.      * Reset the interface, and stay in the ring
  350.      */
  351.     addr->vvocsr = VV_RST;            /* take over output */
  352.     addr->vvocsr = VV_CPB;            /* clear packet buffer */
  353.     addr->vvicsr = VV_RST | VV_HEN;        /* take over input, */
  354.                         /* keep relay closed */
  355.     if (cansleep) {
  356.         timeout(wakeup, (caddr_t)vs, hz/2);
  357.         sleep((caddr_t)vs, PZERO);    /* let contacts settle */
  358.     } else
  359.         DELAY(500000);            /* let contacts settle */
  360.  
  361.     vs->vs_init = 0;            /* clear counters, etc. */
  362.     vs->vs_refused = 0;
  363.     vs->vs_timeouts = 0;
  364.     vs->vs_otimeout = 0;
  365.     vs->vs_ibadf = 0;
  366.     vs->vs_parity = 0;
  367.     vs->vs_lastx = 256;            /* an invalid address */
  368.     vs->vs_lastr = 256;            /* an invalid address */
  369.  
  370.     /*
  371.      * Hang a receive and start any
  372.      * pending writes by faking a transmit complete.
  373.      */
  374.     s = splimp();
  375.     ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
  376.     addr->vviba = (u_short)ubaaddr;
  377.     addr->vviea = (u_short)(ubaaddr >> 16);
  378.     addr->vviwc = -(VVBUFSIZE) >> 1;
  379.     addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
  380.     vs->vs_oactive = 1;
  381.     vs->vs_if.if_flags |= IFF_UP;
  382.     vs->vs_flags = VS_RUNNING;        /* clear VS_INIT */
  383.     wakeup((caddr_t)vs);
  384.     vvxint(unit);
  385.     splx(s);
  386. }
  387.  
  388. /*
  389.  * Do a moderately thorough self-test in all three modes. Mostly
  390.  * to keeps defective nodes off the ring, rather than to be especially
  391.  * thorough. The key issue is to detect any cable breaks before joining
  392.  * the ring. Return our node address on success, return -1 on failure.
  393.  *
  394.  */
  395.  
  396. /* the three self-test modes */
  397. static u_short vv_modes[] = {
  398.     VV_STE|VV_LPB,            /* digital loopback */
  399.     VV_STE,                /* analog loopback */
  400.     VV_HEN                /* network mode */
  401. };
  402.  
  403. vvidentify(unit)
  404.     int unit;
  405. {
  406.     register struct vv_softc *vs;
  407.     register struct uba_device *ui;
  408.     register struct vvreg *addr;
  409.     register struct mbuf *m;
  410.     register struct vv_header *v;
  411.     register int ubaaddr;
  412.     register int i, successes, failures, waitcount;
  413.     u_short shost = NOHOST;
  414.  
  415.     vs = &vv_softc[unit];
  416.     ui = vvinfo[unit];
  417.     addr = (struct vvreg *)ui->ui_addr;
  418.  
  419.     /*
  420.      * Build a multicast message to identify our address
  421.      * We need do this only once, since nobody else is about to use
  422.      * the intermediate transmit buffer (ifu_w.ifrw_addr) that
  423.      * if_ubainit() aquired for us.
  424.      */
  425.     MGETHDR(m, M_DONTWAIT, MT_HEADER);
  426.     if (m == NULL) {
  427.         printf("vv%d: can't initialize, m_get() failed\n", unit);
  428.         return (NOHOST);
  429.     }
  430.     m->m_pkthdr.len = m->m_len = sizeof(struct vv_header);
  431.     v = mtod(m, struct vv_header *);
  432.     v->vh_dhost = VV_BROADCAST;    /* multicast destination address */
  433.     v->vh_shost = 0;        /* will be overwritten with ours */
  434.     v->vh_version = RING_VERSION;
  435.     v->vh_type = RING_DIAGNOSTICS;
  436.     v->vh_info = 0;
  437.     /* map xmit message into uba, copying to intermediate buffer */
  438.     vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
  439.  
  440.     /*
  441.      * For each of the modes (digital, analog, network), go through
  442.      * a self-test that requires me to send VVIDENTSUCC good packets
  443.      * in VVIDENTRETRY attempts. Use broadcast destination to find out
  444.      * who I am, then use this as my address to check my address match
  445.      * logic. Only data checked is the vh_type field.
  446.      */
  447.  
  448.     for (i = 0; i < 3; i++) {
  449.         successes = 0;    /* clear successes for this mode */
  450.         failures = 0;    /* and clear failures, too */
  451.  
  452.         /* take over device, and leave ring */
  453.         addr->vvicsr = VV_RST;
  454.         addr->vvocsr = VV_RST;
  455.         addr->vvicsr = vv_modes[i];    /* test mode */
  456.  
  457.         /*
  458.          * let the flag and token timers pop so that the init ring bit
  459.          * will be allowed to work, by waiting about 1 second
  460.          */
  461.         timeout(wakeup, (caddr_t)vs, hz);
  462.         sleep((caddr_t)vs, PZERO);
  463.  
  464.         /*
  465.          * retry loop
  466.           */
  467.         while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
  468.         {
  469.             /* start a receive */
  470.             ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
  471.             addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
  472.             addr->vviba = (u_short) ubaaddr;
  473.             addr->vviea = (u_short) (ubaaddr >> 16);
  474.             addr->vviwc = -(VVBUFSIZE) >> 1;
  475.             addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
  476.  
  477. #ifdef notdef
  478.             /* purge stale data from BDP */
  479.             if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
  480.                 UBAPURGE(vs->vs_ifuba.ifu_uba,
  481.                     vs->vs_ifuba.ifu_w.ifrw_bdp);
  482. #endif
  483.  
  484.             /* do a transmit */
  485.             ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
  486.             addr->vvocsr = VV_RST;    /* abort last try */
  487.             addr->vvoba = (u_short) ubaaddr;
  488.             addr->vvoea = (u_short) (ubaaddr >> 16);
  489.             addr->vvowc = -((vs->vs_olen + 1) >> 1);
  490.             addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
  491.  
  492.             /* poll receive side for completion */
  493.             DELAY(10000);        /* give it a chance */
  494.             for (waitcount = 0; waitcount < 10; waitcount++) {
  495.                 if (addr->vvicsr & VV_RDY)
  496.                     goto gotit;
  497.                 DELAY(1000);
  498.             }
  499.             failures++;        /* no luck */
  500.             continue;
  501.  
  502. gotit:            /* we got something--is it any good? */
  503.             if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
  504.                 (addr->vvocsr & (VVXERR|VV_RFS))) {
  505.                 failures++;
  506.                 continue;
  507.             }
  508.  
  509.             /* Purge BDP before looking at received packet */
  510.             if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
  511.                 UBAPURGE(vs->vs_ifuba.ifu_uba,
  512.                     vs->vs_ifuba.ifu_r.ifrw_bdp);
  513. #ifdef notdef
  514.             m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
  515.                 0, &vs->vs_if);
  516.             if (m != NULL)
  517.                 m_freem(m);
  518. #endif
  519.             
  520.             v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
  521.  
  522.             /* check message type, catch our node address */
  523.             if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
  524.                 if (shost == NOHOST) {
  525.                     shost = v->vh_shost & 0xff;
  526.                     /* send to ourself now */
  527.                     ((struct vv_header *)
  528.                         (vs->vs_ifuba.ifu_r.ifrw_addr))
  529.                         ->vh_dhost = shost;
  530.                 }
  531.                 successes++;
  532.             } else {
  533.                 failures++;
  534.             }
  535.             v->vh_type = 0;  /* clear to check again */
  536.         }
  537.  
  538.         if (failures >= VVIDENTRETRY)
  539.         {
  540.             printf("vv%d: failed self-test after %d tries \
  541. in %s mode\n",
  542.                 unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
  543.                 (i == 1 ? "analog loopback" : "network"));
  544.             printf("vv%d: icsr = %b, ocsr = %b\n",
  545.                 unit, 0xffff & addr->vvicsr, VV_IBITS,
  546.                 0xffff & addr->vvocsr, VV_OBITS);
  547.             addr->vvicsr = VV_RST;    /* kill the sick board */
  548.             addr->vvocsr = VV_RST;
  549.             shost = NOHOST;
  550.             goto done;
  551.         }
  552.     }
  553.  
  554. done:
  555.     /* deallocate mbuf used for send packet (won't be one, anyways) */
  556.     if (vs->vs_ifuba.ifu_xtofree) {
  557.         m_freem(vs->vs_ifuba.ifu_xtofree);
  558.         vs->vs_ifuba.ifu_xtofree = 0;
  559.     }
  560.  
  561.     return(shost);
  562. }
  563.  
  564. /*
  565.  * Start or restart output on interface.
  566.  * If interface is active, this is a retransmit, so just
  567.  * restuff registers and go.
  568.  * If interface is not already active, get another datagram
  569.  * to send off of the interface queue, and map it to the interface
  570.  * before starting the output.
  571.  */
  572. vvstart(dev)
  573.     dev_t dev;
  574. {
  575.     register struct uba_device *ui;
  576.     register struct vv_softc *vs;
  577.     register struct vvreg *addr;
  578.     register struct mbuf *m;
  579.     register int unit, ubaaddr, dest, s;
  580.  
  581.     unit = VVUNIT(dev);
  582.     ui = vvinfo[unit];
  583.     vs = &vv_softc[unit];
  584.     if (vs->vs_oactive)
  585.         goto restart;
  586.     /*
  587.      * Not already active: dequeue another request
  588.      * and map it to the UNIBUS.  If no more requests,
  589.      * just return.
  590.      */
  591.     s = splimp();
  592.     IF_DEQUEUE(&vs->vs_if.if_snd, m);
  593.     splx(s);
  594.     if (m == NULL) {
  595.         vs->vs_oactive = 0;
  596.         return;
  597.     }
  598.     dest = mtod(m, struct vv_header *)->vh_dhost;
  599.     vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
  600.     vs->vs_lastx = dest;
  601.     vs->vs_if.if_obytes += vs->vs_olen;
  602.     vs->vs_if.if_lastchange = time;
  603. restart:
  604.     /*
  605.      * Have request mapped to UNIBUS for transmission.
  606.      * Purge any stale data from this BDP, and start the output.
  607.      *
  608.      * Make sure this packet will fit in the interface.
  609.      */
  610.     if (vs->vs_olen > VVBUFSIZE) {
  611.         printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
  612.         panic("vvdriver vs_olen botch");
  613.     }
  614.  
  615.     vs->vs_if.if_timer = VVTIMEOUT;
  616.     vs->vs_oactive = 1;
  617.  
  618.     /* ship it */
  619. #ifdef notdef
  620.     if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
  621.         UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
  622. #endif
  623.     addr = (struct vvreg *)ui->ui_addr;
  624.     ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);
  625.     addr->vvoba = (u_short) ubaaddr;
  626.     addr->vvoea = (u_short) (ubaaddr >> 16);
  627.     addr->vvowc = -((vs->vs_olen + 1) >> 1);
  628.     addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
  629.     if (addr->vvocsr & VV_NOK)
  630.         vs->vs_init++;            /* count ring inits */
  631.     addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
  632. }
  633.  
  634. /*
  635.  * proNET transmit interrupt
  636.  * Start another output if more data to send.
  637.  */
  638. vvxint(unit)
  639.     int unit;
  640. {
  641.     register struct uba_device *ui;
  642.     register struct vv_softc *vs;
  643.     register struct vvreg *addr;
  644.     register int oc;
  645.  
  646.     ui = vvinfo[unit];
  647.     vs = &vv_softc[unit];
  648. #ifdef QBA
  649.     splx(vs->vs_ipl);
  650. #endif
  651.     vs->vs_if.if_timer = 0;
  652.     addr = (struct vvreg *)ui->ui_addr;
  653.     oc = 0xffff & (addr->vvocsr);
  654.     if (vs->vs_oactive == 0) {
  655.         vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit,
  656.             oc, VV_OBITS);
  657.         return;
  658.     }
  659.  
  660.     /*
  661.      * we retransmit on soft error
  662.      * TODO: sort retransmits to end of queue if possible!
  663.      */
  664.     if (oc & (VV_OPT | VV_RFS)) {
  665.         if (vs->vs_tries++ < VVRETRY) {
  666.             if (oc & VV_OPT)
  667.                 vs->vs_otimeout++;
  668.             if (oc & VV_RFS) {
  669.                 vs->vs_if.if_collisions++;
  670.                 vs->vs_refused++;
  671.             }
  672.             vvstart(unit);        /* restart this message */
  673.             return;
  674.         }
  675.     }
  676.     vs->vs_if.if_opackets++;
  677.     vs->vs_oactive = 0;
  678.     vs->vs_tries = 0;
  679.  
  680.     if (oc & VVXERR) {
  681.         vs->vs_if.if_obytes -= vs->vs_olen;
  682.         vs->vs_if.if_oerrors++;
  683.         vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n",
  684.             unit, 0xffff & oc, VV_OBITS);
  685.     }
  686.     if (vs->vs_ifuba.ifu_xtofree) {
  687.         m_freem(vs->vs_ifuba.ifu_xtofree);
  688.         vs->vs_ifuba.ifu_xtofree = 0;
  689.     }
  690.     vvstart(unit);
  691. }
  692.  
  693. /*
  694.  * Transmit watchdog timer routine.
  695.  * This routine gets called when we lose a transmit interrupt.
  696.  * The best we can do is try to restart output.
  697.  */
  698. vvwatchdog(unit)
  699.     int unit;
  700. {
  701.     register struct vv_softc *vs;
  702.  
  703.     vs = &vv_softc[unit];
  704.     log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit);
  705.     vs->vs_timeouts++;
  706.     vvstart(unit);
  707. }
  708.  
  709. /*
  710.  * proNET interface receiver interrupt.
  711.  * If input error just drop packet.
  712.  * Otherwise purge input buffered data path and examine
  713.  * packet to determine type.  If can't determine length
  714.  * from type, then have to drop packet.  Otherwise decapsulate
  715.  * packet based on type and pass to type specific higher-level
  716.  * input routine.
  717.  */
  718. vvrint(unit)
  719.     int unit;
  720. {
  721.     register struct vv_softc *vs;
  722.     register struct vvreg *addr;
  723.     register struct vv_header *vv;
  724.     register struct ifqueue *inq;
  725.     register struct mbuf *m;
  726.     int ubaaddr, len, off, s;
  727.     short resid;
  728.  
  729.     vs = &vv_softc[unit];
  730. #ifdef QBA
  731.     splx(vs->vs_ipl);
  732. #endif
  733.     vs->vs_if.if_ipackets++;
  734.     vs->vs_if.if_lastchange = time;
  735.     addr = (struct vvreg *)vvinfo[unit]->ui_addr;
  736.  
  737.     /*
  738.      * Purge BDP
  739.      */
  740.     if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
  741.         UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
  742.  
  743.     /*
  744.      * receive errors?
  745.      */
  746.     if (addr->vvicsr & VVRERR) {
  747.         vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit,
  748.             0xffff&(addr->vvicsr), VV_IBITS);
  749.         if (addr->vvicsr & VV_BDF)
  750.             vs->vs_ibadf++;
  751.         goto dropit;
  752.     }
  753.  
  754.     /*
  755.      * parity errors?
  756.      */
  757.     if (addr->vvicsr & VV_LDE) {
  758.         /* we don't have to clear it because the receive command */
  759.         /* writes 0 to parity bit */
  760.         vs->vs_parity++;
  761.  
  762.         /*
  763.          * only on 10 megabit proNET is VV_LDE an end-to-end parity
  764.          * bit. On 80 megabit, it returns to the intended use of
  765.          * node-to-node parity. End-to-end parity errors on 80 megabit
  766.          * give VV_BDF.
  767.          */
  768.         if (vs->vs_is80 == 0)
  769.             goto dropit;
  770.     }
  771.  
  772.     /*
  773.      * Get packet length from residual word count
  774.      *
  775.      * Compute header offset if trailer protocol
  776.      *
  777.      * Pull packet off interface.  Off is nonzero if packet
  778.      * has trailing header; if_rubaget will then force this header
  779.      * information to be at the front.  The vh_info field
  780.      * carries the offset to the trailer data in trailer
  781.      * format packets.
  782.      */
  783.     vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
  784.     vvtracehdr("vi", vv);
  785.     resid = addr->vviwc & 01777;    /* only low 10 bits valid */
  786.     if (resid)
  787.         resid |= 0176000;    /* high 6 bits are undefined */
  788.     len = ((VVBUFSIZE >> 1) + resid) << 1;
  789.     len -= sizeof(struct vv_header);
  790.  
  791.     if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
  792.         vvlog(LOG_DEBUG, "vv%d: len too long or short, \
  793. len = %d, vvicsr = %b\n",
  794.                 unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
  795.         goto dropit;
  796.     }
  797.  
  798.     /* check the protocol header version */
  799.     if (vv->vh_version != RING_VERSION) {
  800.         vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n",
  801.             unit, vv->vh_version & 0xff);
  802.         goto dropit;
  803.     }
  804.  
  805. #define    vvdataaddr(vv, off, type)    ((type)(((caddr_t)((vv)+1)+(off))))
  806.     if (vv->vh_type == RING_TRAILER ) {
  807.         off = ntohs((u_short)vv->vh_info);
  808.         if (off > VVMTU) {
  809.             vvlog(LOG_DEBUG,
  810.                 "vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
  811.                 unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
  812.             goto dropit;
  813.         }
  814.         vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
  815.         resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
  816.         if (off + resid > len) {
  817.             vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n",
  818.                 unit);
  819.             vvlog(LOG_DEBUG,
  820.                 "vv%d: off = %d, resid = %d, vvicsr = %b\n",
  821.                 unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS);
  822.             goto dropit;
  823.         }
  824.         len = off + resid;
  825.     } else
  826.         off = 0;
  827.  
  828.     if (len == 0) {
  829.         vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit,
  830.                 0xffff&(addr->vvicsr), VV_IBITS);
  831.         goto dropit;
  832.     }
  833.  
  834.     m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
  835.     if (m == NULL) {
  836.         vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n",
  837.             unit, 0xffff&(addr->vvicsr), VV_IBITS);
  838.         goto dropit;
  839.     }
  840.     vs->vs_if.if_ibytes += m->m_pkthdr.len;
  841.     if (vv->vh_dhost == VV_BROADCAST) {
  842.         m->m_flags |= M_BCAST;
  843.         vs->vs_if.if_imcasts++;
  844.     }
  845.     /* Keep track of source address of this packet */
  846.     vs->vs_lastr = vv->vh_shost;
  847.  
  848.     /*
  849.      * Demultiplex on packet type
  850.      */
  851.     switch (vv->vh_type) {
  852.  
  853. #ifdef INET
  854.     case RING_IP:
  855.         schednetisr(NETISR_IP);
  856.         inq = &ipintrq;
  857.         break;
  858. #endif
  859.     default:
  860.         vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n",
  861.             unit, vv->vh_type);
  862.         m_freem(m);
  863.         vs->vs_if.if_noproto++;
  864.         goto setup;
  865.     }
  866.     s = splimp();
  867.     if (IF_QFULL(inq)) {
  868.         IF_DROP(inq);
  869.         m_freem(m);
  870.         vs->vs_if.if_iqdrops++;
  871.     } else
  872.         IF_ENQUEUE(inq, m);
  873.     splx(s);
  874.     /*
  875.      * Reset for the next packet.
  876.      */
  877. setup:
  878.     ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);
  879.     addr->vviba = (u_short) ubaaddr;
  880.     addr->vviea = (u_short) (ubaaddr >> 16);
  881.     addr->vviwc = -(VVBUFSIZE) >> 1;
  882.     addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
  883.     return;
  884.  
  885.     /*
  886.      * Drop packet on floor -- count them!!
  887.      */
  888. dropit:
  889.     vs->vs_if.if_ierrors++;
  890.     goto setup;
  891. }
  892.  
  893. /*
  894.  * proNET output routine.
  895.  * Encapsulate a packet of type family for the local net.
  896.  * Use trailer local net encapsulation if enough data in first
  897.  * packet leaves a multiple of 512 bytes of data in remainder.
  898.  */
  899. vvoutput(ifp, m0, dst, rt)
  900.     struct ifnet *ifp;
  901.     struct mbuf *m0;
  902.     struct sockaddr *dst;
  903.     struct rtentry *rt;
  904. {
  905.     register struct mbuf *m;
  906.     register struct vv_header *vv;
  907.     register int off;
  908.     register int unit;
  909.     register struct vvreg *addr;
  910.     register struct vv_softc *vs;
  911.     register int s;
  912.     int type, dest, error;
  913.  
  914.     m = m0;
  915.     unit = ifp->if_unit;
  916.     if ((ifp->if_flags & IFF_UP) == 0)
  917.         return (ENETDOWN);
  918.     addr = (struct vvreg *)vvinfo[unit]->ui_addr;
  919.     vs = &vv_softc[unit];
  920.  
  921.     /*
  922.      * Check to see if the input side has wedged due the UBA
  923.      * vectoring through 0.
  924.      *
  925.      * We are lower than device ipl when we enter this routine,
  926.      * so if the interface is ready with an input packet then
  927.      * an input interrupt must have slipped through the cracks.
  928.      *
  929.      * Avoid the race with an input interrupt by watching to see
  930.      * if any packets come in.
  931.      */
  932.     s = vs->vs_if.if_ipackets;
  933.     if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
  934.         log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n",
  935.                 unit, 0xffff&(addr->vvicsr), VV_IBITS);
  936.         s = splimp();
  937.         vvrint(unit);
  938.         splx(s);
  939.     }
  940.  
  941.     switch (dst->sa_family) {
  942.  
  943. #ifdef INET
  944.     case AF_INET:
  945.         if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
  946.             dest = VV_BROADCAST;
  947.         else
  948.             dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
  949. #ifdef LOOPBACK
  950.         if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
  951.             return (looutput(&loif, m0, dst, rt));
  952. #endif LOOPBACK
  953.         if (dest >= 0x100) {
  954.             error = EPERM;
  955.             goto bad;
  956.         }
  957.         off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
  958.         /*
  959.          * Trailerize, if the configuration allows it.
  960.          * TODO: Need per host negotiation.
  961.          */
  962.         if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
  963.         if (off > 0 && (off & 0x1ff) == 0 &&
  964.             m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
  965.             type = RING_TRAILER;
  966.             m->m_data -= 2 * sizeof (u_short);
  967.             m->m_len += 2 * sizeof (u_short);
  968.             *mtod(m, u_short *) = htons((short)RING_IP);
  969.             *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
  970.             goto gottrailertype;
  971.         }
  972.         type = RING_IP;
  973.         off = 0;
  974.         goto gottype;
  975. #endif
  976.     default:
  977.         printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
  978.         error = EAFNOSUPPORT;
  979.         goto bad;
  980.     }
  981.  
  982. gottrailertype:
  983.     /*
  984.      * Packet to be sent as trailer: move first packet
  985.      * (control information) to end of chain.
  986.      */
  987.     while (m->m_next)
  988.         m = m->m_next;
  989.     m->m_next = m0;
  990.     m = m0->m_next;
  991.     m0->m_next = 0;
  992.     m0 = m;
  993. gottype:
  994.     /*
  995.      * Add local net header.  If no space in first mbuf,
  996.      * allocate another.
  997.      */
  998.     M_PREPEND(m, sizeof (struct vv_header), M_DONTWAIT);
  999.     if (m == 0) {
  1000.         error = ENOBUFS;
  1001.         goto bad;
  1002.     }
  1003.     vv = mtod(m, struct vv_header *);
  1004.     vv->vh_shost = vs->vs_host;
  1005.     vv->vh_dhost = dest;
  1006.     vv->vh_version = RING_VERSION;
  1007.     vv->vh_type = type;
  1008.     vv->vh_info = htons((u_short)off);
  1009.     vvtracehdr("vo", vv);
  1010.  
  1011.     /*
  1012.      * Queue message on interface, and start output if interface
  1013.      * not yet active.
  1014.      */
  1015.     s = splimp();
  1016.     if (IF_QFULL(&ifp->if_snd)) {
  1017.         IF_DROP(&ifp->if_snd);
  1018.         error = ENOBUFS;
  1019.         goto qfull;
  1020.     }
  1021.     IF_ENQUEUE(&ifp->if_snd, m);
  1022.     if (vs->vs_oactive == 0)
  1023.         vvstart(unit);
  1024.     splx(s);
  1025.     return (0);
  1026. qfull:
  1027.     m0 = m;
  1028.     splx(s);
  1029. bad:
  1030.     m_freem(m0);
  1031.     return(error);
  1032. }
  1033.  
  1034. /*
  1035.  * Process an ioctl request.
  1036.  */
  1037. vvioctl(ifp, cmd, data)
  1038.     register struct ifnet *ifp;
  1039.     int cmd;
  1040.     caddr_t data;
  1041. {
  1042.     register struct vv_softc *vs = &vv_softc[ifp->if_unit];
  1043.     struct ifaddr *ifa = (struct ifaddr *) data;
  1044.     struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]);
  1045.     int s = splimp(), error = 0;
  1046.  
  1047.     switch (cmd) {
  1048.  
  1049.     case SIOCSIFADDR:
  1050.         if ((vs->vs_flags & VS_RUNNING) == 0)
  1051.             vvinit(ifp->if_unit, 1);
  1052.         /*
  1053.          * Did self-test succeed?
  1054.          */
  1055.         if ((ifp->if_flags & IFF_UP) == 0)
  1056.             error = ENETDOWN;
  1057.         else {
  1058.             /*
  1059.              * Attempt to check agreement of protocol address
  1060.              * and board address.
  1061.              */
  1062.             switch (ifa->ifa_addr->sa_family) {
  1063.             case AF_INET:
  1064.                 if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) !=
  1065.                     vs->vs_host)
  1066.                     error = EADDRNOTAVAIL;
  1067.                 break;
  1068.             }
  1069.         }
  1070.         break;
  1071.  
  1072.     case SIOCSIFFLAGS:
  1073.         if ((ifp->if_flags & IFF_UP) == 0 &&
  1074.             vs->vs_flags & VS_RUNNING) {
  1075.             addr->vvicsr = VV_RST;
  1076.             addr->vvocsr = VV_RST;
  1077.             vs->vs_flags &= ~VS_RUNNING;
  1078.         } else if (ifp->if_flags & IFF_UP &&
  1079.             (vs->vs_flags & VS_RUNNING) == 0)
  1080.             vvinit(ifp->if_unit, 1);
  1081.         break;
  1082.  
  1083.     default:
  1084.         error = EINVAL;
  1085.         break;
  1086.     }
  1087.     splx(s);
  1088.     return (error);
  1089. }
  1090.  
  1091. /*
  1092.  * vvprt_hdr(s, v) print the local net header in "v"
  1093.  *    with title is "s"
  1094.  */
  1095. vvprt_hdr(s, v)
  1096.     char *s;
  1097.     register struct vv_header *v;
  1098. {
  1099.     printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
  1100.         s,
  1101.         0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
  1102.         0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
  1103.         0xffff & (int)(v->vh_info));
  1104. }
  1105. #endif NVV
  1106.