The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/scsipi/if_se.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_se.c,v 1.45.2.1 2004/09/11 12:51:35 he Exp $        */
    2 
    3 /*
    4  * Copyright (c) 1997 Ian W. Dall <ian.dall@dsto.defence.gov.au>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Ian W. Dall.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Driver for Cabletron EA41x scsi ethernet adaptor.
   35  *
   36  * Written by Ian Dall <ian.dall@dsto.defence.gov.au> Feb 3, 1997
   37  *
   38  * Acknowledgement: Thanks are due to Philip L. Budne <budd@cs.bu.edu>
   39  * who reverse engineered the EA41x. In developing this code,
   40  * Phil's userland daemon "etherd", was refered to extensively in lieu
   41  * of accurate documentation for the device.
   42  *
   43  * This is a weird device! It doesn't conform to the scsi spec in much
   44  * at all. About the only standard command supported is inquiry. Most
   45  * commands are 6 bytes long, but the recv data is only 1 byte.  Data
   46  * must be received by periodically polling the device with the recv
   47  * command.
   48  *
   49  * This driver is also a bit unusual. It must look like a network
   50  * interface and it must also appear to be a scsi device to the scsi
   51  * system. Hence there are cases where there are two entry points. eg
   52  * sestart is to be called from the scsi subsytem and se_ifstart from
   53  * the network interface subsystem.  In addition, to facilitate scsi
   54  * commands issued by userland programs, there are open, close and
   55  * ioctl entry points. This allows a user program to, for example,
   56  * display the ea41x stats and download new code into the adaptor ---
   57  * functions which can't be performed through the ifconfig interface.
   58  * Normal operation does not require any special userland program.
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __KERNEL_RCSID(0, "$NetBSD: if_se.c,v 1.45.2.1 2004/09/11 12:51:35 he Exp $");
   63 
   64 #include "opt_inet.h"
   65 #include "opt_atalk.h"
   66 #include "opt_ccitt.h"
   67 #include "opt_llc.h"
   68 #include "opt_ns.h"
   69 #include "bpfilter.h"
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/callout.h>
   74 #include <sys/syslog.h>
   75 #include <sys/kernel.h>
   76 #include <sys/file.h>
   77 #include <sys/stat.h>
   78 #include <sys/ioctl.h>
   79 #include <sys/buf.h>
   80 #include <sys/uio.h>
   81 #include <sys/malloc.h>
   82 #include <sys/errno.h>
   83 #include <sys/device.h>
   84 #include <sys/disklabel.h>
   85 #include <sys/disk.h>
   86 #include <sys/proc.h>
   87 #include <sys/conf.h>
   88 
   89 #include <dev/scsipi/scsipi_all.h>
   90 #include <dev/scsipi/scsi_ctron_ether.h>
   91 #include <dev/scsipi/scsiconf.h>
   92 
   93 #include <sys/mbuf.h>
   94 
   95 #include <sys/socket.h>
   96 #include <net/if.h>
   97 #include <net/if_dl.h>
   98 #include <net/if_ether.h>
   99 #include <net/if_media.h>
  100 
  101 #ifdef INET
  102 #include <netinet/in.h>
  103 #include <netinet/if_inarp.h>
  104 #endif
  105 
  106 #ifdef NS
  107 #include <netns/ns.h>
  108 #include <netns/ns_if.h>
  109 #endif
  110 
  111 #ifdef NETATALK
  112 #include <netatalk/at.h>
  113 #endif
  114 
  115 #if defined(CCITT) && defined(LLC)
  116 #include <sys/socketvar.h>
  117 #include <netccitt/x25.h>
  118 #include <netccitt/pk.h>
  119 #include <netccitt/pk_var.h>
  120 #include <netccitt/pk_extern.h>
  121 #endif
  122 
  123 #if NBPFILTER > 0
  124 #include <net/bpf.h>
  125 #include <net/bpfdesc.h>
  126 #endif
  127 
  128 #define SETIMEOUT       1000
  129 #define SEOUTSTANDING   4
  130 #define SERETRIES       4
  131 #define SE_PREFIX       4
  132 #define ETHER_CRC       4
  133 #define SEMINSIZE       60
  134 
  135 /* Make this big enough for an ETHERMTU packet in promiscuous mode. */
  136 #define MAX_SNAP        (ETHERMTU + sizeof(struct ether_header) + \
  137                          SE_PREFIX + ETHER_CRC)
  138 
  139 /* 10 full length packets appears to be the max ever returned. 16k is OK */
  140 #define RBUF_LEN        (16 * 1024)
  141 
  142 /* Tuning parameters: 
  143  * The EA41x only returns a maximum of 10 packets (regardless of size).
  144  * We will attempt to adapt to polling fast enough to get RDATA_GOAL packets
  145  * per read
  146  */
  147 #define RDATA_MAX 10
  148 #define RDATA_GOAL 8
  149 
  150 /* se_poll and se_poll0 are the normal polling rate and the minimum
  151  * polling rate respectively. se_poll0 should be chosen so that at
  152  * maximum ethernet speed, we will read nearly RDATA_MAX packets. se_poll
  153  * should be chosen for reasonable maximum latency.
  154  * In practice, if we are being saturated with min length packets, we
  155  * can't poll fast enough. Polling with zero delay actually
  156  * worsens performance. se_poll0 is enforced to be always at least 1
  157  */
  158 #define SE_POLL 40              /* default in milliseconds */
  159 #define SE_POLL0 10             /* default in milliseconds */
  160 int se_poll = 0;                /* Delay in ticks set at attach time */
  161 int se_poll0 = 0;
  162 int se_max_received = 0;        /* Instrumentation */
  163 
  164 #define PROTOCMD(p, d) \
  165         ((d) = (p))
  166 
  167 #define PROTOCMD_DECL(name, val) \
  168         static const struct scsi_ctron_ether_generic name = val
  169 
  170 #define PROTOCMD_DECL_SPECIAL(name, val) \
  171         static const struct __CONCAT(scsi_,name) name = val
  172 
  173 /* Command initializers for commands using scsi_ctron_ether_generic */
  174 PROTOCMD_DECL(ctron_ether_send, {CTRON_ETHER_SEND});
  175 PROTOCMD_DECL(ctron_ether_add_proto, {CTRON_ETHER_ADD_PROTO});
  176 PROTOCMD_DECL(ctron_ether_get_addr, {CTRON_ETHER_GET_ADDR});
  177 PROTOCMD_DECL(ctron_ether_set_media, {CTRON_ETHER_SET_MEDIA});
  178 PROTOCMD_DECL(ctron_ether_set_addr, {CTRON_ETHER_SET_ADDR});
  179 PROTOCMD_DECL(ctron_ether_set_multi, {CTRON_ETHER_SET_MULTI});
  180 PROTOCMD_DECL(ctron_ether_remove_multi, {CTRON_ETHER_REMOVE_MULTI});
  181 
  182 /* Command initializers for commands using their own structures */
  183 PROTOCMD_DECL_SPECIAL(ctron_ether_recv, {CTRON_ETHER_RECV});
  184 PROTOCMD_DECL_SPECIAL(ctron_ether_set_mode, {CTRON_ETHER_SET_MODE});
  185 
  186 struct se_softc {
  187         struct device sc_dev;
  188         struct ethercom sc_ethercom;    /* Ethernet common part */
  189         struct scsipi_periph *sc_periph;/* contains our targ, lun, etc. */
  190 
  191         struct callout sc_ifstart_ch;
  192         struct callout sc_recv_ch;
  193 
  194         char *sc_tbuf;
  195         char *sc_rbuf;
  196         int protos;
  197 #define PROTO_IP        0x01
  198 #define PROTO_ARP       0x02
  199 #define PROTO_REVARP    0x04
  200 #define PROTO_AT        0x08
  201 #define PROTO_AARP      0x10
  202         int sc_debug;
  203         int sc_flags;
  204 #define SE_NEED_RECV 0x1
  205         int sc_last_timeout;
  206         int sc_enabled;
  207 };
  208 
  209 static int      sematch __P((struct device *, struct cfdata *, void *));
  210 static void     seattach __P((struct device *, struct device *, void *));
  211 
  212 static void     se_ifstart __P((struct ifnet *));
  213 static void     sestart __P((struct scsipi_periph *));
  214 
  215 static void     sedone __P((struct scsipi_xfer *));
  216 static int      se_ioctl __P((struct ifnet *, u_long, caddr_t));
  217 static void     sewatchdog __P((struct ifnet *));
  218 
  219 static __inline u_int16_t ether_cmp __P((void *, void *));
  220 static void     se_recv __P((void *));
  221 static struct mbuf *se_get __P((struct se_softc *, char *, int));
  222 static int      se_read __P((struct se_softc *, char *, int));
  223 static int      se_reset __P((struct se_softc *));
  224 static int      se_add_proto __P((struct se_softc *, int));
  225 static int      se_get_addr __P((struct se_softc *, u_int8_t *));
  226 static int      se_set_media __P((struct se_softc *, int));
  227 static int      se_init __P((struct se_softc *));
  228 static int      se_set_multi __P((struct se_softc *, u_int8_t *));
  229 static int      se_remove_multi __P((struct se_softc *, u_int8_t *));
  230 #if 0
  231 static int      sc_set_all_multi __P((struct se_softc *, int));
  232 #endif
  233 static void     se_stop __P((struct se_softc *));
  234 static __inline int se_scsipi_cmd __P((struct scsipi_periph *periph,
  235                         struct scsipi_generic *scsipi_cmd,
  236                         int cmdlen, u_char *data_addr, int datalen,
  237                         int retries, int timeout, struct buf *bp,
  238                         int flags));
  239 static void     se_delayed_ifstart __P((void *));
  240 static int      se_set_mode(struct se_softc *, int, int);
  241 
  242 int     se_enable __P((struct se_softc *));
  243 void    se_disable __P((struct se_softc *));
  244 
  245 CFATTACH_DECL(se, sizeof(struct se_softc),
  246     sematch, seattach, NULL, NULL);
  247 
  248 extern struct cfdriver se_cd;
  249 
  250 dev_type_open(seopen);
  251 dev_type_close(seclose);
  252 dev_type_ioctl(seioctl);
  253 
  254 const struct cdevsw se_cdevsw = {
  255         seopen, seclose, noread, nowrite, seioctl,
  256         nostop, notty, nopoll, nommap, nokqfilter,
  257 };
  258 
  259 const struct scsipi_periphsw se_switch = {
  260         NULL,                   /* Use default error handler */
  261         sestart,                /* have a queue, served by this */
  262         NULL,                   /* have no async handler */
  263         sedone,                 /* deal with stats at interrupt time */
  264 };
  265 
  266 const struct scsipi_inquiry_pattern se_patterns[] = {
  267         {T_PROCESSOR, T_FIXED,
  268          "CABLETRN",         "EA412",                 ""},
  269         {T_PROCESSOR, T_FIXED,
  270          "Cabletrn",         "EA412",                 ""},
  271 };
  272 
  273 /*
  274  * Compare two Ether/802 addresses for equality, inlined and
  275  * unrolled for speed.
  276  * Note: use this like memcmp()
  277  */
  278 static __inline u_int16_t
  279 ether_cmp(one, two)
  280         void *one, *two;
  281 {
  282         u_int16_t *a = (u_int16_t *) one;
  283         u_int16_t *b = (u_int16_t *) two;
  284         u_int16_t diff;
  285 
  286         diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
  287 
  288         return (diff);
  289 }
  290 
  291 #define ETHER_CMP       ether_cmp
  292 
  293 static int
  294 sematch(parent, match, aux)
  295         struct device *parent;
  296         struct cfdata *match;
  297         void *aux;
  298 {
  299         struct scsipibus_attach_args *sa = aux;
  300         int priority;
  301 
  302         (void)scsipi_inqmatch(&sa->sa_inqbuf,
  303             (caddr_t)se_patterns, sizeof(se_patterns) / sizeof(se_patterns[0]),
  304             sizeof(se_patterns[0]), &priority);
  305         return (priority);
  306 }
  307 
  308 /*
  309  * The routine called by the low level scsi routine when it discovers
  310  * a device suitable for this driver.
  311  */
  312 static void
  313 seattach(parent, self, aux)
  314         struct device *parent, *self;
  315         void *aux;
  316 {
  317         struct se_softc *sc = (void *)self;
  318         struct scsipibus_attach_args *sa = aux;
  319         struct scsipi_periph *periph = sa->sa_periph;
  320         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  321         u_int8_t myaddr[ETHER_ADDR_LEN];
  322 
  323         printf("\n");
  324         SC_DEBUG(periph, SCSIPI_DB2, ("seattach: "));
  325 
  326         callout_init(&sc->sc_ifstart_ch);
  327         callout_init(&sc->sc_recv_ch);
  328 
  329 
  330         /*
  331          * Store information needed to contact our base driver
  332          */
  333         sc->sc_periph = periph;
  334         periph->periph_dev = &sc->sc_dev;
  335         periph->periph_switch = &se_switch;
  336 
  337         /* XXX increase openings? */
  338 
  339         se_poll = (SE_POLL * hz) / 1000;
  340         se_poll = se_poll? se_poll: 1;
  341         se_poll0 = (SE_POLL0 * hz) / 1000;
  342         se_poll0 = se_poll0? se_poll0: 1;
  343 
  344         /*
  345          * Initialize and attach a buffer
  346          */
  347         sc->sc_tbuf = malloc(ETHERMTU + sizeof(struct ether_header),
  348                              M_DEVBUF, M_NOWAIT);
  349         if (sc->sc_tbuf == 0)
  350                 panic("seattach: can't allocate transmit buffer");
  351 
  352         sc->sc_rbuf = malloc(RBUF_LEN, M_DEVBUF, M_NOWAIT);/* A Guess */
  353         if (sc->sc_rbuf == 0)
  354                 panic("seattach: can't allocate receive buffer");
  355 
  356         se_get_addr(sc, myaddr);
  357 
  358         /* Initialize ifnet structure. */
  359         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  360         ifp->if_softc = sc;
  361         ifp->if_start = se_ifstart;
  362         ifp->if_ioctl = se_ioctl;
  363         ifp->if_watchdog = sewatchdog;
  364         ifp->if_flags =
  365             IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
  366         IFQ_SET_READY(&ifp->if_snd);
  367 
  368         /* Attach the interface. */
  369         if_attach(ifp);
  370         ether_ifattach(ifp, myaddr);
  371 }
  372 
  373 
  374 static __inline int
  375 se_scsipi_cmd(periph, scsipi_cmd, cmdlen, data_addr, datalen,
  376                        retries, timeout, bp, flags)
  377         struct scsipi_periph *periph;
  378         struct scsipi_generic *scsipi_cmd;
  379         int cmdlen;
  380         u_char *data_addr;
  381         int datalen;
  382         int retries;
  383         int timeout;
  384         struct buf *bp;
  385         int flags;
  386 {
  387         int error;
  388         int s = splbio();
  389 
  390         error = scsipi_command(periph, NULL, scsipi_cmd, cmdlen, data_addr,
  391             datalen, retries, timeout, bp, flags);
  392         splx(s);
  393         return (error);
  394 }
  395 
  396 /* Start routine for calling from scsi sub system */
  397 static void
  398 sestart(periph)
  399         struct scsipi_periph *periph;
  400 {
  401         struct se_softc *sc = (void *)periph->periph_dev;
  402         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  403         int s = splnet();
  404 
  405         se_ifstart(ifp);
  406         (void) splx(s);
  407 }
  408 
  409 static void
  410 se_delayed_ifstart(v)
  411         void *v;
  412 {
  413         struct ifnet *ifp = v;
  414         struct se_softc *sc = ifp->if_softc;
  415         int s;
  416 
  417         s = splnet();
  418         if (sc->sc_enabled) {
  419                 ifp->if_flags &= ~IFF_OACTIVE;
  420                 se_ifstart(ifp);
  421         }
  422         splx(s);
  423 }
  424 
  425 /*
  426  * Start transmission on the interface.
  427  * Always called at splnet().
  428  */
  429 static void
  430 se_ifstart(ifp)
  431         struct ifnet *ifp;
  432 {
  433         struct se_softc *sc = ifp->if_softc;
  434         struct scsi_ctron_ether_generic send_cmd;
  435         struct mbuf *m, *m0;
  436         int len, error;
  437         u_char *cp;
  438 
  439         /* Don't transmit if interface is busy or not running */
  440         if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
  441                 return;
  442 
  443         IFQ_DEQUEUE(&ifp->if_snd, m0);
  444         if (m0 == 0)
  445                 return;
  446 #if NBPFILTER > 0
  447         /* If BPF is listening on this interface, let it see the
  448          * packet before we commit it to the wire.
  449          */
  450         if (ifp->if_bpf)
  451                 bpf_mtap(ifp->if_bpf, m0);
  452 #endif
  453 
  454         /* We need to use m->m_pkthdr.len, so require the header */
  455         if ((m0->m_flags & M_PKTHDR) == 0)
  456                 panic("ctscstart: no header mbuf");
  457         len = m0->m_pkthdr.len;
  458 
  459         /* Mark the interface busy. */
  460         ifp->if_flags |= IFF_OACTIVE;
  461 
  462         /* Chain; copy into linear buffer we allocated at attach time. */
  463         cp = sc->sc_tbuf;
  464         for (m = m0; m != NULL; ) {
  465                 memcpy(cp, mtod(m, u_char *), m->m_len);
  466                 cp += m->m_len;
  467                 MFREE(m, m0);
  468                 m = m0;
  469         }
  470         if (len < SEMINSIZE) {
  471 #ifdef SEDEBUG
  472                 if (sc->sc_debug)
  473                         printf("se: packet size %d (%d) < %d\n", len,
  474                             cp - (u_char *)sc->sc_tbuf, SEMINSIZE);
  475 #endif
  476                 memset(cp, 0, SEMINSIZE - len);
  477                 len = SEMINSIZE;
  478         }
  479 
  480         /* Fill out SCSI command. */
  481         PROTOCMD(ctron_ether_send, send_cmd);
  482         _lto2b(len, send_cmd.length);
  483 
  484         /* Send command to device. */
  485         error = se_scsipi_cmd(sc->sc_periph,
  486             (struct scsipi_generic *)&send_cmd, sizeof(send_cmd),
  487             sc->sc_tbuf, len, SERETRIES,
  488             SETIMEOUT, NULL, XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_DATA_OUT);
  489         if (error) {
  490                 printf("%s: not queued, error %d\n",
  491                     sc->sc_dev.dv_xname, error);
  492                 ifp->if_oerrors++;
  493                 ifp->if_flags &= ~IFF_OACTIVE;
  494         } else
  495                 ifp->if_opackets++;
  496         if (sc->sc_flags & SE_NEED_RECV) {
  497                 sc->sc_flags &= ~SE_NEED_RECV;
  498                 se_recv((void *) sc);
  499         }
  500 }
  501 
  502 
  503 /*
  504  * Called from the scsibus layer via our scsi device switch.
  505  */
  506 static void
  507 sedone(xs)
  508         struct scsipi_xfer *xs;
  509 {
  510         int error;
  511         struct se_softc *sc = (void *)xs->xs_periph->periph_dev;
  512         struct scsipi_generic *cmd = xs->cmd;
  513         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  514         int s;
  515 
  516         error = !(xs->error == XS_NOERROR);
  517 
  518         s = splnet();
  519         if(IS_SEND(cmd)) {
  520                 if (xs->error == XS_BUSY) {
  521                         printf("se: busy, retry txmit\n");
  522                         callout_reset(&sc->sc_ifstart_ch, hz,
  523                             se_delayed_ifstart, ifp);
  524                 } else {
  525                         ifp->if_flags &= ~IFF_OACTIVE;
  526                         /* the generic scsipi_done will call
  527                          * sestart (through scsipi_free_xs).
  528                          */
  529                 }
  530         } else if(IS_RECV(cmd)) {
  531                 /* RECV complete */
  532                 /* pass data up. reschedule a recv */
  533                 /* scsipi_free_xs will call start. Harmless. */
  534                 if (error) {
  535                         /* Reschedule after a delay */
  536                         callout_reset(&sc->sc_recv_ch, se_poll,
  537                             se_recv, (void *)sc);
  538                 } else {
  539                         int n, ntimeo;
  540                         n = se_read(sc, xs->data, xs->datalen - xs->resid);
  541                         if (n > se_max_received)
  542                                 se_max_received = n;
  543                         if (n == 0)
  544                                 ntimeo = se_poll;
  545                         else if (n >= RDATA_MAX)
  546                                 ntimeo = se_poll0;
  547                         else {
  548                                 ntimeo = sc->sc_last_timeout;
  549                                 ntimeo = (ntimeo * RDATA_GOAL)/n;
  550                                 ntimeo = (ntimeo < se_poll0?
  551                                           se_poll0: ntimeo);
  552                                 ntimeo = (ntimeo > se_poll?
  553                                           se_poll: ntimeo);
  554                         }
  555                         sc->sc_last_timeout = ntimeo;
  556                         if (ntimeo == se_poll0  &&
  557                             IFQ_IS_EMPTY(&ifp->if_snd) == 0)
  558                                 /* Output is pending. Do next recv
  559                                  * after the next send.  */
  560                                 sc->sc_flags |= SE_NEED_RECV;
  561                         else {
  562                                 callout_reset(&sc->sc_recv_ch, ntimeo,
  563                                     se_recv, (void *)sc);
  564                         }
  565                 }
  566         }
  567         splx(s);
  568 }
  569 
  570 static void
  571 se_recv(v)
  572         void *v;
  573 {
  574         /* do a recv command */
  575         struct se_softc *sc = (struct se_softc *) v;
  576         struct scsi_ctron_ether_recv recv_cmd;
  577         int error;
  578 
  579         if (sc->sc_enabled == 0)
  580                 return;
  581 
  582         PROTOCMD(ctron_ether_recv, recv_cmd);
  583 
  584         error = se_scsipi_cmd(sc->sc_periph,
  585             (struct scsipi_generic *)&recv_cmd, sizeof(recv_cmd),
  586             sc->sc_rbuf, RBUF_LEN, SERETRIES, SETIMEOUT, NULL,
  587             XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_DATA_IN);
  588         if (error)
  589                 callout_reset(&sc->sc_recv_ch, se_poll, se_recv, (void *)sc);
  590 }
  591 
  592 /*
  593  * We copy the data into mbufs.  When full cluster sized units are present
  594  * we copy into clusters.
  595  */
  596 static struct mbuf *
  597 se_get(sc, data, totlen)
  598         struct se_softc *sc;
  599         char *data;
  600         int totlen;
  601 {
  602         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  603         struct mbuf *m, *m0, *newm;
  604         int len;
  605 
  606         MGETHDR(m0, M_DONTWAIT, MT_DATA);
  607         if (m0 == 0)
  608                 return (0);
  609         m0->m_pkthdr.rcvif = ifp;
  610         m0->m_pkthdr.len = totlen;
  611         len = MHLEN;
  612         m = m0;
  613 
  614         while (totlen > 0) {
  615                 if (totlen >= MINCLSIZE) {
  616                         MCLGET(m, M_DONTWAIT);
  617                         if ((m->m_flags & M_EXT) == 0)
  618                                 goto bad;
  619                         len = MCLBYTES;
  620                 }
  621 
  622                 if (m == m0) {
  623                         caddr_t newdata = (caddr_t)
  624                             ALIGN(m->m_data + sizeof(struct ether_header)) -
  625                             sizeof(struct ether_header);
  626                         len -= newdata - m->m_data;
  627                         m->m_data = newdata;
  628                 }
  629 
  630                 m->m_len = len = min(totlen, len);
  631                 memcpy(mtod(m, caddr_t), data, len);
  632                 data += len;
  633 
  634                 totlen -= len;
  635                 if (totlen > 0) {
  636                         MGET(newm, M_DONTWAIT, MT_DATA);
  637                         if (newm == 0)
  638                                 goto bad;
  639                         len = MLEN;
  640                         m = m->m_next = newm;
  641                 }
  642         }
  643 
  644         return (m0);
  645 
  646 bad:
  647         m_freem(m0);
  648         return (0);
  649 }
  650 
  651 /*
  652  * Pass packets to higher levels.
  653  */
  654 static int
  655 se_read(sc, data, datalen)
  656         struct se_softc *sc;
  657         char *data;
  658         int datalen;
  659 {
  660         struct mbuf *m;
  661         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  662         int n;
  663 
  664         n = 0;
  665         while (datalen >= 2) {
  666                 int len = _2btol(data);
  667                 data += 2;
  668                 datalen -= 2;
  669 
  670                 if (len == 0)
  671                         break;
  672 #ifdef SEDEBUG
  673                 if (sc->sc_debug) {
  674                         printf("se_read: datalen = %d, packetlen = %d, proto = 0x%04x\n", datalen, len,
  675                          ntohs(((struct ether_header *)data)->ether_type));
  676                 }
  677 #endif
  678                 if (len <= sizeof(struct ether_header) ||
  679                     len > MAX_SNAP) {
  680 #ifdef SEDEBUG
  681                         printf("%s: invalid packet size %d; dropping\n",
  682                                sc->sc_dev.dv_xname, len);
  683 #endif
  684                         ifp->if_ierrors++;
  685                         goto next_packet;
  686                 }
  687 
  688                 /* Don't need crc. Must keep ether header for BPF */
  689                 m = se_get(sc, data, len - ETHER_CRC);
  690                 if (m == 0) {
  691 #ifdef SEDEBUG
  692                         if (sc->sc_debug)
  693                                 printf("se_read: se_get returned null\n");
  694 #endif
  695                         ifp->if_ierrors++;
  696                         goto next_packet;
  697                 }
  698                 if ((ifp->if_flags & IFF_PROMISC) != 0) {
  699                         m_adj(m, SE_PREFIX);
  700                 }
  701                 ifp->if_ipackets++;
  702 
  703 #if NBPFILTER > 0
  704                 /*
  705                  * Check if there's a BPF listener on this interface.
  706                  * If so, hand off the raw packet to BPF.
  707                  */
  708                 if (ifp->if_bpf)
  709                         bpf_mtap(ifp->if_bpf, m);
  710 #endif
  711 
  712                 /* Pass the packet up. */
  713                 (*ifp->if_input)(ifp, m);
  714 
  715         next_packet:
  716                 data += len;
  717                 datalen -= len;
  718                 n++;
  719         }
  720         return (n);
  721 }
  722 
  723 
  724 static void
  725 sewatchdog(ifp)
  726         struct ifnet *ifp;
  727 {
  728         struct se_softc *sc = ifp->if_softc;
  729 
  730         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
  731         ++ifp->if_oerrors;
  732 
  733         se_reset(sc);
  734 }
  735 
  736 static int
  737 se_reset(sc)
  738         struct se_softc *sc;
  739 {
  740         int error;
  741         int s = splnet();
  742 #if 0
  743         /* Maybe we don't *really* want to reset the entire bus
  744          * because the ctron isn't working. We would like to send a
  745          * "BUS DEVICE RESET" message, but don't think the ctron
  746          * understands it.
  747          */
  748         error = se_scsipi_cmd(sc->sc_periph, 0, 0, 0, 0, SERETRIES, 2000, NULL,
  749             XS_CTL_RESET);
  750 #endif
  751         error = se_init(sc);
  752         splx(s);
  753         return (error);
  754 }
  755 
  756 static int
  757 se_add_proto(sc, proto)
  758         struct se_softc *sc;
  759         int proto;
  760 {
  761         int error;
  762         struct scsi_ctron_ether_generic add_proto_cmd;
  763         u_int8_t data[2];
  764         _lto2b(proto, data);
  765 #ifdef SEDEBUG
  766         if (sc->sc_debug)
  767                 printf("se: adding proto 0x%02x%02x\n", data[0], data[1]);
  768 #endif
  769 
  770         PROTOCMD(ctron_ether_add_proto, add_proto_cmd);
  771         _lto2b(sizeof(data), add_proto_cmd.length);
  772         error = se_scsipi_cmd(sc->sc_periph,
  773             (struct scsipi_generic *) &add_proto_cmd, sizeof(add_proto_cmd),
  774             data, sizeof(data), SERETRIES, SETIMEOUT, NULL,
  775             XS_CTL_DATA_OUT | XS_CTL_DATA_ONSTACK);
  776         return (error);
  777 }
  778 
  779 static int
  780 se_get_addr(sc, myaddr)
  781         struct se_softc *sc;
  782         u_int8_t *myaddr;
  783 {
  784         int error;
  785         struct scsi_ctron_ether_generic get_addr_cmd;
  786 
  787         PROTOCMD(ctron_ether_get_addr, get_addr_cmd);
  788         _lto2b(ETHER_ADDR_LEN, get_addr_cmd.length);
  789         error = se_scsipi_cmd(sc->sc_periph,
  790             (struct scsipi_generic *) &get_addr_cmd, sizeof(get_addr_cmd),
  791             myaddr, ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL,
  792             XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK);
  793         printf("%s: ethernet address %s\n", sc->sc_dev.dv_xname,
  794             ether_sprintf(myaddr));
  795         return (error);
  796 }
  797 
  798 
  799 static int
  800 se_set_media(sc, type)
  801         struct se_softc *sc;
  802         int type;
  803 {
  804         int error;
  805         struct scsi_ctron_ether_generic set_media_cmd;
  806 
  807         PROTOCMD(ctron_ether_set_media, set_media_cmd);
  808         set_media_cmd.byte3 = type;
  809         error = se_scsipi_cmd(sc->sc_periph,
  810             (struct scsipi_generic *) &set_media_cmd, sizeof(set_media_cmd),
  811             0, 0, SERETRIES, SETIMEOUT, NULL, 0);
  812         return (error);
  813 }
  814 
  815 static int
  816 se_set_mode(sc, len, mode)
  817         struct se_softc *sc;
  818         int len;
  819         int mode;
  820 {
  821         int error;
  822         struct scsi_ctron_ether_set_mode set_mode_cmd;
  823 
  824         PROTOCMD(ctron_ether_set_mode, set_mode_cmd);
  825         set_mode_cmd.mode = mode;
  826         _lto2b(len, set_mode_cmd.length);
  827         error = se_scsipi_cmd(sc->sc_periph,
  828             (struct scsipi_generic *) &set_mode_cmd, sizeof(set_mode_cmd),
  829             0, 0, SERETRIES, SETIMEOUT, NULL, 0);
  830         return (error);
  831 }
  832 
  833 
  834 static int
  835 se_init(sc)
  836         struct se_softc *sc;
  837 {
  838         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  839         struct scsi_ctron_ether_generic set_addr_cmd;
  840         int error;
  841 
  842 #if NBPFILTER > 0
  843         if (ifp->if_flags & IFF_PROMISC) {
  844                 error = se_set_mode(sc, MAX_SNAP, 1);
  845         }
  846         else
  847 #endif
  848                 error = se_set_mode(sc, ETHERMTU + sizeof(struct ether_header),
  849                     0);
  850         if (error != 0)
  851                 return (error);
  852 
  853         PROTOCMD(ctron_ether_set_addr, set_addr_cmd);
  854         _lto2b(ETHER_ADDR_LEN, set_addr_cmd.length);
  855         error = se_scsipi_cmd(sc->sc_periph,
  856             (struct scsipi_generic *) &set_addr_cmd, sizeof(set_addr_cmd),
  857             LLADDR(ifp->if_sadl), ETHER_ADDR_LEN, SERETRIES, SETIMEOUT, NULL,
  858             XS_CTL_DATA_OUT);
  859         if (error != 0)
  860                 return (error);
  861 
  862         if ((sc->protos & PROTO_IP) &&
  863             (error = se_add_proto(sc, ETHERTYPE_IP)) != 0)
  864                 return (error);
  865         if ((sc->protos & PROTO_ARP) &&
  866             (error = se_add_proto(sc, ETHERTYPE_ARP)) != 0)
  867                 return (error);
  868         if ((sc->protos & PROTO_REVARP) &&
  869             (error = se_add_proto(sc, ETHERTYPE_REVARP)) != 0)
  870                 return (error);
  871 #ifdef NETATALK
  872         if ((sc->protos & PROTO_AT) &&
  873             (error = se_add_proto(sc, ETHERTYPE_ATALK)) != 0)
  874                 return (error);
  875         if ((sc->protos & PROTO_AARP) &&
  876             (error = se_add_proto(sc, ETHERTYPE_AARP)) != 0)
  877                 return (error);
  878 #endif
  879 
  880         if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == IFF_UP) {
  881                 ifp->if_flags |= IFF_RUNNING;
  882                 se_recv(sc);
  883                 ifp->if_flags &= ~IFF_OACTIVE;
  884                 se_ifstart(ifp);
  885         }
  886         return (error);
  887 }
  888 
  889 static int
  890 se_set_multi(sc, addr)
  891         struct se_softc *sc;
  892         u_int8_t *addr;
  893 {
  894         struct scsi_ctron_ether_generic set_multi_cmd;
  895         int error;
  896 
  897         if (sc->sc_debug)
  898                 printf("%s: set_set_multi: %s\n", sc->sc_dev.dv_xname,
  899                     ether_sprintf(addr));
  900 
  901         PROTOCMD(ctron_ether_set_multi, set_multi_cmd);
  902         _lto2b(sizeof(addr), set_multi_cmd.length);
  903         error = se_scsipi_cmd(sc->sc_periph,
  904             (struct scsipi_generic *) &set_multi_cmd, sizeof(set_multi_cmd),
  905             addr, sizeof(addr), SERETRIES, SETIMEOUT, NULL, XS_CTL_DATA_OUT);
  906         return (error);
  907 }
  908 
  909 static int
  910 se_remove_multi(sc, addr)
  911         struct se_softc *sc;
  912         u_int8_t *addr;
  913 {
  914         struct scsi_ctron_ether_generic remove_multi_cmd;
  915         int error;
  916 
  917         if (sc->sc_debug)
  918                 printf("%s: se_remove_multi: %s\n", sc->sc_dev.dv_xname,
  919                     ether_sprintf(addr));
  920 
  921         PROTOCMD(ctron_ether_remove_multi, remove_multi_cmd);
  922         _lto2b(sizeof(addr), remove_multi_cmd.length);
  923         error = se_scsipi_cmd(sc->sc_periph,
  924             (struct scsipi_generic *) &remove_multi_cmd,
  925             sizeof(remove_multi_cmd),
  926             addr, sizeof(addr), SERETRIES, SETIMEOUT, NULL, XS_CTL_DATA_OUT);
  927         return (error);
  928 }
  929 
  930 #if 0   /* not used  --thorpej */
  931 static int
  932 sc_set_all_multi(sc, set)
  933         struct se_softc *sc;
  934         int set;
  935 {
  936         int error = 0;
  937         u_int8_t *addr;
  938         struct ethercom *ac = &sc->sc_ethercom;
  939         struct ether_multi *enm;
  940         struct ether_multistep step;
  941 
  942         ETHER_FIRST_MULTI(step, ac, enm);
  943         while (enm != NULL) {
  944                 if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
  945                         /*
  946                          * We must listen to a range of multicast addresses.
  947                          * For now, just accept all multicasts, rather than
  948                          * trying to set only those filter bits needed to match
  949                          * the range.  (At this time, the only use of address
  950                          * ranges is for IP multicast routing, for which the
  951                          * range is big enough to require all bits set.)
  952                          */
  953                         /* We have no way of adding a range to this device.
  954                          * stepping through all addresses in the range is
  955                          * typically not possible. The only real alternative
  956                          * is to go into promicuous mode and filter by hand.
  957                          */
  958                         return (ENODEV);
  959 
  960                 }
  961 
  962                 addr = enm->enm_addrlo;
  963                 if ((error = set ? se_set_multi(sc, addr) :
  964                     se_remove_multi(sc, addr)) != 0)
  965                         return (error);
  966                 ETHER_NEXT_MULTI(step, enm);
  967         }
  968         return (error);
  969 }
  970 #endif /* not used */
  971 
  972 static void
  973 se_stop(sc)
  974         struct se_softc *sc;
  975 {
  976 
  977         /* Don't schedule any reads */
  978         callout_stop(&sc->sc_recv_ch);
  979 
  980         /* How can we abort any scsi cmds in progress? */
  981 }
  982 
  983 
  984 /*
  985  * Process an ioctl request.
  986  */
  987 static int
  988 se_ioctl(ifp, cmd, data)
  989         struct ifnet *ifp;
  990         u_long cmd;
  991         caddr_t data;
  992 {
  993         struct se_softc *sc = ifp->if_softc;
  994         struct ifaddr *ifa = (struct ifaddr *)data;
  995         struct ifreq *ifr = (struct ifreq *)data;
  996         int s, error = 0;
  997 
  998         s = splnet();
  999 
 1000         switch (cmd) {
 1001 
 1002         case SIOCSIFADDR:
 1003                 if ((error = se_enable(sc)) != 0)
 1004                         break;
 1005                 ifp->if_flags |= IFF_UP;
 1006 
 1007                 if ((error = se_set_media(sc, CMEDIA_AUTOSENSE) != 0))
 1008                         break;
 1009 
 1010                 switch (ifa->ifa_addr->sa_family) {
 1011 #ifdef INET
 1012                 case AF_INET:
 1013                         sc->protos |= (PROTO_IP | PROTO_ARP | PROTO_REVARP);
 1014                         if ((error = se_init(sc)) != 0)
 1015                                 break;
 1016                         arp_ifinit(ifp, ifa);
 1017                         break;
 1018 #endif
 1019 #ifdef NS
 1020                 case AF_NS:
 1021                     {
 1022                         struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
 1023 
 1024                         if (ns_nullhost(*ina))
 1025                                 ina->x_host =
 1026                                     *(union ns_host *)LLADDR(ifp->if_sadl);
 1027                         else
 1028                                 memcpy(LLADDR(ifp->if_sadl),
 1029                                     ina->x_host.c_host, ETHER_ADDR_LEN);
 1030                         /* Set new address. */
 1031 
 1032                         error = se_init(sc);
 1033                         break;
 1034                     }
 1035 #endif
 1036 #ifdef NETATALK
 1037                 case AF_APPLETALK:
 1038                         sc->protos |= (PROTO_AT | PROTO_AARP);
 1039                         if ((error = se_init(sc)) != 0)
 1040                                 break;
 1041                         break;
 1042 #endif
 1043                 default:
 1044                         error = se_init(sc);
 1045                         break;
 1046                 }
 1047                 break;
 1048 
 1049 #if defined(CCITT) && defined(LLC)
 1050         case SIOCSIFCONF_X25:
 1051                 if ((error = se_enable(sc)) != 0)
 1052                         break;
 1053                 ifp->if_flags |= IFF_UP;
 1054                 ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
 1055                 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
 1056                 if (error == 0)
 1057                         error = se_init(sc);
 1058                 break;
 1059 #endif /* CCITT && LLC */
 1060 
 1061         case SIOCSIFFLAGS:
 1062                 if ((ifp->if_flags & IFF_UP) == 0 &&
 1063                     (ifp->if_flags & IFF_RUNNING) != 0) {
 1064                         /*
 1065                          * If interface is marked down and it is running, then
 1066                          * stop it.
 1067                          */
 1068                         se_stop(sc);
 1069                         ifp->if_flags &= ~IFF_RUNNING;
 1070                         se_disable(sc);
 1071                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
 1072                            (ifp->if_flags & IFF_RUNNING) == 0) {
 1073                         /*
 1074                          * If interface is marked up and it is stopped, then
 1075                          * start it.
 1076                          */
 1077                         if ((error = se_enable(sc)) != 0)
 1078                                 break;
 1079                         error = se_init(sc);
 1080                 } else if (sc->sc_enabled) {
 1081                         /*
 1082                          * Reset the interface to pick up changes in any other
 1083                          * flags that affect hardware registers.
 1084                          */
 1085                         error = se_init(sc);
 1086                 }
 1087 #ifdef SEDEBUG
 1088                 if (ifp->if_flags & IFF_DEBUG)
 1089                         sc->sc_debug = 1;
 1090                 else
 1091                         sc->sc_debug = 0;
 1092 #endif
 1093                 break;
 1094 
 1095         case SIOCADDMULTI:
 1096                 if (sc->sc_enabled == 0) {
 1097                         error = EIO;
 1098                         break;
 1099                 }
 1100                 if (ether_addmulti(ifr, &sc->sc_ethercom) == ENETRESET)
 1101                         error = se_set_multi(sc, ifr->ifr_addr.sa_data);
 1102                 else
 1103                         error = 0;
 1104                 break;
 1105         case SIOCDELMULTI:
 1106                 if (sc->sc_enabled == 0) {
 1107                         error = EIO;
 1108                         break;
 1109                 }
 1110                 if (ether_delmulti(ifr, &sc->sc_ethercom) == ENETRESET)
 1111                         error = se_remove_multi(sc, ifr->ifr_addr.sa_data);
 1112                 else
 1113                         error = 0;
 1114                 break;
 1115 
 1116         default:
 1117 
 1118                 error = EINVAL;
 1119                 break;
 1120         }
 1121 
 1122         splx(s);
 1123         return (error);
 1124 }
 1125 
 1126 /*
 1127  * Enable the network interface.
 1128  */
 1129 int
 1130 se_enable(sc)
 1131         struct se_softc *sc;
 1132 {
 1133         struct scsipi_periph *periph = sc->sc_periph;
 1134         struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
 1135         int error = 0;
 1136 
 1137         if (sc->sc_enabled == 0 &&
 1138             (error = scsipi_adapter_addref(adapt)) == 0)
 1139                 sc->sc_enabled = 1;
 1140         else
 1141                 printf("%s: device enable failed\n",
 1142                     sc->sc_dev.dv_xname);
 1143 
 1144         return (error);
 1145 }
 1146 
 1147 /*
 1148  * Disable the network interface.
 1149  */
 1150 void
 1151 se_disable(sc)
 1152         struct se_softc *sc;
 1153 {
 1154         struct scsipi_periph *periph = sc->sc_periph;
 1155         struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
 1156 
 1157         if (sc->sc_enabled != 0) {
 1158                 scsipi_adapter_delref(adapt);
 1159                 sc->sc_enabled = 0;
 1160         }
 1161 }
 1162 
 1163 #define SEUNIT(z)       (minor(z))
 1164 /*
 1165  * open the device.
 1166  */
 1167 int
 1168 seopen(dev, flag, fmt, p)
 1169         dev_t dev;
 1170         int flag, fmt;
 1171         struct proc *p;
 1172 {
 1173         int unit, error;
 1174         struct se_softc *sc;
 1175         struct scsipi_periph *periph;
 1176         struct scsipi_adapter *adapt;
 1177 
 1178         unit = SEUNIT(dev);
 1179         if (unit >= se_cd.cd_ndevs)
 1180                 return (ENXIO);
 1181         sc = se_cd.cd_devs[unit];
 1182         if (sc == NULL)
 1183                 return (ENXIO);
 1184 
 1185         periph = sc->sc_periph;
 1186         adapt = periph->periph_channel->chan_adapter;
 1187 
 1188         if ((error = scsipi_adapter_addref(adapt)) != 0)
 1189                 return (error);
 1190 
 1191         SC_DEBUG(periph, SCSIPI_DB1,
 1192             ("scopen: dev=0x%x (unit %d (of %d))\n", dev, unit,
 1193             se_cd.cd_ndevs));
 1194 
 1195         periph->periph_flags |= PERIPH_OPEN;
 1196 
 1197         SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
 1198         return (0);
 1199 }
 1200 
 1201 /*
 1202  * close the device.. only called if we are the LAST
 1203  * occurence of an open device
 1204  */
 1205 int
 1206 seclose(dev, flag, fmt, p)
 1207         dev_t dev;
 1208         int flag, fmt;
 1209         struct proc *p;
 1210 {
 1211         struct se_softc *sc = se_cd.cd_devs[SEUNIT(dev)];
 1212         struct scsipi_periph *periph = sc->sc_periph;
 1213         struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
 1214 
 1215         SC_DEBUG(sc->sc_periph, SCSIPI_DB1, ("closing\n"));
 1216 
 1217         scsipi_wait_drain(periph);
 1218 
 1219         scsipi_adapter_delref(adapt);
 1220         periph->periph_flags &= ~PERIPH_OPEN;
 1221 
 1222         return (0);
 1223 }
 1224 
 1225 /*
 1226  * Perform special action on behalf of the user
 1227  * Only does generic scsi ioctls.
 1228  */
 1229 int
 1230 seioctl(dev, cmd, addr, flag, p)
 1231         dev_t dev;
 1232         u_long cmd;
 1233         caddr_t addr;
 1234         int flag;
 1235         struct proc *p;
 1236 {
 1237         struct se_softc *sc = se_cd.cd_devs[SEUNIT(dev)];
 1238 
 1239         return (scsipi_do_ioctl(sc->sc_periph, dev, cmd, addr, flag, p));
 1240 }

Cache object: 99010e0d2ff97a1077e3908debebdea8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.