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/cam/ctl/ctl_frontend.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) 2003 Silicon Graphics International Corp.
    5  * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org>
    6  * All rights reserved.
    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  *    without modification.
   14  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   15  *    substantially similar to the "NO WARRANTY" disclaimer below
   16  *    ("Disclaimer") and any redistribution must be conditioned upon
   17  *    including a substantially similar Disclaimer requirement for further
   18  *    binary redistribution.
   19  *
   20  * NO WARRANTY
   21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   25  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGES.
   32  *
   33  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend.c#4 $
   34  */
   35 /*
   36  * CAM Target Layer front end interface code
   37  *
   38  * Author: Ken Merry <ken@FreeBSD.org>
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __FBSDID("$FreeBSD$");
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/types.h>
   48 #include <sys/malloc.h>
   49 #include <sys/lock.h>
   50 #include <sys/mutex.h>
   51 #include <sys/condvar.h>
   52 #include <sys/endian.h>
   53 #include <sys/queue.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/nv.h>
   56 #include <sys/dnv.h>
   57 
   58 #include <cam/scsi/scsi_all.h>
   59 #include <cam/scsi/scsi_da.h>
   60 #include <cam/ctl/ctl_io.h>
   61 #include <cam/ctl/ctl.h>
   62 #include <cam/ctl/ctl_frontend.h>
   63 #include <cam/ctl/ctl_backend.h>
   64 /* XXX KDM move defines from ctl_ioctl.h to somewhere else */
   65 #include <cam/ctl/ctl_ioctl.h>
   66 #include <cam/ctl/ctl_ha.h>
   67 #include <cam/ctl/ctl_private.h>
   68 #include <cam/ctl/ctl_debug.h>
   69 
   70 extern struct ctl_softc *control_softc;
   71 
   72 int
   73 ctl_frontend_register(struct ctl_frontend *fe)
   74 {
   75         struct ctl_softc *softc = control_softc;
   76         struct ctl_frontend *fe_tmp;
   77         int error;
   78 
   79         KASSERT(softc != NULL, ("CTL is not initialized"));
   80 
   81         /* Sanity check, make sure this isn't a duplicate registration. */
   82         mtx_lock(&softc->ctl_lock);
   83         STAILQ_FOREACH(fe_tmp, &softc->fe_list, links) {
   84                 if (strcmp(fe_tmp->name, fe->name) == 0) {
   85                         mtx_unlock(&softc->ctl_lock);
   86                         return (-1);
   87                 }
   88         }
   89         mtx_unlock(&softc->ctl_lock);
   90         STAILQ_INIT(&fe->port_list);
   91 
   92         /* Call the frontend's initialization routine. */
   93         if (fe->init != NULL) {
   94                 if ((error = fe->init()) != 0) {
   95                         printf("%s frontend init error: %d\n",
   96                             fe->name, error);
   97                         return (error);
   98                 }
   99         }
  100 
  101         mtx_lock(&softc->ctl_lock);
  102         softc->num_frontends++;
  103         STAILQ_INSERT_TAIL(&softc->fe_list, fe, links);
  104         mtx_unlock(&softc->ctl_lock);
  105         return (0);
  106 }
  107 
  108 int
  109 ctl_frontend_deregister(struct ctl_frontend *fe)
  110 {
  111         struct ctl_softc *softc = control_softc;
  112         int error;
  113 
  114         /* Call the frontend's shutdown routine.*/
  115         if (fe->shutdown != NULL) {
  116                 if ((error = fe->shutdown()) != 0) {
  117                         printf("%s frontend shutdown error: %d\n",
  118                             fe->name, error);
  119                         return (error);
  120                 }
  121         }
  122 
  123         mtx_lock(&softc->ctl_lock);
  124         STAILQ_REMOVE(&softc->fe_list, fe, ctl_frontend, links);
  125         softc->num_frontends--;
  126         mtx_unlock(&softc->ctl_lock);
  127         return (0);
  128 }
  129 
  130 struct ctl_frontend *
  131 ctl_frontend_find(char *frontend_name)
  132 {
  133         struct ctl_softc *softc = control_softc;
  134         struct ctl_frontend *fe;
  135 
  136         mtx_lock(&softc->ctl_lock);
  137         STAILQ_FOREACH(fe, &softc->fe_list, links) {
  138                 if (strcmp(fe->name, frontend_name) == 0) {
  139                         mtx_unlock(&softc->ctl_lock);
  140                         return (fe);
  141                 }
  142         }
  143         mtx_unlock(&softc->ctl_lock);
  144         return (NULL);
  145 }
  146 
  147 int
  148 ctl_port_register(struct ctl_port *port)
  149 {
  150         struct ctl_softc *softc = control_softc;
  151         struct ctl_port *tport, *nport;
  152         void *pool;
  153         int port_num;
  154         int retval;
  155 
  156         KASSERT(softc != NULL, ("CTL is not initialized"));
  157         port->ctl_softc = softc;
  158 
  159         mtx_lock(&softc->ctl_lock);
  160         if (port->targ_port >= 0)
  161                 port_num = port->targ_port;
  162         else
  163                 port_num = ctl_ffz(softc->ctl_port_mask,
  164                     softc->port_min, softc->port_max);
  165         if ((port_num < 0) ||
  166             (ctl_set_mask(softc->ctl_port_mask, port_num) < 0)) {
  167                 mtx_unlock(&softc->ctl_lock);
  168                 return (1);
  169         }
  170         softc->num_ports++;
  171         mtx_unlock(&softc->ctl_lock);
  172 
  173         /*
  174          * Initialize the initiator and portname mappings
  175          */
  176         port->max_initiators = CTL_MAX_INIT_PER_PORT;
  177         port->wwpn_iid = malloc(sizeof(*port->wwpn_iid) * port->max_initiators,
  178             M_CTL, M_NOWAIT | M_ZERO);
  179         if (port->wwpn_iid == NULL) {
  180                 retval = ENOMEM;
  181                 goto error;
  182         }
  183 
  184         /*
  185          * We add 20 to whatever the caller requests, so he doesn't get
  186          * burned by queueing things back to the pending sense queue.  In
  187          * theory, there should probably only be one outstanding item, at
  188          * most, on the pending sense queue for a LUN.  We'll clear the
  189          * pending sense queue on the next command, whether or not it is
  190          * a REQUEST SENSE.
  191          */
  192         retval = ctl_pool_create(softc, port->port_name,
  193                                  port->num_requested_ctl_io + 20, &pool);
  194         if (retval != 0) {
  195                 free(port->wwpn_iid, M_CTL);
  196 error:
  197                 port->targ_port = -1;
  198                 mtx_lock(&softc->ctl_lock);
  199                 ctl_clear_mask(softc->ctl_port_mask, port_num);
  200                 mtx_unlock(&softc->ctl_lock);
  201                 return (retval);
  202         }
  203         port->targ_port = port_num;
  204         port->ctl_pool_ref = pool;
  205         if (port->options == NULL)
  206                 port->options = nvlist_create(0);
  207         port->stats.item = port_num;
  208         mtx_init(&port->port_lock, "CTL port", NULL, MTX_DEF);
  209 
  210         mtx_lock(&softc->ctl_lock);
  211         STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links);
  212         for (tport = NULL, nport = STAILQ_FIRST(&softc->port_list);
  213             nport != NULL && nport->targ_port < port_num;
  214             tport = nport, nport = STAILQ_NEXT(tport, links)) {
  215         }
  216         if (tport)
  217                 STAILQ_INSERT_AFTER(&softc->port_list, tport, port, links);
  218         else
  219                 STAILQ_INSERT_HEAD(&softc->port_list, port, links);
  220         softc->ctl_ports[port->targ_port] = port;
  221         mtx_unlock(&softc->ctl_lock);
  222 
  223         return (retval);
  224 }
  225 
  226 int
  227 ctl_port_deregister(struct ctl_port *port)
  228 {
  229         struct ctl_softc *softc = port->ctl_softc;
  230         struct ctl_io_pool *pool = (struct ctl_io_pool *)port->ctl_pool_ref;
  231         int i;
  232 
  233         if (port->targ_port == -1)
  234                 return (1);
  235 
  236         mtx_lock(&softc->ctl_lock);
  237         STAILQ_REMOVE(&softc->port_list, port, ctl_port, links);
  238         STAILQ_REMOVE(&port->frontend->port_list, port, ctl_port, fe_links);
  239         softc->num_ports--;
  240         ctl_clear_mask(softc->ctl_port_mask, port->targ_port);
  241         softc->ctl_ports[port->targ_port] = NULL;
  242         mtx_unlock(&softc->ctl_lock);
  243 
  244         ctl_pool_free(pool);
  245         nvlist_destroy(port->options);
  246 
  247         ctl_lun_map_deinit(port);
  248         free(port->port_devid, M_CTL);
  249         port->port_devid = NULL;
  250         free(port->target_devid, M_CTL);
  251         port->target_devid = NULL;
  252         free(port->init_devid, M_CTL);
  253         port->init_devid = NULL;
  254         for (i = 0; i < port->max_initiators; i++)
  255                 free(port->wwpn_iid[i].name, M_CTL);
  256         free(port->wwpn_iid, M_CTL);
  257         mtx_destroy(&port->port_lock);
  258 
  259         return (0);
  260 }
  261 
  262 void
  263 ctl_port_set_wwns(struct ctl_port *port, int wwnn_valid, uint64_t wwnn,
  264                       int wwpn_valid, uint64_t wwpn)
  265 {
  266         struct scsi_vpd_id_descriptor *desc;
  267         int len, proto;
  268 
  269         if (port->port_type == CTL_PORT_FC)
  270                 proto = SCSI_PROTO_FC << 4;
  271         else if (port->port_type == CTL_PORT_SAS)
  272                 proto = SCSI_PROTO_SAS << 4;
  273         else if (port->port_type == CTL_PORT_ISCSI)
  274                 proto = SCSI_PROTO_ISCSI << 4;
  275         else
  276                 proto = SCSI_PROTO_SPI << 4;
  277 
  278         if (wwnn_valid) {
  279                 port->wwnn = wwnn;
  280 
  281                 free(port->target_devid, M_CTL);
  282 
  283                 len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
  284                 port->target_devid = malloc(sizeof(struct ctl_devid) + len,
  285                     M_CTL, M_WAITOK | M_ZERO);
  286                 port->target_devid->len = len;
  287                 desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
  288                 desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
  289                 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
  290                     SVPD_ID_TYPE_NAA;
  291                 desc->length = CTL_WWPN_LEN;
  292                 scsi_u64to8b(port->wwnn, desc->identifier);
  293         }
  294 
  295         if (wwpn_valid) {
  296                 port->wwpn = wwpn;
  297 
  298                 free(port->port_devid, M_CTL);
  299 
  300                 len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
  301                 port->port_devid = malloc(sizeof(struct ctl_devid) + len,
  302                     M_CTL, M_WAITOK | M_ZERO);
  303                 port->port_devid->len = len;
  304                 desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
  305                 desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
  306                 desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
  307                     SVPD_ID_TYPE_NAA;
  308                 desc->length = CTL_WWPN_LEN;
  309                 scsi_u64to8b(port->wwpn, desc->identifier);
  310         }
  311 }
  312 
  313 void
  314 ctl_port_online(struct ctl_port *port)
  315 {
  316         struct ctl_softc *softc = port->ctl_softc;
  317         struct ctl_lun *lun;
  318         const char *value;
  319         uint32_t l;
  320 
  321         if (port->lun_enable != NULL) {
  322                 if (port->lun_map) {
  323                         for (l = 0; l < port->lun_map_size; l++) {
  324                                 if (ctl_lun_map_from_port(port, l) ==
  325                                     UINT32_MAX)
  326                                         continue;
  327                                 port->lun_enable(port->targ_lun_arg, l);
  328                         }
  329                 } else {
  330                         STAILQ_FOREACH(lun, &softc->lun_list, links)
  331                                 port->lun_enable(port->targ_lun_arg, lun->lun);
  332                 }
  333         }
  334         if (port->port_online != NULL)
  335                 port->port_online(port->onoff_arg);
  336         mtx_lock(&softc->ctl_lock);
  337         if (softc->is_single == 0) {
  338                 value = dnvlist_get_string(port->options, "ha_shared", NULL);
  339                 if (value != NULL && strcmp(value, "on") == 0)
  340                         port->status |= CTL_PORT_STATUS_HA_SHARED;
  341                 else
  342                         port->status &= ~CTL_PORT_STATUS_HA_SHARED;
  343         }
  344         port->status |= CTL_PORT_STATUS_ONLINE;
  345         STAILQ_FOREACH(lun, &softc->lun_list, links) {
  346                 if (ctl_lun_map_to_port(port, lun->lun) == UINT32_MAX)
  347                         continue;
  348                 mtx_lock(&lun->lun_lock);
  349                 ctl_est_ua_all(lun, -1, CTL_UA_INQ_CHANGE);
  350                 mtx_unlock(&lun->lun_lock);
  351         }
  352         mtx_unlock(&softc->ctl_lock);
  353         ctl_isc_announce_port(port);
  354 }
  355 
  356 void
  357 ctl_port_offline(struct ctl_port *port)
  358 {
  359         struct ctl_softc *softc = port->ctl_softc;
  360         struct ctl_lun *lun;
  361         uint32_t l;
  362 
  363         if (port->port_offline != NULL)
  364                 port->port_offline(port->onoff_arg);
  365         if (port->lun_disable != NULL) {
  366                 if (port->lun_map) {
  367                         for (l = 0; l < port->lun_map_size; l++) {
  368                                 if (ctl_lun_map_from_port(port, l) ==
  369                                     UINT32_MAX)
  370                                         continue;
  371                                 port->lun_disable(port->targ_lun_arg, l);
  372                         }
  373                 } else {
  374                         STAILQ_FOREACH(lun, &softc->lun_list, links)
  375                                 port->lun_disable(port->targ_lun_arg, lun->lun);
  376                 }
  377         }
  378         mtx_lock(&softc->ctl_lock);
  379         port->status &= ~CTL_PORT_STATUS_ONLINE;
  380         STAILQ_FOREACH(lun, &softc->lun_list, links) {
  381                 if (ctl_lun_map_to_port(port, lun->lun) == UINT32_MAX)
  382                         continue;
  383                 mtx_lock(&lun->lun_lock);
  384                 ctl_est_ua_all(lun, -1, CTL_UA_INQ_CHANGE);
  385                 mtx_unlock(&lun->lun_lock);
  386         }
  387         mtx_unlock(&softc->ctl_lock);
  388         ctl_isc_announce_port(port);
  389 }
  390 
  391 /*
  392  * vim: ts=8
  393  */

Cache object: a20f24a0523cf6fda7092e720857c578


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