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

  1. /*
  2.  * Copyright (c) 1982, 1986 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Excelan Inc.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  *    @(#)if_ex.c    7.9 (Berkeley) 12/16/90
  37.  */
  38.  
  39. #include "ex.h"
  40. #if NEX > 0
  41.  
  42. /*
  43.  * Excelan EXOS 204 Interface
  44.  *
  45.  *    George Powers
  46.  *    Excelan Inc.
  47.  */
  48.  
  49. #include "sys/param.h"
  50. #include "sys/systm.h"
  51. #include "sys/mbuf.h"
  52. #include "sys/buf.h"
  53. #include "sys/protosw.h"
  54. #include "sys/socket.h"
  55. #include "sys/vmmac.h"
  56. #include "sys/ioctl.h"
  57. #include "sys/syslog.h"
  58. #include "sys/errno.h"
  59.  
  60. #include "net/if.h"
  61. #include "net/netisr.h"
  62. #include "net/route.h"
  63.  
  64. #ifdef    INET
  65. #include "netinet/in.h"
  66. #include "netinet/in_systm.h"
  67. #include "netinet/in_var.h"
  68. #include "netinet/ip.h"
  69. #include "netinet/if_ether.h"
  70. #endif
  71.  
  72. #ifdef NS
  73. #include "netns/ns.h"
  74. #include "netns/ns_if.h"
  75. #endif
  76.  
  77. #ifdef ISO
  78. #include "netiso/iso.h"
  79. #include "netiso/iso_var.h"
  80. extern char all_es_snpa[], all_is_snpa[];
  81. #endif
  82.  
  83. #include "../include/pte.h"
  84. #include "../include/cpu.h"
  85. #include "../include/mtpr.h"
  86. #include "if_exreg.h"
  87. #include "if_uba.h"
  88. #include "../uba/ubareg.h"
  89. #include "../uba/ubavar.h"
  90.  
  91. /* #define DEBUG            /* check for "impossible" events */
  92.  
  93. #define    NH2X 4            /* a sufficient number is critical */
  94. #define    NX2H 4            /* this is pretty arbitrary */
  95. #define    EXWATCHINTVL 10        /* call exwatch() every 10 seconds */
  96.  
  97. int    exprobe(), exattach(), excdint();
  98. struct    uba_device *exinfo[NEX];
  99. u_short exstd[] = { 0 };
  100. struct    uba_driver exdriver =
  101.     { exprobe, 0, exattach, 0, exstd, "ex", exinfo };
  102. int    exinit(),exstart(),ether_output(),exioctl(),exreset(),exwatch();
  103. struct ex_msg *exgetcbuf();
  104.  
  105. /*
  106.  * Ethernet software status per interface.
  107.  *
  108.  * Each interface is referenced by a network interface structure,
  109.  * xs_if, which the routing code uses to locate the interface.
  110.  * This structure contains the output queue for the interface, its address, ...
  111.  * We also have, for each interface, a UBA interface structure, which
  112.  * contains information about the UNIBUS resources held by the interface:
  113.  * map registers, buffered data paths, etc.  Information is cached in this
  114.  * structure for use by the if_uba.c routines in running the interface
  115.  * efficiently.
  116.  */
  117. struct    ex_softc {
  118.     struct    arpcom xs_ac;        /* Ethernet common part */
  119. #define    xs_if    xs_ac.ac_if        /* network-visible interface */
  120. #define    xs_addr    xs_ac.ac_enaddr        /* hardware Ethernet address */
  121. #ifdef DEBUG
  122.     int    xs_wait;
  123. #endif
  124.     struct    ifuba xs_ifuba;        /* UNIBUS resources */
  125.     int    xs_flags;        /* private flags */
  126. #define    EX_XPENDING    1        /* xmit rqst pending on EXOS */
  127. #define    EX_STATPENDING    (1<<1)        /* stats rqst pending on EXOS */
  128. #define    EX_RUNNING    (1<<2)        /* board is running */
  129. #define EX_SETADDR    (1<<3)        /* physaddr has been changed */
  130.     struct    ex_msg *xs_h2xnext;    /* host pointer to request queue */
  131.     struct    ex_msg *xs_x2hnext;    /* host pointer to reply queue */
  132.     int    xs_ubaddr;        /* map info for structs below */
  133. #define    UNIADDR(x)    ((u_long)(x)&0x3FFFF)
  134. #define    P_UNIADDR(x)    ((u_long)(x)&0x3FFF0)
  135.     /* the following structures are always mapped in */
  136.     u_short    xs_h2xhdr;        /* EXOS's request queue header */
  137.     u_short    xs_x2hhdr;        /* EXOS's reply queue header */
  138.     struct    ex_msg xs_h2xent[NH2X];    /* request msg buffers */
  139.     struct    ex_msg xs_x2hent[NX2H];    /* reply msg buffers */
  140.     struct    confmsg xs_cm;        /* configuration message */
  141.     struct    stat_array xs_xsa;    /* EXOS writes stats here */
  142.     /* end mapped area */
  143. #define    INCORE_BASE(p)    ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0))
  144. #define    RVAL_OFF(unit, n) \
  145.     ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit]))
  146. #define    LVAL_OFF(unit, n) \
  147.     ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit]))
  148. #define    H2XHDR_OFFSET(unit)    RVAL_OFF(unit, xs_h2xhdr)
  149. #define    X2HHDR_OFFSET(unit)    RVAL_OFF(unit, xs_x2hhdr)
  150. #define    H2XENT_OFFSET(unit)    LVAL_OFF(unit, xs_h2xent)
  151. #define    X2HENT_OFFSET(unit)    LVAL_OFF(unit, xs_x2hent)
  152. #define    CM_OFFSET(unit)        RVAL_OFF(unit, xs_cm)
  153. #define    SA_OFFSET(unit)        RVAL_OFF(unit, xs_xsa)
  154. #define    INCORE_SIZE(unit)    RVAL_OFF(unit, xs_end)
  155.     int    xs_end;            /* place holder */
  156. } ex_softc[NEX];
  157.  
  158. /*
  159.  * The following structure is a kludge to store a cvec value
  160.  * between the time exprobe is called, and exconfig.
  161.  */
  162. struct    ex_cvecs {
  163.     struct    exdevice *xc_csraddr;
  164.     int    xc_cvec;
  165. }ex_cvecs[NEX];
  166.  
  167. int    ex_ncall = 0;            /* counts calls to exprobe */
  168.  
  169. exprobe(reg)
  170.     caddr_t reg;
  171. {
  172.     register int br, cvec;        /* r11, r10 value-result */
  173.     register struct exdevice *addr = (struct exdevice *)reg;
  174.     register i;
  175.  
  176.     /*
  177.      * We program the EXOS interrupt vector, like dmf device.
  178.      */
  179.     br = 0x15;
  180.     cvec = (uba_hd[numuba].uh_lastiv -= 4);
  181.     ex_cvecs[ex_ncall].xc_csraddr = addr;
  182.     ex_cvecs[ex_ncall].xc_cvec = cvec;
  183.     /*
  184.      * Reset EXOS and run self-test (guaranteed to
  185.      * complete within 2 seconds).
  186.      */
  187.     addr->xd_porta = EX_RESET;
  188.     i = 2000;
  189.     while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
  190.         DELAY(1000);
  191.     if ((addr->xd_portb & EX_TESTOK) == 0) {
  192.         printf("ex: self-test failed\n");
  193.         return 0;
  194.     }
  195. #ifdef lint
  196.     br = br;
  197.     excdint(0);
  198. #endif
  199.     ex_ncall++;
  200.     return (sizeof(struct exdevice));
  201. }
  202.  
  203. /*
  204.  * Interface exists: make available by filling in network interface
  205.  * record.  System will initialize the interface when it is ready
  206.  * to accept packets.  Board is temporarily configured and issues
  207.  * a NET_ADDRS command, only to get the Ethernet address.
  208.  */
  209. exattach(ui)
  210.     register struct uba_device *ui;
  211. {
  212.     register struct ex_softc *xs = &ex_softc[ui->ui_unit];
  213.     register struct ifnet *ifp = &xs->xs_if;
  214.     register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
  215.     register struct ex_msg *bp;
  216.     int unit = ui->ui_unit;
  217.     ifp->if_unit = ui->ui_unit;
  218.     ifp->if_name = "ex";
  219.     ifp->if_mtu = ETHERMTU;
  220.  
  221.     /*
  222.      * Temporarily map queues in order to configure EXOS
  223.      */
  224.     xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
  225.         INCORE_SIZE(unit), 0);
  226.     exconfig(ui, 0);            /* without interrupts */
  227.     if (xs->xs_cm.cm_cc) goto badconf;
  228.  
  229.     bp = exgetcbuf(xs);
  230.     bp->mb_rqst = LLNET_ADDRS;
  231.     bp->mb_na.na_mask = READ_OBJ;
  232.     bp->mb_na.na_slot = PHYSSLOT;
  233.     bp->mb_status |= MH_EXOS;
  234.     addr->xd_portb = EX_NTRUPT;
  235.     bp = xs->xs_x2hnext;
  236.     while ((bp->mb_status & MH_OWNER) == MH_EXOS)    /* poll for reply */
  237.         ;
  238.     printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n",
  239.         ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
  240.         xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
  241.         ether_sprintf(bp->mb_na.na_addrs));
  242.     bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
  243.         sizeof (xs->xs_addr));
  244.  
  245.     ifp->if_init = exinit;
  246.     ifp->if_output = ether_output;
  247.     ifp->if_start = exstart;
  248.     ifp->if_ioctl = exioctl;
  249.     ifp->if_reset = exreset;
  250.     ifp->if_flags = IFF_BROADCAST;
  251.     xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
  252.     if_attach(ifp);
  253. badconf:
  254.     ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
  255. }
  256.  
  257. /*
  258.  * Reset of interface after UNIBUS reset.
  259.  * If interface is on specified uba, reset its state.
  260.  */
  261. exreset(unit, uban)
  262.     int unit, uban;
  263. {
  264.     register struct uba_device *ui;
  265.  
  266.     if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
  267.         ui->ui_ubanum != uban)
  268.         return;
  269.     printf(" ex%d", unit);
  270.     ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
  271.     ex_softc[unit].xs_flags &= ~EX_RUNNING;
  272.     exinit(unit);
  273. }
  274.  
  275. /*
  276.  * Initialization of interface; clear recorded pending
  277.  * operations, and reinitialize UNIBUS usage.
  278.  * Called at boot time (with interrupts disabled?),
  279.  * and at ifconfig time via exioctl, with interrupts disabled.
  280.  */
  281. exinit(unit)
  282.     int unit;
  283. {
  284.     register struct ex_softc *xs = &ex_softc[unit];
  285.     register struct uba_device *ui = exinfo[unit];
  286.     register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
  287.     register struct ifnet *ifp = &xs->xs_if;
  288.     register struct ex_msg *bp;
  289.     int s;
  290.  
  291.     /* not yet, if address still unknown */
  292.     if (ifp->if_addrlist == (struct ifaddr *)0)
  293.         return;
  294.     if (xs->xs_flags & EX_RUNNING)
  295.         return;
  296.  
  297.     if ((ifp->if_flags & IFF_RUNNING) == 0) {
  298.         if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
  299.             sizeof (struct ether_header),
  300.             (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) { 
  301.             printf("ex%d: can't initialize\n", unit);
  302.             xs->xs_if.if_flags &= ~IFF_UP;
  303.             return;
  304.         }
  305.         xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs),
  306.             INCORE_SIZE(unit), 0);
  307.     }
  308.     exconfig(ui, 4);        /* with vectored interrupts*/
  309.     /*
  310.      * Put EXOS on the Ethernet, using NET_MODE command
  311.      */
  312.     bp = exgetcbuf(xs);
  313.     bp->mb_rqst = LLNET_MODE;
  314.     bp->mb_nm.nm_mask = WRITE_OBJ;
  315.     bp->mb_nm.nm_optn = 0;
  316.     bp->mb_nm.nm_mode = MODE_PERF;
  317.     bp->mb_status |= MH_EXOS;
  318.     addr->xd_portb = EX_NTRUPT;
  319.     bp = xs->xs_x2hnext;
  320.     while ((bp->mb_status & MH_OWNER) == MH_EXOS)    /* poll for reply */
  321.         ;
  322.     bp->mb_length = MBDATALEN;
  323.     bp->mb_status |= MH_EXOS;        /* free up buffer */
  324.     addr->xd_portb = EX_NTRUPT;        /* tell EXOS about it */
  325.     xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
  326.  
  327.     ifp->if_watchdog = exwatch;
  328.     ifp->if_timer = EXWATCHINTVL;
  329.     s = splimp();    /* are interrupts always disabled here, anyway? */
  330.     exhangrcv(unit);            /* hang receive request */
  331.     xs->xs_if.if_flags |= IFF_RUNNING;
  332.     xs->xs_flags |= EX_RUNNING;
  333.     if (xs->xs_flags & EX_SETADDR)
  334.         ex_setaddr((u_char *)0, unit);
  335. #ifdef ISO
  336.     ex_setmulti(all_es_snpa, unit, 1);
  337.     ex_setmulti(all_is_snpa, unit, 2);
  338. #endif
  339.     (void) exstart(&xs->xs_if);            /* start transmits */
  340.     splx(s);
  341. }
  342.  
  343. /*
  344.  * Reset, test, and configure EXOS.  This routine assumes
  345.  * that message queues, etc. have already been mapped into
  346.  * the UBA.  It is called by exinit, and should also be
  347.  * callable by exattach.
  348.  */
  349. exconfig(ui, itype)
  350.     struct    uba_device *ui;
  351.     int itype;
  352. {
  353.     register int unit = ui->ui_unit;
  354.     register struct ex_softc *xs = &ex_softc[unit];
  355.     register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
  356.     register struct confmsg *cm = &xs->xs_cm;
  357.     register struct ex_msg *bp;
  358.     int i;
  359.     u_long shiftreg;
  360.  
  361.     xs->xs_flags = 0;
  362.     /*
  363.      * Reset EXOS, wait for self-test to complete
  364.      */
  365.     addr->xd_porta = EX_RESET;
  366.     while ((addr->xd_portb & EX_TESTOK) == 0)
  367.         ;
  368.     /*
  369.      * Set up configuration message.
  370.      */
  371.     cm->cm_1rsrv = 1;
  372.     cm->cm_cc = 0xFF;
  373.     cm->cm_opmode = 0;        /* link-level controller mode */
  374.     cm->cm_dfo = 0x0101;        /* enable host data order conversion */
  375.     cm->cm_dcn1 = 1;
  376.     cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
  377.     cm->cm_ham = 3;            /* absolute address mode */
  378.     cm->cm_3rsrv = 0;
  379.     cm->cm_mapsiz = 0;
  380.     cm->cm_byteptrn[0] = 0x01;    /* EXOS deduces data order of host */
  381.     cm->cm_byteptrn[1] = 0x03;    /*  by looking at this pattern */
  382.     cm->cm_byteptrn[2] = 0x07;
  383.     cm->cm_byteptrn[3] = 0x0F;
  384.     cm->cm_wordptrn[0] = 0x0103;
  385.     cm->cm_wordptrn[1] = 0x070F;
  386.     cm->cm_lwordptrn = 0x0103070F;
  387.     for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
  388.     cm->cm_mba = 0xFFFFFFFF;
  389.     cm->cm_nproc = 0xFF;
  390.     cm->cm_nmbox = 0xFF;
  391.     cm->cm_nmcast = 0xFF;
  392.     cm->cm_nhost = 1;
  393.     cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
  394.     cm->cm_h2xhdr = H2XHDR_OFFSET(unit);
  395.     cm->cm_h2xtyp = 0;        /* should never wait for rqst buffer */
  396.     cm->cm_x2hba = cm->cm_h2xba;
  397.     cm->cm_x2hhdr = X2HHDR_OFFSET(unit);
  398.     cm->cm_x2htyp = itype;        /* 0 for none, 4 for vectored */
  399.     for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
  400. #ifdef DEBUG
  401.     if (i >= NEX)
  402.         panic("ex: matching csr address not found");
  403. #endif
  404.         ;
  405.     cm->cm_x2haddr = ex_cvecs[i].xc_cvec;    /* stashed here by exprobe */
  406.     /*
  407.      * Set up message queues and headers.
  408.      * First the request queue.
  409.      */
  410.     for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
  411.         bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
  412.         bp->mb_rsrv = 0;
  413.         bp->mb_length = MBDATALEN;
  414.         bp->mb_status = MH_HOST;
  415.         bp->mb_next = bp+1;
  416.     }
  417.     xs->xs_h2xhdr =
  418.         xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET(unit);
  419.     xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
  420.  
  421.     /* Now the reply queue. */
  422.     for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
  423.         bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
  424.         bp->mb_rsrv = 0;
  425.         bp->mb_length = MBDATALEN;
  426.         bp->mb_status = MH_EXOS;
  427.         bp->mb_next = bp+1;
  428.     }
  429.     xs->xs_x2hhdr =
  430.         xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET(unit);
  431.     xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
  432.  
  433.     /*
  434.      * Write config msg address to EXOS and wait for
  435.      * configuration to complete (guaranteed response
  436.      * within 2 seconds).
  437.      */
  438.     shiftreg = (u_long)0x0000FFFF;
  439.     for (i = 0; i < 8; i++) {
  440.         if (i == 4)
  441.             shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit);
  442.         while (addr->xd_portb & EX_UNREADY)
  443.             ;
  444.         addr->xd_portb = (u_char)(shiftreg & 0xFF);
  445.         shiftreg >>= 8;
  446.     }
  447.     for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
  448.     if (cm->cm_cc)
  449.         printf("ex%d: configuration failed; cc = %x\n",
  450.             unit, cm->cm_cc);
  451. }
  452.  
  453. /*
  454.  * Start or re-start output on interface.
  455.  * Get another datagram to send off of the interface queue,
  456.  * and map it to the interface before starting the output.
  457.  * This routine is called by exinit(), ether_output(), and excdint().
  458.  * In all cases, interrupts by EXOS are disabled.
  459.  */
  460. exstart(ifp)
  461. struct ifnet *ifp;
  462. {
  463.     int unit = ifp->if_unit;
  464.     struct uba_device *ui = exinfo[unit];
  465.     register struct ex_softc *xs = &ex_softc[unit];
  466.     register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
  467.     register struct ex_msg *bp;
  468.     struct mbuf *m;
  469.         int len;
  470.  
  471. #ifdef DEBUG
  472.     if (xs->xs_if.if_flags & IFF_OACTIVE)
  473.         panic("exstart(): xmit still pending");
  474. #endif
  475.     IF_DEQUEUE(&xs->xs_if.if_snd, m);
  476.     if (m == 0)
  477.         return (0);
  478.     len = if_wubaput(&xs->xs_ifuba, m);
  479.     if (len - sizeof(struct ether_header) < ETHERMIN)
  480.         len = ETHERMIN + sizeof(struct ether_header);
  481.     /*
  482.      * Place a transmit request.
  483.      */
  484.     bp = exgetcbuf(xs);
  485.     bp->mb_rqst = LLRTRANSMIT;
  486.     bp->mb_et.et_nblock = 1;
  487.     bp->mb_et.et_blks[0].bb_len = (u_short)len;
  488.     *(u_long *)bp->mb_et.et_blks[0].bb_addr =
  489.         UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
  490.     xs->xs_if.if_flags |= IFF_OACTIVE;
  491.     bp->mb_status |= MH_EXOS;
  492.     addr->xd_portb = EX_NTRUPT;
  493.     return (0);
  494. }
  495.  
  496. /*
  497.  * Command done interrupt.
  498.  */
  499. excdint(unit)
  500.     int unit;
  501. {
  502.     register struct ex_softc *xs = &ex_softc[unit];
  503.     register struct ex_msg *bp = xs->xs_x2hnext;
  504.     struct uba_device *ui = exinfo[unit];
  505.     struct exdevice *addr = (struct exdevice *)ui->ui_addr;
  506.  
  507.     while ((bp->mb_status & MH_OWNER) == MH_HOST) {
  508.         switch (bp->mb_rqst) {
  509.         case LLRECEIVE:
  510.             exrecv(unit, bp);
  511.             exhangrcv(unit);
  512.             break;
  513.         case LLRTRANSMIT:
  514. #ifdef DEBUG
  515.             if ((xs->xs_if.if_flags & IFF_OACTIVE) == 0)
  516.                 panic("exxmit: no xmit pending");
  517. #endif
  518.             xs->xs_if.if_flags &= ~IFF_OACTIVE;
  519.             xs->xs_if.if_opackets++;
  520.             if (bp->mb_rply == LL_OK) {
  521.                 ;
  522.             } else if (bp->mb_rply & LLXM_1RTRY) {
  523.                 xs->xs_if.if_collisions++;
  524.             } else if (bp->mb_rply & LLXM_RTRYS) {
  525.                 xs->xs_if.if_collisions += 2;    /* guess */
  526.             } else if (bp->mb_rply & LLXM_ERROR) {
  527.                 xs->xs_if.if_oerrors++;
  528.                 log(LOG_ERR, "ex%d: transmit error=%b\n",
  529.                     unit, bp->mb_rply, XMIT_BITS);
  530.             }
  531.             if (xs->xs_ifuba.ifu_xtofree) {
  532.                 m_freem(xs->xs_ifuba.ifu_xtofree);
  533.                 xs->xs_ifuba.ifu_xtofree = 0;
  534.             }
  535.             (void) exstart(&xs->xs_if);
  536.             break;
  537.         case LLNET_STSTCS:
  538.             xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
  539.             xs->xs_flags &= ~EX_STATPENDING;
  540.             break;
  541.         case LLNET_ADDRS:
  542.         case LLNET_RECV:
  543.             break;
  544. #ifdef    DEBUG
  545.         default:
  546.             panic("ex%d: unknown reply");
  547. #endif
  548.         } /* end of switch */
  549.         bp->mb_length = MBDATALEN;
  550.         bp->mb_status |= MH_EXOS;        /* free up buffer */
  551.         addr->xd_portb = EX_NTRUPT;        /* tell EXOS about it */
  552.         bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
  553.     }
  554. }
  555.  
  556. /*
  557.  * Get a request buffer, fill in standard values, advance pointer.
  558.  */
  559. struct ex_msg *
  560. exgetcbuf(xs)
  561.     struct ex_softc *xs;
  562. {
  563.     register struct ex_msg *bp = xs->xs_h2xnext;
  564.  
  565. #ifdef DEBUG
  566.     if ((bp->mb_status & MH_OWNER) == MH_EXOS)
  567.         panic("exgetcbuf(): EXOS owns message buffer");
  568. #endif
  569.     bp->mb_1rsrv = 0;
  570.     bp->mb_length = MBDATALEN;
  571.     xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
  572.     return bp;
  573. }
  574.  
  575. /*
  576.  * Process Ethernet receive completion:
  577.  *    If input error just drop packet.
  578.  *    Otherwise purge input buffered data path and examine 
  579.  *    packet to determine type.  If can't determine length
  580.  *    from type, then have to drop packet.  Otherwise decapsulate
  581.  *    packet based on type and pass to type-specific higher-level
  582.  *    input routine.
  583.  */
  584. exrecv(unit, bp)
  585.     int unit;
  586.     register struct ex_msg *bp;
  587. {
  588.     register struct ex_softc *xs = &ex_softc[unit];
  589.     register struct ether_header *eh;
  590.         struct mbuf *m;
  591.     register int len, off, resid;
  592.     register struct ifqueue *inq;
  593.     int s;
  594.  
  595.     xs->xs_if.if_ipackets++;
  596.     len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
  597.     if (bp->mb_rply != LL_OK) {
  598.         xs->xs_if.if_ierrors++;
  599.         log(LOG_ERR, "ex%d: receive error=%b\n",
  600.             unit, bp->mb_rply, RECV_BITS);
  601.         return;
  602.     }
  603.     eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
  604.  
  605.     /*
  606.      * Deal with trailer protocol: if type is trailer
  607.      * get true type from first 16-bit word past data.
  608.      * Remember that type was trailer by setting off.
  609.      */
  610.     eh->ether_type = ntohs((u_short)eh->ether_type);
  611. #define    exdataaddr(eh, off, type)    ((type)(((caddr_t)((eh)+1)+(off))))
  612.     if (eh->ether_type >= ETHERTYPE_TRAIL &&
  613.         eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
  614.         off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
  615.         if (off >= ETHERMTU)
  616.             return;        /* sanity */
  617.         eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
  618.         resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
  619.         if (off + resid > len)
  620.             return;        /* sanity */
  621.         len = off + resid;
  622.     } else
  623.         off = 0;
  624.     if (len == 0)
  625.         return;
  626.  
  627.     /*
  628.      * Pull packet off interface.  Off is nonzero if packet
  629.      * has trailing header; if_rubaget will then force this header
  630.      * information to be at the front, but we still have to drop
  631.      * the type and length which are at the front of any trailer data.
  632.      */
  633.     m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if);
  634.     if (m == 0)
  635.         return;
  636.     ether_input(&xs->xs_if, eh, m);
  637. }
  638.  
  639. /*
  640.  * Send receive request to EXOS.
  641.  * This routine is called by exinit and excdint,
  642.  * with interrupts disabled in both cases.
  643.  */
  644. exhangrcv(unit)
  645.     int unit;
  646. {
  647.     register struct ex_softc *xs = &ex_softc[unit];
  648.     register struct ex_msg *bp = exgetcbuf(xs);
  649.     struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
  650.     
  651.     bp->mb_rqst = LLRECEIVE;
  652.     bp->mb_er.er_nblock = 1;
  653.     bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
  654.     *(u_long *)bp->mb_er.er_blks[0].bb_addr =
  655.         UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
  656.     bp->mb_status |= MH_EXOS;
  657.     addr->xd_portb = EX_NTRUPT;
  658. }
  659.  
  660. /*
  661.  * Watchdog routine - place stats request to EXOS
  662.  * (This could be dispensed with, if you don't care
  663.  *  about the if_ierrors count, or are willing to receive
  664.  *  bad packets in order to derive it.)
  665.  */
  666. exwatch(unit)
  667.     int unit;
  668. {
  669.     struct uba_device *ui = exinfo[unit];
  670.     struct exdevice *addr = (struct exdevice *)ui->ui_addr;
  671.     register struct ex_softc *xs = &ex_softc[unit];
  672.     register struct ex_msg *bp;
  673.     int s = splimp();
  674.  
  675.     if (xs->xs_flags & EX_STATPENDING) goto exspnd;
  676.     bp = exgetcbuf(xs);
  677.     xs->xs_flags |= EX_STATPENDING;
  678.     bp->mb_rqst = LLNET_STSTCS;
  679.     bp->mb_ns.ns_mask = READ_OBJ;
  680.     bp->mb_ns.ns_rsrv = 0;
  681.     bp->mb_ns.ns_nobj = 8;        /* read all 8 stats objects */
  682.     bp->mb_ns.ns_xobj = 0;        /* starting with the 1st one */
  683.     bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit);
  684.     bp->mb_status |= MH_EXOS;
  685.     addr->xd_portb = EX_NTRUPT;
  686. exspnd:
  687.     splx(s);
  688.     xs->xs_if.if_timer = EXWATCHINTVL;
  689. }
  690.  
  691. /*
  692.  * Process an ioctl request.
  693.  */
  694. exioctl(ifp, cmd, data)
  695.     register struct ifnet *ifp;
  696.     int cmd;
  697.     caddr_t data;
  698. {
  699.     register struct ifaddr *ifa = (struct ifaddr *)data;
  700.     register struct ex_softc *xs = &ex_softc[ifp->if_unit];
  701.     int s = splimp(), error = 0;
  702.  
  703.     switch (cmd) {
  704.  
  705.     case SIOCSIFADDR:
  706.                 ifp->if_flags |= IFF_UP;
  707.                 exinit(ifp->if_unit);
  708.  
  709.                 switch (ifa->ifa_addr->sa_family) {
  710. #ifdef INET
  711.         case AF_INET:
  712.             ((struct arpcom *)ifp)->ac_ipaddr =
  713.                 IA_SIN(ifa)->sin_addr;
  714.             arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
  715.             break;
  716. #endif
  717. #ifdef NS
  718.         case AF_NS:
  719.             {
  720.             register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  721.             
  722.             if (ns_nullhost(*ina))
  723.                 ina->x_host = *(union ns_host *)(xs->xs_addr);
  724.             else
  725.                 ex_setaddr(ina->x_host.c_host,ifp->if_unit);
  726.             break;
  727.             }
  728. #endif
  729.         }
  730.         break;
  731.  
  732.     case SIOCSIFFLAGS:
  733.         if ((ifp->if_flags & IFF_UP) == 0 &&
  734.             xs->xs_flags & EX_RUNNING) {
  735.             ((struct exdevice *)
  736.               (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET;
  737.             xs->xs_flags &= ~EX_RUNNING;
  738.         } else if (ifp->if_flags & IFF_UP &&
  739.             (xs->xs_flags & EX_RUNNING) == 0)
  740.             exinit(ifp->if_unit);
  741.         break;
  742.  
  743.     default:
  744.         error = EINVAL;
  745.     }
  746.     splx(s);
  747.     return (error);
  748. }
  749.  
  750. /*
  751.  * set ethernet address for unit
  752.  */
  753. ex_setaddr(physaddr, unit)
  754.     u_char *physaddr;
  755.     int unit;
  756. {
  757.     register struct ex_softc *xs = &ex_softc[unit];
  758.     
  759.     if (physaddr) {
  760.         xs->xs_flags |= EX_SETADDR;
  761.         bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
  762.     }
  763.     ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
  764. }
  765. /*
  766.  * enable multicast reception on a particular address.
  767.  */
  768. ex_setmulti(linkaddr, unit, slot)
  769.     u_char *linkaddr;
  770.     int unit;
  771. {
  772.     register struct ex_softc *xs = &ex_softc[unit];
  773.     struct uba_device *ui = exinfo[unit];
  774.     register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
  775.     register struct ex_msg *bp;
  776.     
  777.     if (! (xs->xs_flags & EX_RUNNING))
  778.         return;
  779.     bp = exgetcbuf(xs);
  780.     bp->mb_rqst = LLNET_ADDRS;
  781.     bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
  782.     bp->mb_na.na_slot = slot;
  783.     bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
  784.     bp->mb_status |= MH_EXOS;
  785.     addr->xd_portb = EX_NTRUPT;
  786.     bp = xs->xs_x2hnext;
  787.     while ((bp->mb_status & MH_OWNER) == MH_EXOS)    /* poll for reply */
  788.         ;
  789. #ifdef    DEBUG
  790.     log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
  791.         (slot == PHYSSLOT ? "reset addr" : "add multicast"
  792.         ether_sprintf(bp->mb_na.na_addrs), slot);
  793. #endif
  794.     /*
  795.      * Now, re-enable reception on slot.
  796.      */
  797.     bp = exgetcbuf(xs);
  798.     bp->mb_rqst = LLNET_RECV;
  799.     bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
  800.     bp->mb_nr.nr_slot = slot;
  801.     bp->mb_status |= MH_EXOS;
  802.     addr->xd_portb = EX_NTRUPT;
  803.     bp = xs->xs_x2hnext;
  804.     while ((bp->mb_status & MH_OWNER) == MH_EXOS)    /* poll for reply */
  805.         ;
  806. }
  807. #endif
  808.