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_iscsi.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  * $FreeBSD$
   31  */
   32 
   33 /*
   34  * CTL frontend for the iSCSI protocol.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __FBSDID("$FreeBSD$");
   39 
   40 #include <sys/param.h>
   41 #include <sys/capsicum.h>
   42 #include <sys/condvar.h>
   43 #include <sys/endian.h>
   44 #include <sys/file.h>
   45 #include <sys/kernel.h>
   46 #include <sys/kthread.h>
   47 #include <sys/lock.h>
   48 #include <sys/malloc.h>
   49 #include <sys/module.h>
   50 #include <sys/mutex.h>
   51 #include <sys/queue.h>
   52 #include <sys/sbuf.h>
   53 #include <sys/socket.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/systm.h>
   56 #include <sys/uio.h>
   57 #include <sys/unistd.h>
   58 #include <sys/nv.h>
   59 #include <sys/dnv.h>
   60 #include <vm/uma.h>
   61 
   62 #include <cam/scsi/scsi_all.h>
   63 #include <cam/scsi/scsi_da.h>
   64 #include <cam/ctl/ctl_io.h>
   65 #include <cam/ctl/ctl.h>
   66 #include <cam/ctl/ctl_backend.h>
   67 #include <cam/ctl/ctl_error.h>
   68 #include <cam/ctl/ctl_frontend.h>
   69 #include <cam/ctl/ctl_debug.h>
   70 #include <cam/ctl/ctl_ha.h>
   71 #include <cam/ctl/ctl_ioctl.h>
   72 #include <cam/ctl/ctl_private.h>
   73 
   74 #include <dev/iscsi/icl.h>
   75 #include <dev/iscsi/icl_wrappers.h>
   76 #include <dev/iscsi/iscsi_proto.h>
   77 #include <cam/ctl/ctl_frontend_iscsi.h>
   78 
   79 #ifdef ICL_KERNEL_PROXY
   80 #include <sys/socketvar.h>
   81 #endif
   82 
   83 #ifdef ICL_KERNEL_PROXY
   84 FEATURE(cfiscsi_kernel_proxy, "iSCSI target built with ICL_KERNEL_PROXY");
   85 #endif
   86 
   87 /* Used for internal nexus reset task. */
   88 #define ISCSI_BHS_OPCODE_INTERNAL       0x3e
   89 
   90 static MALLOC_DEFINE(M_CFISCSI, "cfiscsi", "Memory used for CTL iSCSI frontend");
   91 static uma_zone_t cfiscsi_data_wait_zone;
   92 
   93 SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, iscsi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
   94     "CAM Target Layer iSCSI Frontend");
   95 static int debug = 1;
   96 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, debug, CTLFLAG_RWTUN,
   97     &debug, 1, "Enable debug messages");
   98 static int ping_timeout = 5;
   99 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, ping_timeout, CTLFLAG_RWTUN,
  100     &ping_timeout, 5, "Interval between ping (NOP-Out) requests, in seconds");
  101 static int login_timeout = 60;
  102 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, login_timeout, CTLFLAG_RWTUN,
  103     &login_timeout, 60, "Time to wait for ctld(8) to finish Login Phase, in seconds");
  104 static int maxtags = 256;
  105 SYSCTL_INT(_kern_cam_ctl_iscsi, OID_AUTO, maxtags, CTLFLAG_RWTUN,
  106     &maxtags, 0, "Max number of requests queued by initiator");
  107 
  108 #define CFISCSI_DEBUG(X, ...)                                           \
  109         do {                                                            \
  110                 if (debug > 1) {                                        \
  111                         printf("%s: " X "\n",                           \
  112                             __func__, ## __VA_ARGS__);                  \
  113                 }                                                       \
  114         } while (0)
  115 
  116 #define CFISCSI_WARN(X, ...)                                            \
  117         do {                                                            \
  118                 if (debug > 0) {                                        \
  119                         printf("WARNING: %s: " X "\n",                  \
  120                             __func__, ## __VA_ARGS__);                  \
  121                 }                                                       \
  122         } while (0)
  123 
  124 #define CFISCSI_SESSION_DEBUG(S, X, ...)                                \
  125         do {                                                            \
  126                 if (debug > 1) {                                        \
  127                         printf("%s: %s (%s): " X "\n",                  \
  128                             __func__, S->cs_initiator_addr,             \
  129                             S->cs_initiator_name, ## __VA_ARGS__);      \
  130                 }                                                       \
  131         } while (0)
  132 
  133 #define CFISCSI_SESSION_WARN(S, X, ...)                                 \
  134         do  {                                                           \
  135                 if (debug > 0) {                                        \
  136                         printf("WARNING: %s (%s): " X "\n",             \
  137                             S->cs_initiator_addr,                       \
  138                             S->cs_initiator_name, ## __VA_ARGS__);      \
  139                 }                                                       \
  140         } while (0)
  141 
  142 #define CFISCSI_SESSION_LOCK(X)         mtx_lock(&X->cs_lock)
  143 #define CFISCSI_SESSION_UNLOCK(X)       mtx_unlock(&X->cs_lock)
  144 #define CFISCSI_SESSION_LOCK_ASSERT(X)  mtx_assert(&X->cs_lock, MA_OWNED)
  145 
  146 #define CONN_SESSION(X)                 ((struct cfiscsi_session *)(X)->ic_prv0)
  147 #define PDU_SESSION(X)                  CONN_SESSION((X)->ip_conn)
  148 
  149 struct cfiscsi_priv {
  150         void            *request;
  151         uint32_t         expdatasn;
  152         uint32_t         r2tsn;
  153 };
  154 #define PRIV(io)        \
  155     ((struct cfiscsi_priv *)&(io)->io_hdr.ctl_private[CTL_PRIV_FRONTEND])
  156 #define PRIV_REQUEST(io)                PRIV(io)->request
  157 #define PRIV_EXPDATASN(io)              PRIV(io)->expdatasn
  158 #define PRIV_R2TSN(io)                  PRIV(io)->r2tsn
  159 
  160 static int      cfiscsi_init(void);
  161 static int      cfiscsi_shutdown(void);
  162 static void     cfiscsi_online(void *arg);
  163 static void     cfiscsi_offline(void *arg);
  164 static int      cfiscsi_info(void *arg, struct sbuf *sb);
  165 static int      cfiscsi_ioctl(struct cdev *dev,
  166                     u_long cmd, caddr_t addr, int flag, struct thread *td);
  167 static void     cfiscsi_datamove(union ctl_io *io);
  168 static void     cfiscsi_datamove_in(union ctl_io *io);
  169 static void     cfiscsi_datamove_out(union ctl_io *io);
  170 static void     cfiscsi_done(union ctl_io *io);
  171 static bool     cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request);
  172 static void     cfiscsi_pdu_handle_nop_out(struct icl_pdu *request);
  173 static void     cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request);
  174 static void     cfiscsi_pdu_handle_task_request(struct icl_pdu *request);
  175 static void     cfiscsi_pdu_handle_data_out(struct icl_pdu *request);
  176 static void     cfiscsi_pdu_handle_logout_request(struct icl_pdu *request);
  177 static void     cfiscsi_session_terminate(struct cfiscsi_session *cs);
  178 static struct cfiscsi_data_wait *cfiscsi_data_wait_new(
  179                     struct cfiscsi_session *cs, union ctl_io *io,
  180                     uint32_t initiator_task_tag,
  181                     uint32_t *target_transfer_tagp);
  182 static void     cfiscsi_data_wait_free(struct cfiscsi_session *cs,
  183                     struct cfiscsi_data_wait *cdw);
  184 static struct cfiscsi_target    *cfiscsi_target_find(struct cfiscsi_softc
  185                     *softc, const char *name, uint16_t tag);
  186 static struct cfiscsi_target    *cfiscsi_target_find_or_create(
  187     struct cfiscsi_softc *softc, const char *name, const char *alias,
  188     uint16_t tag);
  189 static void     cfiscsi_target_release(struct cfiscsi_target *ct);
  190 static void     cfiscsi_session_delete(struct cfiscsi_session *cs);
  191 
  192 static struct cfiscsi_softc cfiscsi_softc;
  193 
  194 static struct ctl_frontend cfiscsi_frontend =
  195 {
  196         .name = "iscsi",
  197         .init = cfiscsi_init,
  198         .ioctl = cfiscsi_ioctl,
  199         .shutdown = cfiscsi_shutdown,
  200 };
  201 CTL_FRONTEND_DECLARE(cfiscsi, cfiscsi_frontend);
  202 MODULE_DEPEND(cfiscsi, icl, 1, 1, 1);
  203 
  204 static struct icl_pdu *
  205 cfiscsi_pdu_new_response(struct icl_pdu *request, int flags)
  206 {
  207 
  208         return (icl_pdu_new(request->ip_conn, flags));
  209 }
  210 
  211 static bool
  212 cfiscsi_pdu_update_cmdsn(const struct icl_pdu *request)
  213 {
  214         const struct iscsi_bhs_scsi_command *bhssc;
  215         struct cfiscsi_session *cs;
  216         uint32_t cmdsn, curcmdsn;
  217 
  218         cs = PDU_SESSION(request);
  219 
  220         /*
  221          * Every incoming PDU - not just NOP-Out - resets the ping timer.
  222          * The purpose of the timeout is to reset the connection when it stalls;
  223          * we don't want this to happen when NOP-In or NOP-Out ends up delayed
  224          * in some queue.
  225          */
  226         cs->cs_timeout = 0;
  227 
  228         /*
  229          * Immediate commands carry cmdsn, but it is neither incremented nor
  230          * verified.
  231          */
  232         if (request->ip_bhs->bhs_opcode & ISCSI_BHS_OPCODE_IMMEDIATE)
  233                 return (false);
  234 
  235         /*
  236          * Data-Out PDUs don't contain CmdSN.
  237          */
  238         if (request->ip_bhs->bhs_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
  239                 return (false);
  240 
  241         /*
  242          * We're only using fields common for all the request
  243          * (initiator -> target) PDUs.
  244          */
  245         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
  246         curcmdsn = cmdsn = ntohl(bhssc->bhssc_cmdsn);
  247 
  248         /*
  249          * Increment session cmdsn and exit if we received the expected value.
  250          */
  251         do {
  252                 if (atomic_fcmpset_32(&cs->cs_cmdsn, &curcmdsn, cmdsn + 1))
  253                         return (false);
  254         } while (curcmdsn == cmdsn);
  255 
  256         /*
  257          * The target MUST silently ignore any non-immediate command outside
  258          * of this range.
  259          */
  260         if (ISCSI_SNLT(cmdsn, curcmdsn) ||
  261             ISCSI_SNGT(cmdsn, curcmdsn - 1 + maxtags)) {
  262                 CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
  263                     "while expected %u", cmdsn, curcmdsn);
  264                 return (true);
  265         }
  266 
  267         /*
  268          * We don't support multiple connections now, so any discontinuity in
  269          * CmdSN means lost PDUs.  Since we don't support PDU retransmission --
  270          * terminate the connection.
  271          */
  272         CFISCSI_SESSION_WARN(cs, "received PDU with CmdSN %u, "
  273             "while expected %u; dropping connection",
  274             cmdsn, curcmdsn);
  275         cfiscsi_session_terminate(cs);
  276         return (true);
  277 }
  278 
  279 static void
  280 cfiscsi_pdu_handle(struct icl_pdu *request)
  281 {
  282         struct cfiscsi_session *cs;
  283         bool ignore;
  284 
  285         cs = PDU_SESSION(request);
  286 
  287         ignore = cfiscsi_pdu_update_cmdsn(request);
  288         if (ignore) {
  289                 icl_pdu_free(request);
  290                 return;
  291         }
  292 
  293         /*
  294          * Handle the PDU; this includes e.g. receiving the remaining
  295          * part of PDU and submitting the SCSI command to CTL
  296          * or queueing a reply.  The handling routine is responsible
  297          * for freeing the PDU when it's no longer needed.
  298          */
  299         switch (request->ip_bhs->bhs_opcode &
  300             ~ISCSI_BHS_OPCODE_IMMEDIATE) {
  301         case ISCSI_BHS_OPCODE_NOP_OUT:
  302                 cfiscsi_pdu_handle_nop_out(request);
  303                 break;
  304         case ISCSI_BHS_OPCODE_SCSI_COMMAND:
  305                 cfiscsi_pdu_handle_scsi_command(request);
  306                 break;
  307         case ISCSI_BHS_OPCODE_TASK_REQUEST:
  308                 cfiscsi_pdu_handle_task_request(request);
  309                 break;
  310         case ISCSI_BHS_OPCODE_SCSI_DATA_OUT:
  311                 cfiscsi_pdu_handle_data_out(request);
  312                 break;
  313         case ISCSI_BHS_OPCODE_LOGOUT_REQUEST:
  314                 cfiscsi_pdu_handle_logout_request(request);
  315                 break;
  316         default:
  317                 CFISCSI_SESSION_WARN(cs, "received PDU with unsupported "
  318                     "opcode 0x%x; dropping connection",
  319                     request->ip_bhs->bhs_opcode);
  320                 icl_pdu_free(request);
  321                 cfiscsi_session_terminate(cs);
  322         }
  323 
  324 }
  325 
  326 static void
  327 cfiscsi_receive_callback(struct icl_pdu *request)
  328 {
  329 #ifdef ICL_KERNEL_PROXY
  330         struct cfiscsi_session *cs;
  331 
  332         cs = PDU_SESSION(request);
  333         if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
  334                 if (cs->cs_login_pdu == NULL)
  335                         cs->cs_login_pdu = request;
  336                 else
  337                         icl_pdu_free(request);
  338                 cv_signal(&cs->cs_login_cv);
  339                 return;
  340         }
  341 #endif
  342 
  343         cfiscsi_pdu_handle(request);
  344 }
  345 
  346 static void
  347 cfiscsi_error_callback(struct icl_conn *ic)
  348 {
  349         struct cfiscsi_session *cs;
  350 
  351         cs = CONN_SESSION(ic);
  352 
  353         CFISCSI_SESSION_WARN(cs, "connection error; dropping connection");
  354         cfiscsi_session_terminate(cs);
  355 }
  356 
  357 static int
  358 cfiscsi_pdu_prepare(struct icl_pdu *response)
  359 {
  360         struct cfiscsi_session *cs;
  361         struct iscsi_bhs_scsi_response *bhssr;
  362         bool advance_statsn = true;
  363         uint32_t cmdsn;
  364 
  365         cs = PDU_SESSION(response);
  366 
  367         CFISCSI_SESSION_LOCK_ASSERT(cs);
  368 
  369         /*
  370          * We're only using fields common for all the response
  371          * (target -> initiator) PDUs.
  372          */
  373         bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
  374 
  375         /*
  376          * 10.8.3: "The StatSN for this connection is not advanced
  377          * after this PDU is sent."
  378          */
  379         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_R2T)
  380                 advance_statsn = false;
  381 
  382         /*
  383          * 10.19.2: "However, when the Initiator Task Tag is set to 0xffffffff,
  384          * StatSN for the connection is not advanced after this PDU is sent."
  385          */
  386         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_NOP_IN && 
  387             bhssr->bhssr_initiator_task_tag == 0xffffffff)
  388                 advance_statsn = false;
  389 
  390         /*
  391          * See the comment below - StatSN is not meaningful and must
  392          * not be advanced.
  393          */
  394         if (bhssr->bhssr_opcode == ISCSI_BHS_OPCODE_SCSI_DATA_IN &&
  395             (bhssr->bhssr_flags & BHSDI_FLAGS_S) == 0)
  396                 advance_statsn = false;
  397 
  398         /*
  399          * 10.7.3: "The fields StatSN, Status, and Residual Count
  400          * only have meaningful content if the S bit is set to 1."
  401          */
  402         if (bhssr->bhssr_opcode != ISCSI_BHS_OPCODE_SCSI_DATA_IN ||
  403             (bhssr->bhssr_flags & BHSDI_FLAGS_S))
  404                 bhssr->bhssr_statsn = htonl(cs->cs_statsn);
  405         cmdsn = cs->cs_cmdsn;
  406         bhssr->bhssr_expcmdsn = htonl(cmdsn);
  407         bhssr->bhssr_maxcmdsn = htonl(cmdsn - 1 +
  408             imax(0, maxtags - cs->cs_outstanding_ctl_pdus));
  409 
  410         if (advance_statsn)
  411                 cs->cs_statsn++;
  412 
  413         return (0);
  414 }
  415 
  416 static void
  417 cfiscsi_pdu_queue(struct icl_pdu *response)
  418 {
  419         struct cfiscsi_session *cs;
  420 
  421         cs = PDU_SESSION(response);
  422 
  423         CFISCSI_SESSION_LOCK(cs);
  424         cfiscsi_pdu_prepare(response);
  425         icl_pdu_queue(response);
  426         CFISCSI_SESSION_UNLOCK(cs);
  427 }
  428 
  429  static void
  430 cfiscsi_pdu_queue_cb(struct icl_pdu *response, icl_pdu_cb cb)
  431 {
  432         struct cfiscsi_session *cs = PDU_SESSION(response);
  433 
  434         CFISCSI_SESSION_LOCK(cs);
  435         cfiscsi_pdu_prepare(response);
  436         icl_pdu_queue_cb(response, cb);
  437         CFISCSI_SESSION_UNLOCK(cs);
  438 }
  439 
  440 static void
  441 cfiscsi_pdu_handle_nop_out(struct icl_pdu *request)
  442 {
  443         struct cfiscsi_session *cs;
  444         struct iscsi_bhs_nop_out *bhsno;
  445         struct iscsi_bhs_nop_in *bhsni;
  446         struct icl_pdu *response;
  447         void *data = NULL;
  448         size_t datasize;
  449         int error;
  450 
  451         cs = PDU_SESSION(request);
  452         bhsno = (struct iscsi_bhs_nop_out *)request->ip_bhs;
  453 
  454         if (bhsno->bhsno_initiator_task_tag == 0xffffffff) {
  455                 /*
  456                  * Nothing to do, iscsi_pdu_update_statsn() already
  457                  * zeroed the timeout.
  458                  */
  459                 icl_pdu_free(request);
  460                 return;
  461         }
  462 
  463         datasize = icl_pdu_data_segment_length(request);
  464         if (datasize > 0) {
  465                 data = malloc(datasize, M_CFISCSI, M_NOWAIT | M_ZERO);
  466                 if (data == NULL) {
  467                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
  468                             "dropping connection");
  469                         icl_pdu_free(request);
  470                         cfiscsi_session_terminate(cs);
  471                         return;
  472                 }
  473                 icl_pdu_get_data(request, 0, data, datasize);
  474         }
  475 
  476         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
  477         if (response == NULL) {
  478                 CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
  479                     "droppping connection");
  480                 free(data, M_CFISCSI);
  481                 icl_pdu_free(request);
  482                 cfiscsi_session_terminate(cs);
  483                 return;
  484         }
  485         bhsni = (struct iscsi_bhs_nop_in *)response->ip_bhs;
  486         bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
  487         bhsni->bhsni_flags = 0x80;
  488         bhsni->bhsni_initiator_task_tag = bhsno->bhsno_initiator_task_tag;
  489         bhsni->bhsni_target_transfer_tag = 0xffffffff;
  490         if (datasize > 0) {
  491                 error = icl_pdu_append_data(response, data, datasize, M_NOWAIT);
  492                 if (error != 0) {
  493                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
  494                             "dropping connection");
  495                         free(data, M_CFISCSI);
  496                         icl_pdu_free(request);
  497                         icl_pdu_free(response);
  498                         cfiscsi_session_terminate(cs);
  499                         return;
  500                 }
  501                 free(data, M_CFISCSI);
  502         }
  503 
  504         icl_pdu_free(request);
  505         cfiscsi_pdu_queue(response);
  506 }
  507 
  508 static void
  509 cfiscsi_pdu_handle_scsi_command(struct icl_pdu *request)
  510 {
  511         struct iscsi_bhs_scsi_command *bhssc;
  512         struct cfiscsi_session *cs;
  513         union ctl_io *io;
  514         int error;
  515 
  516         cs = PDU_SESSION(request);
  517         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
  518         //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
  519         //    bhssc->bhssc_initiator_task_tag);
  520 
  521         if (request->ip_data_len > 0 && cs->cs_immediate_data == false) {
  522                 CFISCSI_SESSION_WARN(cs, "unsolicited data with "
  523                     "ImmediateData=No; dropping connection");
  524                 icl_pdu_free(request);
  525                 cfiscsi_session_terminate(cs);
  526                 return;
  527         }
  528         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
  529         ctl_zero_io(io);
  530         PRIV_REQUEST(io) = request;
  531         io->io_hdr.io_type = CTL_IO_SCSI;
  532         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
  533         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
  534         io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhssc->bhssc_lun));
  535         io->scsiio.priority = (bhssc->bhssc_pri & BHSSC_PRI_MASK) >>
  536             BHSSC_PRI_SHIFT;
  537         io->scsiio.tag_num = bhssc->bhssc_initiator_task_tag;
  538         switch ((bhssc->bhssc_flags & BHSSC_FLAGS_ATTR)) {
  539         case BHSSC_FLAGS_ATTR_UNTAGGED:
  540                 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
  541                 break;
  542         case BHSSC_FLAGS_ATTR_SIMPLE:
  543                 io->scsiio.tag_type = CTL_TAG_SIMPLE;
  544                 break;
  545         case BHSSC_FLAGS_ATTR_ORDERED:
  546                 io->scsiio.tag_type = CTL_TAG_ORDERED;
  547                 break;
  548         case BHSSC_FLAGS_ATTR_HOQ:
  549                 io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
  550                 break;
  551         case BHSSC_FLAGS_ATTR_ACA:
  552                 io->scsiio.tag_type = CTL_TAG_ACA;
  553                 break;
  554         default:
  555                 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
  556                 CFISCSI_SESSION_WARN(cs, "unhandled tag type %d",
  557                     bhssc->bhssc_flags & BHSSC_FLAGS_ATTR);
  558                 break;
  559         }
  560         io->scsiio.cdb_len = sizeof(bhssc->bhssc_cdb); /* Which is 16. */
  561         memcpy(io->scsiio.cdb, bhssc->bhssc_cdb, sizeof(bhssc->bhssc_cdb));
  562         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
  563         error = ctl_run(io);
  564         if (error != CTL_RETVAL_COMPLETE) {
  565                 CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d; "
  566                     "dropping connection", error);
  567                 ctl_free_io(io);
  568                 refcount_release(&cs->cs_outstanding_ctl_pdus);
  569                 icl_pdu_free(request);
  570                 cfiscsi_session_terminate(cs);
  571         }
  572 }
  573 
  574 static void
  575 cfiscsi_pdu_handle_task_request(struct icl_pdu *request)
  576 {
  577         struct iscsi_bhs_task_management_request *bhstmr;
  578         struct iscsi_bhs_task_management_response *bhstmr2;
  579         struct icl_pdu *response;
  580         struct cfiscsi_session *cs;
  581         union ctl_io *io;
  582         int error;
  583 
  584         cs = PDU_SESSION(request);
  585         bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
  586         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
  587         ctl_zero_io(io);
  588         PRIV_REQUEST(io) = request;
  589         io->io_hdr.io_type = CTL_IO_TASK;
  590         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
  591         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
  592         io->io_hdr.nexus.targ_lun = ctl_decode_lun(be64toh(bhstmr->bhstmr_lun));
  593         io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
  594 
  595         switch (bhstmr->bhstmr_function & ~0x80) {
  596         case BHSTMR_FUNCTION_ABORT_TASK:
  597 #if 0
  598                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK");
  599 #endif
  600                 io->taskio.task_action = CTL_TASK_ABORT_TASK;
  601                 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
  602                 break;
  603         case BHSTMR_FUNCTION_ABORT_TASK_SET:
  604 #if 0
  605                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_ABORT_TASK_SET");
  606 #endif
  607                 io->taskio.task_action = CTL_TASK_ABORT_TASK_SET;
  608                 break;
  609         case BHSTMR_FUNCTION_CLEAR_TASK_SET:
  610 #if 0
  611                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_CLEAR_TASK_SET");
  612 #endif
  613                 io->taskio.task_action = CTL_TASK_CLEAR_TASK_SET;
  614                 break;
  615         case BHSTMR_FUNCTION_LOGICAL_UNIT_RESET:
  616 #if 0
  617                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_LOGICAL_UNIT_RESET");
  618 #endif
  619                 io->taskio.task_action = CTL_TASK_LUN_RESET;
  620                 break;
  621         case BHSTMR_FUNCTION_TARGET_WARM_RESET:
  622 #if 0
  623                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_WARM_RESET");
  624 #endif
  625                 io->taskio.task_action = CTL_TASK_TARGET_RESET;
  626                 break;
  627         case BHSTMR_FUNCTION_TARGET_COLD_RESET:
  628 #if 0
  629                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_TARGET_COLD_RESET");
  630 #endif
  631                 io->taskio.task_action = CTL_TASK_TARGET_RESET;
  632                 break;
  633         case BHSTMR_FUNCTION_QUERY_TASK:
  634 #if 0
  635                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK");
  636 #endif
  637                 io->taskio.task_action = CTL_TASK_QUERY_TASK;
  638                 io->taskio.tag_num = bhstmr->bhstmr_referenced_task_tag;
  639                 break;
  640         case BHSTMR_FUNCTION_QUERY_TASK_SET:
  641 #if 0
  642                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_TASK_SET");
  643 #endif
  644                 io->taskio.task_action = CTL_TASK_QUERY_TASK_SET;
  645                 break;
  646         case BHSTMR_FUNCTION_I_T_NEXUS_RESET:
  647 #if 0
  648                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_I_T_NEXUS_RESET");
  649 #endif
  650                 io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
  651                 break;
  652         case BHSTMR_FUNCTION_QUERY_ASYNC_EVENT:
  653 #if 0
  654                 CFISCSI_SESSION_DEBUG(cs, "BHSTMR_FUNCTION_QUERY_ASYNC_EVENT");
  655 #endif
  656                 io->taskio.task_action = CTL_TASK_QUERY_ASYNC_EVENT;
  657                 break;
  658         default:
  659                 CFISCSI_SESSION_DEBUG(cs, "unsupported function 0x%x",
  660                     bhstmr->bhstmr_function & ~0x80);
  661                 ctl_free_io(io);
  662 
  663                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
  664                 if (response == NULL) {
  665                         CFISCSI_SESSION_WARN(cs, "failed to allocate memory; "
  666                             "dropping connection");
  667                         icl_pdu_free(request);
  668                         cfiscsi_session_terminate(cs);
  669                         return;
  670                 }
  671                 bhstmr2 = (struct iscsi_bhs_task_management_response *)
  672                     response->ip_bhs;
  673                 bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
  674                 bhstmr2->bhstmr_flags = 0x80;
  675                 bhstmr2->bhstmr_response =
  676                     BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
  677                 bhstmr2->bhstmr_initiator_task_tag =
  678                     bhstmr->bhstmr_initiator_task_tag;
  679                 icl_pdu_free(request);
  680                 cfiscsi_pdu_queue(response);
  681                 return;
  682         }
  683 
  684         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
  685         error = ctl_run(io);
  686         if (error != CTL_RETVAL_COMPLETE) {
  687                 CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d; "
  688                     "dropping connection", error);
  689                 ctl_free_io(io);
  690                 refcount_release(&cs->cs_outstanding_ctl_pdus);
  691                 icl_pdu_free(request);
  692                 cfiscsi_session_terminate(cs);
  693         }
  694 }
  695 
  696 static bool
  697 cfiscsi_handle_data_segment(struct icl_pdu *request, struct cfiscsi_data_wait *cdw)
  698 {
  699         struct iscsi_bhs_data_out *bhsdo;
  700         struct cfiscsi_session *cs;
  701         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
  702         size_t copy_len, len, off, buffer_offset;
  703         int ctl_sg_count;
  704         union ctl_io *io;
  705 
  706         cs = PDU_SESSION(request);
  707 
  708         KASSERT((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
  709             ISCSI_BHS_OPCODE_SCSI_DATA_OUT ||
  710             (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
  711             ISCSI_BHS_OPCODE_SCSI_COMMAND,
  712             ("bad opcode 0x%x", request->ip_bhs->bhs_opcode));
  713 
  714         /*
  715          * We're only using fields common for Data-Out and SCSI Command PDUs.
  716          */
  717         bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
  718 
  719         io = cdw->cdw_ctl_io;
  720         KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
  721             ("CTL_FLAG_DATA_IN"));
  722 
  723 #if 0
  724         CFISCSI_SESSION_DEBUG(cs, "received %zd bytes out of %d",
  725             request->ip_data_len, io->scsiio.kern_total_len);
  726 #endif
  727 
  728         if (io->scsiio.kern_sg_entries > 0) {
  729                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
  730                 ctl_sg_count = io->scsiio.kern_sg_entries;
  731         } else {
  732                 ctl_sglist = &ctl_sg_entry;
  733                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
  734                 ctl_sglist->len = io->scsiio.kern_data_len;
  735                 ctl_sg_count = 1;
  736         }
  737 
  738         if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
  739             ISCSI_BHS_OPCODE_SCSI_DATA_OUT)
  740                 buffer_offset = ntohl(bhsdo->bhsdo_buffer_offset);
  741         else
  742                 buffer_offset = 0;
  743         len = icl_pdu_data_segment_length(request);
  744 
  745         /*
  746          * Make sure the offset, as sent by the initiator, matches the offset
  747          * we're supposed to be at in the scatter-gather list.
  748          */
  749         if (buffer_offset >
  750             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled ||
  751             buffer_offset + len <=
  752             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled) {
  753                 CFISCSI_SESSION_WARN(cs, "received bad buffer offset %zd, "
  754                     "expected %zd; dropping connection", buffer_offset,
  755                     (size_t)io->scsiio.kern_rel_offset +
  756                     (size_t)io->scsiio.ext_data_filled);
  757                 ctl_set_data_phase_error(&io->scsiio);
  758                 cfiscsi_session_terminate(cs);
  759                 return (true);
  760         }
  761 
  762         /*
  763          * This is the offset within the PDU data segment, as opposed
  764          * to buffer_offset, which is the offset within the task (SCSI
  765          * command).
  766          */
  767         off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled -
  768             buffer_offset;
  769 
  770         /*
  771          * Iterate over the scatter/gather segments, filling them with data
  772          * from the PDU data segment.  Note that this can get called multiple
  773          * times for one SCSI command; the cdw structure holds state for the
  774          * scatter/gather list.
  775          */
  776         for (;;) {
  777                 KASSERT(cdw->cdw_sg_index < ctl_sg_count,
  778                     ("cdw->cdw_sg_index >= ctl_sg_count"));
  779                 if (cdw->cdw_sg_len == 0) {
  780                         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
  781                         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
  782                 }
  783                 KASSERT(off <= len, ("len > off"));
  784                 copy_len = len - off;
  785                 if (copy_len > cdw->cdw_sg_len)
  786                         copy_len = cdw->cdw_sg_len;
  787 
  788                 icl_pdu_get_data(request, off, cdw->cdw_sg_addr, copy_len);
  789                 cdw->cdw_sg_addr += copy_len;
  790                 cdw->cdw_sg_len -= copy_len;
  791                 off += copy_len;
  792                 io->scsiio.ext_data_filled += copy_len;
  793                 io->scsiio.kern_data_resid -= copy_len;
  794 
  795                 if (cdw->cdw_sg_len == 0) {
  796                         /*
  797                          * End of current segment.
  798                          */
  799                         if (cdw->cdw_sg_index == ctl_sg_count - 1) {
  800                                 /*
  801                                  * Last segment in scatter/gather list.
  802                                  */
  803                                 break;
  804                         }
  805                         cdw->cdw_sg_index++;
  806                 }
  807 
  808                 if (off == len) {
  809                         /*
  810                          * End of PDU payload.
  811                          */
  812                         break;
  813                 }
  814         }
  815 
  816         if (len > off) {
  817                 /*
  818                  * In case of unsolicited data, it's possible that the buffer
  819                  * provided by CTL is smaller than negotiated FirstBurstLength.
  820                  * Just ignore the superfluous data; will ask for them with R2T
  821                  * on next call to cfiscsi_datamove().
  822                  *
  823                  * This obviously can only happen with SCSI Command PDU. 
  824                  */
  825                 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
  826                     ISCSI_BHS_OPCODE_SCSI_COMMAND)
  827                         return (true);
  828 
  829                 CFISCSI_SESSION_WARN(cs, "received too much data: got %zd bytes, "
  830                     "expected %zd; dropping connection",
  831                     icl_pdu_data_segment_length(request), off);
  832                 ctl_set_data_phase_error(&io->scsiio);
  833                 cfiscsi_session_terminate(cs);
  834                 return (true);
  835         }
  836 
  837         if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end &&
  838             (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) == 0) {
  839                 CFISCSI_SESSION_WARN(cs, "got the final packet without "
  840                     "the F flag; flags = 0x%x; dropping connection",
  841                     bhsdo->bhsdo_flags);
  842                 ctl_set_data_phase_error(&io->scsiio);
  843                 cfiscsi_session_terminate(cs);
  844                 return (true);
  845         }
  846 
  847         if (io->scsiio.ext_data_filled != cdw->cdw_r2t_end &&
  848             (bhsdo->bhsdo_flags & BHSDO_FLAGS_F) != 0) {
  849                 if ((request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
  850                     ISCSI_BHS_OPCODE_SCSI_DATA_OUT) {
  851                         CFISCSI_SESSION_WARN(cs, "got the final packet, but the "
  852                             "transmitted size was %zd bytes instead of %d; "
  853                             "dropping connection",
  854                             (size_t)io->scsiio.ext_data_filled,
  855                             cdw->cdw_r2t_end);
  856                         ctl_set_data_phase_error(&io->scsiio);
  857                         cfiscsi_session_terminate(cs);
  858                         return (true);
  859                 } else {
  860                         /*
  861                          * For SCSI Command PDU, this just means we need to
  862                          * solicit more data by sending R2T.
  863                          */
  864                         return (false);
  865                 }
  866         }
  867 
  868         if (io->scsiio.ext_data_filled == cdw->cdw_r2t_end) {
  869 #if 0
  870                 CFISCSI_SESSION_DEBUG(cs, "no longer expecting Data-Out with target "
  871                     "transfer tag 0x%x", cdw->cdw_target_transfer_tag);
  872 #endif
  873 
  874                 return (true);
  875         }
  876 
  877         return (false);
  878 }
  879 
  880 static void
  881 cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
  882 {
  883         struct iscsi_bhs_data_out *bhsdo;
  884         struct cfiscsi_session *cs;
  885         struct cfiscsi_data_wait *cdw = NULL;
  886         union ctl_io *io;
  887         bool done;
  888 
  889         cs = PDU_SESSION(request);
  890         bhsdo = (struct iscsi_bhs_data_out *)request->ip_bhs;
  891 
  892         CFISCSI_SESSION_LOCK(cs);
  893         TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next) {
  894 #if 0
  895                 CFISCSI_SESSION_DEBUG(cs, "have ttt 0x%x, itt 0x%x; looking for "
  896                     "ttt 0x%x, itt 0x%x",
  897                     bhsdo->bhsdo_target_transfer_tag,
  898                     bhsdo->bhsdo_initiator_task_tag,
  899                     cdw->cdw_target_transfer_tag, cdw->cdw_initiator_task_tag));
  900 #endif
  901                 if (bhsdo->bhsdo_target_transfer_tag ==
  902                     cdw->cdw_target_transfer_tag)
  903                         break;
  904         }
  905         CFISCSI_SESSION_UNLOCK(cs);
  906         if (cdw == NULL) {
  907                 CFISCSI_SESSION_WARN(cs, "data transfer tag 0x%x, initiator task tag "
  908                     "0x%x, not found; dropping connection",
  909                     bhsdo->bhsdo_target_transfer_tag, bhsdo->bhsdo_initiator_task_tag);
  910                 icl_pdu_free(request);
  911                 cfiscsi_session_terminate(cs);
  912                 return;
  913         }
  914 
  915         if (cdw->cdw_datasn != ntohl(bhsdo->bhsdo_datasn)) {
  916                 CFISCSI_SESSION_WARN(cs, "received Data-Out PDU with "
  917                     "DataSN %u, while expected %u; dropping connection",
  918                     ntohl(bhsdo->bhsdo_datasn), cdw->cdw_datasn);
  919                 icl_pdu_free(request);
  920                 cfiscsi_session_terminate(cs);
  921                 return;
  922         }
  923         cdw->cdw_datasn += request->ip_additional_pdus + 1;
  924 
  925         io = cdw->cdw_ctl_io;
  926         KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
  927             ("CTL_FLAG_DATA_IN"));
  928 
  929         done = cfiscsi_handle_data_segment(request, cdw);
  930         if (done) {
  931                 CFISCSI_SESSION_LOCK(cs);
  932                 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
  933                 CFISCSI_SESSION_UNLOCK(cs);
  934                 done = (io->scsiio.ext_data_filled != cdw->cdw_r2t_end ||
  935                     io->scsiio.ext_data_filled == io->scsiio.kern_data_len);
  936                 cfiscsi_data_wait_free(cs, cdw);
  937                 io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
  938                 if (done)
  939                         ctl_datamove_done(io, false);
  940                 else
  941                         cfiscsi_datamove_out(io);
  942         }
  943 
  944         icl_pdu_free(request);
  945 }
  946 
  947 static void
  948 cfiscsi_pdu_handle_logout_request(struct icl_pdu *request)
  949 {
  950         struct iscsi_bhs_logout_request *bhslr;
  951         struct iscsi_bhs_logout_response *bhslr2;
  952         struct icl_pdu *response;
  953         struct cfiscsi_session *cs;
  954 
  955         cs = PDU_SESSION(request);
  956         bhslr = (struct iscsi_bhs_logout_request *)request->ip_bhs;
  957         switch (bhslr->bhslr_reason & 0x7f) {
  958         case BHSLR_REASON_CLOSE_SESSION:
  959         case BHSLR_REASON_CLOSE_CONNECTION:
  960                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
  961                 if (response == NULL) {
  962                         CFISCSI_SESSION_DEBUG(cs, "failed to allocate memory");
  963                         icl_pdu_free(request);
  964                         cfiscsi_session_terminate(cs);
  965                         return;
  966                 }
  967                 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
  968                 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
  969                 bhslr2->bhslr_flags = 0x80;
  970                 bhslr2->bhslr_response = BHSLR_RESPONSE_CLOSED_SUCCESSFULLY;
  971                 bhslr2->bhslr_initiator_task_tag =
  972                     bhslr->bhslr_initiator_task_tag;
  973                 icl_pdu_free(request);
  974                 cfiscsi_pdu_queue(response);
  975                 cfiscsi_session_terminate(cs);
  976                 break;
  977         case BHSLR_REASON_REMOVE_FOR_RECOVERY:
  978                 response = cfiscsi_pdu_new_response(request, M_NOWAIT);
  979                 if (response == NULL) {
  980                         CFISCSI_SESSION_WARN(cs,
  981                             "failed to allocate memory; dropping connection");
  982                         icl_pdu_free(request);
  983                         cfiscsi_session_terminate(cs);
  984                         return;
  985                 }
  986                 bhslr2 = (struct iscsi_bhs_logout_response *)response->ip_bhs;
  987                 bhslr2->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_RESPONSE;
  988                 bhslr2->bhslr_flags = 0x80;
  989                 bhslr2->bhslr_response = BHSLR_RESPONSE_RECOVERY_NOT_SUPPORTED;
  990                 bhslr2->bhslr_initiator_task_tag =
  991                     bhslr->bhslr_initiator_task_tag;
  992                 icl_pdu_free(request);
  993                 cfiscsi_pdu_queue(response);
  994                 break;
  995         default:
  996                 CFISCSI_SESSION_WARN(cs, "invalid reason 0%x; dropping connection",
  997                     bhslr->bhslr_reason);
  998                 icl_pdu_free(request);
  999                 cfiscsi_session_terminate(cs);
 1000                 break;
 1001         }
 1002 }
 1003 
 1004 static void
 1005 cfiscsi_callout(void *context)
 1006 {
 1007         struct icl_pdu *cp;
 1008         struct iscsi_bhs_nop_in *bhsni;
 1009         struct cfiscsi_session *cs;
 1010 
 1011         cs = context;
 1012 
 1013         if (cs->cs_terminating) 
 1014                 return;
 1015 
 1016         callout_schedule(&cs->cs_callout, 1 * hz);
 1017 
 1018         atomic_add_int(&cs->cs_timeout, 1);
 1019 
 1020 #ifdef ICL_KERNEL_PROXY
 1021         if (cs->cs_waiting_for_ctld || cs->cs_login_phase) {
 1022                 if (login_timeout > 0 && cs->cs_timeout > login_timeout) {
 1023                         CFISCSI_SESSION_WARN(cs, "login timed out after "
 1024                             "%d seconds; dropping connection", cs->cs_timeout);
 1025                         cfiscsi_session_terminate(cs);
 1026                 }
 1027                 return;
 1028         }
 1029 #endif
 1030 
 1031         if (ping_timeout <= 0) {
 1032                 /*
 1033                  * Pings are disabled.  Don't send NOP-In in this case;
 1034                  * user might have disabled pings to work around problems
 1035                  * with certain initiators that can't properly handle
 1036                  * NOP-In, such as iPXE.  Reset the timeout, to avoid
 1037                  * triggering reconnection, should the user decide to
 1038                  * reenable them.
 1039                  */
 1040                 cs->cs_timeout = 0;
 1041                 return;
 1042         }
 1043 
 1044         if (cs->cs_timeout >= ping_timeout) {
 1045                 CFISCSI_SESSION_WARN(cs, "no ping reply (NOP-Out) after %d seconds; "
 1046                     "dropping connection",  ping_timeout);
 1047                 cfiscsi_session_terminate(cs);
 1048                 return;
 1049         }
 1050 
 1051         /*
 1052          * If the ping was reset less than one second ago - which means
 1053          * that we've received some PDU during the last second - assume
 1054          * the traffic flows correctly and don't bother sending a NOP-Out.
 1055          *
 1056          * (It's 2 - one for one second, and one for incrementing is_timeout
 1057          * earlier in this routine.)
 1058          */
 1059         if (cs->cs_timeout < 2)
 1060                 return;
 1061 
 1062         cp = icl_pdu_new(cs->cs_conn, M_NOWAIT);
 1063         if (cp == NULL) {
 1064                 CFISCSI_SESSION_WARN(cs, "failed to allocate memory");
 1065                 return;
 1066         }
 1067         bhsni = (struct iscsi_bhs_nop_in *)cp->ip_bhs;
 1068         bhsni->bhsni_opcode = ISCSI_BHS_OPCODE_NOP_IN;
 1069         bhsni->bhsni_flags = 0x80;
 1070         bhsni->bhsni_initiator_task_tag = 0xffffffff;
 1071 
 1072         cfiscsi_pdu_queue(cp);
 1073 }
 1074 
 1075 static struct cfiscsi_data_wait *
 1076 cfiscsi_data_wait_new(struct cfiscsi_session *cs, union ctl_io *io,
 1077     uint32_t initiator_task_tag, uint32_t *target_transfer_tagp)
 1078 {
 1079         struct cfiscsi_data_wait *cdw;
 1080         int error;
 1081 
 1082         cdw = uma_zalloc(cfiscsi_data_wait_zone, M_NOWAIT | M_ZERO);
 1083         if (cdw == NULL) {
 1084                 CFISCSI_SESSION_WARN(cs,
 1085                     "failed to allocate %zd bytes", sizeof(*cdw));
 1086                 return (NULL);
 1087         }
 1088 
 1089         error = icl_conn_transfer_setup(cs->cs_conn, PRIV_REQUEST(io), io,
 1090             target_transfer_tagp, &cdw->cdw_icl_prv);
 1091         if (error != 0) {
 1092                 CFISCSI_SESSION_WARN(cs,
 1093                     "icl_conn_transfer_setup() failed with error %d", error);
 1094                 uma_zfree(cfiscsi_data_wait_zone, cdw);
 1095                 return (NULL);
 1096         }
 1097 
 1098         cdw->cdw_ctl_io = io;
 1099         cdw->cdw_target_transfer_tag = *target_transfer_tagp;
 1100         cdw->cdw_initiator_task_tag = initiator_task_tag;
 1101 
 1102         return (cdw);
 1103 }
 1104 
 1105 static void
 1106 cfiscsi_data_wait_free(struct cfiscsi_session *cs,
 1107     struct cfiscsi_data_wait *cdw)
 1108 {
 1109 
 1110         icl_conn_transfer_done(cs->cs_conn, cdw->cdw_icl_prv);
 1111         uma_zfree(cfiscsi_data_wait_zone, cdw);
 1112 }
 1113 
 1114 static void
 1115 cfiscsi_data_wait_abort(struct cfiscsi_session *cs,
 1116     struct cfiscsi_data_wait *cdw, int status)
 1117 {
 1118         union ctl_io *cdw_io;
 1119 
 1120         /*
 1121          * Set nonzero port status; this prevents backends from
 1122          * assuming that the data transfer actually succeeded
 1123          * and writing uninitialized data to disk.
 1124          */
 1125         MPASS(status != 0);
 1126         cdw_io = cdw->cdw_ctl_io;
 1127         cdw_io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG;
 1128         cdw_io->scsiio.io_hdr.port_status = status;
 1129         cfiscsi_data_wait_free(cs, cdw);
 1130         ctl_datamove_done(cdw_io, false);
 1131 }
 1132 
 1133 static void
 1134 cfiscsi_session_terminate_tasks(struct cfiscsi_session *cs)
 1135 {
 1136         struct cfiscsi_data_wait *cdw;
 1137         struct icl_pdu *ip;
 1138         union ctl_io *io;
 1139         int error, last, wait;
 1140 
 1141         if (cs->cs_target == NULL)
 1142                 return;         /* No target yet, so nothing to do. */
 1143         ip = icl_pdu_new(cs->cs_conn, M_WAITOK);
 1144         ip->ip_bhs->bhs_opcode = ISCSI_BHS_OPCODE_INTERNAL;
 1145         io = ctl_alloc_io(cs->cs_target->ct_port.ctl_pool_ref);
 1146         ctl_zero_io(io);
 1147         PRIV_REQUEST(io) = ip;
 1148         io->io_hdr.io_type = CTL_IO_TASK;
 1149         io->io_hdr.nexus.initid = cs->cs_ctl_initid;
 1150         io->io_hdr.nexus.targ_port = cs->cs_target->ct_port.targ_port;
 1151         io->io_hdr.nexus.targ_lun = 0;
 1152         io->taskio.tag_type = CTL_TAG_SIMPLE; /* XXX */
 1153         io->taskio.task_action = CTL_TASK_I_T_NEXUS_RESET;
 1154         wait = cs->cs_outstanding_ctl_pdus;
 1155         refcount_acquire(&cs->cs_outstanding_ctl_pdus);
 1156         error = ctl_run(io);
 1157         if (error != CTL_RETVAL_COMPLETE) {
 1158                 CFISCSI_SESSION_WARN(cs, "ctl_run() failed; error %d", error);
 1159                 refcount_release(&cs->cs_outstanding_ctl_pdus);
 1160                 ctl_free_io(io);
 1161                 icl_pdu_free(ip);
 1162         }
 1163 
 1164         CFISCSI_SESSION_LOCK(cs);
 1165         cs->cs_terminating_tasks = true;
 1166         while ((cdw = TAILQ_FIRST(&cs->cs_waiting_for_data_out)) != NULL) {
 1167                 TAILQ_REMOVE(&cs->cs_waiting_for_data_out, cdw, cdw_next);
 1168                 CFISCSI_SESSION_UNLOCK(cs);
 1169                 cfiscsi_data_wait_abort(cs, cdw, 42);
 1170                 CFISCSI_SESSION_LOCK(cs);
 1171         }
 1172         CFISCSI_SESSION_UNLOCK(cs);
 1173 
 1174         /*
 1175          * Wait for CTL to terminate all the tasks.
 1176          */
 1177         if (wait > 0)
 1178                 CFISCSI_SESSION_WARN(cs,
 1179                     "waiting for CTL to terminate %d tasks", wait);
 1180         for (;;) {
 1181                 refcount_acquire(&cs->cs_outstanding_ctl_pdus);
 1182                 last = refcount_release(&cs->cs_outstanding_ctl_pdus);
 1183                 if (last != 0)
 1184                         break;
 1185                 tsleep(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus),
 1186                     0, "cfiscsi_terminate", hz / 100);
 1187         }
 1188         if (wait > 0)
 1189                 CFISCSI_SESSION_WARN(cs, "tasks terminated");
 1190 }
 1191 
 1192 static void
 1193 cfiscsi_maintenance_thread(void *arg)
 1194 {
 1195         struct cfiscsi_session *cs;
 1196 
 1197         cs = arg;
 1198 
 1199         for (;;) {
 1200                 CFISCSI_SESSION_LOCK(cs);
 1201                 if (cs->cs_terminating == false || cs->cs_handoff_in_progress)
 1202                         cv_wait(&cs->cs_maintenance_cv, &cs->cs_lock);
 1203                 CFISCSI_SESSION_UNLOCK(cs);
 1204 
 1205                 if (cs->cs_terminating && cs->cs_handoff_in_progress == false) {
 1206                         /*
 1207                          * We used to wait up to 30 seconds to deliver queued
 1208                          * PDUs to the initiator.  We also tried hard to deliver
 1209                          * SCSI Responses for the aborted PDUs.  We don't do
 1210                          * that anymore.  We might need to revisit that.
 1211                          */
 1212                         callout_drain(&cs->cs_callout);
 1213                         icl_conn_close(cs->cs_conn);
 1214 
 1215                         /*
 1216                          * At this point ICL receive thread is no longer
 1217                          * running; no new tasks can be queued.
 1218                          */
 1219                         cfiscsi_session_terminate_tasks(cs);
 1220                         cfiscsi_session_delete(cs);
 1221                         kthread_exit();
 1222                         return;
 1223                 }
 1224                 CFISCSI_SESSION_DEBUG(cs, "nothing to do");
 1225         }
 1226 }
 1227 
 1228 static void
 1229 cfiscsi_session_terminate(struct cfiscsi_session *cs)
 1230 {
 1231 
 1232         cs->cs_terminating = true;
 1233         cv_signal(&cs->cs_maintenance_cv);
 1234 #ifdef ICL_KERNEL_PROXY
 1235         cv_signal(&cs->cs_login_cv);
 1236 #endif
 1237 }
 1238 
 1239 static int
 1240 cfiscsi_session_register_initiator(struct cfiscsi_session *cs)
 1241 {
 1242         struct cfiscsi_target *ct;
 1243         char *name;
 1244         int i;
 1245 
 1246         KASSERT(cs->cs_ctl_initid == -1, ("already registered"));
 1247 
 1248         ct = cs->cs_target;
 1249         name = strdup(cs->cs_initiator_id, M_CTL);
 1250         i = ctl_add_initiator(&ct->ct_port, -1, 0, name);
 1251         if (i < 0) {
 1252                 CFISCSI_SESSION_WARN(cs, "ctl_add_initiator failed with error %d",
 1253                     i);
 1254                 cs->cs_ctl_initid = -1;
 1255                 return (1);
 1256         }
 1257         cs->cs_ctl_initid = i;
 1258 #if 0
 1259         CFISCSI_SESSION_DEBUG(cs, "added initiator id %d", i);
 1260 #endif
 1261 
 1262         return (0);
 1263 }
 1264 
 1265 static void
 1266 cfiscsi_session_unregister_initiator(struct cfiscsi_session *cs)
 1267 {
 1268         int error;
 1269 
 1270         if (cs->cs_ctl_initid == -1)
 1271                 return;
 1272 
 1273         error = ctl_remove_initiator(&cs->cs_target->ct_port, cs->cs_ctl_initid);
 1274         if (error != 0) {
 1275                 CFISCSI_SESSION_WARN(cs, "ctl_remove_initiator failed with error %d",
 1276                     error);
 1277         }
 1278         cs->cs_ctl_initid = -1;
 1279 }
 1280 
 1281 static struct cfiscsi_session *
 1282 cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload)
 1283 {
 1284         struct cfiscsi_session *cs;
 1285         int error;
 1286 
 1287         cs = malloc(sizeof(*cs), M_CFISCSI, M_NOWAIT | M_ZERO);
 1288         if (cs == NULL) {
 1289                 CFISCSI_WARN("malloc failed");
 1290                 return (NULL);
 1291         }
 1292         cs->cs_ctl_initid = -1;
 1293 
 1294         refcount_init(&cs->cs_outstanding_ctl_pdus, 0);
 1295         TAILQ_INIT(&cs->cs_waiting_for_data_out);
 1296         mtx_init(&cs->cs_lock, "cfiscsi_lock", NULL, MTX_DEF);
 1297         cv_init(&cs->cs_maintenance_cv, "cfiscsi_mt");
 1298 #ifdef ICL_KERNEL_PROXY
 1299         cv_init(&cs->cs_login_cv, "cfiscsi_login");
 1300 #endif
 1301 
 1302         /*
 1303          * The purpose of this is to avoid racing with session shutdown.
 1304          * Otherwise we could have the maintenance thread call icl_conn_close()
 1305          * before we call icl_conn_handoff().
 1306          */
 1307         cs->cs_handoff_in_progress = true;
 1308 
 1309         cs->cs_conn = icl_new_conn(offload, false, "cfiscsi", &cs->cs_lock);
 1310         if (cs->cs_conn == NULL) {
 1311                 free(cs, M_CFISCSI);
 1312                 return (NULL);
 1313         }
 1314         cs->cs_conn->ic_receive = cfiscsi_receive_callback;
 1315         cs->cs_conn->ic_error = cfiscsi_error_callback;
 1316         cs->cs_conn->ic_prv0 = cs;
 1317 
 1318         error = kthread_add(cfiscsi_maintenance_thread, cs, NULL, NULL, 0, 0, "cfiscsimt");
 1319         if (error != 0) {
 1320                 CFISCSI_SESSION_WARN(cs, "kthread_add(9) failed with error %d", error);
 1321                 free(cs, M_CFISCSI);
 1322                 return (NULL);
 1323         }
 1324 
 1325         mtx_lock(&softc->lock);
 1326         cs->cs_id = ++softc->last_session_id;
 1327         TAILQ_INSERT_TAIL(&softc->sessions, cs, cs_next);
 1328         mtx_unlock(&softc->lock);
 1329 
 1330         /*
 1331          * Start pinging the initiator.
 1332          */
 1333         callout_init(&cs->cs_callout, 1);
 1334         callout_reset(&cs->cs_callout, 1 * hz, cfiscsi_callout, cs);
 1335 
 1336         return (cs);
 1337 }
 1338 
 1339 static void
 1340 cfiscsi_session_delete(struct cfiscsi_session *cs)
 1341 {
 1342         struct cfiscsi_softc *softc;
 1343 
 1344         softc = &cfiscsi_softc;
 1345 
 1346         KASSERT(cs->cs_outstanding_ctl_pdus == 0,
 1347             ("destroying session with outstanding CTL pdus"));
 1348         KASSERT(TAILQ_EMPTY(&cs->cs_waiting_for_data_out),
 1349             ("destroying session with non-empty queue"));
 1350 
 1351         mtx_lock(&softc->lock);
 1352         TAILQ_REMOVE(&softc->sessions, cs, cs_next);
 1353         mtx_unlock(&softc->lock);
 1354 
 1355         cfiscsi_session_unregister_initiator(cs);
 1356         if (cs->cs_target != NULL)
 1357                 cfiscsi_target_release(cs->cs_target);
 1358         icl_conn_close(cs->cs_conn);
 1359         icl_conn_free(cs->cs_conn);
 1360         free(cs, M_CFISCSI);
 1361         cv_signal(&softc->sessions_cv);
 1362 }
 1363 
 1364 static int
 1365 cfiscsi_init(void)
 1366 {
 1367         struct cfiscsi_softc *softc;
 1368 
 1369         softc = &cfiscsi_softc;
 1370         bzero(softc, sizeof(*softc));
 1371         mtx_init(&softc->lock, "cfiscsi", NULL, MTX_DEF);
 1372 
 1373         cv_init(&softc->sessions_cv, "cfiscsi_sessions");
 1374 #ifdef ICL_KERNEL_PROXY
 1375         cv_init(&softc->accept_cv, "cfiscsi_accept");
 1376 #endif
 1377         TAILQ_INIT(&softc->sessions);
 1378         TAILQ_INIT(&softc->targets);
 1379 
 1380         cfiscsi_data_wait_zone = uma_zcreate("cfiscsi_data_wait",
 1381             sizeof(struct cfiscsi_data_wait), NULL, NULL, NULL, NULL,
 1382             UMA_ALIGN_PTR, 0);
 1383 
 1384         return (0);
 1385 }
 1386 
 1387 static int
 1388 cfiscsi_shutdown(void)
 1389 {
 1390         struct cfiscsi_softc *softc = &cfiscsi_softc;
 1391 
 1392         if (!TAILQ_EMPTY(&softc->sessions) || !TAILQ_EMPTY(&softc->targets))
 1393                 return (EBUSY);
 1394 
 1395         uma_zdestroy(cfiscsi_data_wait_zone);
 1396 #ifdef ICL_KERNEL_PROXY
 1397         cv_destroy(&softc->accept_cv);
 1398 #endif
 1399         cv_destroy(&softc->sessions_cv);
 1400         mtx_destroy(&softc->lock);
 1401         return (0);
 1402 }
 1403 
 1404 #ifdef ICL_KERNEL_PROXY
 1405 static void
 1406 cfiscsi_accept(struct socket *so, struct sockaddr *sa, int portal_id)
 1407 {
 1408         struct cfiscsi_session *cs;
 1409 
 1410         cs = cfiscsi_session_new(&cfiscsi_softc, NULL);
 1411         if (cs == NULL) {
 1412                 CFISCSI_WARN("failed to create session");
 1413                 return;
 1414         }
 1415 
 1416         icl_conn_handoff_sock(cs->cs_conn, so);
 1417         cs->cs_initiator_sa = sa;
 1418         cs->cs_portal_id = portal_id;
 1419         cs->cs_handoff_in_progress = false;
 1420         cs->cs_waiting_for_ctld = true;
 1421         cv_signal(&cfiscsi_softc.accept_cv);
 1422 
 1423         CFISCSI_SESSION_LOCK(cs);
 1424         /*
 1425          * Wake up the maintenance thread if we got scheduled for termination
 1426          * somewhere between cfiscsi_session_new() and icl_conn_handoff_sock().
 1427          */
 1428         if (cs->cs_terminating)
 1429                 cfiscsi_session_terminate(cs);
 1430         CFISCSI_SESSION_UNLOCK(cs);
 1431 }
 1432 #endif
 1433 
 1434 static void
 1435 cfiscsi_online(void *arg)
 1436 {
 1437         struct cfiscsi_softc *softc;
 1438         struct cfiscsi_target *ct;
 1439         int online;
 1440 
 1441         ct = (struct cfiscsi_target *)arg;
 1442         softc = ct->ct_softc;
 1443 
 1444         mtx_lock(&softc->lock);
 1445         if (ct->ct_online) {
 1446                 mtx_unlock(&softc->lock);
 1447                 return;
 1448         }
 1449         ct->ct_online = 1;
 1450         online = softc->online++;
 1451         mtx_unlock(&softc->lock);
 1452         if (online > 0)
 1453                 return;
 1454 
 1455 #ifdef ICL_KERNEL_PROXY
 1456         if (softc->listener != NULL)
 1457                 icl_listen_free(softc->listener);
 1458         softc->listener = icl_listen_new(cfiscsi_accept);
 1459 #endif
 1460 }
 1461 
 1462 static void
 1463 cfiscsi_offline(void *arg)
 1464 {
 1465         struct cfiscsi_softc *softc;
 1466         struct cfiscsi_target *ct;
 1467         struct cfiscsi_session *cs;
 1468         int error, online;
 1469 
 1470         ct = (struct cfiscsi_target *)arg;
 1471         softc = ct->ct_softc;
 1472 
 1473         mtx_lock(&softc->lock);
 1474         if (!ct->ct_online) {
 1475                 mtx_unlock(&softc->lock);
 1476                 return;
 1477         }
 1478         ct->ct_online = 0;
 1479         online = --softc->online;
 1480 
 1481         do {
 1482                 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
 1483                         if (cs->cs_target == ct)
 1484                                 cfiscsi_session_terminate(cs);
 1485                 }
 1486                 TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
 1487                         if (cs->cs_target == ct)
 1488                                 break;
 1489                 }
 1490                 if (cs != NULL) {
 1491                         error = cv_wait_sig(&softc->sessions_cv, &softc->lock);
 1492                         if (error != 0) {
 1493                                 CFISCSI_SESSION_DEBUG(cs,
 1494                                     "cv_wait failed with error %d\n", error);
 1495                                 break;
 1496                         }
 1497                 }
 1498         } while (cs != NULL && ct->ct_online == 0);
 1499         mtx_unlock(&softc->lock);
 1500         if (online > 0)
 1501                 return;
 1502 
 1503 #ifdef ICL_KERNEL_PROXY
 1504         icl_listen_free(softc->listener);
 1505         softc->listener = NULL;
 1506 #endif
 1507 }
 1508 
 1509 static int
 1510 cfiscsi_info(void *arg, struct sbuf *sb)
 1511 {
 1512         struct cfiscsi_target *ct = (struct cfiscsi_target *)arg;
 1513         int retval;
 1514 
 1515         retval = sbuf_printf(sb, "\t<cfiscsi_state>%d</cfiscsi_state>\n",
 1516             ct->ct_state);
 1517         return (retval);
 1518 }
 1519 
 1520 static void
 1521 cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
 1522 {
 1523         struct cfiscsi_softc *softc;
 1524         struct cfiscsi_session *cs, *cs2;
 1525         struct cfiscsi_target *ct;
 1526         struct ctl_iscsi_handoff_params *cihp;
 1527         int error;
 1528 
 1529         cihp = (struct ctl_iscsi_handoff_params *)&(ci->data);
 1530         softc = &cfiscsi_softc;
 1531 
 1532         CFISCSI_DEBUG("new connection from %s (%s) to %s",
 1533             cihp->initiator_name, cihp->initiator_addr,
 1534             cihp->target_name);
 1535 
 1536         ct = cfiscsi_target_find(softc, cihp->target_name,
 1537             cihp->portal_group_tag);
 1538         if (ct == NULL) {
 1539                 ci->status = CTL_ISCSI_ERROR;
 1540                 snprintf(ci->error_str, sizeof(ci->error_str),
 1541                     "%s: target not found", __func__);
 1542                 return;
 1543         }
 1544 
 1545 #ifdef ICL_KERNEL_PROXY
 1546         if (cihp->socket > 0 && cihp->connection_id > 0) {
 1547                 snprintf(ci->error_str, sizeof(ci->error_str),
 1548                     "both socket and connection_id set");
 1549                 ci->status = CTL_ISCSI_ERROR;
 1550                 cfiscsi_target_release(ct);
 1551                 return;
 1552         }
 1553         if (cihp->socket == 0) {
 1554                 mtx_lock(&cfiscsi_softc.lock);
 1555                 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
 1556                         if (cs->cs_id == cihp->connection_id)
 1557                                 break;
 1558                 }
 1559                 if (cs == NULL) {
 1560                         mtx_unlock(&cfiscsi_softc.lock);
 1561                         snprintf(ci->error_str, sizeof(ci->error_str),
 1562                             "connection not found");
 1563                         ci->status = CTL_ISCSI_ERROR;
 1564                         cfiscsi_target_release(ct);
 1565                         return;
 1566                 }
 1567                 mtx_unlock(&cfiscsi_softc.lock);
 1568         } else {
 1569 #endif
 1570                 cs = cfiscsi_session_new(softc, cihp->offload);
 1571                 if (cs == NULL) {
 1572                         ci->status = CTL_ISCSI_ERROR;
 1573                         snprintf(ci->error_str, sizeof(ci->error_str),
 1574                             "%s: cfiscsi_session_new failed", __func__);
 1575                         cfiscsi_target_release(ct);
 1576                         return;
 1577                 }
 1578 #ifdef ICL_KERNEL_PROXY
 1579         }
 1580 #endif
 1581 
 1582         /*
 1583          * First PDU of Full Feature phase has the same CmdSN as the last
 1584          * PDU from the Login Phase received from the initiator.  Thus,
 1585          * the -1 below.
 1586          */
 1587         cs->cs_cmdsn = cihp->cmdsn;
 1588         cs->cs_statsn = cihp->statsn;
 1589         cs->cs_conn->ic_max_recv_data_segment_length =
 1590             cihp->max_recv_data_segment_length;
 1591         cs->cs_conn->ic_max_send_data_segment_length =
 1592             cihp->max_send_data_segment_length;
 1593         cs->cs_max_burst_length = cihp->max_burst_length;
 1594         cs->cs_first_burst_length = cihp->first_burst_length;
 1595         cs->cs_immediate_data = !!cihp->immediate_data;
 1596         if (cihp->header_digest == CTL_ISCSI_DIGEST_CRC32C)
 1597                 cs->cs_conn->ic_header_crc32c = true;
 1598         if (cihp->data_digest == CTL_ISCSI_DIGEST_CRC32C)
 1599                 cs->cs_conn->ic_data_crc32c = true;
 1600 
 1601         strlcpy(cs->cs_initiator_name,
 1602             cihp->initiator_name, sizeof(cs->cs_initiator_name));
 1603         strlcpy(cs->cs_initiator_addr,
 1604             cihp->initiator_addr, sizeof(cs->cs_initiator_addr));
 1605         strlcpy(cs->cs_initiator_alias,
 1606             cihp->initiator_alias, sizeof(cs->cs_initiator_alias));
 1607         memcpy(cs->cs_initiator_isid,
 1608             cihp->initiator_isid, sizeof(cs->cs_initiator_isid));
 1609         snprintf(cs->cs_initiator_id, sizeof(cs->cs_initiator_id),
 1610             "%s,i,0x%02x%02x%02x%02x%02x%02x", cs->cs_initiator_name,
 1611             cihp->initiator_isid[0], cihp->initiator_isid[1],
 1612             cihp->initiator_isid[2], cihp->initiator_isid[3],
 1613             cihp->initiator_isid[4], cihp->initiator_isid[5]);
 1614 
 1615         mtx_lock(&softc->lock);
 1616         if (ct->ct_online == 0) {
 1617                 mtx_unlock(&softc->lock);
 1618                 CFISCSI_SESSION_LOCK(cs);
 1619                 cs->cs_handoff_in_progress = false;
 1620                 cfiscsi_session_terminate(cs);
 1621                 CFISCSI_SESSION_UNLOCK(cs);
 1622                 cfiscsi_target_release(ct);
 1623                 ci->status = CTL_ISCSI_ERROR;
 1624                 snprintf(ci->error_str, sizeof(ci->error_str),
 1625                     "%s: port offline", __func__);
 1626                 return;
 1627         }
 1628         cs->cs_target = ct;
 1629         mtx_unlock(&softc->lock);
 1630 
 1631 restart:
 1632         if (!cs->cs_terminating) {
 1633                 mtx_lock(&softc->lock);
 1634                 TAILQ_FOREACH(cs2, &softc->sessions, cs_next) {
 1635                         if (cs2 != cs && cs2->cs_tasks_aborted == false &&
 1636                             cs->cs_target == cs2->cs_target &&
 1637                             strcmp(cs->cs_initiator_id, cs2->cs_initiator_id) == 0) {
 1638                                 if (strcmp(cs->cs_initiator_addr,
 1639                                     cs2->cs_initiator_addr) != 0) {
 1640                                         CFISCSI_SESSION_WARN(cs2,
 1641                                             "session reinstatement from "
 1642                                             "different address %s",
 1643                                             cs->cs_initiator_addr);
 1644                                 } else {
 1645                                         CFISCSI_SESSION_DEBUG(cs2,
 1646                                             "session reinstatement");
 1647                                 }
 1648                                 cfiscsi_session_terminate(cs2);
 1649                                 mtx_unlock(&softc->lock);
 1650                                 pause("cfiscsi_reinstate", 1);
 1651                                 goto restart;
 1652                         }
 1653                 }
 1654                 mtx_unlock(&softc->lock);
 1655         }
 1656 
 1657         /*
 1658          * Register initiator with CTL.
 1659          */
 1660         cfiscsi_session_register_initiator(cs);
 1661 
 1662 #ifdef ICL_KERNEL_PROXY
 1663         if (cihp->socket > 0) {
 1664 #endif
 1665                 error = icl_conn_handoff(cs->cs_conn, cihp->socket);
 1666                 if (error != 0) {
 1667                         CFISCSI_SESSION_LOCK(cs);
 1668                         cs->cs_handoff_in_progress = false;
 1669                         cfiscsi_session_terminate(cs);
 1670                         CFISCSI_SESSION_UNLOCK(cs);
 1671                         ci->status = CTL_ISCSI_ERROR;
 1672                         snprintf(ci->error_str, sizeof(ci->error_str),
 1673                             "%s: icl_conn_handoff failed with error %d",
 1674                             __func__, error);
 1675                         return;
 1676                 }
 1677 #ifdef ICL_KERNEL_PROXY
 1678         }
 1679 #endif
 1680 
 1681 #ifdef ICL_KERNEL_PROXY
 1682         cs->cs_login_phase = false;
 1683 
 1684         /*
 1685          * First PDU of the Full Feature phase has likely already arrived.
 1686          * We have to pick it up and execute properly.
 1687          */
 1688         if (cs->cs_login_pdu != NULL) {
 1689                 CFISCSI_SESSION_DEBUG(cs, "picking up first PDU");
 1690                 cfiscsi_pdu_handle(cs->cs_login_pdu);
 1691                 cs->cs_login_pdu = NULL;
 1692         }
 1693 #endif
 1694 
 1695         CFISCSI_SESSION_LOCK(cs);
 1696         cs->cs_handoff_in_progress = false;
 1697 
 1698         /*
 1699          * Wake up the maintenance thread if we got scheduled for termination.
 1700          */
 1701         if (cs->cs_terminating)
 1702                 cfiscsi_session_terminate(cs);
 1703         CFISCSI_SESSION_UNLOCK(cs);
 1704 
 1705         ci->status = CTL_ISCSI_OK;
 1706 }
 1707 
 1708 static void
 1709 cfiscsi_ioctl_list(struct ctl_iscsi *ci)
 1710 {
 1711         struct ctl_iscsi_list_params *cilp;
 1712         struct cfiscsi_session *cs;
 1713         struct cfiscsi_softc *softc;
 1714         struct sbuf *sb;
 1715         int error;
 1716 
 1717         cilp = (struct ctl_iscsi_list_params *)&(ci->data);
 1718         softc = &cfiscsi_softc;
 1719 
 1720         sb = sbuf_new(NULL, NULL, cilp->alloc_len, SBUF_FIXEDLEN);
 1721         if (sb == NULL) {
 1722                 ci->status = CTL_ISCSI_ERROR;
 1723                 snprintf(ci->error_str, sizeof(ci->error_str),
 1724                     "Unable to allocate %d bytes for iSCSI session list",
 1725                     cilp->alloc_len);
 1726                 return;
 1727         }
 1728 
 1729         sbuf_printf(sb, "<ctlislist>\n");
 1730         mtx_lock(&softc->lock);
 1731         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
 1732                 if (cs->cs_target == NULL)
 1733                         continue;
 1734                 error = sbuf_printf(sb, "<connection id=\"%d\">"
 1735                     "<initiator>%s</initiator>"
 1736                     "<initiator_addr>%s</initiator_addr>"
 1737                     "<initiator_alias>%s</initiator_alias>"
 1738                     "<target>%s</target>"
 1739                     "<target_alias>%s</target_alias>"
 1740                     "<target_portal_group_tag>%u</target_portal_group_tag>"
 1741                     "<header_digest>%s</header_digest>"
 1742                     "<data_digest>%s</data_digest>"
 1743                     "<max_recv_data_segment_length>%d</max_recv_data_segment_length>"
 1744                     "<max_send_data_segment_length>%d</max_send_data_segment_length>"
 1745                     "<max_burst_length>%d</max_burst_length>"
 1746                     "<first_burst_length>%d</first_burst_length>"
 1747                     "<immediate_data>%d</immediate_data>"
 1748                     "<iser>%d</iser>"
 1749                     "<offload>%s</offload>"
 1750                     "</connection>\n",
 1751                     cs->cs_id,
 1752                     cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias,
 1753                     cs->cs_target->ct_name, cs->cs_target->ct_alias,
 1754                     cs->cs_target->ct_tag,
 1755                     cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
 1756                     cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
 1757                     cs->cs_conn->ic_max_recv_data_segment_length,
 1758                     cs->cs_conn->ic_max_send_data_segment_length,
 1759                     cs->cs_max_burst_length,
 1760                     cs->cs_first_burst_length,
 1761                     cs->cs_immediate_data,
 1762                     cs->cs_conn->ic_iser,
 1763                     cs->cs_conn->ic_offload);
 1764                 if (error != 0)
 1765                         break;
 1766         }
 1767         mtx_unlock(&softc->lock);
 1768         error = sbuf_printf(sb, "</ctlislist>\n");
 1769         if (error != 0) {
 1770                 sbuf_delete(sb);
 1771                 ci->status = CTL_ISCSI_LIST_NEED_MORE_SPACE;
 1772                 snprintf(ci->error_str, sizeof(ci->error_str),
 1773                     "Out of space, %d bytes is too small", cilp->alloc_len);
 1774                 return;
 1775         }
 1776         sbuf_finish(sb);
 1777 
 1778         error = copyout(sbuf_data(sb), cilp->conn_xml, sbuf_len(sb) + 1);
 1779         if (error != 0) {
 1780                 sbuf_delete(sb);
 1781                 snprintf(ci->error_str, sizeof(ci->error_str),
 1782                     "copyout failed with error %d", error);
 1783                 ci->status = CTL_ISCSI_ERROR;
 1784                 return;
 1785         }
 1786         cilp->fill_len = sbuf_len(sb) + 1;
 1787         ci->status = CTL_ISCSI_OK;
 1788         sbuf_delete(sb);
 1789 }
 1790 
 1791 static void
 1792 cfiscsi_ioctl_logout(struct ctl_iscsi *ci)
 1793 {
 1794         struct icl_pdu *response;
 1795         struct iscsi_bhs_asynchronous_message *bhsam;
 1796         struct ctl_iscsi_logout_params *cilp;
 1797         struct cfiscsi_session *cs;
 1798         struct cfiscsi_softc *softc;
 1799         int found = 0;
 1800 
 1801         cilp = (struct ctl_iscsi_logout_params *)&(ci->data);
 1802         softc = &cfiscsi_softc;
 1803 
 1804         mtx_lock(&softc->lock);
 1805         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
 1806                 if (cilp->all == 0 && cs->cs_id != cilp->connection_id &&
 1807                     strcmp(cs->cs_initiator_name, cilp->initiator_name) != 0 &&
 1808                     strcmp(cs->cs_initiator_addr, cilp->initiator_addr) != 0)
 1809                         continue;
 1810 
 1811                 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
 1812                 if (response == NULL) {
 1813                         ci->status = CTL_ISCSI_ERROR;
 1814                         snprintf(ci->error_str, sizeof(ci->error_str),
 1815                             "Unable to allocate memory");
 1816                         mtx_unlock(&softc->lock);
 1817                         return;
 1818                 }
 1819                 bhsam =
 1820                     (struct iscsi_bhs_asynchronous_message *)response->ip_bhs;
 1821                 bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
 1822                 bhsam->bhsam_flags = 0x80;
 1823                 bhsam->bhsam_async_event = BHSAM_EVENT_TARGET_REQUESTS_LOGOUT;
 1824                 bhsam->bhsam_parameter3 = htons(10);
 1825                 cfiscsi_pdu_queue(response);
 1826                 found++;
 1827         }
 1828         mtx_unlock(&softc->lock);
 1829 
 1830         if (found == 0) {
 1831                 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
 1832                 snprintf(ci->error_str, sizeof(ci->error_str),
 1833                     "No matching connections found");
 1834                 return;
 1835         }
 1836 
 1837         ci->status = CTL_ISCSI_OK;
 1838 }
 1839 
 1840 static void
 1841 cfiscsi_ioctl_terminate(struct ctl_iscsi *ci)
 1842 {
 1843         struct icl_pdu *response;
 1844         struct iscsi_bhs_asynchronous_message *bhsam;
 1845         struct ctl_iscsi_terminate_params *citp;
 1846         struct cfiscsi_session *cs;
 1847         struct cfiscsi_softc *softc;
 1848         int found = 0;
 1849 
 1850         citp = (struct ctl_iscsi_terminate_params *)&(ci->data);
 1851         softc = &cfiscsi_softc;
 1852 
 1853         mtx_lock(&softc->lock);
 1854         TAILQ_FOREACH(cs, &softc->sessions, cs_next) {
 1855                 if (citp->all == 0 && cs->cs_id != citp->connection_id &&
 1856                     strcmp(cs->cs_initiator_name, citp->initiator_name) != 0 &&
 1857                     strcmp(cs->cs_initiator_addr, citp->initiator_addr) != 0)
 1858                         continue;
 1859 
 1860                 response = icl_pdu_new(cs->cs_conn, M_NOWAIT);
 1861                 if (response == NULL) {
 1862                         /*
 1863                          * Oh well.  Just terminate the connection.
 1864                          */
 1865                 } else {
 1866                         bhsam = (struct iscsi_bhs_asynchronous_message *)
 1867                             response->ip_bhs;
 1868                         bhsam->bhsam_opcode = ISCSI_BHS_OPCODE_ASYNC_MESSAGE;
 1869                         bhsam->bhsam_flags = 0x80;
 1870                         bhsam->bhsam_0xffffffff = 0xffffffff;
 1871                         bhsam->bhsam_async_event =
 1872                             BHSAM_EVENT_TARGET_TERMINATES_SESSION;
 1873                         cfiscsi_pdu_queue(response);
 1874                 }
 1875                 cfiscsi_session_terminate(cs);
 1876                 found++;
 1877         }
 1878         mtx_unlock(&softc->lock);
 1879 
 1880         if (found == 0) {
 1881                 ci->status = CTL_ISCSI_SESSION_NOT_FOUND;
 1882                 snprintf(ci->error_str, sizeof(ci->error_str),
 1883                     "No matching connections found");
 1884                 return;
 1885         }
 1886 
 1887         ci->status = CTL_ISCSI_OK;
 1888 }
 1889 
 1890 static void
 1891 cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
 1892 {
 1893         struct ctl_iscsi_limits_params *cilp;
 1894         struct icl_drv_limits idl;
 1895         int error;
 1896 
 1897         cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
 1898 
 1899         error = icl_limits(cilp->offload, false, cilp->socket, &idl);
 1900         if (error != 0) {
 1901                 ci->status = CTL_ISCSI_ERROR;
 1902                 snprintf(ci->error_str, sizeof(ci->error_str),
 1903                         "%s: icl_limits failed with error %d",
 1904                         __func__, error);
 1905                 return;
 1906         }
 1907 
 1908         cilp->max_recv_data_segment_length =
 1909             idl.idl_max_recv_data_segment_length;
 1910         cilp->max_send_data_segment_length =
 1911             idl.idl_max_send_data_segment_length;
 1912         cilp->max_burst_length = idl.idl_max_burst_length;
 1913         cilp->first_burst_length = idl.idl_first_burst_length;
 1914 
 1915         ci->status = CTL_ISCSI_OK;
 1916 }
 1917 
 1918 #ifdef ICL_KERNEL_PROXY
 1919 static void
 1920 cfiscsi_ioctl_listen(struct ctl_iscsi *ci)
 1921 {
 1922         struct ctl_iscsi_listen_params *cilp;
 1923         struct sockaddr *sa;
 1924         int error;
 1925 
 1926         cilp = (struct ctl_iscsi_listen_params *)&(ci->data);
 1927 
 1928         if (cfiscsi_softc.listener == NULL) {
 1929                 CFISCSI_DEBUG("no listener");
 1930                 snprintf(ci->error_str, sizeof(ci->error_str), "no listener");
 1931                 ci->status = CTL_ISCSI_ERROR;
 1932                 return;
 1933         }
 1934 
 1935         error = getsockaddr(&sa, (void *)cilp->addr, cilp->addrlen);
 1936         if (error != 0) {
 1937                 CFISCSI_DEBUG("getsockaddr, error %d", error);
 1938                 snprintf(ci->error_str, sizeof(ci->error_str), "getsockaddr failed");
 1939                 ci->status = CTL_ISCSI_ERROR;
 1940                 return;
 1941         }
 1942 
 1943         error = icl_listen_add(cfiscsi_softc.listener, cilp->iser, cilp->domain,
 1944             cilp->socktype, cilp->protocol, sa, cilp->portal_id);
 1945         if (error != 0) {
 1946                 free(sa, M_SONAME);
 1947                 CFISCSI_DEBUG("icl_listen_add, error %d", error);
 1948                 snprintf(ci->error_str, sizeof(ci->error_str),
 1949                     "icl_listen_add failed, error %d", error);
 1950                 ci->status = CTL_ISCSI_ERROR;
 1951                 return;
 1952         }
 1953 
 1954         ci->status = CTL_ISCSI_OK;
 1955 }
 1956 
 1957 static void
 1958 cfiscsi_ioctl_accept(struct ctl_iscsi *ci)
 1959 {
 1960         struct ctl_iscsi_accept_params *ciap;
 1961         struct cfiscsi_session *cs;
 1962         int error;
 1963 
 1964         ciap = (struct ctl_iscsi_accept_params *)&(ci->data);
 1965 
 1966         mtx_lock(&cfiscsi_softc.lock);
 1967         for (;;) {
 1968                 TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
 1969                         if (cs->cs_waiting_for_ctld)
 1970                                 break;
 1971                 }
 1972                 if (cs != NULL)
 1973                         break;
 1974                 error = cv_wait_sig(&cfiscsi_softc.accept_cv, &cfiscsi_softc.lock);
 1975                 if (error != 0) {
 1976                         mtx_unlock(&cfiscsi_softc.lock);
 1977                         snprintf(ci->error_str, sizeof(ci->error_str), "interrupted");
 1978                         ci->status = CTL_ISCSI_ERROR;
 1979                         return;
 1980                 }
 1981         }
 1982         mtx_unlock(&cfiscsi_softc.lock);
 1983 
 1984         cs->cs_waiting_for_ctld = false;
 1985         cs->cs_login_phase = true;
 1986 
 1987         ciap->connection_id = cs->cs_id;
 1988         ciap->portal_id = cs->cs_portal_id;
 1989         ciap->initiator_addrlen = cs->cs_initiator_sa->sa_len;
 1990         error = copyout(cs->cs_initiator_sa, ciap->initiator_addr,
 1991             cs->cs_initiator_sa->sa_len);
 1992         if (error != 0) {
 1993                 snprintf(ci->error_str, sizeof(ci->error_str),
 1994                     "copyout failed with error %d", error);
 1995                 ci->status = CTL_ISCSI_ERROR;
 1996                 return;
 1997         }
 1998 
 1999         ci->status = CTL_ISCSI_OK;
 2000 }
 2001 
 2002 static void
 2003 cfiscsi_ioctl_send(struct ctl_iscsi *ci)
 2004 {
 2005         struct ctl_iscsi_send_params *cisp;
 2006         struct cfiscsi_session *cs;
 2007         struct icl_pdu *ip;
 2008         size_t datalen;
 2009         void *data;
 2010         int error;
 2011 
 2012         cisp = (struct ctl_iscsi_send_params *)&(ci->data);
 2013 
 2014         mtx_lock(&cfiscsi_softc.lock);
 2015         TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
 2016                 if (cs->cs_id == cisp->connection_id)
 2017                         break;
 2018         }
 2019         if (cs == NULL) {
 2020                 mtx_unlock(&cfiscsi_softc.lock);
 2021                 snprintf(ci->error_str, sizeof(ci->error_str), "connection not found");
 2022                 ci->status = CTL_ISCSI_ERROR;
 2023                 return;
 2024         }
 2025         mtx_unlock(&cfiscsi_softc.lock);
 2026 
 2027 #if 0
 2028         if (cs->cs_login_phase == false)
 2029                 return (EBUSY);
 2030 #endif
 2031 
 2032         if (cs->cs_terminating) {
 2033                 snprintf(ci->error_str, sizeof(ci->error_str), "connection is terminating");
 2034                 ci->status = CTL_ISCSI_ERROR;
 2035                 return;
 2036         }
 2037 
 2038         datalen = cisp->data_segment_len;
 2039         /*
 2040          * XXX
 2041          */
 2042         //if (datalen > CFISCSI_MAX_DATA_SEGMENT_LENGTH) {
 2043         if (datalen > 65535) {
 2044                 snprintf(ci->error_str, sizeof(ci->error_str), "data segment too big");
 2045                 ci->status = CTL_ISCSI_ERROR;
 2046                 return;
 2047         }
 2048         if (datalen > 0) {
 2049                 data = malloc(datalen, M_CFISCSI, M_WAITOK);
 2050                 error = copyin(cisp->data_segment, data, datalen);
 2051                 if (error != 0) {
 2052                         free(data, M_CFISCSI);
 2053                         snprintf(ci->error_str, sizeof(ci->error_str), "copyin error %d", error);
 2054                         ci->status = CTL_ISCSI_ERROR;
 2055                         return;
 2056                 }
 2057         }
 2058 
 2059         ip = icl_pdu_new(cs->cs_conn, M_WAITOK);
 2060         memcpy(ip->ip_bhs, cisp->bhs, sizeof(*ip->ip_bhs));
 2061         if (datalen > 0) {
 2062                 icl_pdu_append_data(ip, data, datalen, M_WAITOK);
 2063                 free(data, M_CFISCSI);
 2064         }
 2065         CFISCSI_SESSION_LOCK(cs);
 2066         icl_pdu_queue(ip);
 2067         CFISCSI_SESSION_UNLOCK(cs);
 2068         ci->status = CTL_ISCSI_OK;
 2069 }
 2070 
 2071 static void
 2072 cfiscsi_ioctl_receive(struct ctl_iscsi *ci)
 2073 {
 2074         struct ctl_iscsi_receive_params *cirp;
 2075         struct cfiscsi_session *cs;
 2076         struct icl_pdu *ip;
 2077         void *data;
 2078         int error;
 2079 
 2080         cirp = (struct ctl_iscsi_receive_params *)&(ci->data);
 2081 
 2082         mtx_lock(&cfiscsi_softc.lock);
 2083         TAILQ_FOREACH(cs, &cfiscsi_softc.sessions, cs_next) {
 2084                 if (cs->cs_id == cirp->connection_id)
 2085                         break;
 2086         }
 2087         if (cs == NULL) {
 2088                 mtx_unlock(&cfiscsi_softc.lock);
 2089                 snprintf(ci->error_str, sizeof(ci->error_str),
 2090                     "connection not found");
 2091                 ci->status = CTL_ISCSI_ERROR;
 2092                 return;
 2093         }
 2094         mtx_unlock(&cfiscsi_softc.lock);
 2095 
 2096 #if 0
 2097         if (is->is_login_phase == false)
 2098                 return (EBUSY);
 2099 #endif
 2100 
 2101         CFISCSI_SESSION_LOCK(cs);
 2102         while (cs->cs_login_pdu == NULL && cs->cs_terminating == false) {
 2103                 error = cv_wait_sig(&cs->cs_login_cv, &cs->cs_lock);
 2104                 if (error != 0) {
 2105                         CFISCSI_SESSION_UNLOCK(cs);
 2106                         snprintf(ci->error_str, sizeof(ci->error_str),
 2107                             "interrupted by signal");
 2108                         ci->status = CTL_ISCSI_ERROR;
 2109                         return;
 2110                 }
 2111         }
 2112 
 2113         if (cs->cs_terminating) {
 2114                 CFISCSI_SESSION_UNLOCK(cs);
 2115                 snprintf(ci->error_str, sizeof(ci->error_str),
 2116                     "connection terminating");
 2117                 ci->status = CTL_ISCSI_ERROR;
 2118                 return;
 2119         }
 2120         ip = cs->cs_login_pdu;
 2121         cs->cs_login_pdu = NULL;
 2122         CFISCSI_SESSION_UNLOCK(cs);
 2123 
 2124         if (ip->ip_data_len > cirp->data_segment_len) {
 2125                 icl_pdu_free(ip);
 2126                 snprintf(ci->error_str, sizeof(ci->error_str),
 2127                     "data segment too big");
 2128                 ci->status = CTL_ISCSI_ERROR;
 2129                 return;
 2130         }
 2131 
 2132         copyout(ip->ip_bhs, cirp->bhs, sizeof(*ip->ip_bhs));
 2133         if (ip->ip_data_len > 0) {
 2134                 data = malloc(ip->ip_data_len, M_CFISCSI, M_WAITOK);
 2135                 icl_pdu_get_data(ip, 0, data, ip->ip_data_len);
 2136                 copyout(data, cirp->data_segment, ip->ip_data_len);
 2137                 free(data, M_CFISCSI);
 2138         }
 2139 
 2140         icl_pdu_free(ip);
 2141         ci->status = CTL_ISCSI_OK;
 2142 }
 2143 
 2144 #endif /* !ICL_KERNEL_PROXY */
 2145 
 2146 static void
 2147 cfiscsi_ioctl_port_create(struct ctl_req *req)
 2148 {
 2149         struct cfiscsi_target *ct;
 2150         struct ctl_port *port;
 2151         const char *target, *alias, *val;
 2152         struct scsi_vpd_id_descriptor *desc;
 2153         int retval, len, idlen;
 2154         uint16_t tag;
 2155 
 2156         target = dnvlist_get_string(req->args_nvl, "cfiscsi_target", NULL);
 2157         alias = dnvlist_get_string(req->args_nvl, "cfiscsi_target_alias", NULL);
 2158         val = dnvlist_get_string(req->args_nvl, "cfiscsi_portal_group_tag",
 2159             NULL);
 2160 
 2161         if (target == NULL || val == NULL) {
 2162                 req->status = CTL_LUN_ERROR;
 2163                 snprintf(req->error_str, sizeof(req->error_str),
 2164                     "Missing required argument");
 2165                 return;
 2166         }
 2167 
 2168         tag = strtoul(val, NULL, 0);
 2169         ct = cfiscsi_target_find_or_create(&cfiscsi_softc, target, alias, tag);
 2170         if (ct == NULL) {
 2171                 req->status = CTL_LUN_ERROR;
 2172                 snprintf(req->error_str, sizeof(req->error_str),
 2173                     "failed to create target \"%s\"", target);
 2174                 return;
 2175         }
 2176         if (ct->ct_state == CFISCSI_TARGET_STATE_ACTIVE) {
 2177                 req->status = CTL_LUN_ERROR;
 2178                 snprintf(req->error_str, sizeof(req->error_str),
 2179                     "target \"%s\" for portal group tag %u already exists",
 2180                     target, tag);
 2181                 cfiscsi_target_release(ct);
 2182                 return;
 2183         }
 2184         port = &ct->ct_port;
 2185         // WAT
 2186         if (ct->ct_state == CFISCSI_TARGET_STATE_DYING)
 2187                 goto done;
 2188 
 2189         port->frontend = &cfiscsi_frontend;
 2190         port->port_type = CTL_PORT_ISCSI;
 2191         /* XXX KDM what should the real number be here? */
 2192         port->num_requested_ctl_io = 4096;
 2193         port->port_name = "iscsi";
 2194         port->physical_port = (int)tag;
 2195         port->virtual_port = ct->ct_target_id;
 2196         port->port_online = cfiscsi_online;
 2197         port->port_offline = cfiscsi_offline;
 2198         port->port_info = cfiscsi_info;
 2199         port->onoff_arg = ct;
 2200         port->fe_datamove = cfiscsi_datamove;
 2201         port->fe_done = cfiscsi_done;
 2202         port->targ_port = -1;
 2203         port->options = nvlist_clone(req->args_nvl);
 2204 
 2205         /* Generate Port ID. */
 2206         idlen = strlen(target) + strlen(",t,0x0001") + 1;
 2207         idlen = roundup2(idlen, 4);
 2208         len = sizeof(struct scsi_vpd_device_id) + idlen;
 2209         port->port_devid = malloc(sizeof(struct ctl_devid) + len,
 2210             M_CTL, M_WAITOK | M_ZERO);
 2211         port->port_devid->len = len;
 2212         desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
 2213         desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
 2214         desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
 2215             SVPD_ID_TYPE_SCSI_NAME;
 2216         desc->length = idlen;
 2217         snprintf(desc->identifier, idlen, "%s,t,0x%4.4x", target, tag);
 2218 
 2219         /* Generate Target ID. */
 2220         idlen = strlen(target) + 1;
 2221         idlen = roundup2(idlen, 4);
 2222         len = sizeof(struct scsi_vpd_device_id) + idlen;
 2223         port->target_devid = malloc(sizeof(struct ctl_devid) + len,
 2224             M_CTL, M_WAITOK | M_ZERO);
 2225         port->target_devid->len = len;
 2226         desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
 2227         desc->proto_codeset = (SCSI_PROTO_ISCSI << 4) | SVPD_ID_CODESET_UTF8;
 2228         desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
 2229             SVPD_ID_TYPE_SCSI_NAME;
 2230         desc->length = idlen;
 2231         strlcpy(desc->identifier, target, idlen);
 2232 
 2233         retval = ctl_port_register(port);
 2234         if (retval != 0) {
 2235                 free(port->port_devid, M_CFISCSI);
 2236                 free(port->target_devid, M_CFISCSI);
 2237                 cfiscsi_target_release(ct);
 2238                 req->status = CTL_LUN_ERROR;
 2239                 snprintf(req->error_str, sizeof(req->error_str),
 2240                     "ctl_port_register() failed with error %d", retval);
 2241                 return;
 2242         }
 2243 done:
 2244         ct->ct_state = CFISCSI_TARGET_STATE_ACTIVE;
 2245         req->status = CTL_LUN_OK;
 2246         req->result_nvl = nvlist_create(0);
 2247         nvlist_add_number(req->result_nvl, "port_id", port->targ_port);
 2248 }
 2249 
 2250 static void
 2251 cfiscsi_ioctl_port_remove(struct ctl_req *req)
 2252 {
 2253         struct cfiscsi_target *ct;
 2254         const char *target, *val;
 2255         uint16_t tag;
 2256 
 2257         target = dnvlist_get_string(req->args_nvl, "cfiscsi_target", NULL);
 2258         val = dnvlist_get_string(req->args_nvl, "cfiscsi_portal_group_tag",
 2259             NULL);
 2260 
 2261         if (target == NULL || val == NULL) {
 2262                 req->status = CTL_LUN_ERROR;
 2263                 snprintf(req->error_str, sizeof(req->error_str),
 2264                     "Missing required argument");
 2265                 return;
 2266         }
 2267 
 2268         tag = strtoul(val, NULL, 0);
 2269         ct = cfiscsi_target_find(&cfiscsi_softc, target, tag);
 2270         if (ct == NULL) {
 2271                 req->status = CTL_LUN_ERROR;
 2272                 snprintf(req->error_str, sizeof(req->error_str),
 2273                     "can't find target \"%s\"", target);
 2274                 return;
 2275         }
 2276 
 2277         ct->ct_state = CFISCSI_TARGET_STATE_DYING;
 2278         ctl_port_offline(&ct->ct_port);
 2279         cfiscsi_target_release(ct);
 2280         cfiscsi_target_release(ct);
 2281         req->status = CTL_LUN_OK;
 2282 }
 2283 
 2284 static int
 2285 cfiscsi_ioctl(struct cdev *dev,
 2286     u_long cmd, caddr_t addr, int flag, struct thread *td)
 2287 {
 2288         struct ctl_iscsi *ci;
 2289         struct ctl_req *req;
 2290 
 2291         if (cmd == CTL_PORT_REQ) {
 2292                 req = (struct ctl_req *)addr;
 2293                 switch (req->reqtype) {
 2294                 case CTL_REQ_CREATE:
 2295                         cfiscsi_ioctl_port_create(req);
 2296                         break;
 2297                 case CTL_REQ_REMOVE:
 2298                         cfiscsi_ioctl_port_remove(req);
 2299                         break;
 2300                 default:
 2301                         req->status = CTL_LUN_ERROR;
 2302                         snprintf(req->error_str, sizeof(req->error_str),
 2303                             "Unsupported request type %d", req->reqtype);
 2304                 }
 2305                 return (0);
 2306         }
 2307 
 2308         if (cmd != CTL_ISCSI)
 2309                 return (ENOTTY);
 2310 
 2311         ci = (struct ctl_iscsi *)addr;
 2312         switch (ci->type) {
 2313         case CTL_ISCSI_HANDOFF:
 2314                 cfiscsi_ioctl_handoff(ci);
 2315                 break;
 2316         case CTL_ISCSI_LIST:
 2317                 cfiscsi_ioctl_list(ci);
 2318                 break;
 2319         case CTL_ISCSI_LOGOUT:
 2320                 cfiscsi_ioctl_logout(ci);
 2321                 break;
 2322         case CTL_ISCSI_TERMINATE:
 2323                 cfiscsi_ioctl_terminate(ci);
 2324                 break;
 2325         case CTL_ISCSI_LIMITS:
 2326                 cfiscsi_ioctl_limits(ci);
 2327                 break;
 2328 #ifdef ICL_KERNEL_PROXY
 2329         case CTL_ISCSI_LISTEN:
 2330                 cfiscsi_ioctl_listen(ci);
 2331                 break;
 2332         case CTL_ISCSI_ACCEPT:
 2333                 cfiscsi_ioctl_accept(ci);
 2334                 break;
 2335         case CTL_ISCSI_SEND:
 2336                 cfiscsi_ioctl_send(ci);
 2337                 break;
 2338         case CTL_ISCSI_RECEIVE:
 2339                 cfiscsi_ioctl_receive(ci);
 2340                 break;
 2341 #else
 2342         case CTL_ISCSI_LISTEN:
 2343         case CTL_ISCSI_ACCEPT:
 2344         case CTL_ISCSI_SEND:
 2345         case CTL_ISCSI_RECEIVE:
 2346                 ci->status = CTL_ISCSI_ERROR;
 2347                 snprintf(ci->error_str, sizeof(ci->error_str),
 2348                     "%s: CTL compiled without ICL_KERNEL_PROXY",
 2349                     __func__);
 2350                 break;
 2351 #endif /* !ICL_KERNEL_PROXY */
 2352         default:
 2353                 ci->status = CTL_ISCSI_ERROR;
 2354                 snprintf(ci->error_str, sizeof(ci->error_str),
 2355                     "%s: invalid iSCSI request type %d", __func__, ci->type);
 2356                 break;
 2357         }
 2358 
 2359         return (0);
 2360 }
 2361 
 2362 static void
 2363 cfiscsi_target_hold(struct cfiscsi_target *ct)
 2364 {
 2365 
 2366         refcount_acquire(&ct->ct_refcount);
 2367 }
 2368 
 2369 static void
 2370 cfiscsi_target_release(struct cfiscsi_target *ct)
 2371 {
 2372         struct cfiscsi_softc *softc;
 2373 
 2374         softc = ct->ct_softc;
 2375         mtx_lock(&softc->lock);
 2376         if (refcount_release(&ct->ct_refcount)) {
 2377                 TAILQ_REMOVE(&softc->targets, ct, ct_next);
 2378                 mtx_unlock(&softc->lock);
 2379                 if (ct->ct_state != CFISCSI_TARGET_STATE_INVALID) {
 2380                         ct->ct_state = CFISCSI_TARGET_STATE_INVALID;
 2381                         if (ctl_port_deregister(&ct->ct_port) != 0)
 2382                                 printf("%s: ctl_port_deregister() failed\n",
 2383                                     __func__);
 2384                 }
 2385                 free(ct, M_CFISCSI);
 2386 
 2387                 return;
 2388         }
 2389         mtx_unlock(&softc->lock);
 2390 }
 2391 
 2392 static struct cfiscsi_target *
 2393 cfiscsi_target_find(struct cfiscsi_softc *softc, const char *name, uint16_t tag)
 2394 {
 2395         struct cfiscsi_target *ct;
 2396 
 2397         mtx_lock(&softc->lock);
 2398         TAILQ_FOREACH(ct, &softc->targets, ct_next) {
 2399                 if (ct->ct_tag != tag ||
 2400                     strcmp(name, ct->ct_name) != 0 ||
 2401                     ct->ct_state != CFISCSI_TARGET_STATE_ACTIVE)
 2402                         continue;
 2403                 cfiscsi_target_hold(ct);
 2404                 mtx_unlock(&softc->lock);
 2405                 return (ct);
 2406         }
 2407         mtx_unlock(&softc->lock);
 2408 
 2409         return (NULL);
 2410 }
 2411 
 2412 static struct cfiscsi_target *
 2413 cfiscsi_target_find_or_create(struct cfiscsi_softc *softc, const char *name,
 2414     const char *alias, uint16_t tag)
 2415 {
 2416         struct cfiscsi_target *ct, *newct;
 2417 
 2418         if (name[0] == '\0' || strlen(name) >= CTL_ISCSI_NAME_LEN)
 2419                 return (NULL);
 2420 
 2421         newct = malloc(sizeof(*newct), M_CFISCSI, M_WAITOK | M_ZERO);
 2422 
 2423         mtx_lock(&softc->lock);
 2424         TAILQ_FOREACH(ct, &softc->targets, ct_next) {
 2425                 if (ct->ct_tag != tag ||
 2426                     strcmp(name, ct->ct_name) != 0 ||
 2427                     ct->ct_state == CFISCSI_TARGET_STATE_INVALID)
 2428                         continue;
 2429                 cfiscsi_target_hold(ct);
 2430                 mtx_unlock(&softc->lock);
 2431                 free(newct, M_CFISCSI);
 2432                 return (ct);
 2433         }
 2434 
 2435         strlcpy(newct->ct_name, name, sizeof(newct->ct_name));
 2436         if (alias != NULL)
 2437                 strlcpy(newct->ct_alias, alias, sizeof(newct->ct_alias));
 2438         newct->ct_tag = tag;
 2439         refcount_init(&newct->ct_refcount, 1);
 2440         newct->ct_softc = softc;
 2441         if (TAILQ_EMPTY(&softc->targets))
 2442                 softc->last_target_id = 0;
 2443         newct->ct_target_id = ++softc->last_target_id;
 2444         TAILQ_INSERT_TAIL(&softc->targets, newct, ct_next);
 2445         mtx_unlock(&softc->lock);
 2446 
 2447         return (newct);
 2448 }
 2449 
 2450 static void
 2451 cfiscsi_pdu_done(struct icl_pdu *ip, int error)
 2452 {
 2453 
 2454         if (error != 0)
 2455                 ; // XXX: Do something on error?
 2456         ((ctl_ref)ip->ip_prv0)(ip->ip_prv1, -1);
 2457 }
 2458 
 2459 static void
 2460 cfiscsi_datamove_in(union ctl_io *io)
 2461 {
 2462         struct cfiscsi_session *cs;
 2463         struct icl_pdu *request, *response;
 2464         const struct iscsi_bhs_scsi_command *bhssc;
 2465         struct iscsi_bhs_data_in *bhsdi;
 2466         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
 2467         size_t len, expected_len, sg_len, buffer_offset;
 2468         size_t max_send_data_segment_length;
 2469         const char *sg_addr;
 2470         icl_pdu_cb cb;
 2471         int ctl_sg_count, error, i;
 2472 
 2473         request = PRIV_REQUEST(io);
 2474         cs = PDU_SESSION(request);
 2475 
 2476         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
 2477         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
 2478             ISCSI_BHS_OPCODE_SCSI_COMMAND,
 2479             ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
 2480 
 2481         if (io->scsiio.kern_sg_entries > 0) {
 2482                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
 2483                 ctl_sg_count = io->scsiio.kern_sg_entries;
 2484         } else {
 2485                 ctl_sglist = &ctl_sg_entry;
 2486                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
 2487                 ctl_sglist->len = io->scsiio.kern_data_len;
 2488                 ctl_sg_count = 1;
 2489         }
 2490 
 2491         /*
 2492          * This is the offset within the current SCSI command; for the first
 2493          * call to cfiscsi_datamove() it will be 0, and for subsequent ones
 2494          * it will be the sum of lengths of previous ones.
 2495          */
 2496         buffer_offset = io->scsiio.kern_rel_offset;
 2497 
 2498         /*
 2499          * This is the transfer length expected by the initiator.  It can be
 2500          * different from the amount of data from the SCSI point of view.
 2501          */
 2502         expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
 2503 
 2504         /*
 2505          * If the transfer is outside of expected length -- we are done.
 2506          */
 2507         if (buffer_offset >= expected_len) {
 2508 #if 0
 2509                 CFISCSI_SESSION_DEBUG(cs, "buffer_offset = %zd, "
 2510                     "already sent the expected len", buffer_offset);
 2511 #endif
 2512                 ctl_datamove_done(io, true);
 2513                 return;
 2514         }
 2515 
 2516         if (io->scsiio.kern_data_ref != NULL)
 2517                 cb = cfiscsi_pdu_done;
 2518         else
 2519                 cb = NULL;
 2520 
 2521         i = 0;
 2522         sg_addr = NULL;
 2523         sg_len = 0;
 2524         response = NULL;
 2525         bhsdi = NULL;
 2526         if (cs->cs_conn->ic_hw_isomax != 0)
 2527                 max_send_data_segment_length = cs->cs_conn->ic_hw_isomax;
 2528         else
 2529                 max_send_data_segment_length =
 2530                     cs->cs_conn->ic_max_send_data_segment_length;
 2531         for (;;) {
 2532                 if (response == NULL) {
 2533                         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
 2534                         if (response == NULL) {
 2535                                 CFISCSI_SESSION_WARN(cs, "failed to "
 2536                                     "allocate memory; dropping connection");
 2537                                 ctl_set_busy(&io->scsiio);
 2538                                 ctl_datamove_done(io, true);
 2539                                 cfiscsi_session_terminate(cs);
 2540                                 return;
 2541                         }
 2542                         bhsdi = (struct iscsi_bhs_data_in *)response->ip_bhs;
 2543                         bhsdi->bhsdi_opcode = ISCSI_BHS_OPCODE_SCSI_DATA_IN;
 2544                         bhsdi->bhsdi_initiator_task_tag =
 2545                             bhssc->bhssc_initiator_task_tag;
 2546                         bhsdi->bhsdi_target_transfer_tag = 0xffffffff;
 2547                         bhsdi->bhsdi_datasn = htonl(PRIV_EXPDATASN(io));
 2548                         bhsdi->bhsdi_buffer_offset = htonl(buffer_offset);
 2549                 }
 2550 
 2551                 KASSERT(i < ctl_sg_count, ("i >= ctl_sg_count"));
 2552                 if (sg_len == 0) {
 2553                         sg_addr = ctl_sglist[i].addr;
 2554                         sg_len = ctl_sglist[i].len;
 2555                         KASSERT(sg_len > 0, ("sg_len <= 0"));
 2556                 }
 2557 
 2558                 len = sg_len;
 2559 
 2560                 /*
 2561                  * Truncate to maximum data segment length.
 2562                  */
 2563                 KASSERT(response->ip_data_len < max_send_data_segment_length,
 2564                     ("ip_data_len %zd >= max_send_data_segment_length %zd",
 2565                     response->ip_data_len, max_send_data_segment_length));
 2566                 if (response->ip_data_len + len > max_send_data_segment_length) {
 2567                         len = max_send_data_segment_length - response->ip_data_len;
 2568                         KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
 2569                             len, sg_len));
 2570                 }
 2571 
 2572                 /*
 2573                  * Truncate to expected data transfer length.
 2574                  */
 2575                 KASSERT(buffer_offset + response->ip_data_len < expected_len,
 2576                     ("buffer_offset %zd + ip_data_len %zd >= expected_len %zd",
 2577                     buffer_offset, response->ip_data_len, expected_len));
 2578                 if (buffer_offset + response->ip_data_len + len > expected_len) {
 2579                         CFISCSI_SESSION_DEBUG(cs, "truncating from %zd "
 2580                             "to expected data transfer length %zd",
 2581                             buffer_offset + response->ip_data_len + len, expected_len);
 2582                         len = expected_len - (buffer_offset + response->ip_data_len);
 2583                         KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
 2584                             len, sg_len));
 2585                 }
 2586 
 2587                 error = icl_pdu_append_data(response, sg_addr, len,
 2588                     M_NOWAIT | (cb ? ICL_NOCOPY : 0));
 2589                 if (error != 0) {
 2590                         CFISCSI_SESSION_WARN(cs, "failed to "
 2591                             "allocate memory; dropping connection");
 2592                         icl_pdu_free(response);
 2593                         ctl_set_busy(&io->scsiio);
 2594                         ctl_datamove_done(io, true);
 2595                         cfiscsi_session_terminate(cs);
 2596                         return;
 2597                 }
 2598                 sg_addr += len;
 2599                 sg_len -= len;
 2600                 io->scsiio.kern_data_resid -= len;
 2601 
 2602                 KASSERT(buffer_offset + response->ip_data_len <= expected_len,
 2603                     ("buffer_offset %zd + ip_data_len %zd > expected_len %zd",
 2604                     buffer_offset, response->ip_data_len, expected_len));
 2605                 if (buffer_offset + response->ip_data_len == expected_len) {
 2606                         /*
 2607                          * Already have the amount of data the initiator wanted.
 2608                          */
 2609                         break;
 2610                 }
 2611 
 2612                 if (sg_len == 0) {
 2613                         /*
 2614                          * End of scatter-gather segment;
 2615                          * proceed to the next one...
 2616                          */
 2617                         if (i == ctl_sg_count - 1) {
 2618                                 /*
 2619                                  * ... unless this was the last one.
 2620                                  */
 2621                                 break;
 2622                         }
 2623                         i++;
 2624                 }
 2625 
 2626                 if (response->ip_data_len == max_send_data_segment_length) {
 2627                         /*
 2628                          * Can't stuff more data into the current PDU;
 2629                          * queue it.  Note that's not enough to check
 2630                          * for kern_data_resid == 0 instead; there
 2631                          * may be several Data-In PDUs for the final
 2632                          * call to cfiscsi_datamove(), and we want
 2633                          * to set the F flag only on the last of them.
 2634                          */
 2635                         buffer_offset += response->ip_data_len;
 2636                         if (buffer_offset == io->scsiio.kern_total_len ||
 2637                             buffer_offset == expected_len) {
 2638                                 buffer_offset -= response->ip_data_len;
 2639                                 break;
 2640                         }
 2641                         PRIV_EXPDATASN(io) += howmany(response->ip_data_len,
 2642                             cs->cs_conn->ic_max_send_data_segment_length);
 2643                         if (cb != NULL) {
 2644                                 response->ip_prv0 = io->scsiio.kern_data_ref;
 2645                                 response->ip_prv1 = io->scsiio.kern_data_arg;
 2646                                 io->scsiio.kern_data_ref(io->scsiio.kern_data_arg, 1);
 2647                         }
 2648                         cfiscsi_pdu_queue_cb(response, cb);
 2649                         response = NULL;
 2650                         bhsdi = NULL;
 2651                 }
 2652         }
 2653         if (response != NULL) {
 2654                 buffer_offset += response->ip_data_len;
 2655                 if (buffer_offset == io->scsiio.kern_total_len ||
 2656                     buffer_offset == expected_len) {
 2657                         bhsdi->bhsdi_flags |= BHSDI_FLAGS_F;
 2658                         if (io->io_hdr.status == CTL_SUCCESS) {
 2659                                 bhsdi->bhsdi_flags |= BHSDI_FLAGS_S;
 2660                                 if (io->scsiio.kern_total_len <
 2661                                     ntohl(bhssc->bhssc_expected_data_transfer_length)) {
 2662                                         bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
 2663                                         bhsdi->bhsdi_residual_count =
 2664                                             htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
 2665                                             io->scsiio.kern_total_len);
 2666                                 } else if (io->scsiio.kern_total_len >
 2667                                     ntohl(bhssc->bhssc_expected_data_transfer_length)) {
 2668                                         bhsdi->bhsdi_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
 2669                                         bhsdi->bhsdi_residual_count =
 2670                                             htonl(io->scsiio.kern_total_len -
 2671                                             ntohl(bhssc->bhssc_expected_data_transfer_length));
 2672                                 }
 2673                                 bhsdi->bhsdi_status = io->scsiio.scsi_status;
 2674                                 io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
 2675                         }
 2676                 }
 2677                 KASSERT(response->ip_data_len > 0, ("sending empty Data-In"));
 2678                 PRIV_EXPDATASN(io) += howmany(response->ip_data_len,
 2679                     cs->cs_conn->ic_max_send_data_segment_length);
 2680                 if (cb != NULL) {
 2681                         response->ip_prv0 = io->scsiio.kern_data_ref;
 2682                         response->ip_prv1 = io->scsiio.kern_data_arg;
 2683                         io->scsiio.kern_data_ref(io->scsiio.kern_data_arg, 1);
 2684                 }
 2685                 cfiscsi_pdu_queue_cb(response, cb);
 2686         }
 2687 
 2688         ctl_datamove_done(io, true);
 2689 }
 2690 
 2691 static void
 2692 cfiscsi_datamove_out(union ctl_io *io)
 2693 {
 2694         struct cfiscsi_session *cs;
 2695         struct icl_pdu *request, *response;
 2696         const struct iscsi_bhs_scsi_command *bhssc;
 2697         struct iscsi_bhs_r2t *bhsr2t;
 2698         struct cfiscsi_data_wait *cdw;
 2699         struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
 2700         uint32_t expected_len, datamove_len, r2t_off, r2t_len;
 2701         uint32_t target_transfer_tag;
 2702         bool done;
 2703 
 2704         request = PRIV_REQUEST(io);
 2705         cs = PDU_SESSION(request);
 2706 
 2707         bhssc = (const struct iscsi_bhs_scsi_command *)request->ip_bhs;
 2708         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
 2709             ISCSI_BHS_OPCODE_SCSI_COMMAND,
 2710             ("bhssc->bhssc_opcode != ISCSI_BHS_OPCODE_SCSI_COMMAND"));
 2711 
 2712         /*
 2713          * Complete write underflow.  Not a single byte to read.  Return.
 2714          */
 2715         expected_len = ntohl(bhssc->bhssc_expected_data_transfer_length);
 2716         if (io->scsiio.kern_rel_offset >= expected_len) {
 2717                 ctl_datamove_done(io, true);
 2718                 return;
 2719         }
 2720 
 2721         datamove_len = MIN(io->scsiio.kern_data_len,
 2722             expected_len - io->scsiio.kern_rel_offset);
 2723 
 2724         target_transfer_tag =
 2725             atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1);
 2726         if (target_transfer_tag == 0xffffffff) {
 2727                 target_transfer_tag =
 2728                     atomic_fetchadd_32(&cs->cs_target_transfer_tag, 1);
 2729         }
 2730         cdw = cfiscsi_data_wait_new(cs, io, bhssc->bhssc_initiator_task_tag,
 2731             &target_transfer_tag);
 2732         if (cdw == NULL) {
 2733                 CFISCSI_SESSION_WARN(cs, "failed to "
 2734                     "allocate memory; dropping connection");
 2735                 ctl_set_busy(&io->scsiio);
 2736                 ctl_datamove_done(io, true);
 2737                 cfiscsi_session_terminate(cs);
 2738                 return;
 2739         }
 2740 #if 0
 2741         CFISCSI_SESSION_DEBUG(cs, "expecting Data-Out with initiator "
 2742             "task tag 0x%x, target transfer tag 0x%x",
 2743             bhssc->bhssc_initiator_task_tag, target_transfer_tag);
 2744 #endif
 2745 
 2746         cdw->cdw_ctl_io = io;
 2747         cdw->cdw_target_transfer_tag = target_transfer_tag;
 2748         cdw->cdw_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
 2749         cdw->cdw_r2t_end = datamove_len;
 2750         cdw->cdw_datasn = 0;
 2751 
 2752         /* Set initial data pointer for the CDW respecting ext_data_filled. */
 2753         if (io->scsiio.kern_sg_entries > 0) {
 2754                 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
 2755         } else {
 2756                 ctl_sglist = &ctl_sg_entry;
 2757                 ctl_sglist->addr = io->scsiio.kern_data_ptr;
 2758                 ctl_sglist->len = datamove_len;
 2759         }
 2760         cdw->cdw_sg_index = 0;
 2761         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
 2762         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
 2763         r2t_off = io->scsiio.ext_data_filled;
 2764         while (r2t_off > 0) {
 2765                 if (r2t_off >= cdw->cdw_sg_len) {
 2766                         r2t_off -= cdw->cdw_sg_len;
 2767                         cdw->cdw_sg_index++;
 2768                         cdw->cdw_sg_addr = ctl_sglist[cdw->cdw_sg_index].addr;
 2769                         cdw->cdw_sg_len = ctl_sglist[cdw->cdw_sg_index].len;
 2770                         continue;
 2771                 }
 2772                 cdw->cdw_sg_addr += r2t_off;
 2773                 cdw->cdw_sg_len -= r2t_off;
 2774                 r2t_off = 0;
 2775         }
 2776 
 2777         if (cs->cs_immediate_data &&
 2778             io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled <
 2779             icl_pdu_data_segment_length(request)) {
 2780                 done = cfiscsi_handle_data_segment(request, cdw);
 2781                 if (done) {
 2782                         cfiscsi_data_wait_free(cs, cdw);
 2783                         ctl_datamove_done(io, true);
 2784                         return;
 2785                 }
 2786         }
 2787 
 2788         r2t_off = io->scsiio.kern_rel_offset + io->scsiio.ext_data_filled;
 2789         r2t_len = MIN(datamove_len - io->scsiio.ext_data_filled,
 2790             cs->cs_max_burst_length);
 2791         cdw->cdw_r2t_end = io->scsiio.ext_data_filled + r2t_len;
 2792 
 2793         CFISCSI_SESSION_LOCK(cs);
 2794         if (cs->cs_terminating_tasks) {
 2795                 CFISCSI_SESSION_UNLOCK(cs);
 2796                 KASSERT((io->io_hdr.flags & CTL_FLAG_ABORT) != 0,
 2797                     ("%s: I/O request %p on termating session %p not aborted",
 2798                     __func__, io, cs));
 2799                 CFISCSI_SESSION_WARN(cs, "aborting data_wait for aborted I/O");
 2800                 cfiscsi_data_wait_abort(cs, cdw, 44);
 2801                 return;
 2802         }
 2803         TAILQ_INSERT_TAIL(&cs->cs_waiting_for_data_out, cdw, cdw_next);
 2804         CFISCSI_SESSION_UNLOCK(cs);
 2805 
 2806         /*
 2807          * XXX: We should limit the number of outstanding R2T PDUs
 2808          *      per task to MaxOutstandingR2T.
 2809          */
 2810         response = cfiscsi_pdu_new_response(request, M_NOWAIT);
 2811         if (response == NULL) {
 2812                 CFISCSI_SESSION_WARN(cs, "failed to "
 2813                     "allocate memory; dropping connection");
 2814                 ctl_set_busy(&io->scsiio);
 2815                 ctl_datamove_done(io, true);
 2816                 cfiscsi_session_terminate(cs);
 2817                 return;
 2818         }
 2819         io->io_hdr.flags |= CTL_FLAG_DMA_INPROG;
 2820         bhsr2t = (struct iscsi_bhs_r2t *)response->ip_bhs;
 2821         bhsr2t->bhsr2t_opcode = ISCSI_BHS_OPCODE_R2T;
 2822         bhsr2t->bhsr2t_flags = 0x80;
 2823         bhsr2t->bhsr2t_lun = bhssc->bhssc_lun;
 2824         bhsr2t->bhsr2t_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
 2825         bhsr2t->bhsr2t_target_transfer_tag = target_transfer_tag;
 2826         /*
 2827          * XXX: Here we assume that cfiscsi_datamove() won't ever
 2828          *      be running concurrently on several CPUs for a given
 2829          *      command.
 2830          */
 2831         bhsr2t->bhsr2t_r2tsn = htonl(PRIV_R2TSN(io)++);
 2832         /*
 2833          * This is the offset within the current SCSI command;
 2834          * i.e. for the first call of datamove(), it will be 0,
 2835          * and for subsequent ones it will be the sum of lengths
 2836          * of previous ones.
 2837          *
 2838          * The ext_data_filled is to account for unsolicited
 2839          * (immediate) data that might have already arrived.
 2840          */
 2841         bhsr2t->bhsr2t_buffer_offset = htonl(r2t_off);
 2842         /*
 2843          * This is the total length (sum of S/G lengths) this call
 2844          * to cfiscsi_datamove() is supposed to handle, limited by
 2845          * MaxBurstLength.
 2846          */
 2847         bhsr2t->bhsr2t_desired_data_transfer_length = htonl(r2t_len);
 2848         cfiscsi_pdu_queue(response);
 2849 }
 2850 
 2851 static void
 2852 cfiscsi_datamove(union ctl_io *io)
 2853 {
 2854 
 2855         if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN)
 2856                 cfiscsi_datamove_in(io);
 2857         else {
 2858                 /* We hadn't received anything during this datamove yet. */
 2859                 io->scsiio.ext_data_filled = 0;
 2860                 cfiscsi_datamove_out(io);
 2861         }
 2862 }
 2863 
 2864 static void
 2865 cfiscsi_scsi_command_done(union ctl_io *io)
 2866 {
 2867         struct icl_pdu *request, *response;
 2868         struct iscsi_bhs_scsi_command *bhssc;
 2869         struct iscsi_bhs_scsi_response *bhssr;
 2870 #ifdef DIAGNOSTIC
 2871         struct cfiscsi_data_wait *cdw;
 2872         struct cfiscsi_session *cs;
 2873 #endif
 2874         uint16_t sense_length;
 2875 
 2876         request = PRIV_REQUEST(io);
 2877         bhssc = (struct iscsi_bhs_scsi_command *)request->ip_bhs;
 2878         KASSERT((bhssc->bhssc_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
 2879             ISCSI_BHS_OPCODE_SCSI_COMMAND,
 2880             ("replying to wrong opcode 0x%x", bhssc->bhssc_opcode));
 2881 
 2882         //CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x",
 2883         //    bhssc->bhssc_initiator_task_tag);
 2884 
 2885 #ifdef DIAGNOSTIC
 2886         cs = PDU_SESSION(request);
 2887         CFISCSI_SESSION_LOCK(cs);
 2888         TAILQ_FOREACH(cdw, &cs->cs_waiting_for_data_out, cdw_next)
 2889                 KASSERT(bhssc->bhssc_initiator_task_tag !=
 2890                     cdw->cdw_initiator_task_tag, ("dangling cdw"));
 2891         CFISCSI_SESSION_UNLOCK(cs);
 2892 #endif
 2893 
 2894         /*
 2895          * Do not return status for aborted commands.
 2896          * There are exceptions, but none supported by CTL yet.
 2897          */
 2898         if (((io->io_hdr.flags & CTL_FLAG_ABORT) &&
 2899              (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) ||
 2900             (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) {
 2901                 ctl_free_io(io);
 2902                 icl_pdu_free(request);
 2903                 return;
 2904         }
 2905 
 2906         response = cfiscsi_pdu_new_response(request, M_WAITOK);
 2907         bhssr = (struct iscsi_bhs_scsi_response *)response->ip_bhs;
 2908         bhssr->bhssr_opcode = ISCSI_BHS_OPCODE_SCSI_RESPONSE;
 2909         bhssr->bhssr_flags = 0x80;
 2910         /*
 2911          * XXX: We don't deal with bidirectional under/overflows;
 2912          *      does anything actually support those?
 2913          */
 2914         if (io->scsiio.kern_total_len <
 2915             ntohl(bhssc->bhssc_expected_data_transfer_length)) {
 2916                 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_UNDERFLOW;
 2917                 bhssr->bhssr_residual_count =
 2918                     htonl(ntohl(bhssc->bhssc_expected_data_transfer_length) -
 2919                     io->scsiio.kern_total_len);
 2920                 //CFISCSI_SESSION_DEBUG(cs, "underflow; residual count %d",
 2921                 //    ntohl(bhssr->bhssr_residual_count));
 2922         } else if (io->scsiio.kern_total_len >
 2923             ntohl(bhssc->bhssc_expected_data_transfer_length)) {
 2924                 bhssr->bhssr_flags |= BHSSR_FLAGS_RESIDUAL_OVERFLOW;
 2925                 bhssr->bhssr_residual_count = htonl(io->scsiio.kern_total_len -
 2926                     ntohl(bhssc->bhssc_expected_data_transfer_length));
 2927                 //CFISCSI_SESSION_DEBUG(cs, "overflow; residual count %d",
 2928                 //    ntohl(bhssr->bhssr_residual_count));
 2929         }
 2930         bhssr->bhssr_response = BHSSR_RESPONSE_COMMAND_COMPLETED;
 2931         bhssr->bhssr_status = io->scsiio.scsi_status;
 2932         bhssr->bhssr_initiator_task_tag = bhssc->bhssc_initiator_task_tag;
 2933         bhssr->bhssr_expdatasn = htonl(PRIV_EXPDATASN(io));
 2934 
 2935         if (io->scsiio.sense_len > 0) {
 2936 #if 0
 2937                 CFISCSI_SESSION_DEBUG(cs, "returning %d bytes of sense data",
 2938                     io->scsiio.sense_len);
 2939 #endif
 2940                 sense_length = htons(io->scsiio.sense_len);
 2941                 icl_pdu_append_data(response,
 2942                     &sense_length, sizeof(sense_length), M_WAITOK);
 2943                 icl_pdu_append_data(response,
 2944                     &io->scsiio.sense_data, io->scsiio.sense_len, M_WAITOK);
 2945         }
 2946 
 2947         ctl_free_io(io);
 2948         icl_pdu_free(request);
 2949         cfiscsi_pdu_queue(response);
 2950 }
 2951 
 2952 static void
 2953 cfiscsi_task_management_done(union ctl_io *io)
 2954 {
 2955         struct icl_pdu *request, *response;
 2956         struct iscsi_bhs_task_management_request *bhstmr;
 2957         struct iscsi_bhs_task_management_response *bhstmr2;
 2958         struct cfiscsi_data_wait *cdw, *tmpcdw;
 2959         struct cfiscsi_session *cs, *tcs;
 2960         struct cfiscsi_softc *softc;
 2961         int cold_reset = 0;
 2962 
 2963         request = PRIV_REQUEST(io);
 2964         cs = PDU_SESSION(request);
 2965         bhstmr = (struct iscsi_bhs_task_management_request *)request->ip_bhs;
 2966         KASSERT((bhstmr->bhstmr_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) ==
 2967             ISCSI_BHS_OPCODE_TASK_REQUEST,
 2968             ("replying to wrong opcode 0x%x", bhstmr->bhstmr_opcode));
 2969 
 2970 #if 0
 2971         CFISCSI_SESSION_DEBUG(cs, "initiator task tag 0x%x; referenced task tag 0x%x",
 2972             bhstmr->bhstmr_initiator_task_tag,
 2973             bhstmr->bhstmr_referenced_task_tag);
 2974 #endif
 2975 
 2976         if ((bhstmr->bhstmr_function & ~0x80) ==
 2977             BHSTMR_FUNCTION_ABORT_TASK) {
 2978                 /*
 2979                  * Make sure we no longer wait for Data-Out for this command.
 2980                  */
 2981                 CFISCSI_SESSION_LOCK(cs);
 2982                 TAILQ_FOREACH_SAFE(cdw,
 2983                     &cs->cs_waiting_for_data_out, cdw_next, tmpcdw) {
 2984                         if (bhstmr->bhstmr_referenced_task_tag !=
 2985                             cdw->cdw_initiator_task_tag)
 2986                                 continue;
 2987 
 2988 #if 0
 2989                         CFISCSI_SESSION_DEBUG(cs, "removing csw for initiator task "
 2990                             "tag 0x%x", bhstmr->bhstmr_initiator_task_tag);
 2991 #endif
 2992                         TAILQ_REMOVE(&cs->cs_waiting_for_data_out,
 2993                             cdw, cdw_next);
 2994                         cfiscsi_data_wait_abort(cs, cdw, 43);
 2995                 }
 2996                 CFISCSI_SESSION_UNLOCK(cs);
 2997         }
 2998         if ((bhstmr->bhstmr_function & ~0x80) ==
 2999             BHSTMR_FUNCTION_TARGET_COLD_RESET &&
 3000             io->io_hdr.status == CTL_SUCCESS)
 3001                 cold_reset = 1;
 3002 
 3003         response = cfiscsi_pdu_new_response(request, M_WAITOK);
 3004         bhstmr2 = (struct iscsi_bhs_task_management_response *)
 3005             response->ip_bhs;
 3006         bhstmr2->bhstmr_opcode = ISCSI_BHS_OPCODE_TASK_RESPONSE;
 3007         bhstmr2->bhstmr_flags = 0x80;
 3008         switch (io->taskio.task_status) {
 3009         case CTL_TASK_FUNCTION_COMPLETE:
 3010                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_COMPLETE;
 3011                 break;
 3012         case CTL_TASK_FUNCTION_SUCCEEDED:
 3013                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_SUCCEEDED;
 3014                 break;
 3015         case CTL_TASK_LUN_DOES_NOT_EXIST:
 3016                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_LUN_DOES_NOT_EXIST;
 3017                 break;
 3018         case CTL_TASK_FUNCTION_NOT_SUPPORTED:
 3019         default:
 3020                 bhstmr2->bhstmr_response = BHSTMR_RESPONSE_FUNCTION_NOT_SUPPORTED;
 3021                 break;
 3022         }
 3023         memcpy(bhstmr2->bhstmr_additional_reponse_information,
 3024             io->taskio.task_resp, sizeof(io->taskio.task_resp));
 3025         bhstmr2->bhstmr_initiator_task_tag = bhstmr->bhstmr_initiator_task_tag;
 3026 
 3027         ctl_free_io(io);
 3028         icl_pdu_free(request);
 3029         cfiscsi_pdu_queue(response);
 3030 
 3031         if (cold_reset) {
 3032                 softc = cs->cs_target->ct_softc;
 3033                 mtx_lock(&softc->lock);
 3034                 TAILQ_FOREACH(tcs, &softc->sessions, cs_next) {
 3035                         if (tcs->cs_target == cs->cs_target)
 3036                                 cfiscsi_session_terminate(tcs);
 3037                 }
 3038                 mtx_unlock(&softc->lock);
 3039         }
 3040 }
 3041 
 3042 static void
 3043 cfiscsi_done(union ctl_io *io)
 3044 {
 3045         struct icl_pdu *request;
 3046         struct cfiscsi_session *cs;
 3047 
 3048         KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
 3049                 ("invalid CTL status %#x", io->io_hdr.status));
 3050 
 3051         request = PRIV_REQUEST(io);
 3052         cs = PDU_SESSION(request);
 3053 
 3054         switch (request->ip_bhs->bhs_opcode & ~ISCSI_BHS_OPCODE_IMMEDIATE) {
 3055         case ISCSI_BHS_OPCODE_SCSI_COMMAND:
 3056                 cfiscsi_scsi_command_done(io);
 3057                 break;
 3058         case ISCSI_BHS_OPCODE_TASK_REQUEST:
 3059                 cfiscsi_task_management_done(io);
 3060                 break;
 3061         case ISCSI_BHS_OPCODE_INTERNAL:
 3062                 /*
 3063                  * Implicit task termination has just completed; nothing to do.
 3064                  */
 3065                 icl_pdu_free(request);
 3066                 cs->cs_tasks_aborted = true;
 3067                 refcount_release(&cs->cs_outstanding_ctl_pdus);
 3068                 wakeup(__DEVOLATILE(void *, &cs->cs_outstanding_ctl_pdus));
 3069                 ctl_free_io(io);
 3070                 return;
 3071         default:
 3072                 panic("cfiscsi_done called with wrong opcode 0x%x",
 3073                     request->ip_bhs->bhs_opcode);
 3074         }
 3075 
 3076         refcount_release(&cs->cs_outstanding_ctl_pdus);
 3077 }

Cache object: df589a4e5598d0bb84b989cf0a673178


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