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

  1. /*
  2.  * Copyright (c) 1989 The 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.5 (Berkeley) 12/16/90
  37.  */
  38.  
  39. #include "ex.h"
  40.  
  41. #if    NEX > 0 
  42.  
  43. /*
  44.  * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers
  45.  */
  46. #include "sys/param.h"
  47. #include "sys/systm.h"
  48. #include "sys/mbuf.h"
  49. #include "sys/buf.h"
  50. #include "sys/protosw.h"
  51. #include "sys/socket.h"
  52. #include "sys/vmmac.h"
  53. #include "sys/ioctl.h"
  54. #include "sys/errno.h"
  55. #include "sys/vmparam.h"
  56. #include "sys/syslog.h"
  57. #include "sys/uio.h"
  58.  
  59. #include "net/if.h"
  60. #include "net/netisr.h"
  61. #include "net/route.h"
  62.  
  63. #ifdef INET
  64. #include "netinet/in.h"
  65. #include "netinet/in_systm.h"
  66. #include "netinet/in_var.h"
  67. #include "netinet/ip.h"
  68. #include "netinet/if_ether.h"
  69. #endif
  70.  
  71. #ifdef NS
  72. #include "netns/ns.h"
  73. #include "netns/ns_if.h"
  74. #endif
  75.  
  76. #ifdef ISO
  77. #include "netiso/iso.h"
  78. #include "netiso/iso_var.h"
  79. extern char all_es_snpa[], all_is_snpa[];
  80. #endif 
  81.  
  82. #include "../include/cpu.h"
  83. #include "../include/pte.h"
  84. #include "../include/mtpr.h"
  85.  
  86. #include "../vba/vbavar.h"
  87. #include "if_exreg.h"
  88. #include "if_vba.h"
  89.  
  90.  
  91. #define    NH2X 32            /* Host to eXcelan request buffers */
  92.  
  93. #define    NX2H 16            /* eXcelan to Host reply buffers */
  94. #define    NREC    16        /* Number of RECeive buffers */
  95. #define    NTRB    4        /* Number of TRansmit Buffers */
  96. #define NVBI    (NREC + NTRB)
  97.  
  98. #define EXWATCHINTVL    10    /* call exwatch every x secs */
  99.  
  100. int    exprobe(), exslave(), exattach(), exintr(), exstart();
  101. struct    vba_device *exinfo[NEX];
  102.  
  103. long    exstd[] = { 0 };
  104.  
  105.  
  106. struct    vba_driver exdriver =
  107.     { exprobe, 0, exattach, exstart, exstd, "ex", exinfo };
  108. int    exinit(),ether_output(),exioctl(),exreset(),exwatch();
  109. struct    ex_msg *exgetcbuf();
  110. int    ex_ncall = 0;            /* counts calls to exprobe */
  111. u_long    busoff;
  112.  
  113. /*
  114.  * Ethernet software status per interface.
  115.  *
  116.  * Each interface is referenced by a network interface structure, xs_if, which 
  117.  * the routing code uses to locate the interface.  This structure contains the 
  118.  * output queue for the interface, its address, ... NOTE: To configure multiple
  119.  * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr).
  120.  */
  121. struct    ex_softc {
  122.     struct        arpcom xs_ac;    /* Ethernet common part */
  123. #define    xs_if        xs_ac.ac_if    /* network-visible interface */
  124. #define    xs_addr        xs_ac.ac_enaddr    /* hardware Ethernet address */
  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.     int        xs_cvec;    /* probe stores cvec here */
  131.     short        xs_enetunit;    /* unit number for enet filtering */
  132.     short        xs_enetinit;    /* enet inetrface is initialized */
  133.     struct    ex_msg    *xs_h2xnext;    /* host pointer to request queue */
  134.     struct    ex_msg     *xs_x2hnext;    /* host pointer to reply queue */
  135.     u_long        xs_qbaddr;    /* map info for structs below */
  136.     struct    ex_shm    {
  137.     /* the following structures are always mapped in */
  138.     u_short        sm_h2xhdr;    /* EXOS's request queue header */
  139.     u_short        sm_x2hhdr;    /* EXOS's reply queue header */
  140.     struct ex_msg     sm_h2xent[NH2X];/* request msg buffers */
  141.     struct ex_msg     sm_x2hent[NX2H];/* reply msg buffers */
  142.     struct ex_conf    sm_cm;        /* configuration message */
  143.     struct ex_stat    sm_xsa;    /* EXOS writes stats here */
  144.     /* end mapped area */
  145.     }         *xs_shm;    /* host pointer to shared area */
  146. #define    xs_h2xhdr    xs_shm->sm_h2xhdr
  147. #define    xs_x2hhdr    xs_shm->sm_x2hhdr
  148. #define    xs_h2xent    xs_shm->sm_h2xent
  149. #define    xs_x2hent    xs_shm->sm_x2hent
  150. #define    xs_cm        xs_shm->sm_cm
  151. #define    xs_xsa        xs_shm->sm_xsa
  152. #define    BUSADDR(x)    (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF))
  153. #define    P_BUSADDR(x)    (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0))
  154. #define    INCORE_BASE(p)    (((u_long)(p)->xs_shm) & 0xFFFFFFF0)
  155. /* we will arrange that the shared memory begins on a 16 byte boundary */
  156. #define    RVAL_OFF(n)    (((char *)&(((struct ex_shm *)0)->n))-(char *)0)
  157. #define    LVAL_OFF(n)    (((char *)(((struct ex_shm *)0)->n))-(char *)0)
  158. #define    H2XHDR_OFFSET    RVAL_OFF(sm_h2xhdr)
  159. #define    X2HHDR_OFFSET    RVAL_OFF(sm_x2hhdr)
  160. #define    H2XENT_OFFSET    LVAL_OFF(sm_h2xent)
  161. #define    X2HENT_OFFSET    LVAL_OFF(sm_x2hent)
  162. #define    CM_OFFSET    RVAL_OFF(sm_cm)
  163. #define    SA_OFFSET    RVAL_OFF(sm_xsa)
  164.     struct        ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */
  165.     struct        ifvba *xs_pkblist; /* free list of above */
  166. #define GetPkBuf(b, v)  ((v = (b)->mb_pkb = xs->xs_pkblist),\
  167.               (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf))
  168. #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\
  169.                             (xs->xs_pkblist = v))
  170.     char        xs_nrec;    /* number of pending receive buffers */
  171.     char        xs_ntrb;    /* number of pending transmit buffers */
  172. } ex_softc[NEX];
  173.  
  174. int ex_padcheck = sizeof (struct ex_softc);
  175.  
  176. exprobe(reg, vi)
  177.     caddr_t reg;
  178.     struct vba_device *vi;
  179. {
  180.     register br, cvec;        /* r12, r11 value-result */
  181.     register struct exdevice *exaddr = (struct exdevice *)reg;
  182.     int    i;
  183.  
  184.     if (badaddr((caddr_t)exaddr, 2))
  185.         return 0;
  186.     /*
  187.      * Reset EXOS and run self-test (should complete within 2 seconds).
  188.      */
  189.     movow(&exaddr->ex_porta, EX_RESET);
  190.     for (i = 1000000; i; i--) {
  191.         uncache(&(exaddr->ex_portb));
  192.         if (exaddr->ex_portb & EX_TESTOK)
  193.             break;
  194.     }
  195.     if ((exaddr->ex_portb & EX_TESTOK) == 0)
  196.         return 0;
  197.     br = 0x15;
  198.     cvec = --vi->ui_hd->vh_lastiv;
  199.     ex_softc[vi->ui_unit].xs_cvec = cvec;
  200.     ex_ncall++;
  201.     return (sizeof(struct exdevice));
  202. }
  203.  
  204. /*
  205.  * Interface exists: make available by filling in network interface record.  
  206.  * System will initialize the interface when it is ready to accept packets.  
  207.  * A NET_ADDRS command is done to get the ethernet address.
  208.  */
  209. exattach(ui)
  210.     register struct vba_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 *exaddr = (struct exdevice *)ui->ui_addr;
  215.     register struct ex_msg *bp;
  216.  
  217.     ifp->if_unit = ui->ui_unit;
  218.     ifp->if_name = "ex";
  219.     ifp->if_mtu = ETHERMTU;
  220.     ifp->if_init = exinit;
  221.     ifp->if_ioctl = exioctl;
  222.     ifp->if_output = ether_output;
  223.     ifp->if_reset = exreset;
  224.     ifp->if_start = exstart;
  225.     ifp->if_flags = IFF_BROADCAST;
  226.  
  227.     /*
  228.      * Note: extra memory gets returned by if_vbareserve()
  229.      * first, so, being page alligned, it is also 16-byte alligned.
  230.      */
  231.     if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF,
  232.             (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0)
  233.         return;
  234.     /*
  235.      * Temporarily map queues in order to configure EXOS
  236.      */
  237.     xs->xs_qbaddr = INCORE_BASE(xs);
  238.     exconfig(ui, 0);            /* without interrupts */
  239.     if (xs->xs_cm.cm_cc)
  240.         return;                /* bad conf */
  241.     /*
  242.      * Get Ethernet address.
  243.      */
  244.     if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)
  245.         panic("exattach");
  246.     bp->mb_na.na_mask = READ_OBJ;
  247.     bp->mb_na.na_slot = PHYSSLOT;
  248.     bp->mb_status |= MH_EXOS;
  249.     movow(&exaddr->ex_portb, EX_NTRUPT);
  250.     bp = xs->xs_x2hnext;
  251.     while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
  252.     printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",
  253.         ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
  254.         xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
  255.         ether_sprintf(bp->mb_na.na_addrs));
  256.     bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
  257.         sizeof(xs->xs_addr));
  258.     if_attach(ifp);
  259. }
  260.  
  261. /*
  262.  * Reset of interface after BUS reset.
  263.  * If interface is on specified vba, reset its state.
  264.  */
  265. exreset(unit)
  266. int unit;
  267. {
  268.     register struct vba_device *ui;
  269.  
  270.     if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)
  271.         return;
  272.     printf(" ex%d", unit);
  273.     ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
  274.     ex_softc[unit].xs_flags &= ~EX_RUNNING;
  275.  
  276.     exinit(unit);
  277. }
  278.  
  279. /*
  280.  * Initialization of interface; clear recorded pending operations, and 
  281.  * reinitialize BUS usage. Called at boot time, and at ifconfig time via 
  282.  * exioctl, with interrupts disabled.
  283.  */
  284. exinit(unit)
  285. int unit;
  286. {
  287.     register struct ex_softc *xs = &ex_softc[unit];
  288.     register struct vba_device *ui = exinfo[unit];
  289.     register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
  290.     register struct ifnet *ifp = &xs->xs_if;
  291.     register struct sockaddr_in *sin;
  292.     register struct ex_msg     *bp;
  293.     int s;
  294.  
  295.     /* not yet, if address still unknown */
  296.     if (ifp->if_addrlist == (struct ifaddr *)0)
  297.         return;
  298.     if (xs->xs_flags & EX_RUNNING)
  299.         return;
  300.  
  301.     xs->xs_qbaddr = INCORE_BASE(xs);
  302.     exconfig(ui, 4);        /* with vectored interrupts*/
  303.  
  304.     /*
  305.      * Put EXOS on the Ethernet, using NET_MODE command
  306.      */
  307.     if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)
  308.         panic("exinit");
  309.     bp->mb_nm.nm_mask = WRITE_OBJ;
  310.     bp->mb_nm.nm_optn = 0;
  311.     bp->mb_nm.nm_mode = MODE_PERF;
  312.     bp->mb_status |= MH_EXOS;
  313.     movow(&exaddr->ex_portb, EX_NTRUPT);
  314.     bp = xs->xs_x2hnext;
  315.     while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
  316.         ;
  317.     bp->mb_length = MBDATALEN;
  318.     bp->mb_status |= MH_EXOS;        /* free up buffer */
  319.     movow(&exaddr->ex_portb, EX_NTRUPT);
  320.     xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
  321.  
  322.     ifp->if_watchdog = exwatch;
  323.     ifp->if_timer = EXWATCHINTVL;
  324.     s = splimp();        /* are interrupts disabled here, anyway? */
  325.     exhangrcv(unit);
  326.     xs->xs_if.if_flags |= IFF_RUNNING;
  327.     xs->xs_flags |= EX_RUNNING;
  328.     if (xs->xs_flags & EX_SETADDR)
  329.         ex_setaddr((u_char *)0, unit);
  330. #ifdef ISO
  331.     ex_setmulti(all_es_snpa, unit, 1);
  332.     ex_setmulti(all_is_snpa, unit, 2);
  333. #endif
  334.     exstart(&ex_softc[unit].xs_if);        /* start transmits */
  335.     splx(s);        /* are interrupts disabled here, anyway? */
  336. }
  337.  
  338. /*
  339.  * Reset, test, and configure EXOS.  It is called by exinit, and exattach.
  340.  * Returns 0 if successful, 1 if self-test failed.
  341.  */
  342. exconfig(ui, itype)
  343. struct    vba_device *ui;
  344. int itype;
  345. {
  346.     register int unit = ui->ui_unit;
  347.     register struct ex_softc *xs = &ex_softc[unit];
  348.     register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;
  349.     register struct ex_conf *cm = &xs->xs_cm;
  350.     register struct ex_msg     *bp;
  351.     register struct ifvba *pkb;
  352.     int     i;
  353.     u_long     shiftreg;
  354.     static    u_char    cmaddr[8] = {0xFF, 0xFF, 0, 0};
  355.  
  356.     xs->xs_flags = 0;
  357.     /*
  358.      * Reset EXOS, wait for self-test to complete
  359.      */
  360.     movow(&exaddr->ex_porta, EX_RESET);
  361.     do {
  362.         uncache(&exaddr->ex_portb);
  363.     } while ((exaddr->ex_portb & EX_TESTOK) == 0) ;
  364.     /*
  365.      * Set up configuration message.
  366.      */
  367.     cm->cm_1rsrv = 1;
  368.     cm->cm_cc = 0xFF;
  369.     cm->cm_opmode = 0;        /* link-level controller mode */
  370.     cm->cm_dfo = 0x0101;        /* enable host data order conversion */
  371.     cm->cm_dcn1 = 1;
  372.     cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
  373.     cm->cm_ham = 3;            /* absolute address mode */
  374.     cm->cm_3rsrv = 0;
  375.     cm->cm_mapsiz = 0;
  376.     cm->cm_byteptrn[0] = 0x01;    /* EXOS deduces data order of host */
  377.     cm->cm_byteptrn[1] = 0x03;    /*  by looking at this pattern */
  378.     cm->cm_byteptrn[2] = 0x07;
  379.     cm->cm_byteptrn[3] = 0x0F;
  380.     cm->cm_wordptrn[0] = 0x0103;
  381.     cm->cm_wordptrn[1] = 0x070F;
  382.     cm->cm_lwordptrn = 0x0103070F;
  383.     for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
  384.     cm->cm_mba = 0xFFFFFFFF;
  385.     cm->cm_nproc = 0xFF;
  386.     cm->cm_nmbox = 0xFF;
  387.     cm->cm_nmcast = 0xFF;
  388.     cm->cm_nhost = 1;
  389.     cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);
  390.     cm->cm_h2xhdr = H2XHDR_OFFSET;
  391.     cm->cm_h2xtyp = 0;        /* should never wait for rqst buffer */
  392.     cm->cm_x2hba = cm->cm_h2xba;
  393.     cm->cm_x2hhdr = X2HHDR_OFFSET;
  394.     cm->cm_x2htyp = itype;        /* 0 for none, 4 for vectored */
  395.     cm->cm_x2haddr = xs->xs_cvec;    /* ivec allocated in exprobe */
  396.     /*
  397.      * Set up message queues and headers.
  398.      * First the request queue
  399.      */
  400.     for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
  401.         bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
  402.         bp->mb_rsrv = 0;
  403.         bp->mb_length = MBDATALEN;
  404.         bp->mb_status = MH_HOST;
  405.         bp->mb_next = bp+1;
  406.     }
  407.     xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;
  408.     xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
  409.  
  410.     /* Now the reply queue. */
  411.     for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
  412.         bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
  413.         bp->mb_rsrv = 0;
  414.         bp->mb_length = MBDATALEN;
  415.         bp->mb_status = MH_EXOS;
  416.         bp->mb_next = bp+1;
  417.     }
  418.     xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;
  419.     xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
  420.     xs->xs_nrec = 0;
  421.     xs->xs_ntrb = 0;
  422.     xs->xs_pkblist =  xs->xs_vbinfo + NVBI - 1;
  423.     for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--)
  424.         pkb->iff_mbuf = (struct mbuf *)(pkb - 1);
  425.     xs->xs_vbinfo[0].iff_mbuf = 0;
  426.  
  427.     /*
  428.      * Write config msg address to EXOS and wait for configuration to 
  429.      * complete (guaranteed response within 2 seconds).
  430.      */
  431.     shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;
  432.     for (i = 4; i < 8; i++) {
  433.         cmaddr[i] = (u_char)(shiftreg & 0xFF);
  434.         shiftreg >>= 8;
  435.     }
  436.     for (i = 0; i < 8; i++) {
  437.         do {
  438.             uncache(&exaddr->ex_portb);
  439.         } while (exaddr->ex_portb & EX_UNREADY) ;
  440.         DELAY(500);
  441.         movow(&exaddr->ex_portb, cmaddr[i]);
  442.     }
  443.     for (i = 500000; i; --i) {
  444.         DELAY(10);
  445.         uncache(&cm->cm_cc);
  446.         if (cm->cm_cc != 0xFF)
  447.             break;
  448.     }
  449.     if (cm->cm_cc)
  450.         printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);
  451. }
  452.  
  453. /*
  454.  * Start or re-start output on interface. Get another datagram to send off of 
  455.  * the interface queue, and map it to the interface before starting the output.
  456.  * This routine is called by exinit(), exoutput(), and excdint().  In all cases,
  457.  * interrupts by EXOS are disabled.
  458.  */
  459. exstart(ifp)
  460. struct ifnet *ifp;
  461. {
  462.     int unit = ifp->if_unit;
  463.     struct vba_device *ui = exinfo[unit];
  464.     register struct ex_softc *xs = &ex_softc[unit];
  465.     struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
  466.     register struct ex_msg *bp;
  467.     register struct mbuf *m;
  468.         int len;
  469.     register struct ifvba *pkb;
  470.     struct mbuf *m0 = 0;
  471.     register int nb = 0, tlen = 0;
  472.     union l_util {
  473.         u_long    l;
  474.         struct    i86_long i;
  475.     } l_util;
  476.  
  477.     if (xs->xs_ntrb >= NTRB)
  478.         return;
  479.     if (xs->xs_pkblist == 0) {
  480.         printf("ex%d: vbinfo exhausted, would panic", unit);
  481.         return;
  482.     }
  483.     IF_DEQUEUE(&xs->xs_if.if_snd, m);
  484.     if (m == 0)
  485.         return;
  486.     /*
  487.      * Get a transmit request.
  488.      */
  489.     if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) {
  490.         m_freem(m);
  491.         printf("exstart: no command buffers\n");
  492.         return;
  493.     }
  494.     xs->xs_ntrb++;
  495.     GetPkBuf(bp, pkb);
  496.     pkb->iff_mbuf = m;    /* save mbuf pointer to free when done */
  497.     /*
  498.      * point directly to the first group of mbufs to be transmitted. The
  499.      * hardware can only support NFRAGMENTS descriptors.
  500.      */
  501.     while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) {
  502.         l_util.l = BUSADDR(mtod(m, caddr_t));
  503.         bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len;
  504.         bp->mb_et.et_blks[nb].bb_addr = l_util.i;
  505.         if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
  506.             /* Here, the phys memory for the mbuf is out
  507.                of range for the vmebus to talk to it */
  508.             if (m == pkb->iff_mbuf)
  509.                 pkb->iff_mbuf = 0;
  510.             break;
  511.         }
  512.         tlen += m->m_len;
  513.         m0 = m;
  514.         m = m->m_next;
  515.         nb++;
  516.     }
  517.  
  518.     /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */
  519.     if (m0)
  520.         m0->m_next = 0;
  521.  
  522.     /*
  523.      * if not all of the descriptors would fit then merge remaining data
  524.      * into the transmit buffer, and point to it.  Note: the mbufs are freed
  525.      * during the merge, they do not have to be freed when we get the 
  526.      * transmit interrupt.
  527.      */
  528.     if (m) {
  529.         if (m == pkb->iff_mbuf) {
  530.             printf("ex%d: exstart insanity\n", unit);
  531.             pkb->iff_mbuf = 0;
  532.         }
  533.         len = if_vbaput(pkb->iff_buffer, m, 0);
  534.         l_util.l = BUSADDR(pkb->iff_buffer);
  535.         bp->mb_et.et_blks[nb].bb_len = (u_short)len;
  536.         bp->mb_et.et_blks[nb].bb_addr = l_util.i;
  537.         tlen += len;
  538.         nb++;
  539.     }
  540.  
  541.     /*
  542.      * If the total length of the packet is too small,
  543.      * pad the last fragment.  (May run into very obscure problems)
  544.      */
  545.     if (tlen < sizeof(struct ether_header) + ETHERMIN) {
  546.         len = (ETHERMIN + sizeof(struct ether_header)) - tlen;
  547.         bp->mb_et.et_blks[nb-1].bb_len += (u_short)len;
  548.         tlen += len;
  549. #ifdef notdef
  550.                 if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) {
  551.             must copy last frag into private buffer
  552.         }
  553. #endif
  554.     }
  555.  
  556.     /* set number of fragments in descriptor */
  557.     bp->mb_et.et_nblock = nb;
  558.     bp->mb_status |= MH_EXOS;
  559.     movow(&exaddr->ex_portb, EX_NTRUPT);
  560. }
  561.  
  562. /*
  563.  * interrupt service routine.
  564.  */
  565. exintr(unit)
  566.     int unit;
  567. {
  568.     register struct ex_softc *xs = &ex_softc[unit];
  569.     register struct ex_msg *bp = xs->xs_x2hnext;
  570.     struct vba_device *ui = exinfo[unit];
  571.     struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
  572.     struct ex_msg *next_bp;
  573.  
  574.     while ((bp->mb_status & MH_OWNER) == MH_HOST) {
  575.         switch (bp->mb_rqst) {
  576.             case LLRECEIVE:
  577.             if (--xs->xs_nrec < 0) {
  578.                 printf("ex%d: internal receive check\n", unit);
  579.                 xs->xs_nrec = 0;
  580.             }
  581.             exrecv(unit, bp);
  582.             FreePkBuf(bp->mb_pkb);
  583.             bp->mb_pkb = (struct ifvba *)0;
  584.             exhangrcv(unit);
  585.             break;
  586.  
  587.             case LLTRANSMIT:
  588.             case LLRTRANSMIT:
  589.             if (--xs->xs_ntrb < 0) {
  590.                 printf("ex%d: internal transmit check\n", unit);
  591.                 xs->xs_ntrb = 0;
  592.             }
  593.             xs->xs_if.if_opackets++;
  594.             if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
  595.                 ;
  596.             else if (bp->mb_rply & LLXM_1RTRY)
  597.                 xs->xs_if.if_collisions++;
  598.             else if (bp->mb_rply & LLXM_RTRYS)
  599.                 xs->xs_if.if_collisions += 2;    /* guess */
  600.             else if (bp->mb_rply & LLXM_ERROR)
  601.                 if (xs->xs_if.if_oerrors++ % 100 == 0)
  602.                     printf("ex%d: 100 transmit errors=%b\n",
  603.                         unit, bp->mb_rply, XMIT_BITS);
  604.             if (bp->mb_pkb->iff_mbuf) {
  605.                 m_freem(bp->mb_pkb->iff_mbuf);
  606.                 bp->mb_pkb->iff_mbuf = (struct mbuf *)0;
  607.             }
  608.             FreePkBuf(bp->mb_pkb);
  609.             bp->mb_pkb = (struct ifvba *)0;
  610.             exstart(&xs->xs_if);
  611.             exhangrcv(unit);
  612.             break;
  613.  
  614.             case LLNET_STSTCS:
  615.             xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc;
  616.             xs->xs_flags &= ~EX_STATPENDING;
  617.             case LLNET_ADDRS:
  618.             case LLNET_RECV:
  619.             if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE)
  620.                 ;
  621.             else
  622.                 printf("ex%d: %s, request 0x%x, reply 0x%x\n",
  623.                   unit, "unsucessful stat or address change",
  624.                   bp->mb_rqst, bp->mb_rply);
  625.             break;
  626.  
  627.             default:
  628.             printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst);
  629.         }
  630.         bp->mb_length = MBDATALEN;
  631.         next_bp = bp->mb_next;
  632.         bp->mb_status |= MH_EXOS;    /* free up buffer */
  633.         bp = next_bp;            /* paranoia about race */
  634.         movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */
  635.     }
  636.     xs->xs_x2hnext = bp;
  637. }
  638.  
  639. /*
  640.  * Get a request buffer, fill in standard values, advance pointer.
  641.  */
  642. struct ex_msg *
  643. exgetcbuf(xs, req)
  644. struct ex_softc *xs;
  645. int req;
  646. {
  647.     register struct ex_msg *bp;
  648.     struct ifvba *pkb;
  649.     int s = splimp();
  650.  
  651.     bp = xs->xs_h2xnext;
  652.     if ((bp->mb_status & MH_OWNER) == MH_EXOS) {
  653.         splx(s);
  654.         return (struct ex_msg *)0;
  655.     }
  656.     xs->xs_h2xnext = bp->mb_next;
  657.     bp->mb_1rsrv = 0;
  658.     bp->mb_rqst = req;
  659.     bp->mb_length = MBDATALEN;
  660.     bp->mb_pkb = (struct ifvba *)0;
  661.     splx(s);
  662.     return bp;
  663. }
  664.  
  665. /*
  666.  * Process Ethernet receive completion:  If input error just drop packet, 
  667.  * otherwise examine packet to determine type.  If can't determine length from 
  668.  * type, then have to drop packet, otherwise decapsulate packet based on type 
  669.  * and pass to type-specific higher-level input routine.
  670.  */
  671. exrecv(unit, bp)
  672. int unit;
  673. register struct ex_msg *bp;
  674. {
  675.     register struct ex_softc *xs = &ex_softc[unit];
  676.     register struct ether_header *eh;
  677.         register struct mbuf *m;
  678.     int len, off, resid;
  679.     register struct ifqueue *inq;
  680.     int s;
  681.  
  682.     xs->xs_if.if_ipackets++;
  683.     /*     total length               - header                      - crc */
  684.     len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
  685.     if (bp->mb_rply != LL_OK) {
  686.         if (xs->xs_if.if_ierrors++ % 100 == 0)
  687.             printf("ex%d: 100 receive errors=%b\n",
  688.                 unit, bp->mb_rply, RECV_BITS);
  689.         return;
  690.     }
  691.     eh = (struct ether_header *)(bp->mb_pkb->iff_buffer);
  692.  
  693.     /*
  694.      * Deal with trailer protocol: if type is PUP trailer get true type from
  695.      * first 16-bit word past data.  Remember that type was trailer by 
  696.      * setting off.
  697.      */
  698.     eh->ether_type = ntohs((u_short)eh->ether_type);
  699. #define    exdataaddr(eh, off, type)    ((type)(((caddr_t)((eh)+1)+(off))))
  700.     if (eh->ether_type >= ETHERTYPE_TRAIL &&
  701.         eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
  702.         off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
  703.         if (off >= ETHERMTU)
  704.             return;            /* sanity */
  705.         eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
  706.         resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
  707.         if (off + resid > len)
  708.             return;            /* sanity */
  709.         len = off + resid;
  710.     } else
  711.         off = 0;
  712.     if (len == 0)
  713.         return;
  714.     /*
  715.      * Pull packet off interface.  Off is nonzero if packet
  716.      * has trailing header; if_vbaget will then force this header
  717.      * information to be at the front, but we still have to drop
  718.      * the type and length which are at the front of any trailer data.
  719.      */
  720.     m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0);
  721.     if (m == 0)
  722.         return;
  723.     ether_input(&xs->xs_if, eh, m);
  724.     return;
  725. }
  726.  
  727. /*
  728.  * Hang a receive request. This routine is called by exinit and excdint,
  729.  * with interrupts disabled in both cases.
  730.  */
  731. exhangrcv(unit)
  732.     int unit;
  733. {
  734.     register struct ex_softc *xs = &ex_softc[unit];
  735.     register struct ex_msg *bp;
  736.     register struct ifvba *pkb;
  737.     short mustint = 0;
  738.     union l_util {
  739.         u_long    l;
  740.         struct    i86_long i;
  741.     } l_util;
  742.  
  743.     while (xs->xs_nrec < NREC) {
  744.         if (xs->xs_pkblist == (struct ifvba *)0)
  745.             break;
  746.         if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) {
  747.             break;
  748.         }
  749.         GetPkBuf(bp, pkb);
  750.         pkb->iff_mbuf = 0;
  751.         xs->xs_nrec += 1;
  752.         bp->mb_er.er_nblock = 1;
  753.         bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
  754.         l_util.l = BUSADDR(pkb->iff_buffer);
  755.         bp->mb_er.er_blks[0].bb_addr = l_util.i;
  756.         bp->mb_status |= MH_EXOS;
  757.         mustint = 1;
  758.     }
  759.     if (mustint == 0)
  760.         return;
  761.     movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);
  762. }
  763.  
  764. /*
  765.  * Ethernet output routine is ether_output().
  766.  */
  767.  
  768. /*
  769.  * Watchdog routine (currently not used). Might use this to get stats from EXOS.
  770.  */
  771. exwatch(unit)
  772. int unit;
  773. {
  774.     struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr;
  775.     register struct ex_softc *xs = &ex_softc[unit];
  776.     register struct ex_msg *bp;
  777.     int s = splimp();
  778.  
  779.     if (xs->xs_flags & EX_STATPENDING)
  780.         goto exspnd;
  781.     if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) {
  782.         splx(s);
  783.         return;
  784.     }
  785.     xs->xs_flags |= EX_STATPENDING;
  786.     bp->mb_ns.ns_mask = READ_OBJ;
  787.     bp->mb_ns.ns_rsrv = 0;
  788.     bp->mb_ns.ns_nobj = 8;
  789.     bp->mb_ns.ns_xobj = 0;
  790.     bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET;
  791.     bp->mb_status |= MH_EXOS;
  792.     movow(&exaddr->ex_portb, EX_NTRUPT);
  793. exspnd:    splx(s);
  794.     xs->xs_if.if_timer = EXWATCHINTVL;
  795. }
  796.  
  797. /*
  798.  * Process an ioctl request.
  799.  */
  800. exioctl(ifp, cmd, data)
  801.     register struct ifnet *ifp;
  802.     int cmd;
  803.     caddr_t data;
  804. {
  805.     register struct ifaddr *ifa = (struct ifaddr *)data;
  806.     register struct ex_softc *xs = &ex_softc[ifp->if_unit];
  807.     int s = splimp(), error = 0;
  808.  
  809.     switch (cmd) {
  810.  
  811.     case SIOCSIFADDR:
  812.                 ifp->if_flags |= IFF_UP;
  813.                 exinit(ifp->if_unit);
  814.  
  815.                 switch (ifa->ifa_addr->sa_family) {
  816. #ifdef INET
  817.         case AF_INET:
  818.             ((struct arpcom *)ifp)->ac_ipaddr =
  819.                 IA_SIN(ifa)->sin_addr;
  820.             arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
  821.             break;
  822. #endif
  823. #ifdef NS
  824.         case AF_NS:
  825.             {
  826.             register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  827.             
  828.             if (ns_nullhost(*ina))
  829.                 ina->x_host = *(union ns_host *)(xs->xs_addr);
  830.             else
  831.                 ex_setaddr(ina->x_host.c_host,ifp->if_unit);
  832.             break;
  833.             }
  834. #endif
  835.         }
  836.         break;
  837.  
  838.     case SIOCSIFFLAGS:
  839.         if ((ifp->if_flags & IFF_UP) == 0 &&
  840.             xs->xs_flags & EX_RUNNING) {
  841.             movow(&((struct exdevice *)
  842.               (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET);
  843.             xs->xs_flags &= ~EX_RUNNING;
  844.         } else if (ifp->if_flags & IFF_UP &&
  845.             (xs->xs_flags & EX_RUNNING) == 0)
  846.             exinit(ifp->if_unit);
  847.         break;
  848.  
  849.     default:
  850.         error = EINVAL;
  851.     }
  852.     splx(s);
  853.     return (error);
  854. }
  855.  
  856. /*
  857.  * set ethernet address for unit
  858.  */
  859. ex_setaddr(physaddr, unit)
  860.     u_char *physaddr;
  861.     int unit;
  862. {
  863.     register struct ex_softc *xs = &ex_softc[unit];
  864.     
  865.     if (physaddr) {
  866.         xs->xs_flags |= EX_SETADDR;
  867.         bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
  868.     }
  869.     ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);
  870. }
  871.  
  872. /*
  873.  * Enable multicast reception for unit.
  874.  */
  875. ex_setmulti(linkaddr, unit, slot)
  876.     u_char *linkaddr;
  877.     int unit, slot;
  878. {
  879.     register struct ex_softc *xs = &ex_softc[unit];
  880.     struct vba_device *ui = exinfo[unit];
  881.     register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
  882.     register struct ex_msg *bp;
  883.     
  884.     if (!(xs->xs_flags & EX_RUNNING))
  885.         return;
  886.     bp = exgetcbuf(xs, LLNET_ADDRS);
  887.     bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
  888.     bp->mb_na.na_slot = slot;
  889.     bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6);
  890.     bp->mb_status |= MH_EXOS;
  891.     movow(&addr->ex_portb, EX_NTRUPT);
  892.     bp = xs->xs_x2hnext;
  893.     while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
  894. #ifdef    DEBUG
  895.     log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit,
  896.         (slot == PHYSSLOT ? "reset addr" : "add multicast"
  897.         ether_sprintf(bp->mb_na.na_addrs), slot);
  898. #endif
  899.     /*
  900.      * Now, re-enable reception on slot.
  901.      */
  902.     bp = exgetcbuf(xs, LLNET_RECV);
  903.     bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
  904.     bp->mb_nr.nr_slot = slot;
  905.     bp->mb_status |= MH_EXOS;
  906.     movow(&addr->ex_portb, EX_NTRUPT);
  907.     bp = xs->xs_x2hnext;
  908.     while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
  909.         ;
  910. }
  911. #endif
  912.