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