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

Cache object: cf11334001b5f3a6bcd82222a59fdbbb


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