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/iscsi/icl.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2012 The FreeBSD Foundation
    5  *
    6  * This software was developed by Edward Tomasz Napierala under sponsorship
    7  * from the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  *
   30  */
   31 
   32 /*
   33  * iSCSI Common Layer.  It's used by both the initiator and target to send
   34  * and receive iSCSI PDUs.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD$");
   39 
   40 #include <sys/param.h>
   41 #include <sys/condvar.h>
   42 #include <sys/conf.h>
   43 #include <sys/lock.h>
   44 #include <sys/kernel.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mutex.h>
   47 #include <sys/module.h>
   48 #include <sys/queue.h>
   49 #include <sys/sbuf.h>
   50 #include <sys/socket.h>
   51 #include <sys/sysctl.h>
   52 #include <sys/systm.h>
   53 #include <sys/sx.h>
   54 
   55 #include <dev/iscsi/icl.h>
   56 #include <icl_conn_if.h>
   57 
   58 struct icl_module {
   59         TAILQ_ENTRY(icl_module)         im_next;
   60         char                            *im_name;
   61         bool                            im_iser;
   62         int                             im_priority;
   63         int                             (*im_limits)(struct icl_drv_limits *idl,
   64                                             int socket);
   65         struct icl_conn                 *(*im_new_conn)(const char *name,
   66                                             struct mtx *lock);
   67 };
   68 
   69 struct icl_softc {
   70         struct sx                       sc_lock;
   71         TAILQ_HEAD(, icl_module)        sc_modules;
   72 };
   73 
   74 static int sysctl_kern_icl_offloads(SYSCTL_HANDLER_ARGS);
   75 static MALLOC_DEFINE(M_ICL, "icl", "iSCSI Common Layer");
   76 static struct icl_softc *sc;
   77 
   78 SYSCTL_NODE(_kern, OID_AUTO, icl, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
   79     "iSCSI Common Layer");
   80 int icl_debug = 1;
   81 SYSCTL_INT(_kern_icl, OID_AUTO, debug, CTLFLAG_RWTUN,
   82     &icl_debug, 0, "Enable debug messages");
   83 SYSCTL_PROC(_kern_icl, OID_AUTO, offloads,
   84     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
   85     NULL, false, sysctl_kern_icl_offloads, "A",
   86     "List of ICL modules");
   87 SYSCTL_PROC(_kern_icl, OID_AUTO, iser_offloads,
   88     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
   89     NULL, true, sysctl_kern_icl_offloads, "A",
   90     "List of iSER ICL modules");
   91 
   92 static int
   93 sysctl_kern_icl_offloads(SYSCTL_HANDLER_ARGS)
   94 {
   95         const struct icl_module *im;
   96         struct sbuf sb;
   97         bool iser = arg2;
   98         int error;
   99 
  100         sbuf_new(&sb, NULL, 256, SBUF_AUTOEXTEND | SBUF_INCLUDENUL);
  101 
  102         sx_slock(&sc->sc_lock);
  103         TAILQ_FOREACH(im, &sc->sc_modules, im_next) {
  104                 if (im->im_iser != iser)
  105                         continue;
  106                 if (im != TAILQ_FIRST(&sc->sc_modules))
  107                         sbuf_putc(&sb, ' ');
  108                 sbuf_printf(&sb, "%s", im->im_name);
  109         }
  110         sx_sunlock(&sc->sc_lock);
  111 
  112         error = sbuf_finish(&sb);
  113         if (error == 0)
  114                 error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
  115         sbuf_delete(&sb);
  116         return (error);
  117 }
  118 
  119 static struct icl_module *
  120 icl_find(const char *name, bool iser, bool quiet)
  121 {
  122         struct icl_module *im, *im_max;
  123 
  124         sx_assert(&sc->sc_lock, SA_LOCKED);
  125 
  126         /*
  127          * If the name was not specified, pick a module with highest
  128          * priority.
  129          */
  130         if (name == NULL || name[0] == '\0') {
  131                 im_max = NULL;
  132                 TAILQ_FOREACH(im, &sc->sc_modules, im_next) {
  133                         if (im->im_iser != iser)
  134                                 continue;
  135                         if (im_max == NULL ||
  136                             im->im_priority > im_max->im_priority)
  137                                 im_max = im;
  138                 }
  139 
  140                 if (iser && im_max == NULL && !quiet)
  141                         ICL_WARN("no iSER-capable offload found");
  142 
  143                 return (im_max);
  144         }
  145 
  146         TAILQ_FOREACH(im, &sc->sc_modules, im_next) {
  147                 if (strcasecmp(im->im_name, name) != 0)
  148                         continue;
  149 
  150                 if (!im->im_iser && iser && !quiet) {
  151                         ICL_WARN("offload \"%s\" is not iSER-capable", name);
  152                         return (NULL);
  153                 }
  154                 if (im->im_iser && !iser && !quiet) {
  155                         ICL_WARN("offload \"%s\" is iSER-only", name);
  156                         return (NULL);
  157                 }
  158 
  159                 return (im);
  160         }
  161 
  162         if (!quiet)
  163                 ICL_WARN("offload \"%s\" not found", name);
  164 
  165         return (NULL);
  166 }
  167 
  168 struct icl_conn *
  169 icl_new_conn(const char *offload, bool iser, const char *name, struct mtx *lock)
  170 {
  171         struct icl_module *im;
  172         struct icl_conn *ic;
  173 
  174         sx_slock(&sc->sc_lock);
  175         im = icl_find(offload, iser, false);
  176         if (im == NULL) {
  177                 sx_sunlock(&sc->sc_lock);
  178                 return (NULL);
  179         }
  180 
  181         ic = im->im_new_conn(name, lock);
  182         sx_sunlock(&sc->sc_lock);
  183 
  184         return (ic);
  185 }
  186 
  187 int
  188 icl_limits(const char *offload, bool iser, int socket,
  189     struct icl_drv_limits *idl)
  190 {
  191         struct icl_module *im;
  192         int error;
  193 
  194         bzero(idl, sizeof(*idl));
  195         sx_slock(&sc->sc_lock);
  196         im = icl_find(offload, iser, false);
  197         if (im == NULL) {
  198                 sx_sunlock(&sc->sc_lock);
  199                 return (ENXIO);
  200         }
  201 
  202         error = im->im_limits(idl, socket);
  203         sx_sunlock(&sc->sc_lock);
  204 
  205         /*
  206          * Validate the limits provided by the driver against values allowed by
  207          * the iSCSI RFC.  0 means iscsid/ctld should pick a reasonable value.
  208          *
  209          * Note that max_send_dsl is an internal implementation detail and not
  210          * part of the RFC.
  211          */
  212 #define OUT_OF_RANGE(x, lo, hi) ((x) != 0 && ((x) < (lo) || (x) > (hi)))
  213         if (error == 0 &&
  214             (OUT_OF_RANGE(idl->idl_max_recv_data_segment_length, 512, 16777215) ||
  215             OUT_OF_RANGE(idl->idl_max_send_data_segment_length, 512, 16777215) ||
  216             OUT_OF_RANGE(idl->idl_max_burst_length, 512, 16777215) ||
  217             OUT_OF_RANGE(idl->idl_first_burst_length, 512, 16777215))) {
  218                 error = EINVAL;
  219         }
  220 #undef OUT_OF_RANGE
  221 
  222         /*
  223          * If both first_burst and max_burst are provided then first_burst must
  224          * not exceed max_burst.
  225          */
  226         if (error == 0 && idl->idl_first_burst_length > 0 &&
  227             idl->idl_max_burst_length > 0 &&
  228             idl->idl_first_burst_length > idl->idl_max_burst_length) {
  229                 error = EINVAL;
  230         }
  231 
  232         return (error);
  233 }
  234 
  235 int
  236 icl_register(const char *offload, bool iser, int priority,
  237     int (*limits)(struct icl_drv_limits *, int),
  238     struct icl_conn *(*new_conn)(const char *, struct mtx *))
  239 {
  240         struct icl_module *im;
  241 
  242         sx_xlock(&sc->sc_lock);
  243         im = icl_find(offload, iser, true);
  244         if (im != NULL) {
  245                 ICL_WARN("offload \"%s\" already registered", offload);
  246                 sx_xunlock(&sc->sc_lock);
  247                 return (EBUSY);
  248         }
  249 
  250         im = malloc(sizeof(*im), M_ICL, M_ZERO | M_WAITOK);
  251         im->im_name = strdup(offload, M_ICL);
  252         im->im_iser = iser;
  253         im->im_priority = priority;
  254         im->im_limits = limits;
  255         im->im_new_conn = new_conn;
  256 
  257         TAILQ_INSERT_HEAD(&sc->sc_modules, im, im_next);
  258         sx_xunlock(&sc->sc_lock);
  259 
  260         ICL_DEBUG("offload \"%s\" registered", offload);
  261         return (0);
  262 }
  263 
  264 int
  265 icl_unregister(const char *offload, bool rdma)
  266 {
  267         struct icl_module *im;
  268 
  269         sx_xlock(&sc->sc_lock);
  270         im = icl_find(offload, rdma, true);
  271         if (im == NULL) {
  272                 ICL_WARN("offload \"%s\" not registered", offload);
  273                 sx_xunlock(&sc->sc_lock);
  274                 return (ENXIO);
  275         }
  276 
  277         TAILQ_REMOVE(&sc->sc_modules, im, im_next);
  278         sx_xunlock(&sc->sc_lock);
  279 
  280         free(im->im_name, M_ICL);
  281         free(im, M_ICL);
  282 
  283         ICL_DEBUG("offload \"%s\" unregistered", offload);
  284         return (0);
  285 }
  286 
  287 static int
  288 icl_load(void)
  289 {
  290 
  291         sc = malloc(sizeof(*sc), M_ICL, M_ZERO | M_WAITOK);
  292         sx_init(&sc->sc_lock, "icl");
  293         TAILQ_INIT(&sc->sc_modules);
  294 
  295         return (0);
  296 }
  297 
  298 static int
  299 icl_unload(void)
  300 {
  301 
  302         sx_slock(&sc->sc_lock);
  303         KASSERT(TAILQ_EMPTY(&sc->sc_modules), ("still have modules"));
  304         sx_sunlock(&sc->sc_lock);
  305 
  306         sx_destroy(&sc->sc_lock);
  307         free(sc, M_ICL);
  308 
  309         return (0);
  310 }
  311 
  312 static int
  313 icl_modevent(module_t mod, int what, void *arg)
  314 {
  315 
  316         switch (what) {
  317         case MOD_LOAD:
  318                 return (icl_load());
  319         case MOD_UNLOAD:
  320                 return (icl_unload());
  321         default:
  322                 return (EINVAL);
  323         }
  324 }
  325 
  326 moduledata_t icl_data = {
  327         "icl",
  328         icl_modevent,
  329         0
  330 };
  331 
  332 DECLARE_MODULE(icl, icl_data, SI_SUB_DRIVERS, SI_ORDER_FIRST);
  333 MODULE_VERSION(icl, 1);

Cache object: 33788e218caef8081d86471306a3c4d0


[ 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.