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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/ocs_fc/ocs_scsi.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  * Copyright (c) 2017 Broadcom. All rights reserved.
    3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright notice,
   12  *    this list of conditions and the following disclaimer in the documentation
   13  *    and/or other materials provided with the distribution.
   14  *
   15  * 3. Neither the name of the copyright holder nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * $FreeBSD$
   32  */
   33 
   34 /**
   35  * @file
   36  * OCS Linux SCSI API base driver implementation.
   37  */
   38 
   39 /**
   40  * @defgroup scsi_api_base SCSI Base Target/Initiator
   41  */
   42 
   43 #include "ocs.h"
   44 #include "ocs_els.h"
   45 #include "ocs_scsi.h"
   46 #include "ocs_vpd.h"
   47 #include "ocs_utils.h"
   48 #include "ocs_device.h"
   49 
   50 #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]"
   51 #define SCSI_ITT_SIZE(ocs)      ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8)
   52 
   53 #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag
   54 
   55 #define enable_tsend_auto_resp(ocs)             ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TSEND) == 0)
   56 #define enable_treceive_auto_resp(ocs)  ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TRECEIVE) == 0)
   57 
   58 #define scsi_io_printf(io, fmt, ...) ocs_log_info(io->ocs, "[%s]" SCSI_IOFMT fmt, \
   59         io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__)
   60 
   61 #define scsi_io_trace(io, fmt, ...) \
   62         do { \
   63                 if (OCS_LOG_ENABLE_SCSI_TRACE(io->ocs)) \
   64                         scsi_io_printf(io, fmt, ##__VA_ARGS__); \
   65         } while (0)
   66 
   67 #define scsi_log(ocs, fmt, ...) \
   68         do { \
   69                 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) \
   70                         ocs_log_info(ocs, fmt, ##__VA_ARGS__); \
   71         } while (0)
   72 
   73 static int32_t ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg);
   74 static int32_t ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
   75         uint32_t ext, void *arg);
   76 
   77 static void ocs_scsi_io_free_ovfl(ocs_io_t *io);
   78 static uint32_t ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count);
   79 static int ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info);
   80 static ocs_scsi_io_status_e ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc);
   81 static uint32_t ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[],
   82         uint32_t addrlen_count, ocs_dif_t *dif, int is_crc);
   83 static uint32_t ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif);
   84 static uint32_t ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif);
   85 static int32_t ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info,
   86         ocs_hw_dif_info_t *hw_dif_info);
   87 static int32_t ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio);
   88 static int32_t ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io);
   89 static void _ocs_scsi_io_free(void *arg);
   90 
   91 /**
   92  * @ingroup scsi_api_base
   93  * @brief Returns a big-endian 32-bit value given a pointer.
   94  *
   95  * @param p Pointer to the 32-bit big-endian location.
   96  *
   97  * @return Returns the byte-swapped 32-bit value.
   98  */
   99 
  100 static inline uint32_t
  101 ocs_fc_getbe32(void *p)
  102 {
  103         return ocs_be32toh(*((uint32_t*)p));
  104 }
  105 
  106 /**
  107  * @ingroup scsi_api_base
  108  * @brief Enable IO allocation.
  109  *
  110  * @par Description
  111  * The SCSI and Transport IO allocation functions are enabled. If the allocation functions
  112  * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
  113  * fail.
  114  *
  115  * @param node Pointer to node object.
  116  *
  117  * @return None.
  118  */
  119 void
  120 ocs_scsi_io_alloc_enable(ocs_node_t *node)
  121 {
  122         ocs_assert(node != NULL);
  123         ocs_lock(&node->active_ios_lock);
  124                 node->io_alloc_enabled = TRUE;
  125         ocs_unlock(&node->active_ios_lock);
  126 }
  127 
  128 /**
  129  * @ingroup scsi_api_base
  130  * @brief Disable IO allocation
  131  *
  132  * @par Description
  133  * The SCSI and Transport IO allocation functions are disabled. If the allocation functions
  134  * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
  135  * fail.
  136  *
  137  * @param node Pointer to node object
  138  *
  139  * @return None.
  140  */
  141 void
  142 ocs_scsi_io_alloc_disable(ocs_node_t *node)
  143 {
  144         ocs_assert(node != NULL);
  145         ocs_lock(&node->active_ios_lock);
  146                 node->io_alloc_enabled = FALSE;
  147         ocs_unlock(&node->active_ios_lock);
  148 }
  149 
  150 /**
  151  * @ingroup scsi_api_base
  152  * @brief Allocate a SCSI IO context.
  153  *
  154  * @par Description
  155  * A SCSI IO context is allocated and associated with a @c node. This function
  156  * is called by an initiator-client when issuing SCSI commands to remote
  157  * target devices. On completion, ocs_scsi_io_free() is called.
  158  * @n @n
  159  * The returned ocs_io_t structure has an element of type ocs_scsi_ini_io_t named
  160  * "ini_io" that is declared and used by an initiator-client for private information.
  161  *
  162  * @param node Pointer to the associated node structure.
  163  * @param role Role for IO (originator/responder).
  164  *
  165  * @return Returns the pointer to the IO context, or NULL.
  166  *
  167  */
  168 
  169 ocs_io_t *
  170 ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
  171 {
  172         ocs_t *ocs;
  173         ocs_xport_t *xport;
  174         ocs_io_t *io;
  175 
  176         ocs_assert(node, NULL);
  177         ocs_assert(node->ocs, NULL);
  178 
  179         ocs = node->ocs;
  180         ocs_assert(ocs->xport, NULL);
  181         xport = ocs->xport;
  182 
  183         ocs_lock(&node->active_ios_lock);
  184 
  185                 if (!node->io_alloc_enabled) {
  186                         ocs_unlock(&node->active_ios_lock);
  187                         return NULL;
  188                 }
  189 
  190                 io = ocs_io_alloc(ocs);
  191                 if (io == NULL) {
  192                         ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
  193                         ocs_unlock(&node->active_ios_lock);
  194                         return NULL;
  195                 }
  196 
  197                 /* initialize refcount */
  198                 ocs_ref_init(&io->ref, _ocs_scsi_io_free, io);
  199 
  200                 if (io->hio != NULL) {
  201                         ocs_log_err(node->ocs, "assertion failed: io->hio is not NULL\n");
  202                         ocs_io_free(ocs, io);
  203                         ocs_unlock(&node->active_ios_lock);
  204                         return NULL;
  205                 }
  206 
  207                 /* set generic fields */
  208                 io->ocs = ocs;
  209                 io->node = node;
  210 
  211                 /* set type and name */
  212                 io->io_type = OCS_IO_TYPE_IO;
  213                 io->display_name = "scsi_io";
  214 
  215                 switch (role) {
  216                 case OCS_SCSI_IO_ROLE_ORIGINATOR:
  217                         io->cmd_ini = TRUE;
  218                         io->cmd_tgt = FALSE;
  219                         break;
  220                 case OCS_SCSI_IO_ROLE_RESPONDER:
  221                         io->cmd_ini = FALSE;
  222                         io->cmd_tgt = TRUE;
  223                         break;
  224                 }
  225 
  226                 /* Add to node's active_ios list */
  227                 ocs_list_add_tail(&node->active_ios, io);
  228 
  229         ocs_unlock(&node->active_ios_lock);
  230 
  231         return io;
  232 }
  233 
  234 /**
  235  * @ingroup scsi_api_base
  236  * @brief Free a SCSI IO context (internal).
  237  *
  238  * @par Description
  239  * The IO context previously allocated using ocs_scsi_io_alloc()
  240  * is freed. This is called from within the transport layer,
  241  * when the reference count goes to zero.
  242  *
  243  * @param arg Pointer to the IO context.
  244  *
  245  * @return None.
  246  */
  247 static void
  248 _ocs_scsi_io_free(void *arg)
  249 {
  250         ocs_io_t *io = (ocs_io_t *)arg;
  251         ocs_t *ocs = io->ocs;
  252         ocs_node_t *node = io->node;
  253         int send_empty_event;
  254 
  255         ocs_assert(io != NULL);
  256 
  257         scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
  258 
  259         ocs_assert(ocs_io_busy(io));
  260 
  261         ocs_lock(&node->active_ios_lock);
  262                 ocs_list_remove(&node->active_ios, io);
  263                 send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->active_ios);
  264         ocs_unlock(&node->active_ios_lock);
  265 
  266         if (send_empty_event) {
  267                 ocs_node_post_event(node, OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY, NULL);
  268         }
  269 
  270         io->node = NULL;
  271         ocs_io_free(ocs, io);
  272 
  273 }
  274 
  275 /**
  276  * @ingroup scsi_api_base
  277  * @brief Free a SCSI IO context.
  278  *
  279  * @par Description
  280  * The IO context previously allocated using ocs_scsi_io_alloc() is freed.
  281  *
  282  * @param io Pointer to the IO context.
  283  *
  284  * @return None.
  285  */
  286 void
  287 ocs_scsi_io_free(ocs_io_t *io)
  288 {
  289         scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
  290         ocs_assert(ocs_ref_read_count(&io->ref) > 0);
  291         ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
  292 }
  293 
  294 static int32_t
  295 ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
  296         ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
  297         ocs_scsi_dif_info_t *dif_info,
  298         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
  299         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags);
  300 
  301 /**
  302  * @brief Target response completion callback.
  303  *
  304  * @par Description
  305  * Function is called upon the completion of a target IO request.
  306  *
  307  * @param hio Pointer to the HW IO structure.
  308  * @param rnode Remote node associated with the IO that is completing.
  309  * @param length Length of the response payload.
  310  * @param status Completion status.
  311  * @param ext_status Extended completion status.
  312  * @param app Application-specific data (generally a pointer to the IO context).
  313  *
  314  * @return None.
  315  */
  316 
  317 static void
  318 ocs_target_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
  319         int32_t status, uint32_t ext_status, void *app)
  320 {
  321         ocs_io_t *io = app;
  322         ocs_t *ocs;
  323         ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
  324         uint16_t additional_length;
  325         uint8_t edir;
  326         uint8_t tdpv;
  327         ocs_hw_dif_info_t *dif_info = &io->hw_dif;
  328         int is_crc;
  329 
  330         ocs_assert(io);
  331 
  332         scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
  333 
  334         ocs = io->ocs;
  335         ocs_assert(ocs);
  336 
  337         ocs_scsi_io_free_ovfl(io);
  338 
  339         io->transferred += length;
  340 
  341         /* Call target server completion */
  342         if (io->scsi_tgt_cb) {
  343                 ocs_scsi_io_cb_t cb = io->scsi_tgt_cb;
  344                 uint32_t flags = 0;
  345 
  346                 /* Clear the callback before invoking the callback */
  347                 io->scsi_tgt_cb = NULL;
  348 
  349                 /* if status was good, and auto-good-response was set, then callback
  350                  * target-server with IO_CMPL_RSP_SENT, otherwise send IO_CMPL
  351                  */
  352                 if ((status == 0) && (io->auto_resp))
  353                         flags |= OCS_SCSI_IO_CMPL_RSP_SENT;
  354                 else
  355                         flags |= OCS_SCSI_IO_CMPL;
  356 
  357                 switch (status) {
  358                 case SLI4_FC_WCQE_STATUS_SUCCESS:
  359                         scsi_status = OCS_SCSI_STATUS_GOOD;
  360                         break;
  361                 case SLI4_FC_WCQE_STATUS_DI_ERROR:
  362                         if (ext_status & SLI4_FC_DI_ERROR_GE) {
  363                                 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
  364                         } else if (ext_status & SLI4_FC_DI_ERROR_AE) {
  365                                 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
  366                         } else if (ext_status & SLI4_FC_DI_ERROR_RE) {
  367                                 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
  368                         } else {
  369                                 additional_length = ((ext_status >> 16) & 0xFFFF);
  370 
  371                                 /* Capture the EDIR and TDPV bits as 0 or 1 for easier printing. */
  372                                 edir = !!(ext_status & SLI4_FC_DI_ERROR_EDIR);
  373                                 tdpv = !!(ext_status & SLI4_FC_DI_ERROR_TDPV);
  374 
  375                                 is_crc = ocs_scsi_dif_guard_is_crc(edir, dif_info);
  376 
  377                                 if (edir == 0) {
  378                                         /* For reads, we have everything in memory.  Start checking from beginning. */
  379                                         scsi_status = ocs_scsi_dif_check_unknown(io, 0, io->wire_len, is_crc);
  380                                 } else {
  381                                         /* For writes, use the additional length to determine where to look for the error.
  382                                          * The additional_length field is set to 0 if it is not supported.
  383                                          * The additional length field is valid if:
  384                                          *    . additional_length is not zero
  385                                          *    . Total Data Placed is valid
  386                                          *    . Error Direction is RX (1)
  387                                          *    . Operation is a pass thru (CRC or CKSUM on IN, and CRC or CHKSUM on OUT) (all pass-thru cases except raw)
  388                                          */
  389                                         if ((additional_length != 0) && (tdpv != 0) &&
  390                                             (dif_info->dif == SLI4_DIF_PASS_THROUGH) && (dif_info->dif_oper != OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW) ) {
  391                                                 scsi_status = ocs_scsi_dif_check_unknown(io, length, additional_length, is_crc);
  392                                         } else {
  393                                                 /* If we can't do additional checking, then fall-back to guard error */
  394                                                 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
  395                                         }
  396                                 }
  397                         }
  398                         break;
  399                 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
  400                         switch (ext_status) {
  401                         case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET:
  402                         case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
  403                                 scsi_status = OCS_SCSI_STATUS_ABORTED;
  404                                 break;
  405                         case SLI4_FC_LOCAL_REJECT_INVALID_RPI:
  406                                 scsi_status = OCS_SCSI_STATUS_NEXUS_LOST;
  407                                 break;
  408                         case SLI4_FC_LOCAL_REJECT_NO_XRI:
  409                                 scsi_status = OCS_SCSI_STATUS_NO_IO;
  410                                 break;
  411                         default:
  412                                 /* TODO: we have seen 0x0d (TX_DMA_FAILED error) */
  413                                 scsi_status = OCS_SCSI_STATUS_ERROR;
  414                                 break;
  415                         }
  416                         break;
  417 
  418                 case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT:
  419                         /* target IO timed out */
  420                         scsi_status = OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED;
  421                         break;
  422 
  423                 case SLI4_FC_WCQE_STATUS_SHUTDOWN:
  424                         /* Target IO cancelled by HW */
  425                         scsi_status = OCS_SCSI_STATUS_SHUTDOWN;
  426                         break;
  427 
  428                 default:
  429                         scsi_status = OCS_SCSI_STATUS_ERROR;
  430                         break;
  431                 }
  432 
  433                 cb(io, scsi_status, flags, io->scsi_tgt_cb_arg);
  434         }
  435         ocs_scsi_check_pending(ocs);
  436 }
  437 
  438 /**
  439  * @brief Determine if an IO is using CRC for DIF guard format.
  440  *
  441  * @param direction IO direction: 1 for write, 0 for read.
  442  * @param dif_info Pointer to HW DIF info data.
  443  *
  444  * @return Returns TRUE if using CRC, FALSE if not.
  445  */
  446 static int
  447 ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info)
  448 {
  449         int is_crc;
  450 
  451         if (direction) {
  452                 /* For writes, check if operation is "OUT_CRC" or not */
  453                 switch(dif_info->dif_oper) {
  454                         case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC:
  455                         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
  456                         case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC:
  457                                 is_crc = TRUE;
  458                                 break;
  459                         default:
  460                                 is_crc = FALSE;
  461                                 break;
  462                 }
  463         } else {
  464                 /* For reads, check if operation is "IN_CRC" or not */
  465                 switch(dif_info->dif_oper) {
  466                         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF:
  467                         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
  468                         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM:
  469                                 is_crc = TRUE;
  470                                 break;
  471                         default:
  472                                 is_crc = FALSE;
  473                                 break;
  474                 }
  475         }
  476 
  477         return is_crc;
  478 }
  479 
  480 /**
  481  * @brief Check a block and DIF data, computing the appropriate SCSI status
  482  *
  483  * @par Description
  484  * This function is used to check blocks and DIF when given an unknown DIF
  485  * status using the following logic:
  486  *
  487  * Given the address of the last good block, and a length of bytes that includes
  488  * the block with the DIF error, find the bad block. If a block is found with an
  489  * app_tag or ref_tag error, then return the appropriate error. No block is expected
  490  * to have a block guard error since hardware "fixes" the crc. So if no block in the
  491  * range of blocks has an error, then it is presumed to be a BLOCK GUARD error.
  492  *
  493  * @param io Pointer to the IO object.
  494  * @param length Length of bytes covering the good blocks.
  495  * @param check_length Length of bytes that covers the bad block.
  496  * @param is_crc True if guard is using CRC format.
  497  *
  498  * @return Returns SCSI status.
  499  */
  500 
  501 static ocs_scsi_io_status_e
  502 ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc)
  503 {
  504         uint32_t i;
  505         ocs_t *ocs = io->ocs;
  506         ocs_hw_dif_info_t *dif_info = &io->hw_dif;
  507         ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
  508         uint32_t blocksize;                     /* data block size */
  509         uint64_t first_check_block;             /* first block following total data placed */
  510         uint64_t last_check_block;              /* last block to check */
  511         uint32_t check_count;                   /* count of blocks to check */
  512         ocs_scsi_vaddr_len_t addrlen[4];        /* address-length pairs returned from target */
  513         int32_t addrlen_count;                  /* count of address-length pairs */
  514         ocs_dif_t *dif;                         /* pointer to DIF block returned from target */
  515         ocs_scsi_dif_info_t scsi_dif_info = io->scsi_dif_info;
  516 
  517         blocksize = ocs_hw_dif_mem_blocksize(&io->hw_dif, TRUE);
  518         first_check_block = length / blocksize;
  519         last_check_block = ((length + check_length) / blocksize);
  520         check_count = last_check_block - first_check_block;
  521 
  522         ocs_log_debug(ocs, "blocksize %d first check_block %" PRId64 " last_check_block %" PRId64 " check_count %d\n",
  523                 blocksize, first_check_block, last_check_block, check_count);
  524 
  525         for (i = first_check_block; i < last_check_block; i++) {
  526                 addrlen_count = ocs_scsi_get_block_vaddr(io, (scsi_dif_info.lba + i), addrlen, ARRAY_SIZE(addrlen), (void**) &dif);
  527                 if (addrlen_count < 0) {
  528                         ocs_log_test(ocs, "ocs_scsi_get_block_vaddr() failed: %d\n", addrlen_count);
  529                         scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
  530                         break;
  531                 }
  532 
  533                 if (! ocs_scsi_dif_check_guard(dif_info, addrlen, addrlen_count, dif, is_crc)) {
  534                         ocs_log_debug(ocs, "block guard check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
  535                         scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
  536                         break;
  537                 }
  538                 if (! ocs_scsi_dif_check_app_tag(ocs, dif_info, scsi_dif_info.app_tag, dif)) {
  539                         ocs_log_debug(ocs, "app tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
  540                         scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
  541                         break;
  542                 }
  543                 if (! ocs_scsi_dif_check_ref_tag(ocs, dif_info, (scsi_dif_info.ref_tag + i), dif)) {
  544                         ocs_log_debug(ocs, "ref tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
  545                         scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
  546                         break;
  547                 }
  548         }
  549         return scsi_status;
  550 }
  551 
  552 /**
  553  * @brief Check the block guard of block data
  554  *
  555  * @par Description
  556  * Using the dif_info for the transfer, check the block guard value.
  557  *
  558  * @param dif_info Pointer to HW DIF info data.
  559  * @param addrlen Array of address length pairs.
  560  * @param addrlen_count Number of entries in the addrlen[] array.
  561  * @param dif Pointer to the DIF data block being checked.
  562  * @param is_crc True if guard is using CRC format.
  563  *
  564  * @return Returns TRUE if block guard check is ok.
  565  */
  566 static uint32_t
  567 ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count,
  568         ocs_dif_t *dif, int is_crc)
  569 {
  570         uint16_t crc = dif_info->dif_seed;
  571         uint32_t i;
  572         uint16_t checksum;
  573 
  574         if ((dif == NULL)  || !dif_info->check_guard) {
  575                 return TRUE;
  576         }
  577 
  578         if (is_crc) {
  579                 for (i = 0; i < addrlen_count; i++) {
  580                         crc = ocs_scsi_dif_calc_crc(addrlen[i].vaddr, addrlen[i].length, crc);
  581                 }
  582                 return (crc == ocs_be16toh(dif->crc));
  583         } else {
  584                 checksum = ocs_scsi_dif_calc_checksum(addrlen, addrlen_count);
  585 
  586                 return (checksum == dif->crc);
  587         }
  588 }
  589 
  590 /**
  591  * @brief Check the app tag of dif data
  592  *
  593  * @par Description
  594  * Using the dif_info for the transfer, check the app tag.
  595  *
  596  * @param ocs Pointer to the ocs structure for logging.
  597  * @param dif_info Pointer to HW DIF info data.
  598  * @param exp_app_tag The value the app tag is expected to be.
  599  * @param dif Pointer to the DIF data block being checked.
  600  *
  601  * @return Returns TRUE if app tag check is ok.
  602  */
  603 static uint32_t
  604 ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif)
  605 {
  606         if ((dif == NULL)  || !dif_info->check_app_tag) {
  607                 return TRUE;
  608         }
  609 
  610         ocs_log_debug(ocs, "expected app tag 0x%x,  actual 0x%x\n",
  611                 exp_app_tag, ocs_be16toh(dif->app_tag));
  612 
  613         return (exp_app_tag == ocs_be16toh(dif->app_tag));
  614 }
  615 
  616 /**
  617  * @brief Check the ref tag of dif data
  618  *
  619  * @par Description
  620  * Using the dif_info for the transfer, check the app tag.
  621  *
  622  * @param ocs Pointer to the ocs structure for logging.
  623  * @param dif_info Pointer to HW DIF info data.
  624  * @param exp_ref_tag The value the ref tag is expected to be.
  625  * @param dif Pointer to the DIF data block being checked.
  626  *
  627  * @return Returns TRUE if ref tag check is ok.
  628  */
  629 static uint32_t
  630 ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif)
  631 {
  632         if ((dif == NULL)  || !dif_info->check_ref_tag) {
  633                 return TRUE;
  634         }
  635 
  636         if (exp_ref_tag != ocs_be32toh(dif->ref_tag)) {
  637                 ocs_log_debug(ocs, "expected ref tag 0x%x, actual 0x%x\n",
  638                         exp_ref_tag, ocs_be32toh(dif->ref_tag));
  639                 return FALSE;
  640         } else {
  641                 return TRUE;
  642         }
  643 }
  644 
  645 /**
  646  * @brief Return count of SGE's required for request
  647  *
  648  * @par Description
  649  * An accurate count of SGEs is computed and returned.
  650  *
  651  * @param hw_dif Pointer to HW dif information.
  652  * @param sgl Pointer to SGL from back end.
  653  * @param sgl_count Count of SGEs in SGL.
  654  *
  655  * @return Count of SGEs.
  656  */
  657 static uint32_t
  658 ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count)
  659 {
  660         uint32_t count = 0;
  661         uint32_t i;
  662 
  663         /* Convert DIF Information */
  664         if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
  665                 /* If we're not DIF separate, then emit a seed SGE */
  666                 if (!hw_dif->dif_separate) {
  667                         count++;
  668                 }
  669 
  670                 for (i = 0; i < sgl_count; i++) {
  671                         /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
  672                         if (hw_dif->dif_separate) {
  673                                 count += 2;
  674                         }
  675 
  676                         count++;
  677                 }
  678         } else {
  679                 count = sgl_count;
  680         }
  681         return count;
  682 }
  683 
  684 static int32_t
  685 ocs_scsi_build_sgls(ocs_hw_t *hw, ocs_hw_io_t *hio, ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hw_io_type_e type)
  686 {
  687         int32_t rc;
  688         uint32_t i;
  689         ocs_t *ocs = hw->os;
  690         uint32_t blocksize = 0;
  691         uint32_t blockcount;
  692 
  693         ocs_assert(hio, -1);
  694 
  695         /* Initialize HW SGL */
  696         rc = ocs_hw_io_init_sges(hw, hio, type);
  697         if (rc) {
  698                 ocs_log_err(ocs, "ocs_hw_io_init_sges failed: %d\n", rc);
  699                 return -1;
  700         }
  701 
  702         /* Convert DIF Information */
  703         if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
  704                 /* If we're not DIF separate, then emit a seed SGE */
  705                 if (!hw_dif->dif_separate) {
  706                         rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
  707                         if (rc) {
  708                                 return rc;
  709                         }
  710                 }
  711 
  712                 /* if we are doing DIF separate, then figure out the block size so that we
  713                  * can update the ref tag in the DIF seed SGE.   Also verify that the
  714                  * the sgl lengths are all multiples of the blocksize
  715                  */
  716                 if (hw_dif->dif_separate) {
  717                         switch(hw_dif->blk_size) {
  718                         case OCS_HW_DIF_BK_SIZE_512:    blocksize = 512; break;
  719                         case OCS_HW_DIF_BK_SIZE_1024:   blocksize = 1024; break;
  720                         case OCS_HW_DIF_BK_SIZE_2048:   blocksize = 2048; break;
  721                         case OCS_HW_DIF_BK_SIZE_4096:   blocksize = 4096; break;
  722                         case OCS_HW_DIF_BK_SIZE_520:    blocksize = 520; break;
  723                         case OCS_HW_DIF_BK_SIZE_4104:   blocksize = 4104; break;
  724                         default:
  725                                 ocs_log_test(hw->os, "Inavlid hw_dif blocksize %d\n", hw_dif->blk_size);
  726                                 return -1;
  727                         }
  728                         for (i = 0; i < sgl_count; i++) {
  729                                 if ((sgl[i].len % blocksize) != 0) {
  730                                         ocs_log_test(hw->os, "sgl[%d] len of %ld is not multiple of blocksize\n",
  731                                                      i, sgl[i].len);
  732                                         return -1;
  733                                 }
  734                         }
  735                 }
  736 
  737                 for (i = 0; i < sgl_count; i++) {
  738                         ocs_assert(sgl[i].addr, -1);
  739                         ocs_assert(sgl[i].len, -1);
  740 
  741                         /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
  742                         if (hw_dif->dif_separate) {
  743                                 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
  744                                 if (rc) {
  745                                         return rc;
  746                                 }
  747                                 rc = ocs_hw_io_add_dif_sge(hw, hio, sgl[i].dif_addr);
  748                                 if (rc) {
  749                                         return rc;
  750                                 }
  751                                 /* Update the ref_tag for the next DIF seed SGE */
  752                                 blockcount = sgl[i].len / blocksize;
  753                                 if (hw_dif->dif_oper == OCS_HW_DIF_OPER_INSERT) {
  754                                         hw_dif->ref_tag_repl += blockcount;
  755                                 } else {
  756                                         hw_dif->ref_tag_cmp += blockcount;
  757                                 }
  758                         }
  759 
  760                         /* Add data SGE */
  761                         rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
  762                         if (rc) {
  763                                 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
  764                                                 sgl_count, rc);
  765                                 return rc;
  766                         }
  767                 }
  768         } else {
  769                 for (i = 0; i < sgl_count; i++) {
  770                         ocs_assert(sgl[i].addr, -1);
  771                         ocs_assert(sgl[i].len, -1);
  772 
  773                         /* Add data SGE */
  774                         rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
  775                         if (rc) {
  776                                 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
  777                                                 sgl_count, rc);
  778                                 return rc;
  779                         }
  780                 }
  781         }
  782         return 0;
  783 }
  784 
  785 /**
  786  * @ingroup scsi_api_base
  787  * @brief Convert SCSI API T10 DIF information into the FC HW format.
  788  *
  789  * @param ocs Pointer to the ocs structure for logging.
  790  * @param scsi_dif_info Pointer to the SCSI API T10 DIF fields.
  791  * @param hw_dif_info Pointer to the FC HW API T10 DIF fields.
  792  *
  793  * @return Returns 0 on success, or a negative error code value on failure.
  794  */
  795 
  796 static int32_t
  797 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, ocs_hw_dif_info_t *hw_dif_info)
  798 {
  799         uint32_t dif_seed;
  800         ocs_memset(hw_dif_info, 0, sizeof(ocs_hw_dif_info_t));
  801 
  802         if (scsi_dif_info == NULL) {
  803                 hw_dif_info->dif_oper = OCS_HW_DIF_OPER_DISABLED;
  804                 hw_dif_info->blk_size =  OCS_HW_DIF_BK_SIZE_NA;
  805                 return 0;
  806         }
  807 
  808         /* Convert the DIF operation */
  809         switch(scsi_dif_info->dif_oper) {
  810         case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC:
  811                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC;
  812                 hw_dif_info->dif = SLI4_DIF_INSERT;
  813                 break;
  814         case OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF:
  815                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF;
  816                 hw_dif_info->dif = SLI4_DIF_STRIP;
  817                 break;
  818         case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM:
  819                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM;
  820                 hw_dif_info->dif = SLI4_DIF_INSERT;
  821                 break;
  822         case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF:
  823                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF;
  824                 hw_dif_info->dif = SLI4_DIF_STRIP;
  825                 break;
  826         case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC:
  827                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC;
  828                 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
  829                 break;
  830         case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM:
  831                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM;
  832                 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
  833                 break;
  834         case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM:
  835                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM;
  836                 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
  837                 break;
  838         case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC:
  839                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC;
  840                 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
  841                 break;
  842         case OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW:
  843                 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW;
  844                 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
  845                 break;
  846         default:
  847                 ocs_log_test(ocs, "unhandled SCSI DIF operation %d\n",
  848                              scsi_dif_info->dif_oper);
  849                 return -1;
  850         }
  851 
  852         switch(scsi_dif_info->blk_size) {
  853         case OCS_SCSI_DIF_BK_SIZE_512:
  854                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_512;
  855                 break;
  856         case OCS_SCSI_DIF_BK_SIZE_1024:
  857                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_1024;
  858                 break;
  859         case OCS_SCSI_DIF_BK_SIZE_2048:
  860                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_2048;
  861                 break;
  862         case OCS_SCSI_DIF_BK_SIZE_4096:
  863                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4096;
  864                 break;
  865         case OCS_SCSI_DIF_BK_SIZE_520:
  866                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_520;
  867                 break;
  868         case OCS_SCSI_DIF_BK_SIZE_4104:
  869                 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4104;
  870                 break;
  871         default:
  872                 ocs_log_test(ocs, "unhandled SCSI DIF block size %d\n",
  873                              scsi_dif_info->blk_size);
  874                 return -1;
  875         }
  876 
  877         /* If the operation is an INSERT the tags provided are the ones that should be
  878          * inserted, otherwise they're the ones to be checked against. */
  879         if (hw_dif_info->dif == SLI4_DIF_INSERT ) {
  880                 hw_dif_info->ref_tag_repl = scsi_dif_info->ref_tag;
  881                 hw_dif_info->app_tag_repl = scsi_dif_info->app_tag;
  882         } else {
  883                 hw_dif_info->ref_tag_cmp = scsi_dif_info->ref_tag;
  884                 hw_dif_info->app_tag_cmp = scsi_dif_info->app_tag;
  885         }
  886 
  887         hw_dif_info->check_ref_tag = scsi_dif_info->check_ref_tag;
  888         hw_dif_info->check_app_tag = scsi_dif_info->check_app_tag;
  889         hw_dif_info->check_guard = scsi_dif_info->check_guard;
  890         hw_dif_info->auto_incr_ref_tag = 1;
  891         hw_dif_info->dif_separate = scsi_dif_info->dif_separate;
  892         hw_dif_info->disable_app_ffff = scsi_dif_info->disable_app_ffff;
  893         hw_dif_info->disable_app_ref_ffff = scsi_dif_info->disable_app_ref_ffff;
  894 
  895         ocs_hw_get(&ocs->hw, OCS_HW_DIF_SEED, &dif_seed);
  896         hw_dif_info->dif_seed = dif_seed;
  897 
  898         return 0;
  899 }
  900 
  901 /**
  902  * @ingroup scsi_api_base
  903  * @brief This function logs the SGLs for an IO.
  904  *
  905  * @param io Pointer to the IO context.
  906  */
  907 static void ocs_log_sgl(ocs_io_t *io)
  908 {
  909         ocs_hw_io_t *hio = io->hio;
  910         sli4_sge_t *data = NULL;
  911         uint32_t *dword = NULL;
  912         uint32_t i;
  913         uint32_t n_sge;
  914 
  915         scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n",
  916                       ocs_addr32_hi(hio->def_sgl.phys),
  917                       ocs_addr32_lo(hio->def_sgl.phys));
  918         n_sge = (hio->sgl == &hio->def_sgl ? hio->n_sge : hio->def_sgl_count);
  919         for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) {
  920                 dword = (uint32_t*)data;
  921 
  922                 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
  923                          i, dword[0], dword[1], dword[2], dword[3]);
  924 
  925                 if (dword[2] & (1U << 31)) {
  926                         break;
  927                 }
  928         }
  929 
  930         if (hio->ovfl_sgl != NULL &&
  931                 hio->sgl == hio->ovfl_sgl) {
  932                 scsi_io_trace(io, "Overflow at 0x%x 0x%08x\n",
  933                               ocs_addr32_hi(hio->ovfl_sgl->phys),
  934                               ocs_addr32_lo(hio->ovfl_sgl->phys));
  935                 for (i = 0, data = hio->ovfl_sgl->virt; i < hio->n_sge; i++, data++) {
  936                         dword = (uint32_t*)data;
  937 
  938                         scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
  939                                  i, dword[0], dword[1], dword[2], dword[3]);
  940                         if (dword[2] & (1U << 31)) {
  941                                 break;
  942                         }
  943                 }
  944         }
  945 
  946 }
  947 
  948 /**
  949  * @brief Check pending error asynchronous callback function.
  950  *
  951  * @par Description
  952  * Invoke the HW callback function for a given IO. This function is called
  953  * from the NOP mailbox completion context.
  954  *
  955  * @param hw Pointer to HW object.
  956  * @param status Completion status.
  957  * @param mqe Mailbox completion queue entry.
  958  * @param arg General purpose argument.
  959  *
  960  * @return Returns 0.
  961  */
  962 static int32_t
  963 ocs_scsi_check_pending_async_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
  964 {
  965         ocs_io_t *io = arg;
  966 
  967         if (io != NULL) {
  968                 if (io->hw_cb != NULL) {
  969                         ocs_hw_done_t cb = io->hw_cb;
  970 
  971                         io->hw_cb = NULL;
  972                         cb(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io);
  973                 }
  974         }
  975         return 0;
  976 }
  977 
  978 /**
  979  * @brief Check for pending IOs to dispatch.
  980  *
  981  * @par Description
  982  * If there are IOs on the pending list, and a HW IO is available, then
  983  * dispatch the IOs.
  984  *
  985  * @param ocs Pointer to the OCS structure.
  986  *
  987  * @return None.
  988  */
  989 
  990 void
  991 ocs_scsi_check_pending(ocs_t *ocs)
  992 {
  993         ocs_xport_t *xport = ocs->xport;
  994         ocs_io_t *io;
  995         ocs_hw_io_t *hio;
  996         int32_t status;
  997         int count = 0;
  998         int dispatch;
  999 
 1000         /* Guard against recursion */
 1001         if (ocs_atomic_add_return(&xport->io_pending_recursing, 1)) {
 1002                 /* This function is already running.  Decrement and return. */
 1003                 ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
 1004                 return;
 1005         }
 1006 
 1007         do {
 1008                 ocs_lock(&xport->io_pending_lock);
 1009                         status = 0;
 1010                         hio = NULL;
 1011                         io = ocs_list_remove_head(&xport->io_pending_list);
 1012                         if (io != NULL) {
 1013                                 if (io->io_type == OCS_IO_TYPE_ABORT) {
 1014                                         hio = NULL;
 1015                                 } else {
 1016                                         hio = ocs_hw_io_alloc(&ocs->hw);
 1017                                         if (hio == NULL) {
 1018                                                 /*
 1019                                                  * No HW IO available.
 1020                                                  * Put IO back on the front of pending list
 1021                                                  */
 1022                                                 ocs_list_add_head(&xport->io_pending_list, io);
 1023                                                 io = NULL;
 1024                                         } else {
 1025                                                 hio->eq = io->hw_priv;
 1026                                         }
 1027                                 }
 1028                         }
 1029                 /* Must drop the lock before dispatching the IO */
 1030                 ocs_unlock(&xport->io_pending_lock);
 1031 
 1032                 if (io != NULL) {
 1033                         count++;
 1034 
 1035                         /*
 1036                          * We pulled an IO off the pending list,
 1037                          * and either got an HW IO or don't need one
 1038                          */
 1039                         ocs_atomic_sub_return(&xport->io_pending_count, 1);
 1040                         if (hio == NULL) {
 1041                                 status = ocs_scsi_io_dispatch_no_hw_io(io);
 1042                         } else {
 1043                                 status = ocs_scsi_io_dispatch_hw_io(io, hio);
 1044                         }
 1045                         if (status) {
 1046                                 /*
 1047                                  * Invoke the HW callback, but do so in the separate execution context,
 1048                                  * provided by the NOP mailbox completion processing context by using
 1049                                  * ocs_hw_async_call()
 1050                                  */
 1051                                 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
 1052                                         ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
 1053                                 }
 1054                         }
 1055                 }
 1056         } while (io != NULL);
 1057 
 1058         /*
 1059          * If nothing was removed from the list,
 1060          * we might be in a case where we need to abort an
 1061          * active IO and the abort is on the pending list.
 1062          * Look for an abort we can dispatch.
 1063          */
 1064         if (count == 0 ) {
 1065                 dispatch = 0;
 1066 
 1067                 ocs_lock(&xport->io_pending_lock);
 1068                         ocs_list_foreach(&xport->io_pending_list, io) {
 1069                                 if (io->io_type == OCS_IO_TYPE_ABORT) {
 1070                                         if (io->io_to_abort->hio != NULL) {
 1071                                                 /* This IO has a HW IO, so it is active.  Dispatch the abort. */
 1072                                                 dispatch = 1;
 1073                                         } else {
 1074                                                 /* Leave this abort on the pending list and keep looking */
 1075                                                 dispatch = 0;
 1076                                         }
 1077                                 }
 1078                                 if (dispatch) {
 1079                                         ocs_list_remove(&xport->io_pending_list, io);
 1080                                         ocs_atomic_sub_return(&xport->io_pending_count, 1);
 1081                                         break;
 1082                                 }
 1083                         }
 1084                 ocs_unlock(&xport->io_pending_lock);
 1085 
 1086                 if (dispatch) {
 1087                         status = ocs_scsi_io_dispatch_no_hw_io(io);
 1088                         if (status) {
 1089                                 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
 1090                                         ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
 1091                                 }
 1092                         }
 1093                 }
 1094         }
 1095 
 1096         ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
 1097         return;
 1098 }
 1099 
 1100 /**
 1101  * @brief Attempt to dispatch a non-abort IO
 1102  *
 1103  * @par Description
 1104  * An IO is dispatched:
 1105  * - if the pending list is not empty, add IO to pending list
 1106  *   and call a function to process the pending list.
 1107  * - if pending list is empty, try to allocate a HW IO. If none
 1108  *   is available, place this IO at the tail of the pending IO
 1109  *   list.
 1110  * - if HW IO is available, attach this IO to the HW IO and
 1111  *   submit it.
 1112  *
 1113  * @param io Pointer to IO structure.
 1114  * @param cb Callback function.
 1115  *
 1116  * @return Returns 0 on success, a negative error code value on failure.
 1117  */
 1118 
 1119 int32_t
 1120 ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
 1121 {
 1122         ocs_hw_io_t *hio;
 1123         ocs_t *ocs = io->ocs;
 1124         ocs_xport_t *xport = ocs->xport;
 1125 
 1126         ocs_assert(io->cmd_tgt || io->cmd_ini, -1);
 1127         ocs_assert((io->io_type != OCS_IO_TYPE_ABORT), -1);
 1128         io->hw_cb = cb;
 1129 
 1130         /*
 1131          * if this IO already has a HW IO, then this is either not the first phase of
 1132          * the IO. Send it to the HW.
 1133          */
 1134         if (io->hio != NULL) {
 1135                 return ocs_scsi_io_dispatch_hw_io(io, io->hio);
 1136         }
 1137 
 1138         /*
 1139          * We don't already have a HW IO associated with the IO. First check
 1140          * the pending list. If not empty, add IO to the tail and process the
 1141          * pending list.
 1142          */
 1143         ocs_lock(&xport->io_pending_lock);
 1144                 if (!ocs_list_empty(&xport->io_pending_list)) {
 1145                         /*
 1146                          * If this is a low latency request, the put at the front of the IO pending
 1147                          * queue, otherwise put it at the end of the queue.
 1148                          */
 1149                         if (io->low_latency) {
 1150                                 ocs_list_add_head(&xport->io_pending_list, io);
 1151                         } else {
 1152                                 ocs_list_add_tail(&xport->io_pending_list, io);
 1153                         }
 1154                         ocs_unlock(&xport->io_pending_lock);
 1155                         ocs_atomic_add_return(&xport->io_pending_count, 1);
 1156                         ocs_atomic_add_return(&xport->io_total_pending, 1);
 1157 
 1158                         /* process pending list */
 1159                         ocs_scsi_check_pending(ocs);
 1160                         return 0;
 1161                 }
 1162         ocs_unlock(&xport->io_pending_lock);
 1163 
 1164         /*
 1165          * We don't have a HW IO associated with the IO and there's nothing
 1166          * on the pending list. Attempt to allocate a HW IO and dispatch it.
 1167          */
 1168         hio = ocs_hw_io_alloc(&io->ocs->hw);
 1169         if (hio == NULL) {
 1170                 /* Couldn't get a HW IO. Save this IO on the pending list */
 1171                 ocs_lock(&xport->io_pending_lock);
 1172                         ocs_list_add_tail(&xport->io_pending_list, io);
 1173                 ocs_unlock(&xport->io_pending_lock);
 1174 
 1175                 ocs_atomic_add_return(&xport->io_total_pending, 1);
 1176                 ocs_atomic_add_return(&xport->io_pending_count, 1);
 1177                 return 0;
 1178         }
 1179 
 1180         /* We successfully allocated a HW IO; dispatch to HW */
 1181         return ocs_scsi_io_dispatch_hw_io(io, hio);
 1182 }
 1183 
 1184 /**
 1185  * @brief Attempt to dispatch an Abort IO.
 1186  *
 1187  * @par Description
 1188  * An Abort IO is dispatched:
 1189  * - if the pending list is not empty, add IO to pending list
 1190  *   and call a function to process the pending list.
 1191  * - if pending list is empty, send abort to the HW.
 1192  *
 1193  * @param io Pointer to IO structure.
 1194  * @param cb Callback function.
 1195  *
 1196  * @return Returns 0 on success, a negative error code value on failure.
 1197  */
 1198 
 1199 int32_t
 1200 ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb)
 1201 {
 1202         ocs_t *ocs = io->ocs;
 1203         ocs_xport_t *xport = ocs->xport;
 1204 
 1205         ocs_assert((io->io_type == OCS_IO_TYPE_ABORT), -1);
 1206         io->hw_cb = cb;
 1207 
 1208         /*
 1209          * For aborts, we don't need a HW IO, but we still want to pass through
 1210          * the pending list to preserve ordering. Thus, if the pending list is
 1211          * not empty, add this abort to the pending list and process the pending list.
 1212          */
 1213         ocs_lock(&xport->io_pending_lock);
 1214                 if (!ocs_list_empty(&xport->io_pending_list)) {
 1215                         ocs_list_add_tail(&xport->io_pending_list, io);
 1216                         ocs_unlock(&xport->io_pending_lock);
 1217                         ocs_atomic_add_return(&xport->io_pending_count, 1);
 1218                         ocs_atomic_add_return(&xport->io_total_pending, 1);
 1219 
 1220                         /* process pending list */
 1221                         ocs_scsi_check_pending(ocs);
 1222                         return 0;
 1223                 }
 1224         ocs_unlock(&xport->io_pending_lock);
 1225 
 1226         /* nothing on pending list, dispatch abort */
 1227         return ocs_scsi_io_dispatch_no_hw_io(io);
 1228 
 1229 }
 1230 
 1231 /**
 1232  * @brief Dispatch IO
 1233  *
 1234  * @par Description
 1235  * An IO and its associated HW IO is dispatched to the HW.
 1236  *
 1237  * @param io Pointer to IO structure.
 1238  * @param hio Pointer to HW IO structure from which IO will be
 1239  * dispatched.
 1240  *
 1241  * @return Returns 0 on success, a negative error code value on failure.
 1242  */
 1243 
 1244 static int32_t
 1245 ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio)
 1246 {
 1247         int32_t rc;
 1248         ocs_t *ocs = io->ocs;
 1249 
 1250         /* Got a HW IO; update ini/tgt_task_tag with HW IO info and dispatch */
 1251         io->hio = hio;
 1252         if (io->cmd_tgt) {
 1253                 io->tgt_task_tag = hio->indicator;
 1254         } else if (io->cmd_ini) {
 1255                 io->init_task_tag = hio->indicator;
 1256         }
 1257         io->hw_tag = hio->reqtag;
 1258 
 1259         hio->eq = io->hw_priv;
 1260 
 1261         /* Copy WQ steering */
 1262         switch(io->wq_steering) {
 1263         case OCS_SCSI_WQ_STEERING_CLASS >> OCS_SCSI_WQ_STEERING_SHIFT:
 1264                 hio->wq_steering = OCS_HW_WQ_STEERING_CLASS;
 1265                 break;
 1266         case OCS_SCSI_WQ_STEERING_REQUEST >> OCS_SCSI_WQ_STEERING_SHIFT:
 1267                 hio->wq_steering = OCS_HW_WQ_STEERING_REQUEST;
 1268                 break;
 1269         case OCS_SCSI_WQ_STEERING_CPU >> OCS_SCSI_WQ_STEERING_SHIFT:
 1270                 hio->wq_steering = OCS_HW_WQ_STEERING_CPU;
 1271                 break;
 1272         }
 1273 
 1274         switch (io->io_type) {
 1275         case OCS_IO_TYPE_IO: {
 1276                 uint32_t max_sgl;
 1277                 uint32_t total_count;
 1278                 uint32_t host_allocated;
 1279 
 1280                 ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
 1281                 ocs_hw_get(&ocs->hw, OCS_HW_SGL_CHAINING_HOST_ALLOCATED, &host_allocated);
 1282 
 1283                 /*
 1284                  * If the requested SGL is larger than the default size, then we can allocate
 1285                  * an overflow SGL.
 1286                  */
 1287                 total_count = ocs_scsi_count_sgls(&io->hw_dif, io->sgl, io->sgl_count);
 1288 
 1289                 /*
 1290                  * Lancer requires us to allocate the chained memory area, but
 1291                  * Skyhawk must use the SGL list associated with another XRI.
 1292                  */
 1293                 if (host_allocated && total_count > max_sgl) {
 1294                         /* Compute count needed, the number extra plus 1 for the link sge */
 1295                         uint32_t count = total_count - max_sgl + 1;
 1296                         rc = ocs_dma_alloc(ocs, &io->ovfl_sgl, count*sizeof(sli4_sge_t), 64);
 1297                         if (rc) {
 1298                                 ocs_log_err(ocs, "ocs_dma_alloc overflow sgl failed\n");
 1299                                 break;
 1300                         }
 1301                         rc = ocs_hw_io_register_sgl(&ocs->hw, io->hio, &io->ovfl_sgl, count);
 1302                         if (rc) {
 1303                                 ocs_scsi_io_free_ovfl(io);
 1304                                 ocs_log_err(ocs, "ocs_hw_io_register_sgl() failed\n");
 1305                                 break;
 1306                         }
 1307                         /* EVT: update chained_io_count */
 1308                         io->node->chained_io_count++;
 1309                 }
 1310 
 1311                 rc = ocs_scsi_build_sgls(&ocs->hw, io->hio, &io->hw_dif, io->sgl, io->sgl_count, io->hio_type);
 1312                 if (rc) {
 1313                         ocs_scsi_io_free_ovfl(io);
 1314                         break;
 1315                 }
 1316 
 1317                 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
 1318                         ocs_log_sgl(io);
 1319                 }
 1320 
 1321                 if (io->app_id) {
 1322                         io->iparam.fcp_tgt.app_id = io->app_id;
 1323                 }
 1324 
 1325                 rc = ocs_hw_io_send(&io->ocs->hw, io->hio_type, io->hio, io->wire_len, &io->iparam, &io->node->rnode,
 1326                         io->hw_cb, io);
 1327                 break;
 1328         }
 1329         case OCS_IO_TYPE_ELS:
 1330         case OCS_IO_TYPE_CT: {
 1331                 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
 1332                         &io->els_req, io->wire_len,
 1333                         &io->els_rsp, &io->node->rnode, &io->iparam,
 1334                         io->hw_cb, io);
 1335                 break;
 1336         }
 1337         case OCS_IO_TYPE_CT_RESP: {
 1338                 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
 1339                         &io->els_rsp, io->wire_len,
 1340                         NULL, &io->node->rnode, &io->iparam,
 1341                         io->hw_cb, io);
 1342                 break;
 1343         }
 1344         case OCS_IO_TYPE_BLS_RESP: {
 1345                 /* no need to update tgt_task_tag for BLS response since the RX_ID
 1346                  * will be specified by the payload, not the XRI */
 1347                 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
 1348                         NULL, 0, NULL, &io->node->rnode, &io->iparam, io->hw_cb, io);
 1349                 break;
 1350         }
 1351         default:
 1352                 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
 1353                 rc = -1;
 1354                 break;
 1355         }
 1356         return rc;
 1357 }
 1358 
 1359 /**
 1360  * @brief Dispatch IO
 1361  *
 1362  * @par Description
 1363  * An IO that does require a HW IO is dispatched to the HW.
 1364  *
 1365  * @param io Pointer to IO structure.
 1366  *
 1367  * @return Returns 0 on success, or a negative error code value on failure.
 1368  */
 1369 
 1370 static int32_t
 1371 ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io)
 1372 {
 1373         int32_t rc;
 1374 
 1375         switch (io->io_type) {
 1376         case OCS_IO_TYPE_ABORT: {
 1377                 ocs_hw_io_t *hio_to_abort = NULL;
 1378                 ocs_assert(io->io_to_abort, -1);
 1379                 hio_to_abort = io->io_to_abort->hio;
 1380 
 1381                 if (hio_to_abort == NULL) {
 1382                         /*
 1383                          * If "IO to abort" does not have an associated HW IO, immediately
 1384                          * make callback with success. The command must have been sent to
 1385                          * the backend, but the data phase has not yet started, so we don't
 1386                          * have a HW IO.
 1387                          *
 1388                          * Note: since the backend shims should be taking a reference
 1389                          * on io_to_abort, it should not be possible to have been completed
 1390                          * and freed by the backend before the abort got here.
 1391                          */
 1392                         scsi_io_printf(io, "IO: " SCSI_IOFMT " not active\n",
 1393                                        SCSI_IOFMT_ARGS(io->io_to_abort));
 1394                         ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_SUCCESS, 0, io);
 1395                         rc = 0;
 1396                 } else {
 1397                         /* HW IO is valid, abort it */
 1398                         scsi_io_printf(io, "aborting " SCSI_IOFMT "\n", SCSI_IOFMT_ARGS(io->io_to_abort));
 1399                         rc = ocs_hw_io_abort(&io->ocs->hw, hio_to_abort, io->send_abts,
 1400                                               io->hw_cb, io);
 1401                         if (rc) {
 1402                                 int status = SLI4_FC_WCQE_STATUS_SUCCESS;
 1403                                 if ((rc != OCS_HW_RTN_IO_NOT_ACTIVE) &&
 1404                                     (rc != OCS_HW_RTN_IO_ABORT_IN_PROGRESS)) {
 1405                                         status = -1;
 1406                                         scsi_io_printf(io, "Failed to abort IO: " SCSI_IOFMT " status=%d\n",
 1407                                                        SCSI_IOFMT_ARGS(io->io_to_abort), rc);
 1408                                 }
 1409                                 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, status, 0, io);
 1410                                 rc = 0;
 1411                         }
 1412                 }
 1413 
 1414                 break;
 1415         }
 1416         default:
 1417                 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
 1418                 rc = -1;
 1419                 break;
 1420         }
 1421         return rc;
 1422 }
 1423 
 1424 /**
 1425  * @ingroup scsi_api_base
 1426  * @brief Send read/write data.
 1427  *
 1428  * @par Description
 1429  * This call is made by a target-server to initiate a SCSI read or write data phase, transferring
 1430  * data between the target to the remote initiator. The payload is specified by the
 1431  * scatter-gather list @c sgl of length @c sgl_count. The @c wire_len argument
 1432  * specifies the payload length (independent of the scatter-gather list cumulative length).
 1433  * @n @n
 1434  * The @c flags argument has one bit, OCS_SCSI_LAST_DATAPHASE, which is a hint to the base
 1435  * driver that it may use auto SCSI response features if the hardware supports it.
 1436  * @n @n
 1437  * Upon completion, the callback function @b cb is called with flags indicating that the
 1438  * IO has completed (OCS_SCSI_IO_COMPL) and another data phase or response may be sent;
 1439  * that the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP);
 1440  * or that the IO was aborted (OCS_SCSI_IO_ABORTED).
 1441  *
 1442  * @param io Pointer to the IO context.
 1443  * @param flags Flags controlling the sending of data.
 1444  * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
 1445  * @param sgl Pointer to the payload scatter-gather list.
 1446  * @param sgl_count Count of the scatter-gather list elements.
 1447  * @param xwire_len Length of the payload on wire, in bytes.
 1448  * @param type HW IO type.
 1449  * @param enable_ar Enable auto-response if true.
 1450  * @param cb Completion callback.
 1451  * @param arg Application-supplied callback data.
 1452  *
 1453  * @return Returns 0 on success, or a negative error code value on failure.
 1454  */
 1455 
 1456 static inline int32_t
 1457 ocs_scsi_xfer_data(ocs_io_t *io, uint32_t flags,
 1458         ocs_scsi_dif_info_t *dif_info,
 1459         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t xwire_len,
 1460         ocs_hw_io_type_e type, int enable_ar,
 1461         ocs_scsi_io_cb_t cb, void *arg)
 1462 {
 1463         int32_t rc;
 1464         ocs_t *ocs;
 1465         uint32_t disable_ar_tgt_dif = FALSE;
 1466         size_t residual = 0;
 1467 
 1468         if ((dif_info != NULL) && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) {
 1469                 dif_info = NULL;
 1470         }
 1471 
 1472         ocs_assert(io, -1);
 1473 
 1474         if (dif_info != NULL) {
 1475                 ocs_hw_get(&io->ocs->hw, OCS_HW_DISABLE_AR_TGT_DIF, &disable_ar_tgt_dif);
 1476                 if (disable_ar_tgt_dif) {
 1477                         enable_ar = FALSE;
 1478                 }
 1479         }
 1480 
 1481         io->sgl_count = sgl_count;
 1482 
 1483         /* If needed, copy SGL */
 1484         if (sgl && (sgl != io->sgl)) {
 1485                 ocs_assert(sgl_count <= io->sgl_allocated, -1);
 1486                 ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl));
 1487         }
 1488 
 1489         ocs = io->ocs;
 1490         ocs_assert(ocs, -1);
 1491         ocs_assert(io->node, -1);
 1492 
 1493         scsi_io_trace(io, "%s wire_len %d\n", (type == OCS_HW_IO_TARGET_READ) ? "send" : "recv", xwire_len);
 1494 
 1495         ocs_assert(sgl, -1);
 1496         ocs_assert(sgl_count > 0, -1);
 1497         ocs_assert(io->exp_xfer_len > io->transferred, -1);
 1498 
 1499         io->hio_type = type;
 1500 
 1501         io->scsi_tgt_cb = cb;
 1502         io->scsi_tgt_cb_arg = arg;
 1503 
 1504         rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
 1505         if (rc) {
 1506                 return rc;
 1507         }
 1508 
 1509         /* If DIF is used, then save lba for error recovery */
 1510         if (dif_info) {
 1511                 io->scsi_dif_info = *dif_info;
 1512         }
 1513 
 1514         io->wire_len = MIN(xwire_len, io->exp_xfer_len - io->transferred);
 1515         residual = (xwire_len - io->wire_len);
 1516 
 1517         ocs_memset(&io->iparam, 0, sizeof(io->iparam));
 1518         io->iparam.fcp_tgt.ox_id = io->init_task_tag;
 1519         io->iparam.fcp_tgt.offset = io->transferred;
 1520         io->iparam.fcp_tgt.dif_oper = io->hw_dif.dif;
 1521         io->iparam.fcp_tgt.blk_size = io->hw_dif.blk_size;
 1522         io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
 1523         io->iparam.fcp_tgt.timeout = io->timeout;
 1524 
 1525         /* if this is the last data phase and there is no residual, enable
 1526          * auto-good-response
 1527          */
 1528         if (enable_ar && (flags & OCS_SCSI_LAST_DATAPHASE) &&
 1529                 (residual == 0) && ((io->transferred + io->wire_len) == io->exp_xfer_len) && (!(flags & OCS_SCSI_NO_AUTO_RESPONSE))) {
 1530                 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
 1531                 io->auto_resp = TRUE;
 1532         } else {
 1533                 io->auto_resp = FALSE;
 1534         }
 1535 
 1536         /* save this transfer length */
 1537         io->xfer_req = io->wire_len;
 1538 
 1539         /* Adjust the transferred count to account for overrun
 1540          * when the residual is calculated in ocs_scsi_send_resp
 1541          */
 1542         io->transferred += residual;
 1543 
 1544         /* Adjust the SGL size if there is overrun */
 1545 
 1546         if (residual) {
 1547                 ocs_scsi_sgl_t  *sgl_ptr = &io->sgl[sgl_count-1];
 1548 
 1549                 while (residual) {
 1550                         size_t len = sgl_ptr->len;
 1551                         if ( len > residual) {
 1552                                 sgl_ptr->len = len - residual;
 1553                                 residual = 0;
 1554                         } else {
 1555                                 sgl_ptr->len = 0;
 1556                                 residual -= len;
 1557                                 io->sgl_count--;
 1558                         }
 1559                         sgl_ptr--;
 1560                 }
 1561         }
 1562 
 1563         /* Set latency and WQ steering */
 1564         io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
 1565         io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
 1566         io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
 1567 
 1568         return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
 1569 }
 1570 
 1571 int32_t
 1572 ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags,
 1573         ocs_scsi_dif_info_t *dif_info,
 1574         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
 1575         ocs_scsi_io_cb_t cb, void *arg)
 1576 {
 1577         return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_READ,
 1578                                   enable_tsend_auto_resp(io->ocs), cb, arg);
 1579 }
 1580 
 1581 int32_t
 1582 ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags,
 1583         ocs_scsi_dif_info_t *dif_info,
 1584         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
 1585         ocs_scsi_io_cb_t cb, void *arg)
 1586 {
 1587         return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_WRITE,
 1588                                   enable_treceive_auto_resp(io->ocs), cb, arg);
 1589 }
 1590 
 1591 /**
 1592  * @ingroup scsi_api_base
 1593  * @brief Free overflow SGL.
 1594  *
 1595  * @par Description
 1596  * Free the overflow SGL if it is present.
 1597  *
 1598  * @param io Pointer to IO object.
 1599  *
 1600  * @return None.
 1601  */
 1602 static void
 1603 ocs_scsi_io_free_ovfl(ocs_io_t *io) {
 1604         if (io->ovfl_sgl.size) {
 1605                 ocs_dma_free(io->ocs, &io->ovfl_sgl);
 1606         }
 1607 }
 1608 
 1609 /**
 1610  * @ingroup scsi_api_base
 1611  * @brief Send response data.
 1612  *
 1613  * @par Description
 1614  * This function is used by a target-server to send the SCSI response data to a remote
 1615  * initiator node. The target-server populates the @c ocs_scsi_cmd_resp_t
 1616  * argument with scsi status, status qualifier, sense data, and response data, as
 1617  * needed.
 1618  * @n @n
 1619  * Upon completion, the callback function @c cb is invoked. The target-server will generally
 1620  * clean up its IO context resources and call ocs_scsi_io_complete().
 1621  *
 1622  * @param io Pointer to the IO context.
 1623  * @param flags Flags to control sending of the SCSI response.
 1624  * @param rsp Pointer to the response data populated by the caller.
 1625  * @param cb Completion callback.
 1626  * @param arg Application-specified completion callback argument.
 1627 
 1628  * @return Returns 0 on success, or a negative error code value on failure.
 1629  */
 1630 int32_t
 1631 ocs_scsi_send_resp(ocs_io_t *io, uint32_t flags, ocs_scsi_cmd_resp_t *rsp, ocs_scsi_io_cb_t cb, void *arg)
 1632 {
 1633         ocs_t *ocs;
 1634         int32_t residual;
 1635         int auto_resp = TRUE;           /* Always try auto resp */
 1636         uint8_t scsi_status = 0;
 1637         uint16_t scsi_status_qualifier = 0;
 1638         uint8_t *sense_data = NULL;
 1639         uint32_t sense_data_length = 0;
 1640 
 1641         ocs_assert(io, -1);
 1642 
 1643         ocs = io->ocs;
 1644         ocs_assert(ocs, -1);
 1645 
 1646         ocs_assert(io->node, -1);
 1647 
 1648         ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
 1649 
 1650         if (rsp) {
 1651                 scsi_status = rsp->scsi_status;
 1652                 scsi_status_qualifier = rsp->scsi_status_qualifier;
 1653                 sense_data = rsp->sense_data;
 1654                 sense_data_length = rsp->sense_data_length;
 1655                 residual = rsp->residual;
 1656         } else {
 1657                 residual = io->exp_xfer_len - io->transferred;
 1658         }
 1659 
 1660         io->wire_len = 0;
 1661         io->hio_type = OCS_HW_IO_TARGET_RSP;
 1662 
 1663         io->scsi_tgt_cb = cb;
 1664         io->scsi_tgt_cb_arg = arg;
 1665 
 1666         ocs_memset(&io->iparam, 0, sizeof(io->iparam));
 1667         io->iparam.fcp_tgt.ox_id = io->init_task_tag;
 1668         io->iparam.fcp_tgt.offset = 0;
 1669         io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
 1670         io->iparam.fcp_tgt.timeout = io->timeout;
 1671 
 1672         /* Set low latency queueing request */
 1673         io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
 1674         io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
 1675         io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
 1676 
 1677         if ((scsi_status != 0) || residual || sense_data_length) {
 1678                 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
 1679 
 1680                 if (!fcprsp) {
 1681                         ocs_log_err(ocs, "NULL response buffer\n");
 1682                         return -1;
 1683                 }
 1684 
 1685                 auto_resp = FALSE;
 1686 
 1687                 ocs_memset(fcprsp, 0, sizeof(*fcprsp));
 1688 
 1689                 io->wire_len += (sizeof(*fcprsp) - sizeof(fcprsp->data));
 1690 
 1691                 fcprsp->scsi_status = scsi_status;
 1692                 *((uint16_t*)fcprsp->status_qualifier) = ocs_htobe16(scsi_status_qualifier);
 1693 
 1694                 /* set residual status if necessary */
 1695                 if (residual != 0) {
 1696                         /* FCP: if data transferred is less than the amount expected, then this is an
 1697                          * underflow.  If data transferred would have been greater than the amount expected
 1698                          * then this is an overflow
 1699                          */
 1700                         if (residual > 0) {
 1701                                 fcprsp->flags |= FCP_RESID_UNDER;
 1702                                 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(residual);
 1703                         } else {
 1704                                 fcprsp->flags |= FCP_RESID_OVER;
 1705                                 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(-residual);
 1706                         }
 1707                 }
 1708 
 1709                 if (sense_data && sense_data_length) {
 1710                         ocs_assert(sense_data_length <= sizeof(fcprsp->data), -1);
 1711                         fcprsp->flags |= FCP_SNS_LEN_VALID;
 1712                         ocs_memcpy(fcprsp->data, sense_data, sense_data_length);
 1713                         *((uint32_t*)fcprsp->fcp_sns_len) = ocs_htobe32(sense_data_length);
 1714                         io->wire_len += sense_data_length;
 1715                 }
 1716 
 1717                 io->sgl[0].addr = io->rspbuf.phys;
 1718                 io->sgl[0].dif_addr = 0;
 1719                 io->sgl[0].len = io->wire_len;
 1720                 io->sgl_count = 1;
 1721         }
 1722 
 1723         if (auto_resp) {
 1724                 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
 1725         }
 1726 
 1727         return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
 1728 }
 1729 
 1730 /**
 1731  * @ingroup scsi_api_base
 1732  * @brief Send TMF response data.
 1733  *
 1734  * @par Description
 1735  * This function is used by a target-server to send SCSI TMF response data to a remote
 1736  * initiator node.
 1737  * Upon completion, the callback function @c cb is invoked. The target-server will generally
 1738  * clean up its IO context resources and call ocs_scsi_io_complete().
 1739  *
 1740  * @param io Pointer to the IO context.
 1741  * @param rspcode TMF response code.
 1742  * @param addl_rsp_info Additional TMF response information (may be NULL for zero data).
 1743  * @param cb Completion callback.
 1744  * @param arg Application-specified completion callback argument.
 1745  *
 1746  * @return Returns 0 on success, or a negative error code value on failure.
 1747  */
 1748 int32_t
 1749 ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3],
 1750                 ocs_scsi_io_cb_t cb, void *arg)
 1751 {
 1752         int32_t rc = -1;
 1753         ocs_t *ocs = NULL;
 1754         fcp_rsp_iu_t *fcprsp = NULL;
 1755         fcp_rsp_info_t *rspinfo = NULL;
 1756         uint8_t fcp_rspcode;
 1757 
 1758         ocs_assert(io, -1);
 1759         ocs_assert(io->ocs, -1);
 1760         ocs_assert(io->node, -1);
 1761 
 1762         ocs = io->ocs;
 1763 
 1764         io->wire_len = 0;
 1765         ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
 1766 
 1767         switch(rspcode) {
 1768         case OCS_SCSI_TMF_FUNCTION_COMPLETE:
 1769                 fcp_rspcode = FCP_TMF_COMPLETE;
 1770                 break;
 1771         case OCS_SCSI_TMF_FUNCTION_SUCCEEDED:
 1772         case OCS_SCSI_TMF_FUNCTION_IO_NOT_FOUND:
 1773                 fcp_rspcode = FCP_TMF_SUCCEEDED;
 1774                 break;
 1775         case OCS_SCSI_TMF_FUNCTION_REJECTED:
 1776                 fcp_rspcode = FCP_TMF_REJECTED;
 1777                 break;
 1778         case OCS_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER:
 1779                 fcp_rspcode = FCP_TMF_INCORRECT_LUN;
 1780                 break;
 1781         case OCS_SCSI_TMF_SERVICE_DELIVERY:
 1782                 fcp_rspcode = FCP_TMF_FAILED;
 1783                 break;
 1784         default:
 1785                 fcp_rspcode = FCP_TMF_REJECTED;
 1786                 break;
 1787         }
 1788 
 1789         io->hio_type = OCS_HW_IO_TARGET_RSP;
 1790 
 1791         io->scsi_tgt_cb = cb;
 1792         io->scsi_tgt_cb_arg = arg;
 1793 
 1794         if (io->tmf_cmd == OCS_SCSI_TMF_ABORT_TASK) {
 1795                 rc = ocs_target_send_bls_resp(io, cb, arg);
 1796                 return rc;
 1797         }
 1798 
 1799         /* populate the FCP TMF response */
 1800         fcprsp = io->rspbuf.virt;
 1801         ocs_memset(fcprsp, 0, sizeof(*fcprsp));
 1802 
 1803         fcprsp->flags |= FCP_RSP_LEN_VALID;
 1804 
 1805         rspinfo = (fcp_rsp_info_t*) fcprsp->data;
 1806         if (addl_rsp_info != NULL) {
 1807                 ocs_memcpy(rspinfo->addl_rsp_info, addl_rsp_info, sizeof(rspinfo->addl_rsp_info));
 1808         }
 1809         rspinfo->rsp_code = fcp_rspcode;
 1810 
 1811         io->wire_len = sizeof(*fcprsp) - sizeof(fcprsp->data) + sizeof(*rspinfo);
 1812 
 1813         *((uint32_t*)fcprsp->fcp_rsp_len) = ocs_htobe32(sizeof(*rspinfo));
 1814 
 1815         io->sgl[0].addr = io->rspbuf.phys;
 1816         io->sgl[0].dif_addr = 0;
 1817         io->sgl[0].len = io->wire_len;
 1818         io->sgl_count = 1;
 1819 
 1820         ocs_memset(&io->iparam, 0, sizeof(io->iparam));
 1821         io->iparam.fcp_tgt.ox_id = io->init_task_tag;
 1822         io->iparam.fcp_tgt.offset = 0;
 1823         io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
 1824         io->iparam.fcp_tgt.timeout = io->timeout;
 1825 
 1826         rc = ocs_scsi_io_dispatch(io, ocs_target_io_cb);
 1827 
 1828         return rc;
 1829 }
 1830 
 1831 /**
 1832  * @brief Process target abort callback.
 1833  *
 1834  * @par Description
 1835  * Accepts HW abort requests.
 1836  *
 1837  * @param hio HW IO context.
 1838  * @param rnode Remote node.
 1839  * @param length Length of response data.
 1840  * @param status Completion status.
 1841  * @param ext_status Extended completion status.
 1842  * @param app Application-specified callback data.
 1843  *
 1844  * @return Returns 0 on success, or a negative error code value on failure.
 1845  */
 1846 
 1847 static int32_t
 1848 ocs_target_abort_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
 1849 {
 1850         ocs_io_t *io = app;
 1851         ocs_t *ocs;
 1852         ocs_scsi_io_status_e scsi_status;
 1853 
 1854         ocs_assert(io, -1);
 1855         ocs_assert(io->ocs, -1);
 1856 
 1857         ocs = io->ocs;
 1858 
 1859         if (io->abort_cb) {
 1860                 ocs_scsi_io_cb_t abort_cb = io->abort_cb;
 1861                 void *abort_cb_arg = io->abort_cb_arg;
 1862 
 1863                 io->abort_cb = NULL;
 1864                 io->abort_cb_arg = NULL;
 1865 
 1866                 switch (status) {
 1867                 case SLI4_FC_WCQE_STATUS_SUCCESS:
 1868                         scsi_status = OCS_SCSI_STATUS_GOOD;
 1869                         break;
 1870                 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
 1871                         switch (ext_status) {
 1872                         case SLI4_FC_LOCAL_REJECT_NO_XRI:
 1873                                 scsi_status = OCS_SCSI_STATUS_NO_IO;
 1874                                 break;
 1875                         case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS:
 1876                                 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
 1877                                 break;
 1878                         default:
 1879                                 /* TODO: we have seen 0x15 (abort in progress) */
 1880                                 scsi_status = OCS_SCSI_STATUS_ERROR;
 1881                                 break;
 1882                         }
 1883                         break;
 1884                 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
 1885                         scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
 1886                         break;
 1887                 default:
 1888                         scsi_status = OCS_SCSI_STATUS_ERROR;
 1889                         break;
 1890                 }
 1891                 /* invoke callback */
 1892                 abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg);
 1893         }
 1894 
 1895         ocs_assert(io != io->io_to_abort, -1);
 1896 
 1897         /* done with IO to abort */
 1898         ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_tgt_abort_io() */
 1899 
 1900         ocs_io_free(ocs, io);
 1901 
 1902         ocs_scsi_check_pending(ocs);
 1903         return 0;
 1904 }
 1905 
 1906 /**
 1907  * @ingroup scsi_api_base
 1908  * @brief Abort a target IO.
 1909  *
 1910  * @par Description
 1911  * This routine is called from a SCSI target-server. It initiates an abort of a
 1912  * previously-issued target data phase or response request.
 1913  *
 1914  * @param io IO context.
 1915  * @param cb SCSI target server callback.
 1916  * @param arg SCSI target server supplied callback argument.
 1917  *
 1918  * @return Returns 0 on success, or a non-zero value on failure.
 1919  */
 1920 int32_t
 1921 ocs_scsi_tgt_abort_io(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
 1922 {
 1923         ocs_t *ocs;
 1924         ocs_xport_t *xport;
 1925         int32_t rc;
 1926 
 1927         ocs_io_t *abort_io = NULL;
 1928         ocs_assert(io, -1);
 1929         ocs_assert(io->node, -1);
 1930         ocs_assert(io->ocs, -1);
 1931 
 1932         ocs = io->ocs;
 1933         xport = ocs->xport;
 1934 
 1935         /* take a reference on IO being aborted */
 1936         if ((ocs_ref_get_unless_zero(&io->ref) == 0)) {
 1937                 /* command no longer active */
 1938                 scsi_io_printf(io, "command no longer active\n");
 1939                 return -1;
 1940         }
 1941 
 1942         /*
 1943          * allocate a new IO to send the abort request. Use ocs_io_alloc() directly, as
 1944          * we need an IO object that will not fail allocation due to allocations being
 1945          * disabled (in ocs_scsi_io_alloc())
 1946          */
 1947         abort_io = ocs_io_alloc(ocs);
 1948         if (abort_io == NULL) {
 1949                 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
 1950                 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
 1951                 return -1;
 1952         }
 1953 
 1954         /* Save the target server callback and argument */
 1955         ocs_assert(abort_io->hio == NULL, -1);
 1956 
 1957         /* set generic fields */
 1958         abort_io->cmd_tgt = TRUE;
 1959         abort_io->node = io->node;
 1960 
 1961         /* set type and abort-specific fields */
 1962         abort_io->io_type = OCS_IO_TYPE_ABORT;
 1963         abort_io->display_name = "tgt_abort";
 1964         abort_io->io_to_abort = io;
 1965         abort_io->send_abts = FALSE;
 1966         abort_io->abort_cb = cb;
 1967         abort_io->abort_cb_arg = arg;
 1968 
 1969         /* now dispatch IO */
 1970         rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_target_abort_cb);
 1971         if (rc) {
 1972                 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
 1973         }
 1974         return rc;
 1975 }
 1976 
 1977 /**
 1978  * @brief Process target BLS response callback.
 1979  *
 1980  * @par Description
 1981  * Accepts HW abort requests.
 1982  *
 1983  * @param hio HW IO context.
 1984  * @param rnode Remote node.
 1985  * @param length Length of response data.
 1986  * @param status Completion status.
 1987  * @param ext_status Extended completion status.
 1988  * @param app Application-specified callback data.
 1989  *
 1990  * @return Returns 0 on success, or a negative error code value on failure.
 1991  */
 1992 
 1993 static int32_t
 1994 ocs_target_bls_resp_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
 1995 {
 1996         ocs_io_t *io = app;
 1997         ocs_t *ocs;
 1998         ocs_scsi_io_status_e bls_status;
 1999 
 2000         ocs_assert(io, -1);
 2001         ocs_assert(io->ocs, -1);
 2002 
 2003         ocs = io->ocs;
 2004 
 2005         /* BLS isn't really a "SCSI" concept, but use SCSI status */
 2006         if (status) {
 2007                 io_error_log(io, "s=%#x x=%#x\n", status, ext_status);
 2008                 bls_status = OCS_SCSI_STATUS_ERROR;
 2009         } else {
 2010                 bls_status = OCS_SCSI_STATUS_GOOD;
 2011         }
 2012 
 2013         if (io->bls_cb) {
 2014                 ocs_scsi_io_cb_t bls_cb = io->bls_cb;
 2015                 void *bls_cb_arg = io->bls_cb_arg;
 2016 
 2017                 io->bls_cb = NULL;
 2018                 io->bls_cb_arg = NULL;
 2019 
 2020                 /* invoke callback */
 2021                 bls_cb(io, bls_status, 0, bls_cb_arg);
 2022         }
 2023 
 2024         ocs_scsi_check_pending(ocs);
 2025         return 0;
 2026 }
 2027 
 2028 /**
 2029  * @brief Complete abort request.
 2030  *
 2031  * @par Description
 2032  * An abort request is completed by posting a BA_ACC for the IO that requested the abort.
 2033  *
 2034  * @param io Pointer to the IO context.
 2035  * @param cb Callback function to invoke upon completion.
 2036  * @param arg Application-specified completion callback argument.
 2037  *
 2038  * @return Returns 0 on success, or a negative error code value on failure.
 2039  */
 2040 
 2041 static int32_t
 2042 ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
 2043 {
 2044         int32_t rc;
 2045         fc_ba_acc_payload_t *acc;
 2046 
 2047         ocs_assert(io, -1);
 2048 
 2049         /* fill out IO structure with everything needed to send BA_ACC */
 2050         ocs_memset(&io->iparam, 0, sizeof(io->iparam));
 2051         io->iparam.bls.ox_id = io->init_task_tag;
 2052         io->iparam.bls.rx_id = io->abort_rx_id;
 2053 
 2054         acc = (void *)io->iparam.bls.payload;
 2055 
 2056         ocs_memset(io->iparam.bls.payload, 0, sizeof(io->iparam.bls.payload));
 2057         acc->ox_id = io->iparam.bls.ox_id;
 2058         acc->rx_id = io->iparam.bls.rx_id;
 2059         acc->high_seq_cnt = UINT16_MAX;
 2060 
 2061         /* generic io fields have already been populated */
 2062 
 2063         /* set type and BLS-specific fields */
 2064         io->io_type = OCS_IO_TYPE_BLS_RESP;
 2065         io->display_name = "bls_rsp";
 2066         io->hio_type = OCS_HW_BLS_ACC;
 2067         io->bls_cb = cb;
 2068         io->bls_cb_arg = arg;
 2069 
 2070         /* dispatch IO */
 2071         rc = ocs_scsi_io_dispatch(io, ocs_target_bls_resp_cb);
 2072         return rc;
 2073 }
 2074 
 2075 /**
 2076  * @ingroup scsi_api_base
 2077  * @brief Notify the base driver that the IO is complete.
 2078  *
 2079  * @par Description
 2080  * This function is called by a target-server to notify the base driver that an IO
 2081  * has completed, allowing for the base driver to free resources.
 2082  * @n
 2083  * @n @b Note: This function is not called by initiator-clients.
 2084  *
 2085  * @param io Pointer to IO context.
 2086  *
 2087  * @return None.
 2088  */
 2089 void
 2090 ocs_scsi_io_complete(ocs_io_t *io)
 2091 {
 2092         ocs_assert(io);
 2093 
 2094         if (!ocs_io_busy(io)) {
 2095                 ocs_log_test(io->ocs, "Got completion for non-busy io with tag 0x%x\n", io->tag);
 2096                 return;
 2097         }
 2098 
 2099         scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
 2100         ocs_assert(ocs_ref_read_count(&io->ref) > 0);
 2101         ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
 2102 }
 2103 
 2104 /**
 2105  * @brief Handle initiator IO completion.
 2106  *
 2107  * @par Description
 2108  * This callback is made upon completion of an initiator operation (initiator read/write command).
 2109  *
 2110  * @param hio HW IO context.
 2111  * @param rnode Remote node.
 2112  * @param length Length of completion data.
 2113  * @param status Completion status.
 2114  * @param ext_status Extended completion status.
 2115  * @param app Application-specified callback data.
 2116  *
 2117  * @return None.
 2118  */
 2119 
 2120 static void
 2121 ocs_initiator_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
 2122         int32_t status, uint32_t ext_status, void *app)
 2123 {
 2124         ocs_io_t *io = app;
 2125         ocs_t *ocs;
 2126         ocs_scsi_io_status_e scsi_status;
 2127 
 2128         ocs_assert(io);
 2129         ocs_assert(io->scsi_ini_cb);
 2130 
 2131         scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
 2132 
 2133         ocs = io->ocs;
 2134         ocs_assert(ocs);
 2135 
 2136         ocs_scsi_io_free_ovfl(io);
 2137 
 2138         /* Call target server completion */
 2139         if (io->scsi_ini_cb) {
 2140                 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
 2141                 ocs_scsi_cmd_resp_t rsp;
 2142                 ocs_scsi_rsp_io_cb_t cb = io->scsi_ini_cb;
 2143                 uint32_t flags = 0;
 2144                 uint8_t *pd = fcprsp->data;
 2145 
 2146                 /* Clear the callback before invoking the callback */
 2147                 io->scsi_ini_cb = NULL;
 2148 
 2149                 ocs_memset(&rsp, 0, sizeof(rsp));
 2150 
 2151                 /* Unless status is FCP_RSP_FAILURE, fcprsp is not filled in */
 2152                 switch (status) {
 2153                 case SLI4_FC_WCQE_STATUS_SUCCESS:
 2154                         scsi_status = OCS_SCSI_STATUS_GOOD;
 2155                         break;
 2156                 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
 2157                         scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
 2158                         rsp.scsi_status = fcprsp->scsi_status;
 2159                         rsp.scsi_status_qualifier = ocs_be16toh(*((uint16_t*)fcprsp->status_qualifier));
 2160 
 2161                         if (fcprsp->flags & FCP_RSP_LEN_VALID) {
 2162                                 rsp.response_data = pd;
 2163                                 rsp.response_data_length = ocs_fc_getbe32(fcprsp->fcp_rsp_len);
 2164                                 pd += rsp.response_data_length;
 2165                         }
 2166                         if (fcprsp->flags & FCP_SNS_LEN_VALID) {
 2167                                 uint32_t sns_len = ocs_fc_getbe32(fcprsp->fcp_sns_len);
 2168                                 rsp.sense_data = pd;
 2169                                 rsp.sense_data_length = sns_len;
 2170                                 pd += sns_len;
 2171                         }
 2172                         /* Set residual */
 2173                         if (fcprsp->flags & FCP_RESID_OVER) {
 2174                                 rsp.residual = -ocs_fc_getbe32(fcprsp->fcp_resid);
 2175                                 rsp.response_wire_length = length;
 2176                         } else  if (fcprsp->flags & FCP_RESID_UNDER) {
 2177                                 rsp.residual = ocs_fc_getbe32(fcprsp->fcp_resid);
 2178                                 rsp.response_wire_length = length;
 2179                         }
 2180 
 2181                         /*
 2182                          * Note: The FCP_RSP_FAILURE can be returned for initiator IOs when the total data
 2183                          * placed does not match the requested length even if the status is good. If
 2184                          * the status is all zeroes, then we have to assume that a frame(s) were
 2185                          * dropped and change the status to LOCAL_REJECT/OUT_OF_ORDER_DATA
 2186                          */
 2187                         if (length != io->wire_len) {
 2188                                 uint32_t rsp_len = ext_status;
 2189                                 uint8_t *rsp_bytes = io->rspbuf.virt;
 2190                                 uint32_t i;
 2191                                 uint8_t all_zeroes = (rsp_len > 0);
 2192                                 /* Check if the rsp is zero */
 2193                                 for (i = 0; i < rsp_len; i++) {
 2194                                         if (rsp_bytes[i] != 0) {
 2195                                                 all_zeroes = FALSE;
 2196                                                 break;
 2197                                         }
 2198                                 }
 2199                                 if (all_zeroes) {
 2200                                         scsi_status = OCS_SCSI_STATUS_ERROR;
 2201                                         ocs_log_test(io->ocs, "[%s]" SCSI_IOFMT "local reject=0x%02x\n",
 2202                                                      io->node->display_name, SCSI_IOFMT_ARGS(io),
 2203                                                      SLI4_FC_LOCAL_REJECT_OUT_OF_ORDER_DATA);
 2204                                 }
 2205                         }
 2206                         break;
 2207                 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
 2208                         if (ext_status == SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT) {
 2209                                 scsi_status = OCS_SCSI_STATUS_COMMAND_TIMEOUT;
 2210                         } else {
 2211                                 scsi_status = OCS_SCSI_STATUS_ERROR;
 2212                         }
 2213                         break;
 2214                 case SLI4_FC_WCQE_STATUS_DI_ERROR:
 2215                         if (ext_status & 0x01) {
 2216                                 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
 2217                         } else if (ext_status & 0x02) {
 2218                                 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
 2219                         } else if (ext_status & 0x04) {
 2220                                 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
 2221                         } else {
 2222                                 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
 2223                         }
 2224                         break;
 2225                 default:
 2226                         scsi_status = OCS_SCSI_STATUS_ERROR;
 2227                         break;
 2228                 }
 2229 
 2230                 cb(io, scsi_status, &rsp, flags, io->scsi_ini_cb_arg);
 2231         }
 2232         ocs_scsi_check_pending(ocs);
 2233 }
 2234 
 2235 /**
 2236  * @ingroup scsi_api_base
 2237  * @brief Initiate initiator read IO.
 2238  *
 2239  * @par Description
 2240  * This call is made by an initiator-client to send a SCSI read command. The payload
 2241  * for the command is given by a scatter-gather list @c sgl for @c sgl_count
 2242  * entries.
 2243  * @n @n
 2244  * Upon completion, the callback @b cb is invoked and passed request status.
 2245  * If the command completed successfully, the callback is given SCSI response data.
 2246  *
 2247  * @param node Pointer to the node.
 2248  * @param io Pointer to the IO context.
 2249  * @param lun LUN value.
 2250  * @param cdb Pointer to the CDB.
 2251  * @param cdb_len Length of the CDB.
 2252  * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
 2253  * @param sgl Pointer to the scatter-gather list.
 2254  * @param sgl_count Count of the scatter-gather list elements.
 2255  * @param wire_len Length of the payload.
 2256  * @param cb Completion callback.
 2257  * @param arg Application-specified completion callback argument.
 2258  *
 2259  * @return Returns 0 on success, or a negative error code value on failure.
 2260  */
 2261 int32_t
 2262 ocs_scsi_send_rd_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
 2263         ocs_scsi_dif_info_t *dif_info,
 2264         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
 2265         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags)
 2266 {
 2267         int32_t rc;
 2268 
 2269         rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
 2270                               wire_len, 0, cb, arg, flags);
 2271 
 2272         return rc;
 2273 }
 2274 
 2275 /**
 2276  * @ingroup scsi_api_base
 2277  * @brief Initiate initiator write IO.
 2278  *
 2279  * @par Description
 2280  * This call is made by an initiator-client to send a SCSI write command. The payload
 2281  * for the command is given by a scatter-gather list @c sgl for @c sgl_count
 2282  * entries.
 2283  * @n @n
 2284  * Upon completion, the callback @c cb is invoked and passed request status. If the command
 2285  * completed successfully, the callback is given SCSI response data.
 2286  *
 2287  * @param node Pointer to the node.
 2288  * @param io Pointer to IO context.
 2289  * @param lun LUN value.
 2290  * @param cdb Pointer to the CDB.
 2291  * @param cdb_len Length of the CDB.
 2292  * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
 2293  * @param sgl Pointer to the scatter-gather list.
 2294  * @param sgl_count Count of the scatter-gather list elements.
 2295  * @param wire_len Length of the payload.
 2296  * @param cb Completion callback.
 2297  * @param arg Application-specified completion callback argument.
 2298  *
 2299  * @return Returns 0 on success, or a negative error code value on failure.
 2300  */
 2301 int32_t ocs_scsi_send_wr_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
 2302         ocs_scsi_dif_info_t *dif_info,
 2303         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
 2304         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags)
 2305 {
 2306         int32_t rc;
 2307 
 2308         rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
 2309                               wire_len, 0, cb, arg, flags);
 2310 
 2311         return rc;
 2312 }
 2313 
 2314 /**
 2315  * @ingroup scsi_api_base
 2316  * @brief Initiate initiator write IO.
 2317  *
 2318  * @par Description
 2319  * This call is made by an initiator-client to send a SCSI write command. The payload
 2320  * for the command is given by a scatter-gather list @c sgl for @c sgl_count
 2321  * entries.
 2322  * @n @n
 2323  * Upon completion, the callback @c cb is invoked and passed request status. If the command
 2324  * completed successfully, the callback is given SCSI response data.
 2325  *
 2326  * @param node Pointer to the node.
 2327  * @param io Pointer to IO context.
 2328  * @param lun LUN value.
 2329  * @param cdb Pointer to the CDB.
 2330  * @param cdb_len Length of the CDB.
 2331  * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
 2332  * @param sgl Pointer to the scatter-gather list.
 2333  * @param sgl_count Count of the scatter-gather list elements.
 2334  * @param wire_len Length of the payload.
 2335  * @param first_burst Number of first burst bytes to send.
 2336  * @param cb Completion callback.
 2337  * @param arg Application-specified completion callback argument.
 2338  *
 2339  * @return Returns 0 on success, or a negative error code value on failure.
 2340  */
 2341 int32_t
 2342 ocs_scsi_send_wr_io_first_burst(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
 2343         ocs_scsi_dif_info_t *dif_info,
 2344         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
 2345         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags)
 2346 {
 2347         int32_t rc;
 2348 
 2349         rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
 2350                               wire_len, 0, cb, arg, flags);
 2351 
 2352         return rc;
 2353 }
 2354 
 2355 /**
 2356  * @ingroup scsi_api_base
 2357  * @brief Initiate initiator SCSI command with no data.
 2358  *
 2359  * @par Description
 2360  * This call is made by an initiator-client to send a SCSI command with no data.
 2361  * @n @n
 2362  * Upon completion, the callback @c cb is invoked and passed request status. If the command
 2363  * completed successfully, the callback is given SCSI response data.
 2364  *
 2365  * @param node Pointer to the node.
 2366  * @param io Pointer to the IO context.
 2367  * @param lun LUN value.
 2368  * @param cdb Pointer to the CDB.
 2369  * @param cdb_len Length of the CDB.
 2370  * @param cb Completion callback.
 2371  * @param arg Application-specified completion callback argument.
 2372  *
 2373  * @return Returns 0 on success, or a negative error code value on failure.
 2374  */
 2375 int32_t ocs_scsi_send_nodata_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
 2376         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags)
 2377 {
 2378         int32_t rc;
 2379 
 2380         rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_NODATA, node, io, lun, 0, cdb, cdb_len, NULL, NULL, 0, 0, 0, cb, arg, flags);
 2381 
 2382         return rc;
 2383 }
 2384 /**
 2385  * @ingroup scsi_api_base
 2386  * @brief Initiate initiator task management operation.
 2387  *
 2388  * @par Description
 2389  * This command is used to send a SCSI task management function command. If the command
 2390  * requires it (QUERY_TASK_SET for example), a payload may be associated with the command.
 2391  * If no payload is required, then @c sgl_count may be zero and @c sgl is ignored.
 2392  * @n @n
 2393  * Upon completion @c cb is invoked with status and SCSI response data.
 2394  *
 2395  * @param node Pointer to the node.
 2396  * @param io Pointer to the IO context.
 2397  * @param io_to_abort Pointer to the IO context to abort in the
 2398  * case of OCS_SCSI_TMF_ABORT_TASK. Note: this can point to the
 2399  * same the same ocs_io_t as @c io, provided that @c io does not
 2400  * have any outstanding work requests.
 2401  * @param lun LUN value.
 2402  * @param tmf Task management command.
 2403  * @param sgl Pointer to the scatter-gather list.
 2404  * @param sgl_count Count of the scatter-gather list elements.
 2405  * @param len Length of the payload.
 2406  * @param cb Completion callback.
 2407  * @param arg Application-specified completion callback argument.
 2408  *
 2409  * @return Returns 0 on success, or a negative error code value on failure.
 2410  */
 2411 int32_t
 2412 ocs_scsi_send_tmf(ocs_node_t *node, ocs_io_t *io, ocs_io_t *io_to_abort, uint64_t lun, ocs_scsi_tmf_cmd_e tmf,
 2413         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg)
 2414 {
 2415         int32_t rc;
 2416         ocs_assert(io, -1);
 2417 
 2418         if (tmf == OCS_SCSI_TMF_ABORT_TASK) {
 2419                 ocs_assert(io_to_abort, -1);
 2420 
 2421                 /* take a reference on IO being aborted */
 2422                 if ((ocs_ref_get_unless_zero(&io_to_abort->ref) == 0)) {
 2423                         /* command no longer active */
 2424                         scsi_io_printf(io, "command no longer active\n");
 2425                         return -1;
 2426                 }
 2427                 /* generic io fields have already been populated */
 2428 
 2429                 /* abort-specific fields */
 2430                 io->io_type = OCS_IO_TYPE_ABORT;
 2431                 io->display_name = "abort_task";
 2432                 io->io_to_abort = io_to_abort;
 2433                 io->send_abts = TRUE;
 2434                 io->scsi_ini_cb = cb;
 2435                 io->scsi_ini_cb_arg = arg;
 2436 
 2437                 /* now dispatch IO */
 2438                 rc = ocs_scsi_io_dispatch_abort(io, ocs_scsi_abort_io_cb);
 2439                 if (rc) {
 2440                         scsi_io_printf(io, "Failed to dispatch abort\n");
 2441                         ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
 2442                 }
 2443         } else {
 2444                 io->display_name = "tmf";
 2445                 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, tmf, NULL, 0, NULL,
 2446                                       sgl, sgl_count, len, 0, cb, arg, 0);
 2447         }
 2448 
 2449         return rc;
 2450 }
 2451 
 2452 /**
 2453  * @ingroup scsi_api_base
 2454  * @brief Send an FCP IO.
 2455  *
 2456  * @par Description
 2457  * An FCP read/write IO command, with optional task management flags, is sent to @c node.
 2458  *
 2459  * @param type HW IO type to send.
 2460  * @param node Pointer to the node destination of the IO.
 2461  * @param io Pointer to the IO context.
 2462  * @param lun LUN value.
 2463  * @param tmf Task management command.
 2464  * @param cdb Pointer to the SCSI CDB.
 2465  * @param cdb_len Length of the CDB, in bytes.
 2466  * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
 2467  * @param sgl Pointer to the scatter-gather list.
 2468  * @param sgl_count Number of SGL entries in SGL.
 2469  * @param wire_len Payload length, in bytes, of data on wire.
 2470  * @param first_burst Number of first burst bytes to send.
 2471  * @param cb Completion callback.
 2472  * @param arg Application-specified completion callback argument.
 2473  *
 2474  * @return Returns 0 on success, or a negative error code value on failure.
 2475  */
 2476 
 2477 /* tc: could elminiate LUN, as it's part of the IO structure */
 2478 
 2479 static int32_t ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
 2480         ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
 2481         ocs_scsi_dif_info_t *dif_info,
 2482         ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
 2483         ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags)
 2484 {
 2485         int32_t rc;
 2486         ocs_t *ocs;
 2487         fcp_cmnd_iu_t *cmnd;
 2488         uint32_t cmnd_bytes = 0;
 2489         uint32_t *fcp_dl;
 2490         uint8_t tmf_flags = 0;
 2491 
 2492         ocs_assert(io->node, -1);
 2493         ocs_assert(io->node == node, -1);
 2494         ocs_assert(io, -1);
 2495         ocs = io->ocs;
 2496         ocs_assert(cb, -1);
 2497 
 2498         io->sgl_count = sgl_count;
 2499 
 2500         /* Copy SGL if needed */
 2501         if (sgl != io->sgl) {
 2502                 ocs_assert(sgl_count <= io->sgl_allocated, -1);
 2503                 ocs_memcpy(io->sgl, sgl, sizeof(*io->sgl) * sgl_count);
 2504         }
 2505 
 2506         /* save initiator and target task tags for debugging */
 2507         io->tgt_task_tag = 0xffff;
 2508 
 2509         io->wire_len = wire_len;
 2510         io->hio_type = type;
 2511 
 2512         if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
 2513                 char buf[80];
 2514                 ocs_textbuf_t txtbuf;
 2515                 uint32_t i;
 2516 
 2517                 ocs_textbuf_init(ocs, &txtbuf, buf, sizeof(buf));
 2518 
 2519                 ocs_textbuf_printf(&txtbuf, "cdb%d: ", cdb_len);
 2520                 for (i = 0; i < cdb_len; i ++) {
 2521                         ocs_textbuf_printf(&txtbuf, "%02X%s", cdb[i], (i == (cdb_len-1)) ? "" : " ");
 2522                 }
 2523                 scsi_io_printf(io, "%s len %d, %s\n", (io->hio_type == OCS_HW_IO_INITIATOR_READ) ? "read" :
 2524                         (io->hio_type == OCS_HW_IO_INITIATOR_WRITE) ? "write" : "",  io->wire_len,
 2525                         ocs_textbuf_get_buffer(&txtbuf));
 2526         }
 2527 
 2528         ocs_assert(io->cmdbuf.virt, -1);
 2529 
 2530         cmnd = io->cmdbuf.virt;
 2531 
 2532         ocs_assert(sizeof(*cmnd) <= io->cmdbuf.size, -1);
 2533 
 2534         ocs_memset(cmnd, 0, sizeof(*cmnd));
 2535 
 2536         /* Default FCP_CMND IU doesn't include additional CDB bytes but does include FCP_DL */
 2537         cmnd_bytes = sizeof(fcp_cmnd_iu_t) - sizeof(cmnd->fcp_cdb_and_dl) + sizeof(uint32_t);
 2538 
 2539         fcp_dl = (uint32_t*)(&(cmnd->fcp_cdb_and_dl));
 2540 
 2541         if (cdb) {
 2542                 if (cdb_len <= 16) {
 2543                         ocs_memcpy(cmnd->fcp_cdb, cdb, cdb_len);
 2544                 } else {
 2545                         uint32_t addl_cdb_bytes;
 2546 
 2547                         ocs_memcpy(cmnd->fcp_cdb, cdb, 16);
 2548                         addl_cdb_bytes = cdb_len - 16;
 2549                         ocs_memcpy(cmnd->fcp_cdb_and_dl, &(cdb[16]), addl_cdb_bytes);
 2550                         /* additional_fcp_cdb_length is in words, not bytes */
 2551                         cmnd->additional_fcp_cdb_length = (addl_cdb_bytes + 3) / 4;
 2552                         fcp_dl += cmnd->additional_fcp_cdb_length;
 2553 
 2554                         /* Round up additional CDB bytes */
 2555                         cmnd_bytes += (addl_cdb_bytes + 3) & ~0x3;
 2556                 }
 2557         }
 2558 
 2559         be64enc(cmnd->fcp_lun, CAM_EXTLUN_BYTE_SWIZZLE(lun));
 2560 
 2561         if (node->fcp2device) {
 2562                 if(ocs_get_crn(node, &cmnd->command_reference_number,
 2563                                         lun)) {
 2564                         return -1;
 2565                 }
 2566         }
 2567         if (flags & OCS_SCSI_CMD_HEAD_OF_QUEUE)
 2568                 cmnd->task_attribute = FCP_TASK_ATTR_HEAD_OF_QUEUE;
 2569         else if (flags & OCS_SCSI_CMD_ORDERED)
 2570                 cmnd->task_attribute = FCP_TASK_ATTR_ORDERED;
 2571         else if (flags & OCS_SCSI_CMD_UNTAGGED)
 2572                 cmnd->task_attribute = FCP_TASK_ATTR_UNTAGGED;
 2573         else if (flags & OCS_SCSI_CMD_ACA)
 2574                 cmnd->task_attribute = FCP_TASK_ATTR_ACA;
 2575         else
 2576                 cmnd->task_attribute = FCP_TASK_ATTR_SIMPLE;
 2577         cmnd->command_priority = (flags & OCS_SCSI_PRIORITY_MASK) >>
 2578             OCS_SCSI_PRIORITY_SHIFT;
 2579 
 2580         switch (tmf) {
 2581         case OCS_SCSI_TMF_QUERY_TASK_SET:
 2582                 tmf_flags = FCP_QUERY_TASK_SET;
 2583                 break;
 2584         case OCS_SCSI_TMF_ABORT_TASK_SET:
 2585                 tmf_flags = FCP_ABORT_TASK_SET;
 2586                 break;
 2587         case OCS_SCSI_TMF_CLEAR_TASK_SET:
 2588                 tmf_flags = FCP_CLEAR_TASK_SET;
 2589                 break;
 2590         case OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
 2591                 tmf_flags = FCP_QUERY_ASYNCHRONOUS_EVENT;
 2592                 break;
 2593         case OCS_SCSI_TMF_LOGICAL_UNIT_RESET:
 2594                 tmf_flags = FCP_LOGICAL_UNIT_RESET;
 2595                 break;
 2596         case OCS_SCSI_TMF_CLEAR_ACA:
 2597                 tmf_flags = FCP_CLEAR_ACA;
 2598                 break;
 2599         case OCS_SCSI_TMF_TARGET_RESET:
 2600                 tmf_flags = FCP_TARGET_RESET;
 2601                 break;
 2602         default:
 2603                 tmf_flags = 0;
 2604         }
 2605         cmnd->task_management_flags = tmf_flags;
 2606 
 2607         *fcp_dl = ocs_htobe32(io->wire_len);
 2608 
 2609         switch (io->hio_type) {
 2610         case OCS_HW_IO_INITIATOR_READ:
 2611                 cmnd->rddata = 1;
 2612                 break;
 2613         case OCS_HW_IO_INITIATOR_WRITE:
 2614                 cmnd->wrdata = 1;
 2615                 break;
 2616         case  OCS_HW_IO_INITIATOR_NODATA:
 2617                 /* sets neither */
 2618                 break;
 2619         default:
 2620                 ocs_log_test(ocs, "bad IO type %d\n", io->hio_type);
 2621                 return -1;
 2622         }
 2623 
 2624         rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
 2625         if (rc) {
 2626                 return rc;
 2627         }
 2628 
 2629         io->scsi_ini_cb = cb;
 2630         io->scsi_ini_cb_arg = arg;
 2631 
 2632         /* set command and response buffers in the iparam */
 2633         io->iparam.fcp_ini.cmnd = &io->cmdbuf;
 2634         io->iparam.fcp_ini.cmnd_size = cmnd_bytes;
 2635         io->iparam.fcp_ini.rsp = &io->rspbuf;
 2636         io->iparam.fcp_ini.flags = 0;
 2637         io->iparam.fcp_ini.dif_oper = io->hw_dif.dif;
 2638         io->iparam.fcp_ini.blk_size = io->hw_dif.blk_size;
 2639         io->iparam.fcp_ini.timeout = io->timeout;
 2640         io->iparam.fcp_ini.first_burst = first_burst;
 2641 
 2642         return ocs_scsi_io_dispatch(io, ocs_initiator_io_cb);
 2643 }
 2644 
 2645 /**
 2646  * @ingroup scsi_api_base
 2647  * @brief Callback for an aborted IO.
 2648  *
 2649  * @par Description
 2650  * Callback function invoked upon completion of an IO abort request.
 2651  *
 2652  * @param hio HW IO context.
 2653  * @param rnode Remote node.
 2654  * @param len Response length.
 2655  * @param status Completion status.
 2656  * @param ext_status Extended completion status.
 2657  * @param arg Application-specific callback, usually IO context.
 2658 
 2659  * @return Returns 0 on success, or a negative error code value on failure.
 2660  */
 2661 
 2662 static int32_t
 2663 ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
 2664         uint32_t ext_status, void *arg)
 2665 {
 2666         ocs_io_t *io = arg;
 2667         ocs_t *ocs;
 2668         ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
 2669 
 2670         ocs_assert(io, -1);
 2671         ocs_assert(ocs_io_busy(io), -1);
 2672         ocs_assert(io->ocs, -1);
 2673         ocs_assert(io->io_to_abort, -1);
 2674         ocs = io->ocs;
 2675 
 2676         ocs_log_debug(ocs, "status %d ext %d\n", status, ext_status);
 2677 
 2678         /* done with IO to abort */
 2679         ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_send_tmf() */
 2680 
 2681         ocs_scsi_io_free_ovfl(io);
 2682 
 2683         switch (status) {
 2684         case SLI4_FC_WCQE_STATUS_SUCCESS:
 2685                 scsi_status = OCS_SCSI_STATUS_GOOD;
 2686                 break;
 2687         case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
 2688                 if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED) {
 2689                         scsi_status = OCS_SCSI_STATUS_ABORTED;
 2690                 } else if (ext_status == SLI4_FC_LOCAL_REJECT_NO_XRI) {
 2691                         scsi_status = OCS_SCSI_STATUS_NO_IO;
 2692                 } else if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS) {
 2693                         scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
 2694                 } else {
 2695                         ocs_log_test(ocs, "Unhandled local reject 0x%x/0x%x\n", status, ext_status);
 2696                         scsi_status = OCS_SCSI_STATUS_ERROR;
 2697                 }
 2698                 break;
 2699         default:
 2700                 scsi_status = OCS_SCSI_STATUS_ERROR;
 2701                 break;
 2702         }
 2703 
 2704         if (io->scsi_ini_cb) {
 2705                 (*io->scsi_ini_cb)(io, scsi_status, NULL, 0, io->scsi_ini_cb_arg);
 2706         } else {
 2707                 ocs_scsi_io_free(io);
 2708         }
 2709 
 2710         ocs_scsi_check_pending(ocs);
 2711         return 0;
 2712 }
 2713 
 2714 /**
 2715  * @ingroup scsi_api_base
 2716  * @brief Return SCSI API integer valued property.
 2717  *
 2718  * @par Description
 2719  * This function is called by a target-server or initiator-client to
 2720  * retrieve an integer valued property.
 2721  *
 2722  * @param ocs Pointer to the ocs.
 2723  * @param prop Property value to return.
 2724  *
 2725  * @return Returns a value, or 0 if invalid property was requested.
 2726  */
 2727 uint32_t
 2728 ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop)
 2729 {
 2730         ocs_xport_t *xport = ocs->xport;
 2731         uint32_t        val;
 2732 
 2733         switch (prop) {
 2734         case OCS_SCSI_MAX_SGE:
 2735                 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &val)) {
 2736                         return val;
 2737                 }
 2738                 break;
 2739         case OCS_SCSI_MAX_SGL:
 2740                 if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
 2741                         /*
 2742                          * If chain SGL test-mode is enabled, the number of HW SGEs
 2743                          * has been limited; report back original max.
 2744                          */
 2745                         return (OCS_FC_MAX_SGL);
 2746                 }
 2747                 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &val)) {
 2748                         return val;
 2749                 }
 2750                 break;
 2751         case OCS_SCSI_MAX_IOS:
 2752                 return ocs_io_pool_allocated(xport->io_pool);
 2753         case OCS_SCSI_DIF_CAPABLE:
 2754                 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &val)) {
 2755                         return val;
 2756                 }
 2757                 break;
 2758         case OCS_SCSI_MAX_FIRST_BURST:
 2759                 return 0;
 2760         case OCS_SCSI_DIF_MULTI_SEPARATE:
 2761                 if (ocs_hw_get(&ocs->hw, OCS_HW_DIF_MULTI_SEPARATE, &val) == 0) {
 2762                         return val;
 2763                 }
 2764                 break;
 2765         case OCS_SCSI_ENABLE_TASK_SET_FULL:
 2766                 /* Return FALSE if we are send frame capable */
 2767                 if (ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &val) == 0) {
 2768                         return ! val;
 2769                 }
 2770                 break;
 2771         default:
 2772                 break;
 2773         }
 2774 
 2775         ocs_log_debug(ocs, "invalid property request %d\n", prop);
 2776         return 0;
 2777 }
 2778 
 2779 /**
 2780  * @ingroup scsi_api_base
 2781  * @brief Return a property pointer.
 2782  *
 2783  * @par Description
 2784  * This function is called by a target-server or initiator-client to
 2785  * retrieve a pointer to the requested property.
 2786  *
 2787  * @param ocs Pointer to the ocs.
 2788  * @param prop Property value to return.
 2789  *
 2790  * @return Returns pointer to the requested property, or NULL otherwise.
 2791  */
 2792 void *ocs_scsi_get_property_ptr(ocs_t *ocs, ocs_scsi_property_e prop)
 2793 {
 2794         void *rc = NULL;
 2795 
 2796         switch (prop) {
 2797         case OCS_SCSI_WWNN:
 2798                 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
 2799                 break;
 2800         case OCS_SCSI_WWPN:
 2801                 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
 2802                 break;
 2803         case OCS_SCSI_PORTNUM:
 2804                 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_PORTNUM);
 2805                 break;
 2806         case OCS_SCSI_BIOS_VERSION_STRING:
 2807                 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_BIOS_VERSION_STRING);
 2808                 break;
 2809         case OCS_SCSI_SERIALNUMBER:
 2810         {
 2811                 uint8_t *pvpd;
 2812                 uint32_t vpd_len;
 2813 
 2814                 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
 2815                         ocs_log_test(ocs, "Can't get VPD length\n");
 2816                         rc = "\012sn-unknown";
 2817                         break;
 2818                 }
 2819 
 2820                 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
 2821                 if (pvpd) {
 2822                         rc = ocs_find_vpd(pvpd, vpd_len, "SN");
 2823                 }
 2824 
 2825                 if (rc == NULL ||
 2826                     ocs_strlen(rc) == 0) {
 2827                         /* Note: VPD is missing, using wwnn for serial number */
 2828                         scsi_log(ocs, "Note: VPD is missing, using wwnn for serial number\n");
 2829                         /* Use the last 32 bits of the WWN */
 2830                         if ((ocs == NULL) || (ocs->domain == NULL) || (ocs->domain->sport == NULL)) {
 2831                                 rc = "\011(Unknown)";
 2832                         } else {
 2833                                 rc = &ocs->domain->sport->wwnn_str[8];
 2834                         }
 2835                 }
 2836                 break;
 2837         }
 2838         case OCS_SCSI_PARTNUMBER:
 2839         {
 2840                 uint8_t *pvpd;
 2841                 uint32_t vpd_len;
 2842 
 2843                 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
 2844                         ocs_log_test(ocs, "Can't get VPD length\n");
 2845                         rc = "\012pn-unknown";
 2846                         break;
 2847                 }
 2848                 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
 2849                 if (pvpd) {
 2850                         rc = ocs_find_vpd(pvpd, vpd_len, "PN");
 2851                         if (rc == NULL) {
 2852                                 rc = "\012pn-unknown";
 2853                         }
 2854                 } else {
 2855                         rc = "\012pn-unknown";
 2856                 }
 2857                 break;
 2858         }
 2859         default:
 2860                 break;
 2861         }
 2862 
 2863         if (rc == NULL) {
 2864                 ocs_log_debug(ocs, "invalid property request %d\n", prop);
 2865         }
 2866         return rc;
 2867 }
 2868 
 2869 /**
 2870  * @ingroup scsi_api_base
 2871  * @brief Notify that delete initiator is complete.
 2872  *
 2873  * @par Description
 2874  * Sent by the target-server to notify the base driver that the work started from
 2875  * ocs_scsi_del_initiator() is now complete and that it is safe for the node to
 2876  * release the rest of its resources.
 2877  *
 2878  * @param node Pointer to the node.
 2879  *
 2880  * @return None.
 2881  */
 2882 void
 2883 ocs_scsi_del_initiator_complete(ocs_node_t *node)
 2884 {
 2885         /* Notify the node to resume */
 2886         ocs_node_post_event(node, OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
 2887 }
 2888 
 2889 /**
 2890  * @ingroup scsi_api_base
 2891  * @brief Notify that delete target is complete.
 2892  *
 2893  * @par Description
 2894  * Sent by the initiator-client to notify the base driver that the work started from
 2895  * ocs_scsi_del_target() is now complete and that it is safe for the node to
 2896  * release the rest of its resources.
 2897  *
 2898  * @param node Pointer to the node.
 2899  *
 2900  * @return None.
 2901  */
 2902 void
 2903 ocs_scsi_del_target_complete(ocs_node_t *node)
 2904 {
 2905         /* Notify the node to resume */
 2906         ocs_node_post_event(node, OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
 2907 }
 2908 
 2909 /**
 2910  * @brief Update transferred count
 2911  *
 2912  * @par Description
 2913  * Updates io->transferred, as required when using first burst, when the amount
 2914  * of first burst data processed differs from the amount of first burst
 2915  * data received.
 2916  *
 2917  * @param io Pointer to the io object.
 2918  * @param transferred Number of bytes transferred out of first burst buffers.
 2919  *
 2920  * @return None.
 2921  */
 2922 void
 2923 ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred)
 2924 {
 2925         io->transferred = transferred;
 2926 }
 2927 
 2928 /**
 2929  * @brief Register bounce callback for multi-threading.
 2930  *
 2931  * @par Description
 2932  * Register the back end bounce function.
 2933  *
 2934  * @param ocs Pointer to device object.
 2935  * @param fctn Function pointer of bounce function.
 2936  *
 2937  * @return None.
 2938  */
 2939 void
 2940 ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void(*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id,
 2941                                                  uint32_t ox_id))
 2942 {
 2943         ocs_hw_rtn_e rc;
 2944 
 2945         rc = ocs_hw_callback(&ocs->hw, OCS_HW_CB_BOUNCE, fctn, NULL);
 2946         if (rc) {
 2947                 ocs_log_test(ocs, "ocs_hw_callback(OCS_HW_CB_BOUNCE) failed: %d\n", rc);
 2948         }
 2949 }

Cache object: 3ad89713a6ecd68638d5d6fe9b7a5943


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