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_tpc_local.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) 2014 Alexander Motin <mav@FreeBSD.org>
    5  * Copyright (c) 2004, 2005 Silicon Graphics International Corp.
    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, immediately at the beginning of the file.
   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 ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/types.h>
   37 #include <sys/lock.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 #include <sys/condvar.h>
   41 #include <sys/malloc.h>
   42 #include <sys/conf.h>
   43 #include <sys/queue.h>
   44 #include <sys/sysctl.h>
   45 
   46 #include <cam/cam.h>
   47 #include <cam/scsi/scsi_all.h>
   48 #include <cam/scsi/scsi_da.h>
   49 #include <cam/ctl/ctl_io.h>
   50 #include <cam/ctl/ctl.h>
   51 #include <cam/ctl/ctl_frontend.h>
   52 #include <cam/ctl/ctl_util.h>
   53 #include <cam/ctl/ctl_backend.h>
   54 #include <cam/ctl/ctl_ioctl.h>
   55 #include <cam/ctl/ctl_ha.h>
   56 #include <cam/ctl/ctl_private.h>
   57 #include <cam/ctl/ctl_debug.h>
   58 #include <cam/ctl/ctl_scsi_all.h>
   59 #include <cam/ctl/ctl_tpc.h>
   60 #include <cam/ctl/ctl_error.h>
   61 
   62 struct tpcl_softc {
   63         struct ctl_port port;
   64         u_int cur_tag_num;
   65 };
   66 
   67 static struct tpcl_softc tpcl_softc;
   68 
   69 static int tpcl_init(void);
   70 static int tpcl_shutdown(void);
   71 static void tpcl_datamove(union ctl_io *io);
   72 static void tpcl_done(union ctl_io *io);
   73 
   74 static struct ctl_frontend tpcl_frontend =
   75 {
   76         .name = "tpc",
   77         .init = tpcl_init,
   78         .shutdown = tpcl_shutdown,
   79 };
   80 CTL_FRONTEND_DECLARE(ctltpc, tpcl_frontend);
   81 
   82 static int
   83 tpcl_init(void)
   84 {
   85         struct tpcl_softc *tsoftc = &tpcl_softc;
   86         struct ctl_port *port;
   87         struct scsi_transportid_spi *tid;
   88         int error, len;
   89 
   90         memset(tsoftc, 0, sizeof(*tsoftc));
   91 
   92         port = &tsoftc->port;
   93         port->frontend = &tpcl_frontend;
   94         port->port_type = CTL_PORT_INTERNAL;
   95         port->num_requested_ctl_io = 100;
   96         port->port_name = "tpc";
   97         port->fe_datamove = tpcl_datamove;
   98         port->fe_done = tpcl_done;
   99         port->targ_port = -1;
  100         port->max_initiators = 1;
  101 
  102         if ((error = ctl_port_register(port)) != 0) {
  103                 printf("%s: tpc port registration failed\n", __func__);
  104                 return (error);
  105         }
  106 
  107         len = sizeof(struct scsi_transportid_spi);
  108         port->init_devid = malloc(sizeof(struct ctl_devid) + len,
  109             M_CTL, M_WAITOK | M_ZERO);
  110         port->init_devid->len = len;
  111         tid = (struct scsi_transportid_spi *)port->init_devid->data;
  112         tid->format_protocol = SCSI_TRN_SPI_FORMAT_DEFAULT | SCSI_PROTO_SPI;
  113         scsi_ulto2b(0, tid->scsi_addr);
  114         scsi_ulto2b(port->targ_port, tid->rel_trgt_port_id);
  115 
  116         ctl_port_online(port);
  117         return (0);
  118 }
  119 
  120 static int
  121 tpcl_shutdown(void)
  122 {
  123         struct tpcl_softc *tsoftc = &tpcl_softc;
  124         struct ctl_port *port = &tsoftc->port;
  125         int error;
  126 
  127         ctl_port_offline(port);
  128         if ((error = ctl_port_deregister(port)) != 0)
  129                 printf("%s: tpc port deregistration failed\n", __func__);
  130         return (error);
  131 }
  132 
  133 static void
  134 tpcl_datamove(union ctl_io *io)
  135 {
  136         struct ctl_sg_entry *ext_sglist, *kern_sglist;
  137         struct ctl_sg_entry ext_entry, kern_entry;
  138         int ext_sg_entries, kern_sg_entries;
  139         int ext_sg_start, ext_offset;
  140         int len_to_copy;
  141         int kern_watermark, ext_watermark;
  142         struct ctl_scsiio *ctsio;
  143         int i, j;
  144 
  145         CTL_DEBUG_PRINT(("%s\n", __func__));
  146 
  147         ctsio = &io->scsiio;
  148 
  149         /*
  150          * If this is the case, we're probably doing a BBR read and don't
  151          * actually need to transfer the data.  This will effectively
  152          * bit-bucket the data.
  153          */
  154         if (ctsio->ext_data_ptr == NULL)
  155                 goto bailout;
  156 
  157         /*
  158          * To simplify things here, if we have a single buffer, stick it in
  159          * a S/G entry and just make it a single entry S/G list.
  160          */
  161         if (ctsio->ext_sg_entries > 0) {
  162                 int len_seen;
  163 
  164                 ext_sglist = (struct ctl_sg_entry *)ctsio->ext_data_ptr;
  165                 ext_sg_entries = ctsio->ext_sg_entries;
  166                 ext_sg_start = 0;
  167                 ext_offset = 0;
  168                 len_seen = 0;
  169                 for (i = 0; i < ext_sg_entries; i++) {
  170                         if ((len_seen + ext_sglist[i].len) >=
  171                              ctsio->ext_data_filled) {
  172                                 ext_sg_start = i;
  173                                 ext_offset = ctsio->ext_data_filled - len_seen;
  174                                 break;
  175                         }
  176                         len_seen += ext_sglist[i].len;
  177                 }
  178         } else {
  179                 ext_sglist = &ext_entry;
  180                 ext_sglist->addr = ctsio->ext_data_ptr;
  181                 ext_sglist->len = ctsio->ext_data_len;
  182                 ext_sg_entries = 1;
  183                 ext_sg_start = 0;
  184                 ext_offset = ctsio->ext_data_filled;
  185         }
  186 
  187         if (ctsio->kern_sg_entries > 0) {
  188                 kern_sglist = (struct ctl_sg_entry *)ctsio->kern_data_ptr;
  189                 kern_sg_entries = ctsio->kern_sg_entries;
  190         } else {
  191                 kern_sglist = &kern_entry;
  192                 kern_sglist->addr = ctsio->kern_data_ptr;
  193                 kern_sglist->len = ctsio->kern_data_len;
  194                 kern_sg_entries = 1;
  195         }
  196 
  197         kern_watermark = 0;
  198         ext_watermark = ext_offset;
  199         for (i = ext_sg_start, j = 0;
  200              i < ext_sg_entries && j < kern_sg_entries;) {
  201                 uint8_t *ext_ptr, *kern_ptr;
  202 
  203                 len_to_copy = min(ext_sglist[i].len - ext_watermark,
  204                                   kern_sglist[j].len - kern_watermark);
  205 
  206                 ext_ptr = (uint8_t *)ext_sglist[i].addr;
  207                 ext_ptr = ext_ptr + ext_watermark;
  208                 if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {
  209                         /*
  210                          * XXX KDM fix this!
  211                          */
  212                         panic("need to implement bus address support");
  213 #if 0
  214                         kern_ptr = bus_to_virt(kern_sglist[j].addr);
  215 #endif
  216                 } else
  217                         kern_ptr = (uint8_t *)kern_sglist[j].addr;
  218                 kern_ptr = kern_ptr + kern_watermark;
  219 
  220                 if ((ctsio->io_hdr.flags & CTL_FLAG_DATA_MASK) ==
  221                      CTL_FLAG_DATA_IN) {
  222                         CTL_DEBUG_PRINT(("%s: copying %d bytes to user\n",
  223                                          __func__, len_to_copy));
  224                         CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
  225                                          kern_ptr, ext_ptr));
  226                         memcpy(ext_ptr, kern_ptr, len_to_copy);
  227                 } else {
  228                         CTL_DEBUG_PRINT(("%s: copying %d bytes from user\n",
  229                                          __func__, len_to_copy));
  230                         CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__,
  231                                          ext_ptr, kern_ptr));
  232                         memcpy(kern_ptr, ext_ptr, len_to_copy);
  233                 }
  234 
  235                 ctsio->ext_data_filled += len_to_copy;
  236                 ctsio->kern_data_resid -= len_to_copy;
  237 
  238                 ext_watermark += len_to_copy;
  239                 if (ext_sglist[i].len == ext_watermark) {
  240                         i++;
  241                         ext_watermark = 0;
  242                 }
  243 
  244                 kern_watermark += len_to_copy;
  245                 if (kern_sglist[j].len == kern_watermark) {
  246                         j++;
  247                         kern_watermark = 0;
  248                 }
  249         }
  250 
  251         CTL_DEBUG_PRINT(("%s: ext_sg_entries: %d, kern_sg_entries: %d\n",
  252                          __func__, ext_sg_entries, kern_sg_entries));
  253         CTL_DEBUG_PRINT(("%s: ext_data_len = %d, kern_data_len = %d\n",
  254                          __func__, ctsio->ext_data_len, ctsio->kern_data_len));
  255 
  256 bailout:
  257         ctl_datamove_done(io, true);
  258 }
  259 
  260 static void
  261 tpcl_done(union ctl_io *io)
  262 {
  263 
  264         tpc_done(io);
  265 }
  266 
  267 uint64_t
  268 tpcl_resolve(struct ctl_softc *softc, int init_port,
  269     struct scsi_ec_cscd *cscd, uint32_t *ss, uint32_t *ps, uint32_t *pso)
  270 {
  271         struct scsi_ec_cscd_id *cscdid;
  272         struct ctl_port *port;
  273         struct ctl_lun *lun;
  274         uint64_t lunid = UINT64_MAX;
  275 
  276         if (cscd->type_code != EC_CSCD_ID ||
  277             (cscd->luidt_pdt & EC_LUIDT_MASK) != EC_LUIDT_LUN ||
  278             (cscd->luidt_pdt & EC_NUL) != 0)
  279                 return (lunid);
  280 
  281         cscdid = (struct scsi_ec_cscd_id *)cscd;
  282         mtx_lock(&softc->ctl_lock);
  283         if (init_port >= 0)
  284                 port = softc->ctl_ports[init_port];
  285         else
  286                 port = NULL;
  287         STAILQ_FOREACH(lun, &softc->lun_list, links) {
  288                 if (port != NULL &&
  289                     ctl_lun_map_to_port(port, lun->lun) == UINT32_MAX)
  290                         continue;
  291                 if (lun->lun_devid == NULL)
  292                         continue;
  293                 if (scsi_devid_match(lun->lun_devid->data,
  294                     lun->lun_devid->len, &cscdid->codeset,
  295                     cscdid->length + 4) == 0) {
  296                         lunid = lun->lun;
  297                         if (ss)
  298                                 *ss = lun->be_lun->blocksize;
  299                         if (ps)
  300                                 *ps = lun->be_lun->blocksize <<
  301                                     lun->be_lun->pblockexp;
  302                         if (pso)
  303                                 *pso = lun->be_lun->blocksize *
  304                                     lun->be_lun->pblockoff;
  305                         break;
  306                 }
  307         }
  308         mtx_unlock(&softc->ctl_lock);
  309         return (lunid);
  310 };
  311 
  312 union ctl_io *
  313 tpcl_alloc_io(void)
  314 {
  315         struct tpcl_softc *tsoftc = &tpcl_softc;
  316 
  317         return (ctl_alloc_io(tsoftc->port.ctl_pool_ref));
  318 };
  319 
  320 int
  321 tpcl_queue(union ctl_io *io, uint64_t lun)
  322 {
  323         struct tpcl_softc *tsoftc = &tpcl_softc;
  324 
  325         io->io_hdr.nexus.initid = 0;
  326         io->io_hdr.nexus.targ_port = tsoftc->port.targ_port;
  327         io->io_hdr.nexus.targ_lun = lun;
  328         io->scsiio.tag_num = atomic_fetchadd_int(&tsoftc->cur_tag_num, 1);
  329         io->scsiio.ext_data_filled = 0;
  330         return (ctl_queue(io));
  331 }

Cache object: 8f33d0a9b99cbd3a8811dbbbe6bb18ca


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