2 * Copyright (c) 2017 Broadcom. All rights reserved.
3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
36 * OCS Linux SCSI API base driver implementation.
40 * @defgroup scsi_api_base SCSI Base Target/Initiator
46 #if defined(OCS_ENABLE_VPD_SUPPORT)
49 #include "ocs_utils.h"
50 #include "ocs_device.h"
52 #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]"
53 #define SCSI_ITT_SIZE(ocs) ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8)
55 #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag
57 #define enable_tsend_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TSEND) == 0)
58 #define enable_treceive_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TRECEIVE) == 0)
60 #define scsi_io_printf(io, fmt, ...) ocs_log_info(io->ocs, "[%s]" SCSI_IOFMT fmt, \
61 io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__)
63 #define scsi_io_trace(io, fmt, ...) \
65 if (OCS_LOG_ENABLE_SCSI_TRACE(io->ocs)) \
66 scsi_io_printf(io, fmt, ##__VA_ARGS__); \
69 #define scsi_log(ocs, fmt, ...) \
71 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) \
72 ocs_log_info(ocs, fmt, ##__VA_ARGS__); \
75 static int32_t ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg);
76 static int32_t ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
77 uint32_t ext, void *arg);
79 static void ocs_scsi_io_free_ovfl(ocs_io_t *io);
80 static uint32_t ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count);
81 static int ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info);
82 static ocs_scsi_io_status_e ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc);
83 static uint32_t ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[],
84 uint32_t addrlen_count, ocs_dif_t *dif, int is_crc);
85 static uint32_t ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif);
86 static uint32_t ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif);
87 static int32_t ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info,
88 ocs_hw_dif_info_t *hw_dif_info);
89 static int32_t ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio);
90 static int32_t ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io);
91 static void _ocs_scsi_io_free(void *arg);
94 * @ingroup scsi_api_base
95 * @brief Returns a big-endian 32-bit value given a pointer.
97 * @param p Pointer to the 32-bit big-endian location.
99 * @return Returns the byte-swapped 32-bit value.
102 static inline uint32_t
103 ocs_fc_getbe32(void *p)
105 return ocs_be32toh(*((uint32_t*)p));
109 * @ingroup scsi_api_base
110 * @brief Enable IO allocation.
113 * The SCSI and Transport IO allocation functions are enabled. If the allocation functions
114 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
117 * @param node Pointer to node object.
122 ocs_scsi_io_alloc_enable(ocs_node_t *node)
124 ocs_assert(node != NULL);
125 ocs_lock(&node->active_ios_lock);
126 node->io_alloc_enabled = TRUE;
127 ocs_unlock(&node->active_ios_lock);
131 * @ingroup scsi_api_base
132 * @brief Disable IO allocation
135 * The SCSI and Transport IO allocation functions are disabled. If the allocation functions
136 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
139 * @param node Pointer to node object
144 ocs_scsi_io_alloc_disable(ocs_node_t *node)
146 ocs_assert(node != NULL);
147 ocs_lock(&node->active_ios_lock);
148 node->io_alloc_enabled = FALSE;
149 ocs_unlock(&node->active_ios_lock);
153 * @ingroup scsi_api_base
154 * @brief Allocate a SCSI IO context.
157 * A SCSI IO context is allocated and associated with a @c node. This function
158 * is called by an initiator-client when issuing SCSI commands to remote
159 * target devices. On completion, ocs_scsi_io_free() is called.
161 * The returned ocs_io_t structure has an element of type ocs_scsi_ini_io_t named
162 * "ini_io" that is declared and used by an initiator-client for private information.
164 * @param node Pointer to the associated node structure.
165 * @param role Role for IO (originator/responder).
167 * @return Returns the pointer to the IO context, or NULL.
172 ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
178 ocs_assert(node, NULL);
179 ocs_assert(node->ocs, NULL);
182 ocs_assert(ocs->xport, NULL);
185 ocs_lock(&node->active_ios_lock);
187 if (!node->io_alloc_enabled) {
188 ocs_unlock(&node->active_ios_lock);
192 io = ocs_io_alloc(ocs);
194 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
195 ocs_unlock(&node->active_ios_lock);
199 /* initialize refcount */
200 ocs_ref_init(&io->ref, _ocs_scsi_io_free, io);
202 if (io->hio != NULL) {
203 ocs_log_err(node->ocs, "assertion failed: io->hio is not NULL\n");
204 ocs_unlock(&node->active_ios_lock);
208 /* set generic fields */
212 /* set type and name */
213 io->io_type = OCS_IO_TYPE_IO;
214 io->display_name = "scsi_io";
217 case OCS_SCSI_IO_ROLE_ORIGINATOR:
221 case OCS_SCSI_IO_ROLE_RESPONDER:
227 /* Add to node's active_ios list */
228 ocs_list_add_tail(&node->active_ios, io);
230 ocs_unlock(&node->active_ios_lock);
236 * @ingroup scsi_api_base
237 * @brief Free a SCSI IO context (internal).
240 * The IO context previously allocated using ocs_scsi_io_alloc()
241 * is freed. This is called from within the transport layer,
242 * when the reference count goes to zero.
244 * @param arg Pointer to the IO context.
249 _ocs_scsi_io_free(void *arg)
251 ocs_io_t *io = (ocs_io_t *)arg;
252 ocs_t *ocs = io->ocs;
253 ocs_node_t *node = io->node;
254 int send_empty_event;
256 ocs_assert(io != NULL);
258 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
260 ocs_assert(ocs_io_busy(io));
262 ocs_lock(&node->active_ios_lock);
263 ocs_list_remove(&node->active_ios, io);
264 send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->active_ios);
265 ocs_unlock(&node->active_ios_lock);
267 if (send_empty_event) {
268 ocs_node_post_event(node, OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY, NULL);
272 ocs_io_free(ocs, io);
277 * @ingroup scsi_api_base
278 * @brief Free a SCSI IO context.
281 * The IO context previously allocated using ocs_scsi_io_alloc() is freed.
283 * @param io Pointer to the IO context.
288 ocs_scsi_io_free(ocs_io_t *io)
290 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
291 ocs_assert(ocs_ref_read_count(&io->ref) > 0);
292 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
296 ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
297 ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
298 ocs_scsi_dif_info_t *dif_info,
299 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
300 ocs_scsi_rsp_io_cb_t cb, void *arg);
303 * @brief Target response completion callback.
306 * Function is called upon the completion of a target IO request.
308 * @param hio Pointer to the HW IO structure.
309 * @param rnode Remote node associated with the IO that is completing.
310 * @param length Length of the response payload.
311 * @param status Completion status.
312 * @param ext_status Extended completion status.
313 * @param app Application-specific data (generally a pointer to the IO context).
319 ocs_target_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
320 int32_t status, uint32_t ext_status, void *app)
324 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
325 uint16_t additional_length;
328 ocs_hw_dif_info_t *dif_info = &io->hw_dif;
333 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
338 ocs_scsi_io_free_ovfl(io);
340 io->transferred += length;
342 /* Call target server completion */
343 if (io->scsi_tgt_cb) {
344 ocs_scsi_io_cb_t cb = io->scsi_tgt_cb;
347 /* Clear the callback before invoking the callback */
348 io->scsi_tgt_cb = NULL;
350 /* if status was good, and auto-good-response was set, then callback
351 * target-server with IO_CMPL_RSP_SENT, otherwise send IO_CMPL
353 if ((status == 0) && (io->auto_resp))
354 flags |= OCS_SCSI_IO_CMPL_RSP_SENT;
356 flags |= OCS_SCSI_IO_CMPL;
359 case SLI4_FC_WCQE_STATUS_SUCCESS:
360 scsi_status = OCS_SCSI_STATUS_GOOD;
362 case SLI4_FC_WCQE_STATUS_DI_ERROR:
363 if (ext_status & SLI4_FC_DI_ERROR_GE) {
364 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
365 } else if (ext_status & SLI4_FC_DI_ERROR_AE) {
366 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
367 } else if (ext_status & SLI4_FC_DI_ERROR_RE) {
368 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
370 additional_length = ((ext_status >> 16) & 0xFFFF);
372 /* Capture the EDIR and TDPV bits as 0 or 1 for easier printing. */
373 edir = !!(ext_status & SLI4_FC_DI_ERROR_EDIR);
374 tdpv = !!(ext_status & SLI4_FC_DI_ERROR_TDPV);
376 is_crc = ocs_scsi_dif_guard_is_crc(edir, dif_info);
379 /* For reads, we have everything in memory. Start checking from beginning. */
380 scsi_status = ocs_scsi_dif_check_unknown(io, 0, io->wire_len, is_crc);
382 /* For writes, use the additional length to determine where to look for the error.
383 * The additional_length field is set to 0 if it is not supported.
384 * The additional length field is valid if:
385 * . additional_length is not zero
386 * . Total Data Placed is valid
387 * . Error Direction is RX (1)
388 * . Operation is a pass thru (CRC or CKSUM on IN, and CRC or CHKSUM on OUT) (all pass-thru cases except raw)
390 if ((additional_length != 0) && (tdpv != 0) &&
391 (dif_info->dif == SLI4_DIF_PASS_THROUGH) && (dif_info->dif_oper != OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW) ) {
392 scsi_status = ocs_scsi_dif_check_unknown(io, length, additional_length, is_crc);
394 /* If we can't do additional checking, then fall-back to guard error */
395 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
400 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
401 switch (ext_status) {
402 case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET:
403 case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
404 scsi_status = OCS_SCSI_STATUS_ABORTED;
406 case SLI4_FC_LOCAL_REJECT_INVALID_RPI:
407 scsi_status = OCS_SCSI_STATUS_NEXUS_LOST;
409 case SLI4_FC_LOCAL_REJECT_NO_XRI:
410 scsi_status = OCS_SCSI_STATUS_NO_IO;
413 /* TODO: we have seen 0x0d (TX_DMA_FAILED error) */
414 scsi_status = OCS_SCSI_STATUS_ERROR;
419 case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT:
420 /* target IO timed out */
421 scsi_status = OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED;
424 case SLI4_FC_WCQE_STATUS_SHUTDOWN:
425 /* Target IO cancelled by HW */
426 scsi_status = OCS_SCSI_STATUS_SHUTDOWN;
430 scsi_status = OCS_SCSI_STATUS_ERROR;
434 cb(io, scsi_status, flags, io->scsi_tgt_cb_arg);
436 ocs_scsi_check_pending(ocs);
440 * @brief Determine if an IO is using CRC for DIF guard format.
442 * @param direction IO direction: 1 for write, 0 for read.
443 * @param dif_info Pointer to HW DIF info data.
445 * @return Returns TRUE if using CRC, FALSE if not.
448 ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info)
453 /* For writes, check if operation is "OUT_CRC" or not */
454 switch(dif_info->dif_oper) {
455 case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC:
456 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
457 case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC:
465 /* For reads, check if operation is "IN_CRC" or not */
466 switch(dif_info->dif_oper) {
467 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF:
468 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
469 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM:
482 * @brief Check a block and DIF data, computing the appropriate SCSI status
485 * This function is used to check blocks and DIF when given an unknown DIF
486 * status using the following logic:
488 * Given the address of the last good block, and a length of bytes that includes
489 * the block with the DIF error, find the bad block. If a block is found with an
490 * app_tag or ref_tag error, then return the appropriate error. No block is expected
491 * to have a block guard error since hardware "fixes" the crc. So if no block in the
492 * range of blocks has an error, then it is presumed to be a BLOCK GUARD error.
494 * @param io Pointer to the IO object.
495 * @param length Length of bytes covering the good blocks.
496 * @param check_length Length of bytes that covers the bad block.
497 * @param is_crc True if guard is using CRC format.
499 * @return Returns SCSI status.
502 static ocs_scsi_io_status_e
503 ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc)
506 ocs_t *ocs = io->ocs;
507 ocs_hw_dif_info_t *dif_info = &io->hw_dif;
508 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
509 uint32_t blocksize; /* data block size */
510 uint64_t first_check_block; /* first block following total data placed */
511 uint64_t last_check_block; /* last block to check */
512 uint32_t check_count; /* count of blocks to check */
513 ocs_scsi_vaddr_len_t addrlen[4]; /* address-length pairs returned from target */
514 int32_t addrlen_count; /* count of address-length pairs */
515 ocs_dif_t *dif; /* pointer to DIF block returned from target */
516 ocs_scsi_dif_info_t scsi_dif_info = io->scsi_dif_info;
518 blocksize = ocs_hw_dif_mem_blocksize(&io->hw_dif, TRUE);
519 first_check_block = length / blocksize;
520 last_check_block = ((length + check_length) / blocksize);
521 check_count = last_check_block - first_check_block;
523 ocs_log_debug(ocs, "blocksize %d first check_block %" PRId64 " last_check_block %" PRId64 " check_count %d\n",
524 blocksize, first_check_block, last_check_block, check_count);
526 for (i = first_check_block; i < last_check_block; i++) {
527 addrlen_count = ocs_scsi_get_block_vaddr(io, (scsi_dif_info.lba + i), addrlen, ARRAY_SIZE(addrlen), (void**) &dif);
528 if (addrlen_count < 0) {
529 ocs_log_test(ocs, "ocs_scsi_get_block_vaddr() failed: %d\n", addrlen_count);
530 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
534 if (! ocs_scsi_dif_check_guard(dif_info, addrlen, addrlen_count, dif, is_crc)) {
535 ocs_log_debug(ocs, "block guard check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
536 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
539 if (! ocs_scsi_dif_check_app_tag(ocs, dif_info, scsi_dif_info.app_tag, dif)) {
540 ocs_log_debug(ocs, "app tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
541 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
544 if (! ocs_scsi_dif_check_ref_tag(ocs, dif_info, (scsi_dif_info.ref_tag + i), dif)) {
545 ocs_log_debug(ocs, "ref tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
546 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
554 * @brief Check the block guard of block data
557 * Using the dif_info for the transfer, check the block guard value.
559 * @param dif_info Pointer to HW DIF info data.
560 * @param addrlen Array of address length pairs.
561 * @param addrlen_count Number of entries in the addrlen[] array.
562 * @param dif Pointer to the DIF data block being checked.
563 * @param is_crc True if guard is using CRC format.
565 * @return Returns TRUE if block guard check is ok.
568 ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count,
569 ocs_dif_t *dif, int is_crc)
571 uint16_t crc = dif_info->dif_seed;
575 if ((dif == NULL) || !dif_info->check_guard) {
580 for (i = 0; i < addrlen_count; i++) {
581 crc = ocs_scsi_dif_calc_crc(addrlen[i].vaddr, addrlen[i].length, crc);
583 return (crc == ocs_be16toh(dif->crc));
585 checksum = ocs_scsi_dif_calc_checksum(addrlen, addrlen_count);
587 return (checksum == dif->crc);
592 * @brief Check the app tag of dif data
595 * Using the dif_info for the transfer, check the app tag.
597 * @param ocs Pointer to the ocs structure for logging.
598 * @param dif_info Pointer to HW DIF info data.
599 * @param exp_app_tag The value the app tag is expected to be.
600 * @param dif Pointer to the DIF data block being checked.
602 * @return Returns TRUE if app tag check is ok.
605 ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif)
607 if ((dif == NULL) || !dif_info->check_app_tag) {
611 ocs_log_debug(ocs, "expected app tag 0x%x, actual 0x%x\n",
612 exp_app_tag, ocs_be16toh(dif->app_tag));
614 return (exp_app_tag == ocs_be16toh(dif->app_tag));
618 * @brief Check the ref tag of dif data
621 * Using the dif_info for the transfer, check the app tag.
623 * @param ocs Pointer to the ocs structure for logging.
624 * @param dif_info Pointer to HW DIF info data.
625 * @param exp_ref_tag The value the ref tag is expected to be.
626 * @param dif Pointer to the DIF data block being checked.
628 * @return Returns TRUE if ref tag check is ok.
631 ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif)
633 if ((dif == NULL) || !dif_info->check_ref_tag) {
637 if (exp_ref_tag != ocs_be32toh(dif->ref_tag)) {
638 ocs_log_debug(ocs, "expected ref tag 0x%x, actual 0x%x\n",
639 exp_ref_tag, ocs_be32toh(dif->ref_tag));
647 * @brief Return count of SGE's required for request
650 * An accurate count of SGEs is computed and returned.
652 * @param hw_dif Pointer to HW dif information.
653 * @param sgl Pointer to SGL from back end.
654 * @param sgl_count Count of SGEs in SGL.
656 * @return Count of SGEs.
659 ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count)
664 /* Convert DIF Information */
665 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
666 /* If we're not DIF separate, then emit a seed SGE */
667 if (!hw_dif->dif_separate) {
671 for (i = 0; i < sgl_count; i++) {
672 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
673 if (hw_dif->dif_separate) {
686 ocs_scsi_build_sgls(ocs_hw_t *hw, ocs_hw_io_t *hio, ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hw_io_type_e type)
691 uint32_t blocksize = 0;
696 /* Initialize HW SGL */
697 rc = ocs_hw_io_init_sges(hw, hio, type);
699 ocs_log_err(ocs, "ocs_hw_io_init_sges failed: %d\n", rc);
703 /* Convert DIF Information */
704 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
705 /* If we're not DIF separate, then emit a seed SGE */
706 if (!hw_dif->dif_separate) {
707 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
713 /* if we are doing DIF separate, then figure out the block size so that we
714 * can update the ref tag in the DIF seed SGE. Also verify that the
715 * the sgl lengths are all multiples of the blocksize
717 if (hw_dif->dif_separate) {
718 switch(hw_dif->blk_size) {
719 case OCS_HW_DIF_BK_SIZE_512: blocksize = 512; break;
720 case OCS_HW_DIF_BK_SIZE_1024: blocksize = 1024; break;
721 case OCS_HW_DIF_BK_SIZE_2048: blocksize = 2048; break;
722 case OCS_HW_DIF_BK_SIZE_4096: blocksize = 4096; break;
723 case OCS_HW_DIF_BK_SIZE_520: blocksize = 520; break;
724 case OCS_HW_DIF_BK_SIZE_4104: blocksize = 4104; break;
726 ocs_log_test(hw->os, "Inavlid hw_dif blocksize %d\n", hw_dif->blk_size);
729 for (i = 0; i < sgl_count; i++) {
730 if ((sgl[i].len % blocksize) != 0) {
731 ocs_log_test(hw->os, "sgl[%d] len of %ld is not multiple of blocksize\n",
738 for (i = 0; i < sgl_count; i++) {
739 ocs_assert(sgl[i].addr, -1);
740 ocs_assert(sgl[i].len, -1);
742 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
743 if (hw_dif->dif_separate) {
744 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
748 rc = ocs_hw_io_add_dif_sge(hw, hio, sgl[i].dif_addr);
752 /* Update the ref_tag for the next DIF seed SGE */
753 blockcount = sgl[i].len / blocksize;
754 if (hw_dif->dif_oper == OCS_HW_DIF_OPER_INSERT) {
755 hw_dif->ref_tag_repl += blockcount;
757 hw_dif->ref_tag_cmp += blockcount;
762 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
764 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
770 for (i = 0; i < sgl_count; i++) {
771 ocs_assert(sgl[i].addr, -1);
772 ocs_assert(sgl[i].len, -1);
775 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
777 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
787 * @ingroup scsi_api_base
788 * @brief Convert SCSI API T10 DIF information into the FC HW format.
790 * @param ocs Pointer to the ocs structure for logging.
791 * @param scsi_dif_info Pointer to the SCSI API T10 DIF fields.
792 * @param hw_dif_info Pointer to the FC HW API T10 DIF fields.
794 * @return Returns 0 on success, or a negative error code value on failure.
798 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, ocs_hw_dif_info_t *hw_dif_info)
801 ocs_memset(hw_dif_info, 0, sizeof(ocs_hw_dif_info_t));
803 if (scsi_dif_info == NULL) {
804 hw_dif_info->dif_oper = OCS_HW_DIF_OPER_DISABLED;
805 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_NA;
809 /* Convert the DIF operation */
810 switch(scsi_dif_info->dif_oper) {
811 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC:
812 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC;
813 hw_dif_info->dif = SLI4_DIF_INSERT;
815 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF:
816 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF;
817 hw_dif_info->dif = SLI4_DIF_STRIP;
819 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM:
820 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM;
821 hw_dif_info->dif = SLI4_DIF_INSERT;
823 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF:
824 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF;
825 hw_dif_info->dif = SLI4_DIF_STRIP;
827 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC:
828 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC;
829 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
831 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM:
832 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM;
833 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
835 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM:
836 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM;
837 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
839 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC:
840 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC;
841 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
843 case OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW:
844 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW;
845 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
848 ocs_log_test(ocs, "unhandled SCSI DIF operation %d\n",
849 scsi_dif_info->dif_oper);
853 switch(scsi_dif_info->blk_size) {
854 case OCS_SCSI_DIF_BK_SIZE_512:
855 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_512;
857 case OCS_SCSI_DIF_BK_SIZE_1024:
858 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_1024;
860 case OCS_SCSI_DIF_BK_SIZE_2048:
861 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_2048;
863 case OCS_SCSI_DIF_BK_SIZE_4096:
864 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4096;
866 case OCS_SCSI_DIF_BK_SIZE_520:
867 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_520;
869 case OCS_SCSI_DIF_BK_SIZE_4104:
870 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4104;
873 ocs_log_test(ocs, "unhandled SCSI DIF block size %d\n",
874 scsi_dif_info->blk_size);
878 /* If the operation is an INSERT the tags provided are the ones that should be
879 * inserted, otherwise they're the ones to be checked against. */
880 if (hw_dif_info->dif == SLI4_DIF_INSERT ) {
881 hw_dif_info->ref_tag_repl = scsi_dif_info->ref_tag;
882 hw_dif_info->app_tag_repl = scsi_dif_info->app_tag;
884 hw_dif_info->ref_tag_cmp = scsi_dif_info->ref_tag;
885 hw_dif_info->app_tag_cmp = scsi_dif_info->app_tag;
888 hw_dif_info->check_ref_tag = scsi_dif_info->check_ref_tag;
889 hw_dif_info->check_app_tag = scsi_dif_info->check_app_tag;
890 hw_dif_info->check_guard = scsi_dif_info->check_guard;
891 hw_dif_info->auto_incr_ref_tag = 1;
892 hw_dif_info->dif_separate = scsi_dif_info->dif_separate;
893 hw_dif_info->disable_app_ffff = scsi_dif_info->disable_app_ffff;
894 hw_dif_info->disable_app_ref_ffff = scsi_dif_info->disable_app_ref_ffff;
896 ocs_hw_get(&ocs->hw, OCS_HW_DIF_SEED, &dif_seed);
897 hw_dif_info->dif_seed = dif_seed;
903 * @ingroup scsi_api_base
904 * @brief This function logs the SGLs for an IO.
906 * @param io Pointer to the IO context.
908 static void ocs_log_sgl(ocs_io_t *io)
910 ocs_hw_io_t *hio = io->hio;
911 sli4_sge_t *data = NULL;
912 uint32_t *dword = NULL;
916 scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n",
917 ocs_addr32_hi(hio->def_sgl.phys),
918 ocs_addr32_lo(hio->def_sgl.phys));
919 n_sge = (hio->sgl == &hio->def_sgl ? hio->n_sge : hio->def_sgl_count);
920 for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) {
921 dword = (uint32_t*)data;
923 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
924 i, dword[0], dword[1], dword[2], dword[3]);
926 if (dword[2] & (1U << 31)) {
931 if (hio->ovfl_sgl != NULL &&
932 hio->sgl == hio->ovfl_sgl) {
933 scsi_io_trace(io, "Overflow at 0x%x 0x%08x\n",
934 ocs_addr32_hi(hio->ovfl_sgl->phys),
935 ocs_addr32_lo(hio->ovfl_sgl->phys));
936 for (i = 0, data = hio->ovfl_sgl->virt; i < hio->n_sge; i++, data++) {
937 dword = (uint32_t*)data;
939 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
940 i, dword[0], dword[1], dword[2], dword[3]);
941 if (dword[2] & (1U << 31)) {
950 * @brief Check pending error asynchronous callback function.
953 * Invoke the HW callback function for a given IO. This function is called
954 * from the NOP mailbox completion context.
956 * @param hw Pointer to HW object.
957 * @param status Completion status.
958 * @param mqe Mailbox completion queue entry.
959 * @param arg General purpose argument.
964 ocs_scsi_check_pending_async_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
969 if (io->hw_cb != NULL) {
970 ocs_hw_done_t cb = io->hw_cb;
973 cb(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io);
980 * @brief Check for pending IOs to dispatch.
983 * If there are IOs on the pending list, and a HW IO is available, then
986 * @param ocs Pointer to the OCS structure.
992 ocs_scsi_check_pending(ocs_t *ocs)
994 ocs_xport_t *xport = ocs->xport;
1001 /* Guard against recursion */
1002 if (ocs_atomic_add_return(&xport->io_pending_recursing, 1)) {
1003 /* This function is already running. Decrement and return. */
1004 ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
1009 ocs_lock(&xport->io_pending_lock);
1012 io = ocs_list_remove_head(&xport->io_pending_list);
1014 if (io->io_type == OCS_IO_TYPE_ABORT) {
1017 hio = ocs_hw_io_alloc(&ocs->hw);
1020 * No HW IO available.
1021 * Put IO back on the front of pending list
1023 ocs_list_add_head(&xport->io_pending_list, io);
1026 hio->eq = io->hw_priv;
1030 /* Must drop the lock before dispatching the IO */
1031 ocs_unlock(&xport->io_pending_lock);
1037 * We pulled an IO off the pending list,
1038 * and either got an HW IO or don't need one
1040 ocs_atomic_sub_return(&xport->io_pending_count, 1);
1042 status = ocs_scsi_io_dispatch_no_hw_io(io);
1044 status = ocs_scsi_io_dispatch_hw_io(io, hio);
1048 * Invoke the HW callback, but do so in the separate execution context,
1049 * provided by the NOP mailbox completion processing context by using
1050 * ocs_hw_async_call()
1052 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
1053 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
1057 } while (io != NULL);
1060 * If nothing was removed from the list,
1061 * we might be in a case where we need to abort an
1062 * active IO and the abort is on the pending list.
1063 * Look for an abort we can dispatch.
1068 ocs_lock(&xport->io_pending_lock);
1069 ocs_list_foreach(&xport->io_pending_list, io) {
1070 if (io->io_type == OCS_IO_TYPE_ABORT) {
1071 if (io->io_to_abort->hio != NULL) {
1072 /* This IO has a HW IO, so it is active. Dispatch the abort. */
1075 /* Leave this abort on the pending list and keep looking */
1080 ocs_list_remove(&xport->io_pending_list, io);
1081 ocs_atomic_sub_return(&xport->io_pending_count, 1);
1085 ocs_unlock(&xport->io_pending_lock);
1088 status = ocs_scsi_io_dispatch_no_hw_io(io);
1090 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
1091 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
1097 ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
1102 * @brief Attempt to dispatch a non-abort IO
1105 * An IO is dispatched:
1106 * - if the pending list is not empty, add IO to pending list
1107 * and call a function to process the pending list.
1108 * - if pending list is empty, try to allocate a HW IO. If none
1109 * is available, place this IO at the tail of the pending IO
1111 * - if HW IO is available, attach this IO to the HW IO and
1114 * @param io Pointer to IO structure.
1115 * @param cb Callback function.
1117 * @return Returns 0 on success, a negative error code value on failure.
1121 ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
1124 ocs_t *ocs = io->ocs;
1125 ocs_xport_t *xport = ocs->xport;
1127 ocs_assert(io->cmd_tgt || io->cmd_ini, -1);
1128 ocs_assert((io->io_type != OCS_IO_TYPE_ABORT), -1);
1132 * if this IO already has a HW IO, then this is either not the first phase of
1133 * the IO. Send it to the HW.
1135 if (io->hio != NULL) {
1136 return ocs_scsi_io_dispatch_hw_io(io, io->hio);
1140 * We don't already have a HW IO associated with the IO. First check
1141 * the pending list. If not empty, add IO to the tail and process the
1144 ocs_lock(&xport->io_pending_lock);
1145 if (!ocs_list_empty(&xport->io_pending_list)) {
1147 * If this is a low latency request, the put at the front of the IO pending
1148 * queue, otherwise put it at the end of the queue.
1150 if (io->low_latency) {
1151 ocs_list_add_head(&xport->io_pending_list, io);
1153 ocs_list_add_tail(&xport->io_pending_list, io);
1155 ocs_unlock(&xport->io_pending_lock);
1156 ocs_atomic_add_return(&xport->io_pending_count, 1);
1157 ocs_atomic_add_return(&xport->io_total_pending, 1);
1159 /* process pending list */
1160 ocs_scsi_check_pending(ocs);
1163 ocs_unlock(&xport->io_pending_lock);
1166 * We don't have a HW IO associated with the IO and there's nothing
1167 * on the pending list. Attempt to allocate a HW IO and dispatch it.
1169 hio = ocs_hw_io_alloc(&io->ocs->hw);
1171 /* Couldn't get a HW IO. Save this IO on the pending list */
1172 ocs_lock(&xport->io_pending_lock);
1173 ocs_list_add_tail(&xport->io_pending_list, io);
1174 ocs_unlock(&xport->io_pending_lock);
1176 ocs_atomic_add_return(&xport->io_total_pending, 1);
1177 ocs_atomic_add_return(&xport->io_pending_count, 1);
1181 /* We successfully allocated a HW IO; dispatch to HW */
1182 return ocs_scsi_io_dispatch_hw_io(io, hio);
1186 * @brief Attempt to dispatch an Abort IO.
1189 * An Abort IO is dispatched:
1190 * - if the pending list is not empty, add IO to pending list
1191 * and call a function to process the pending list.
1192 * - if pending list is empty, send abort to the HW.
1194 * @param io Pointer to IO structure.
1195 * @param cb Callback function.
1197 * @return Returns 0 on success, a negative error code value on failure.
1201 ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb)
1203 ocs_t *ocs = io->ocs;
1204 ocs_xport_t *xport = ocs->xport;
1206 ocs_assert((io->io_type == OCS_IO_TYPE_ABORT), -1);
1210 * For aborts, we don't need a HW IO, but we still want to pass through
1211 * the pending list to preserve ordering. Thus, if the pending list is
1212 * not empty, add this abort to the pending list and process the pending list.
1214 ocs_lock(&xport->io_pending_lock);
1215 if (!ocs_list_empty(&xport->io_pending_list)) {
1216 ocs_list_add_tail(&xport->io_pending_list, io);
1217 ocs_unlock(&xport->io_pending_lock);
1218 ocs_atomic_add_return(&xport->io_pending_count, 1);
1219 ocs_atomic_add_return(&xport->io_total_pending, 1);
1221 /* process pending list */
1222 ocs_scsi_check_pending(ocs);
1225 ocs_unlock(&xport->io_pending_lock);
1227 /* nothing on pending list, dispatch abort */
1228 return ocs_scsi_io_dispatch_no_hw_io(io);
1233 * @brief Dispatch IO
1236 * An IO and its associated HW IO is dispatched to the HW.
1238 * @param io Pointer to IO structure.
1239 * @param hio Pointer to HW IO structure from which IO will be
1242 * @return Returns 0 on success, a negative error code value on failure.
1246 ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio)
1249 ocs_t *ocs = io->ocs;
1251 /* Got a HW IO; update ini/tgt_task_tag with HW IO info and dispatch */
1254 io->tgt_task_tag = hio->indicator;
1255 } else if (io->cmd_ini) {
1256 io->init_task_tag = hio->indicator;
1258 io->hw_tag = hio->reqtag;
1260 hio->eq = io->hw_priv;
1262 /* Copy WQ steering */
1263 switch(io->wq_steering) {
1264 case OCS_SCSI_WQ_STEERING_CLASS >> OCS_SCSI_WQ_STEERING_SHIFT:
1265 hio->wq_steering = OCS_HW_WQ_STEERING_CLASS;
1267 case OCS_SCSI_WQ_STEERING_REQUEST >> OCS_SCSI_WQ_STEERING_SHIFT:
1268 hio->wq_steering = OCS_HW_WQ_STEERING_REQUEST;
1270 case OCS_SCSI_WQ_STEERING_CPU >> OCS_SCSI_WQ_STEERING_SHIFT:
1271 hio->wq_steering = OCS_HW_WQ_STEERING_CPU;
1275 switch (io->io_type) {
1276 case OCS_IO_TYPE_IO: {
1278 uint32_t total_count;
1279 uint32_t host_allocated;
1281 ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
1282 ocs_hw_get(&ocs->hw, OCS_HW_SGL_CHAINING_HOST_ALLOCATED, &host_allocated);
1285 * If the requested SGL is larger than the default size, then we can allocate
1288 total_count = ocs_scsi_count_sgls(&io->hw_dif, io->sgl, io->sgl_count);
1291 * Lancer requires us to allocate the chained memory area, but
1292 * Skyhawk must use the SGL list associated with another XRI.
1294 if (host_allocated && total_count > max_sgl) {
1295 /* Compute count needed, the number extra plus 1 for the link sge */
1296 uint32_t count = total_count - max_sgl + 1;
1297 rc = ocs_dma_alloc(ocs, &io->ovfl_sgl, count*sizeof(sli4_sge_t), 64);
1299 ocs_log_err(ocs, "ocs_dma_alloc overflow sgl failed\n");
1302 rc = ocs_hw_io_register_sgl(&ocs->hw, io->hio, &io->ovfl_sgl, count);
1304 ocs_scsi_io_free_ovfl(io);
1305 ocs_log_err(ocs, "ocs_hw_io_register_sgl() failed\n");
1308 /* EVT: update chained_io_count */
1309 io->node->chained_io_count++;
1312 rc = ocs_scsi_build_sgls(&ocs->hw, io->hio, &io->hw_dif, io->sgl, io->sgl_count, io->hio_type);
1314 ocs_scsi_io_free_ovfl(io);
1318 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
1323 io->iparam.fcp_tgt.app_id = io->app_id;
1326 rc = ocs_hw_io_send(&io->ocs->hw, io->hio_type, io->hio, io->wire_len, &io->iparam, &io->node->rnode,
1330 case OCS_IO_TYPE_ELS:
1331 case OCS_IO_TYPE_CT: {
1332 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1333 &io->els_req, io->wire_len,
1334 &io->els_rsp, &io->node->rnode, &io->iparam,
1338 case OCS_IO_TYPE_CT_RESP: {
1339 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1340 &io->els_rsp, io->wire_len,
1341 NULL, &io->node->rnode, &io->iparam,
1345 case OCS_IO_TYPE_BLS_RESP: {
1346 /* no need to update tgt_task_tag for BLS response since the RX_ID
1347 * will be specified by the payload, not the XRI */
1348 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1349 NULL, 0, NULL, &io->node->rnode, &io->iparam, io->hw_cb, io);
1353 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
1361 * @brief Dispatch IO
1364 * An IO that does require a HW IO is dispatched to the HW.
1366 * @param io Pointer to IO structure.
1368 * @return Returns 0 on success, or a negative error code value on failure.
1372 ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io)
1376 switch (io->io_type) {
1377 case OCS_IO_TYPE_ABORT: {
1378 ocs_hw_io_t *hio_to_abort = NULL;
1379 ocs_assert(io->io_to_abort, -1);
1380 hio_to_abort = io->io_to_abort->hio;
1382 if (hio_to_abort == NULL) {
1384 * If "IO to abort" does not have an associated HW IO, immediately
1385 * make callback with success. The command must have been sent to
1386 * the backend, but the data phase has not yet started, so we don't
1389 * Note: since the backend shims should be taking a reference
1390 * on io_to_abort, it should not be possible to have been completed
1391 * and freed by the backend before the abort got here.
1393 scsi_io_printf(io, "IO: " SCSI_IOFMT " not active\n",
1394 SCSI_IOFMT_ARGS(io->io_to_abort));
1395 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_SUCCESS, 0, io);
1398 /* HW IO is valid, abort it */
1399 scsi_io_printf(io, "aborting " SCSI_IOFMT "\n", SCSI_IOFMT_ARGS(io->io_to_abort));
1400 rc = ocs_hw_io_abort(&io->ocs->hw, hio_to_abort, io->send_abts,
1403 int status = SLI4_FC_WCQE_STATUS_SUCCESS;
1404 if ((rc != OCS_HW_RTN_IO_NOT_ACTIVE) &&
1405 (rc != OCS_HW_RTN_IO_ABORT_IN_PROGRESS)) {
1407 scsi_io_printf(io, "Failed to abort IO: " SCSI_IOFMT " status=%d\n",
1408 SCSI_IOFMT_ARGS(io->io_to_abort), rc);
1410 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, status, 0, io);
1418 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
1426 * @ingroup scsi_api_base
1427 * @brief Send read/write data.
1430 * This call is made by a target-server to initiate a SCSI read or write data phase, transferring
1431 * data between the target to the remote initiator. The payload is specified by the
1432 * scatter-gather list @c sgl of length @c sgl_count. The @c wire_len argument
1433 * specifies the payload length (independent of the scatter-gather list cumulative length).
1435 * The @c flags argument has one bit, OCS_SCSI_LAST_DATAPHASE, which is a hint to the base
1436 * driver that it may use auto SCSI response features if the hardware supports it.
1438 * Upon completion, the callback function @b cb is called with flags indicating that the
1439 * IO has completed (OCS_SCSI_IO_COMPL) and another data phase or response may be sent;
1440 * that the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP);
1441 * or that the IO was aborted (OCS_SCSI_IO_ABORTED).
1443 * @param io Pointer to the IO context.
1444 * @param flags Flags controlling the sending of data.
1445 * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
1446 * @param sgl Pointer to the payload scatter-gather list.
1447 * @param sgl_count Count of the scatter-gather list elements.
1448 * @param xwire_len Length of the payload on wire, in bytes.
1449 * @param type HW IO type.
1450 * @param enable_ar Enable auto-response if true.
1451 * @param cb Completion callback.
1452 * @param arg Application-supplied callback data.
1454 * @return Returns 0 on success, or a negative error code value on failure.
1457 static inline int32_t
1458 ocs_scsi_xfer_data(ocs_io_t *io, uint32_t flags,
1459 ocs_scsi_dif_info_t *dif_info,
1460 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t xwire_len,
1461 ocs_hw_io_type_e type, int enable_ar,
1462 ocs_scsi_io_cb_t cb, void *arg)
1466 uint32_t disable_ar_tgt_dif = FALSE;
1467 size_t residual = 0;
1469 if ((dif_info != NULL) && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) {
1475 if (dif_info != NULL) {
1476 ocs_hw_get(&io->ocs->hw, OCS_HW_DISABLE_AR_TGT_DIF, &disable_ar_tgt_dif);
1477 if (disable_ar_tgt_dif) {
1482 io->sgl_count = sgl_count;
1484 /* If needed, copy SGL */
1485 if (sgl && (sgl != io->sgl)) {
1486 ocs_assert(sgl_count <= io->sgl_allocated, -1);
1487 ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl));
1491 ocs_assert(ocs, -1);
1492 ocs_assert(io->node, -1);
1494 scsi_io_trace(io, "%s wire_len %d\n", (type == OCS_HW_IO_TARGET_READ) ? "send" : "recv", xwire_len);
1496 ocs_assert(sgl, -1);
1497 ocs_assert(sgl_count > 0, -1);
1498 ocs_assert(io->exp_xfer_len > io->transferred, -1);
1500 io->hio_type = type;
1502 io->scsi_tgt_cb = cb;
1503 io->scsi_tgt_cb_arg = arg;
1505 rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
1510 /* If DIF is used, then save lba for error recovery */
1512 io->scsi_dif_info = *dif_info;
1515 io->wire_len = MIN(xwire_len, io->exp_xfer_len - io->transferred);
1516 residual = (xwire_len - io->wire_len);
1518 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1519 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1520 io->iparam.fcp_tgt.offset = io->transferred;
1521 io->iparam.fcp_tgt.dif_oper = io->hw_dif.dif;
1522 io->iparam.fcp_tgt.blk_size = io->hw_dif.blk_size;
1523 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1524 io->iparam.fcp_tgt.timeout = io->timeout;
1526 /* if this is the last data phase and there is no residual, enable
1527 * auto-good-response
1529 if (enable_ar && (flags & OCS_SCSI_LAST_DATAPHASE) &&
1530 (residual == 0) && ((io->transferred + io->wire_len) == io->exp_xfer_len) && (!(flags & OCS_SCSI_NO_AUTO_RESPONSE))) {
1531 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
1532 io->auto_resp = TRUE;
1534 io->auto_resp = FALSE;
1537 /* save this transfer length */
1538 io->xfer_req = io->wire_len;
1540 /* Adjust the transferred count to account for overrun
1541 * when the residual is calculated in ocs_scsi_send_resp
1543 io->transferred += residual;
1545 /* Adjust the SGL size if there is overrun */
1548 ocs_scsi_sgl_t *sgl_ptr = &io->sgl[sgl_count-1];
1551 size_t len = sgl_ptr->len;
1552 if ( len > residual) {
1553 sgl_ptr->len = len - residual;
1564 /* Set latency and WQ steering */
1565 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
1566 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
1567 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
1569 return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1573 ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags,
1574 ocs_scsi_dif_info_t *dif_info,
1575 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
1576 ocs_scsi_io_cb_t cb, void *arg)
1578 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_READ,
1579 enable_tsend_auto_resp(io->ocs), cb, arg);
1583 ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags,
1584 ocs_scsi_dif_info_t *dif_info,
1585 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
1586 ocs_scsi_io_cb_t cb, void *arg)
1588 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_WRITE,
1589 enable_treceive_auto_resp(io->ocs), cb, arg);
1593 * @ingroup scsi_api_base
1594 * @brief Free overflow SGL.
1597 * Free the overflow SGL if it is present.
1599 * @param io Pointer to IO object.
1604 ocs_scsi_io_free_ovfl(ocs_io_t *io) {
1605 if (io->ovfl_sgl.size) {
1606 ocs_dma_free(io->ocs, &io->ovfl_sgl);
1611 * @ingroup scsi_api_base
1612 * @brief Send response data.
1615 * This function is used by a target-server to send the SCSI response data to a remote
1616 * initiator node. The target-server populates the @c ocs_scsi_cmd_resp_t
1617 * argument with scsi status, status qualifier, sense data, and response data, as
1620 * Upon completion, the callback function @c cb is invoked. The target-server will generally
1621 * clean up its IO context resources and call ocs_scsi_io_complete().
1623 * @param io Pointer to the IO context.
1624 * @param flags Flags to control sending of the SCSI response.
1625 * @param rsp Pointer to the response data populated by the caller.
1626 * @param cb Completion callback.
1627 * @param arg Application-specified completion callback argument.
1629 * @return Returns 0 on success, or a negative error code value on failure.
1632 ocs_scsi_send_resp(ocs_io_t *io, uint32_t flags, ocs_scsi_cmd_resp_t *rsp, ocs_scsi_io_cb_t cb, void *arg)
1636 int auto_resp = TRUE; /* Always try auto resp */
1637 uint8_t scsi_status = 0;
1638 uint16_t scsi_status_qualifier = 0;
1639 uint8_t *sense_data = NULL;
1640 uint32_t sense_data_length = 0;
1645 ocs_assert(ocs, -1);
1647 ocs_assert(io->node, -1);
1649 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
1652 scsi_status = rsp->scsi_status;
1653 scsi_status_qualifier = rsp->scsi_status_qualifier;
1654 sense_data = rsp->sense_data;
1655 sense_data_length = rsp->sense_data_length;
1656 residual = rsp->residual;
1658 residual = io->exp_xfer_len - io->transferred;
1662 io->hio_type = OCS_HW_IO_TARGET_RSP;
1664 io->scsi_tgt_cb = cb;
1665 io->scsi_tgt_cb_arg = arg;
1667 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1668 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1669 io->iparam.fcp_tgt.offset = 0;
1670 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1671 io->iparam.fcp_tgt.timeout = io->timeout;
1673 /* Set low latency queueing request */
1674 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
1675 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
1676 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
1678 if ((scsi_status != 0) || residual || sense_data_length) {
1679 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
1682 ocs_log_err(ocs, "NULL response buffer\n");
1688 ocs_memset(fcprsp, 0, sizeof(*fcprsp));
1690 io->wire_len += (sizeof(*fcprsp) - sizeof(fcprsp->data));
1692 fcprsp->scsi_status = scsi_status;
1693 *((uint16_t*)fcprsp->status_qualifier) = ocs_htobe16(scsi_status_qualifier);
1695 /* set residual status if necessary */
1696 if (residual != 0) {
1697 /* FCP: if data transferred is less than the amount expected, then this is an
1698 * underflow. If data transferred would have been greater than the amount expected
1699 * then this is an overflow
1702 fcprsp->flags |= FCP_RESID_UNDER;
1703 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(residual);
1705 fcprsp->flags |= FCP_RESID_OVER;
1706 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(-residual);
1710 if (sense_data && sense_data_length) {
1711 ocs_assert(sense_data_length <= sizeof(fcprsp->data), -1);
1712 fcprsp->flags |= FCP_SNS_LEN_VALID;
1713 ocs_memcpy(fcprsp->data, sense_data, sense_data_length);
1714 *((uint32_t*)fcprsp->fcp_sns_len) = ocs_htobe32(sense_data_length);
1715 io->wire_len += sense_data_length;
1718 io->sgl[0].addr = io->rspbuf.phys;
1719 io->sgl[0].dif_addr = 0;
1720 io->sgl[0].len = io->wire_len;
1725 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
1728 return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1732 * @ingroup scsi_api_base
1733 * @brief Send TMF response data.
1736 * This function is used by a target-server to send SCSI TMF response data to a remote
1738 * Upon completion, the callback function @c cb is invoked. The target-server will generally
1739 * clean up its IO context resources and call ocs_scsi_io_complete().
1741 * @param io Pointer to the IO context.
1742 * @param rspcode TMF response code.
1743 * @param addl_rsp_info Additional TMF response information (may be NULL for zero data).
1744 * @param cb Completion callback.
1745 * @param arg Application-specified completion callback argument.
1747 * @return Returns 0 on success, or a negative error code value on failure.
1750 ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3],
1751 ocs_scsi_io_cb_t cb, void *arg)
1755 fcp_rsp_iu_t *fcprsp = NULL;
1756 fcp_rsp_info_t *rspinfo = NULL;
1757 uint8_t fcp_rspcode;
1760 ocs_assert(io->ocs, -1);
1761 ocs_assert(io->node, -1);
1766 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
1769 case OCS_SCSI_TMF_FUNCTION_COMPLETE:
1770 fcp_rspcode = FCP_TMF_COMPLETE;
1772 case OCS_SCSI_TMF_FUNCTION_SUCCEEDED:
1773 case OCS_SCSI_TMF_FUNCTION_IO_NOT_FOUND:
1774 fcp_rspcode = FCP_TMF_SUCCEEDED;
1776 case OCS_SCSI_TMF_FUNCTION_REJECTED:
1777 fcp_rspcode = FCP_TMF_REJECTED;
1779 case OCS_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER:
1780 fcp_rspcode = FCP_TMF_INCORRECT_LUN;
1782 case OCS_SCSI_TMF_SERVICE_DELIVERY:
1783 fcp_rspcode = FCP_TMF_FAILED;
1786 fcp_rspcode = FCP_TMF_REJECTED;
1790 io->hio_type = OCS_HW_IO_TARGET_RSP;
1792 io->scsi_tgt_cb = cb;
1793 io->scsi_tgt_cb_arg = arg;
1795 if (io->tmf_cmd == OCS_SCSI_TMF_ABORT_TASK) {
1796 rc = ocs_target_send_bls_resp(io, cb, arg);
1800 /* populate the FCP TMF response */
1801 fcprsp = io->rspbuf.virt;
1802 ocs_memset(fcprsp, 0, sizeof(*fcprsp));
1804 fcprsp->flags |= FCP_RSP_LEN_VALID;
1806 rspinfo = (fcp_rsp_info_t*) fcprsp->data;
1807 if (addl_rsp_info != NULL) {
1808 ocs_memcpy(rspinfo->addl_rsp_info, addl_rsp_info, sizeof(rspinfo->addl_rsp_info));
1810 rspinfo->rsp_code = fcp_rspcode;
1812 io->wire_len = sizeof(*fcprsp) - sizeof(fcprsp->data) + sizeof(*rspinfo);
1814 *((uint32_t*)fcprsp->fcp_rsp_len) = ocs_htobe32(sizeof(*rspinfo));
1816 io->sgl[0].addr = io->rspbuf.phys;
1817 io->sgl[0].dif_addr = 0;
1818 io->sgl[0].len = io->wire_len;
1821 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1822 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1823 io->iparam.fcp_tgt.offset = 0;
1824 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1825 io->iparam.fcp_tgt.timeout = io->timeout;
1827 rc = ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1833 * @brief Process target abort callback.
1836 * Accepts HW abort requests.
1838 * @param hio HW IO context.
1839 * @param rnode Remote node.
1840 * @param length Length of response data.
1841 * @param status Completion status.
1842 * @param ext_status Extended completion status.
1843 * @param app Application-specified callback data.
1845 * @return Returns 0 on success, or a negative error code value on failure.
1849 ocs_target_abort_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
1853 ocs_scsi_io_status_e scsi_status;
1856 ocs_assert(io->ocs, -1);
1861 ocs_scsi_io_cb_t abort_cb = io->abort_cb;
1862 void *abort_cb_arg = io->abort_cb_arg;
1864 io->abort_cb = NULL;
1865 io->abort_cb_arg = NULL;
1868 case SLI4_FC_WCQE_STATUS_SUCCESS:
1869 scsi_status = OCS_SCSI_STATUS_GOOD;
1871 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
1872 switch (ext_status) {
1873 case SLI4_FC_LOCAL_REJECT_NO_XRI:
1874 scsi_status = OCS_SCSI_STATUS_NO_IO;
1876 case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS:
1877 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
1880 /* TODO: we have seen 0x15 (abort in progress) */
1881 scsi_status = OCS_SCSI_STATUS_ERROR;
1885 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
1886 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
1889 scsi_status = OCS_SCSI_STATUS_ERROR;
1892 /* invoke callback */
1893 abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg);
1896 ocs_assert(io != io->io_to_abort, -1);
1898 /* done with IO to abort */
1899 ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_tgt_abort_io() */
1901 ocs_io_free(ocs, io);
1903 ocs_scsi_check_pending(ocs);
1908 * @ingroup scsi_api_base
1909 * @brief Abort a target IO.
1912 * This routine is called from a SCSI target-server. It initiates an abort of a
1913 * previously-issued target data phase or response request.
1915 * @param io IO context.
1916 * @param cb SCSI target server callback.
1917 * @param arg SCSI target server supplied callback argument.
1919 * @return Returns 0 on success, or a non-zero value on failure.
1922 ocs_scsi_tgt_abort_io(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
1928 ocs_io_t *abort_io = NULL;
1930 ocs_assert(io->node, -1);
1931 ocs_assert(io->ocs, -1);
1936 /* take a reference on IO being aborted */
1937 if ((ocs_ref_get_unless_zero(&io->ref) == 0)) {
1938 /* command no longer active */
1939 scsi_io_printf(io, "command no longer active\n");
1944 * allocate a new IO to send the abort request. Use ocs_io_alloc() directly, as
1945 * we need an IO object that will not fail allocation due to allocations being
1946 * disabled (in ocs_scsi_io_alloc())
1948 abort_io = ocs_io_alloc(ocs);
1949 if (abort_io == NULL) {
1950 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
1951 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
1955 /* Save the target server callback and argument */
1956 ocs_assert(abort_io->hio == NULL, -1);
1958 /* set generic fields */
1959 abort_io->cmd_tgt = TRUE;
1960 abort_io->node = io->node;
1962 /* set type and abort-specific fields */
1963 abort_io->io_type = OCS_IO_TYPE_ABORT;
1964 abort_io->display_name = "tgt_abort";
1965 abort_io->io_to_abort = io;
1966 abort_io->send_abts = FALSE;
1967 abort_io->abort_cb = cb;
1968 abort_io->abort_cb_arg = arg;
1970 /* now dispatch IO */
1971 rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_target_abort_cb);
1973 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
1979 * @brief Process target BLS response callback.
1982 * Accepts HW abort requests.
1984 * @param hio HW IO context.
1985 * @param rnode Remote node.
1986 * @param length Length of response data.
1987 * @param status Completion status.
1988 * @param ext_status Extended completion status.
1989 * @param app Application-specified callback data.
1991 * @return Returns 0 on success, or a negative error code value on failure.
1995 ocs_target_bls_resp_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
1999 ocs_scsi_io_status_e bls_status;
2002 ocs_assert(io->ocs, -1);
2006 /* BLS isn't really a "SCSI" concept, but use SCSI status */
2008 io_error_log(io, "s=%#x x=%#x\n", status, ext_status);
2009 bls_status = OCS_SCSI_STATUS_ERROR;
2011 bls_status = OCS_SCSI_STATUS_GOOD;
2015 ocs_scsi_io_cb_t bls_cb = io->bls_cb;
2016 void *bls_cb_arg = io->bls_cb_arg;
2019 io->bls_cb_arg = NULL;
2021 /* invoke callback */
2022 bls_cb(io, bls_status, 0, bls_cb_arg);
2025 ocs_scsi_check_pending(ocs);
2030 * @brief Complete abort request.
2033 * An abort request is completed by posting a BA_ACC for the IO that requested the abort.
2035 * @param io Pointer to the IO context.
2036 * @param cb Callback function to invoke upon completion.
2037 * @param arg Application-specified completion callback argument.
2039 * @return Returns 0 on success, or a negative error code value on failure.
2043 ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
2046 fc_ba_acc_payload_t *acc;
2050 /* fill out IO structure with everything needed to send BA_ACC */
2051 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
2052 io->iparam.bls.ox_id = io->init_task_tag;
2053 io->iparam.bls.rx_id = io->abort_rx_id;
2055 acc = (void *)io->iparam.bls.payload;
2057 ocs_memset(io->iparam.bls.payload, 0, sizeof(io->iparam.bls.payload));
2058 acc->ox_id = io->iparam.bls.ox_id;
2059 acc->rx_id = io->iparam.bls.rx_id;
2060 acc->high_seq_cnt = UINT16_MAX;
2062 /* generic io fields have already been populated */
2064 /* set type and BLS-specific fields */
2065 io->io_type = OCS_IO_TYPE_BLS_RESP;
2066 io->display_name = "bls_rsp";
2067 io->hio_type = OCS_HW_BLS_ACC;
2069 io->bls_cb_arg = arg;
2072 rc = ocs_scsi_io_dispatch(io, ocs_target_bls_resp_cb);
2077 * @ingroup scsi_api_base
2078 * @brief Notify the base driver that the IO is complete.
2081 * This function is called by a target-server to notify the base driver that an IO
2082 * has completed, allowing for the base driver to free resources.
2084 * @n @b Note: This function is not called by initiator-clients.
2086 * @param io Pointer to IO context.
2091 ocs_scsi_io_complete(ocs_io_t *io)
2095 if (!ocs_io_busy(io)) {
2096 ocs_log_test(io->ocs, "Got completion for non-busy io with tag 0x%x\n", io->tag);
2100 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
2101 ocs_assert(ocs_ref_read_count(&io->ref) > 0);
2102 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
2106 * @brief Handle initiator IO completion.
2109 * This callback is made upon completion of an initiator operation (initiator read/write command).
2111 * @param hio HW IO context.
2112 * @param rnode Remote node.
2113 * @param length Length of completion data.
2114 * @param status Completion status.
2115 * @param ext_status Extended completion status.
2116 * @param app Application-specified callback data.
2122 ocs_initiator_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
2123 int32_t status, uint32_t ext_status, void *app)
2127 ocs_scsi_io_status_e scsi_status;
2130 ocs_assert(io->scsi_ini_cb);
2132 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
2137 ocs_scsi_io_free_ovfl(io);
2139 /* Call target server completion */
2140 if (io->scsi_ini_cb) {
2141 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
2142 ocs_scsi_cmd_resp_t rsp;
2143 ocs_scsi_rsp_io_cb_t cb = io->scsi_ini_cb;
2145 uint8_t *pd = fcprsp->data;
2147 /* Clear the callback before invoking the callback */
2148 io->scsi_ini_cb = NULL;
2150 ocs_memset(&rsp, 0, sizeof(rsp));
2152 /* Unless status is FCP_RSP_FAILURE, fcprsp is not filled in */
2154 case SLI4_FC_WCQE_STATUS_SUCCESS:
2155 scsi_status = OCS_SCSI_STATUS_GOOD;
2157 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
2158 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
2159 rsp.scsi_status = fcprsp->scsi_status;
2160 rsp.scsi_status_qualifier = ocs_be16toh(*((uint16_t*)fcprsp->status_qualifier));
2162 if (fcprsp->flags & FCP_RSP_LEN_VALID) {
2163 rsp.response_data = pd;
2164 rsp.response_data_length = ocs_fc_getbe32(fcprsp->fcp_rsp_len);
2165 pd += rsp.response_data_length;
2167 if (fcprsp->flags & FCP_SNS_LEN_VALID) {
2168 uint32_t sns_len = ocs_fc_getbe32(fcprsp->fcp_sns_len);
2169 rsp.sense_data = pd;
2170 rsp.sense_data_length = sns_len;
2174 if (fcprsp->flags & FCP_RESID_OVER) {
2175 rsp.residual = -ocs_fc_getbe32(fcprsp->fcp_resid);
2176 rsp.response_wire_length = length;
2177 } else if (fcprsp->flags & FCP_RESID_UNDER) {
2178 rsp.residual = ocs_fc_getbe32(fcprsp->fcp_resid);
2179 rsp.response_wire_length = length;
2183 * Note: The FCP_RSP_FAILURE can be returned for initiator IOs when the total data
2184 * placed does not match the requested length even if the status is good. If
2185 * the status is all zeroes, then we have to assume that a frame(s) were
2186 * dropped and change the status to LOCAL_REJECT/OUT_OF_ORDER_DATA
2188 if (length != io->wire_len) {
2189 uint32_t rsp_len = ext_status;
2190 uint8_t *rsp_bytes = io->rspbuf.virt;
2192 uint8_t all_zeroes = (rsp_len > 0);
2193 /* Check if the rsp is zero */
2194 for (i = 0; i < rsp_len; i++) {
2195 if (rsp_bytes[i] != 0) {
2201 scsi_status = OCS_SCSI_STATUS_ERROR;
2202 ocs_log_test(io->ocs, "[%s]" SCSI_IOFMT "local reject=0x%02x\n",
2203 io->node->display_name, SCSI_IOFMT_ARGS(io),
2204 SLI4_FC_LOCAL_REJECT_OUT_OF_ORDER_DATA);
2208 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
2209 if (ext_status == SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT) {
2210 scsi_status = OCS_SCSI_STATUS_COMMAND_TIMEOUT;
2212 scsi_status = OCS_SCSI_STATUS_ERROR;
2215 case SLI4_FC_WCQE_STATUS_DI_ERROR:
2216 if (ext_status & 0x01) {
2217 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
2218 } else if (ext_status & 0x02) {
2219 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
2220 } else if (ext_status & 0x04) {
2221 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
2223 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
2227 scsi_status = OCS_SCSI_STATUS_ERROR;
2231 cb(io, scsi_status, &rsp, flags, io->scsi_ini_cb_arg);
2233 ocs_scsi_check_pending(ocs);
2237 * @ingroup scsi_api_base
2238 * @brief Initiate initiator read IO.
2241 * This call is made by an initiator-client to send a SCSI read command. The payload
2242 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2245 * Upon completion, the callback @b cb is invoked and passed request status.
2246 * If the command completed successfully, the callback is given SCSI response data.
2248 * @param node Pointer to the node.
2249 * @param io Pointer to the IO context.
2250 * @param lun LUN value.
2251 * @param cdb Pointer to the CDB.
2252 * @param cdb_len Length of the CDB.
2253 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2254 * @param sgl Pointer to the scatter-gather list.
2255 * @param sgl_count Count of the scatter-gather list elements.
2256 * @param wire_len Length of the payload.
2257 * @param cb Completion callback.
2258 * @param arg Application-specified completion callback argument.
2260 * @return Returns 0 on success, or a negative error code value on failure.
2263 ocs_scsi_send_rd_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2264 ocs_scsi_dif_info_t *dif_info,
2265 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
2266 ocs_scsi_rsp_io_cb_t cb, void *arg)
2270 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2271 wire_len, 0, cb, arg);
2277 * @ingroup scsi_api_base
2278 * @brief Initiate initiator write IO.
2281 * This call is made by an initiator-client to send a SCSI write command. The payload
2282 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2285 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2286 * completed successfully, the callback is given SCSI response data.
2288 * @param node Pointer to the node.
2289 * @param io Pointer to IO context.
2290 * @param lun LUN value.
2291 * @param cdb Pointer to the CDB.
2292 * @param cdb_len Length of the CDB.
2293 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2294 * @param sgl Pointer to the scatter-gather list.
2295 * @param sgl_count Count of the scatter-gather list elements.
2296 * @param wire_len Length of the payload.
2297 * @param cb Completion callback.
2298 * @param arg Application-specified completion callback argument.
2300 * @return Returns 0 on success, or a negative error code value on failure.
2302 int32_t ocs_scsi_send_wr_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2303 ocs_scsi_dif_info_t *dif_info,
2304 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
2305 ocs_scsi_rsp_io_cb_t cb, void *arg)
2309 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2310 wire_len, 0, cb, arg);
2316 * @ingroup scsi_api_base
2317 * @brief Initiate initiator write IO.
2320 * This call is made by an initiator-client to send a SCSI write command. The payload
2321 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2324 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2325 * completed successfully, the callback is given SCSI response data.
2327 * @param node Pointer to the node.
2328 * @param io Pointer to IO context.
2329 * @param lun LUN value.
2330 * @param cdb Pointer to the CDB.
2331 * @param cdb_len Length of the CDB.
2332 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2333 * @param sgl Pointer to the scatter-gather list.
2334 * @param sgl_count Count of the scatter-gather list elements.
2335 * @param wire_len Length of the payload.
2336 * @param first_burst Number of first burst bytes to send.
2337 * @param cb Completion callback.
2338 * @param arg Application-specified completion callback argument.
2340 * @return Returns 0 on success, or a negative error code value on failure.
2343 ocs_scsi_send_wr_io_first_burst(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2344 ocs_scsi_dif_info_t *dif_info,
2345 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
2346 ocs_scsi_rsp_io_cb_t cb, void *arg)
2350 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2351 wire_len, 0, cb, arg);
2357 * @ingroup scsi_api_base
2358 * @brief Initiate initiator SCSI command with no data.
2361 * This call is made by an initiator-client to send a SCSI command with no data.
2363 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2364 * completed successfully, the callback is given SCSI response data.
2366 * @param node Pointer to the node.
2367 * @param io Pointer to the IO context.
2368 * @param lun LUN value.
2369 * @param cdb Pointer to the CDB.
2370 * @param cdb_len Length of the CDB.
2371 * @param cb Completion callback.
2372 * @param arg Application-specified completion callback argument.
2374 * @return Returns 0 on success, or a negative error code value on failure.
2376 int32_t ocs_scsi_send_nodata_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2377 ocs_scsi_rsp_io_cb_t cb, void *arg)
2381 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_NODATA, node, io, lun, 0, cdb, cdb_len, NULL, NULL, 0, 0, 0, cb, arg);
2386 * @ingroup scsi_api_base
2387 * @brief Initiate initiator task management operation.
2390 * This command is used to send a SCSI task management function command. If the command
2391 * requires it (QUERY_TASK_SET for example), a payload may be associated with the command.
2392 * If no payload is required, then @c sgl_count may be zero and @c sgl is ignored.
2394 * Upon completion @c cb is invoked with status and SCSI response data.
2396 * @param node Pointer to the node.
2397 * @param io Pointer to the IO context.
2398 * @param io_to_abort Pointer to the IO context to abort in the
2399 * case of OCS_SCSI_TMF_ABORT_TASK. Note: this can point to the
2400 * same the same ocs_io_t as @c io, provided that @c io does not
2401 * have any outstanding work requests.
2402 * @param lun LUN value.
2403 * @param tmf Task management command.
2404 * @param sgl Pointer to the scatter-gather list.
2405 * @param sgl_count Count of the scatter-gather list elements.
2406 * @param len Length of the payload.
2407 * @param cb Completion callback.
2408 * @param arg Application-specified completion callback argument.
2410 * @return Returns 0 on success, or a negative error code value on failure.
2413 ocs_scsi_send_tmf(ocs_node_t *node, ocs_io_t *io, ocs_io_t *io_to_abort, uint64_t lun, ocs_scsi_tmf_cmd_e tmf,
2414 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg)
2419 if (tmf == OCS_SCSI_TMF_ABORT_TASK) {
2420 ocs_assert(io_to_abort, -1);
2422 /* take a reference on IO being aborted */
2423 if ((ocs_ref_get_unless_zero(&io_to_abort->ref) == 0)) {
2424 /* command no longer active */
2425 scsi_io_printf(io, "command no longer active\n");
2428 /* generic io fields have already been populated */
2430 /* abort-specific fields */
2431 io->io_type = OCS_IO_TYPE_ABORT;
2432 io->display_name = "abort_task";
2433 io->io_to_abort = io_to_abort;
2434 io->send_abts = TRUE;
2435 io->scsi_ini_cb = cb;
2436 io->scsi_ini_cb_arg = arg;
2438 /* now dispatch IO */
2439 rc = ocs_scsi_io_dispatch_abort(io, ocs_scsi_abort_io_cb);
2441 scsi_io_printf(io, "Failed to dispatch abort\n");
2442 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
2445 io->display_name = "tmf";
2446 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, tmf, NULL, 0, NULL,
2447 sgl, sgl_count, len, 0, cb, arg);
2454 * @ingroup scsi_api_base
2455 * @brief Send an FCP IO.
2458 * An FCP read/write IO command, with optional task management flags, is sent to @c node.
2460 * @param type HW IO type to send.
2461 * @param node Pointer to the node destination of the IO.
2462 * @param io Pointer to the IO context.
2463 * @param lun LUN value.
2464 * @param tmf Task management command.
2465 * @param cdb Pointer to the SCSI CDB.
2466 * @param cdb_len Length of the CDB, in bytes.
2467 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2468 * @param sgl Pointer to the scatter-gather list.
2469 * @param sgl_count Number of SGL entries in SGL.
2470 * @param wire_len Payload length, in bytes, of data on wire.
2471 * @param first_burst Number of first burst bytes to send.
2472 * @param cb Completion callback.
2473 * @param arg Application-specified completion callback argument.
2475 * @return Returns 0 on success, or a negative error code value on failure.
2478 /* tc: could elminiate LUN, as it's part of the IO structure */
2480 static int32_t ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
2481 ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
2482 ocs_scsi_dif_info_t *dif_info,
2483 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
2484 ocs_scsi_rsp_io_cb_t cb, void *arg)
2488 fcp_cmnd_iu_t *cmnd;
2489 uint32_t cmnd_bytes = 0;
2491 uint8_t tmf_flags = 0;
2493 ocs_assert(io->node, -1);
2494 ocs_assert(io->node == node, -1);
2499 io->sgl_count = sgl_count;
2501 /* Copy SGL if needed */
2502 if (sgl != io->sgl) {
2503 ocs_assert(sgl_count <= io->sgl_allocated, -1);
2504 ocs_memcpy(io->sgl, sgl, sizeof(*io->sgl) * sgl_count);
2507 /* save initiator and target task tags for debugging */
2508 io->tgt_task_tag = 0xffff;
2510 io->wire_len = wire_len;
2511 io->hio_type = type;
2513 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
2515 ocs_textbuf_t txtbuf;
2518 ocs_textbuf_init(ocs, &txtbuf, buf, sizeof(buf));
2520 ocs_textbuf_printf(&txtbuf, "cdb%d: ", cdb_len);
2521 for (i = 0; i < cdb_len; i ++) {
2522 ocs_textbuf_printf(&txtbuf, "%02X%s", cdb[i], (i == (cdb_len-1)) ? "" : " ");
2524 scsi_io_printf(io, "%s len %d, %s\n", (io->hio_type == OCS_HW_IO_INITIATOR_READ) ? "read" :
2525 (io->hio_type == OCS_HW_IO_INITIATOR_WRITE) ? "write" : "", io->wire_len,
2526 ocs_textbuf_get_buffer(&txtbuf));
2529 ocs_assert(io->cmdbuf.virt, -1);
2531 cmnd = io->cmdbuf.virt;
2533 ocs_assert(sizeof(*cmnd) <= io->cmdbuf.size, -1);
2535 ocs_memset(cmnd, 0, sizeof(*cmnd));
2537 /* Default FCP_CMND IU doesn't include additional CDB bytes but does include FCP_DL */
2538 cmnd_bytes = sizeof(fcp_cmnd_iu_t) - sizeof(cmnd->fcp_cdb_and_dl) + sizeof(uint32_t);
2540 fcp_dl = (uint32_t*)(&(cmnd->fcp_cdb_and_dl));
2543 if (cdb_len <= 16) {
2544 ocs_memcpy(cmnd->fcp_cdb, cdb, cdb_len);
2546 uint32_t addl_cdb_bytes;
2548 ocs_memcpy(cmnd->fcp_cdb, cdb, 16);
2549 addl_cdb_bytes = cdb_len - 16;
2550 ocs_memcpy(cmnd->fcp_cdb_and_dl, &(cdb[16]), addl_cdb_bytes);
2551 /* additional_fcp_cdb_length is in words, not bytes */
2552 cmnd->additional_fcp_cdb_length = (addl_cdb_bytes + 3) / 4;
2553 fcp_dl += cmnd->additional_fcp_cdb_length;
2555 /* Round up additional CDB bytes */
2556 cmnd_bytes += (addl_cdb_bytes + 3) & ~0x3;
2560 be64enc(cmnd->fcp_lun, CAM_EXTLUN_BYTE_SWIZZLE(lun));
2562 if (node->fcp2device) {
2563 if(ocs_get_crn(node, &cmnd->command_reference_number,
2570 case OCS_SCSI_TMF_QUERY_TASK_SET:
2571 tmf_flags = FCP_QUERY_TASK_SET;
2573 case OCS_SCSI_TMF_ABORT_TASK_SET:
2574 tmf_flags = FCP_ABORT_TASK_SET;
2576 case OCS_SCSI_TMF_CLEAR_TASK_SET:
2577 tmf_flags = FCP_CLEAR_TASK_SET;
2579 case OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
2580 tmf_flags = FCP_QUERY_ASYNCHRONOUS_EVENT;
2582 case OCS_SCSI_TMF_LOGICAL_UNIT_RESET:
2583 tmf_flags = FCP_LOGICAL_UNIT_RESET;
2585 case OCS_SCSI_TMF_CLEAR_ACA:
2586 tmf_flags = FCP_CLEAR_ACA;
2588 case OCS_SCSI_TMF_TARGET_RESET:
2589 tmf_flags = FCP_TARGET_RESET;
2594 cmnd->task_management_flags = tmf_flags;
2596 *fcp_dl = ocs_htobe32(io->wire_len);
2598 switch (io->hio_type) {
2599 case OCS_HW_IO_INITIATOR_READ:
2602 case OCS_HW_IO_INITIATOR_WRITE:
2605 case OCS_HW_IO_INITIATOR_NODATA:
2609 ocs_log_test(ocs, "bad IO type %d\n", io->hio_type);
2613 rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
2618 io->scsi_ini_cb = cb;
2619 io->scsi_ini_cb_arg = arg;
2621 /* set command and response buffers in the iparam */
2622 io->iparam.fcp_ini.cmnd = &io->cmdbuf;
2623 io->iparam.fcp_ini.cmnd_size = cmnd_bytes;
2624 io->iparam.fcp_ini.rsp = &io->rspbuf;
2625 io->iparam.fcp_ini.flags = 0;
2626 io->iparam.fcp_ini.dif_oper = io->hw_dif.dif;
2627 io->iparam.fcp_ini.blk_size = io->hw_dif.blk_size;
2628 io->iparam.fcp_ini.timeout = io->timeout;
2629 io->iparam.fcp_ini.first_burst = first_burst;
2631 return ocs_scsi_io_dispatch(io, ocs_initiator_io_cb);
2635 * @ingroup scsi_api_base
2636 * @brief Callback for an aborted IO.
2639 * Callback function invoked upon completion of an IO abort request.
2641 * @param hio HW IO context.
2642 * @param rnode Remote node.
2643 * @param len Response length.
2644 * @param status Completion status.
2645 * @param ext_status Extended completion status.
2646 * @param arg Application-specific callback, usually IO context.
2648 * @return Returns 0 on success, or a negative error code value on failure.
2652 ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
2653 uint32_t ext_status, void *arg)
2657 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
2660 ocs_assert(ocs_io_busy(io), -1);
2661 ocs_assert(io->ocs, -1);
2662 ocs_assert(io->io_to_abort, -1);
2665 ocs_log_debug(ocs, "status %d ext %d\n", status, ext_status);
2667 /* done with IO to abort */
2668 ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_send_tmf() */
2670 ocs_scsi_io_free_ovfl(io);
2673 case SLI4_FC_WCQE_STATUS_SUCCESS:
2674 scsi_status = OCS_SCSI_STATUS_GOOD;
2676 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
2677 if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED) {
2678 scsi_status = OCS_SCSI_STATUS_ABORTED;
2679 } else if (ext_status == SLI4_FC_LOCAL_REJECT_NO_XRI) {
2680 scsi_status = OCS_SCSI_STATUS_NO_IO;
2681 } else if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS) {
2682 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
2684 ocs_log_test(ocs, "Unhandled local reject 0x%x/0x%x\n", status, ext_status);
2685 scsi_status = OCS_SCSI_STATUS_ERROR;
2689 scsi_status = OCS_SCSI_STATUS_ERROR;
2693 if (io->scsi_ini_cb) {
2694 (*io->scsi_ini_cb)(io, scsi_status, NULL, 0, io->scsi_ini_cb_arg);
2696 ocs_scsi_io_free(io);
2699 ocs_scsi_check_pending(ocs);
2704 * @ingroup scsi_api_base
2705 * @brief Return SCSI API integer valued property.
2708 * This function is called by a target-server or initiator-client to
2709 * retrieve an integer valued property.
2711 * @param ocs Pointer to the ocs.
2712 * @param prop Property value to return.
2714 * @return Returns a value, or 0 if invalid property was requested.
2717 ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop)
2719 ocs_xport_t *xport = ocs->xport;
2723 case OCS_SCSI_MAX_SGE:
2724 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &val)) {
2728 case OCS_SCSI_MAX_SGL:
2729 if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
2731 * If chain SGL test-mode is enabled, the number of HW SGEs
2732 * has been limited; report back original max.
2734 return (OCS_FC_MAX_SGL);
2736 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &val)) {
2740 case OCS_SCSI_MAX_IOS:
2741 return ocs_io_pool_allocated(xport->io_pool);
2742 case OCS_SCSI_DIF_CAPABLE:
2743 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &val)) {
2747 case OCS_SCSI_MAX_FIRST_BURST:
2749 case OCS_SCSI_DIF_MULTI_SEPARATE:
2750 if (ocs_hw_get(&ocs->hw, OCS_HW_DIF_MULTI_SEPARATE, &val) == 0) {
2754 case OCS_SCSI_ENABLE_TASK_SET_FULL:
2755 /* Return FALSE if we are send frame capable */
2756 if (ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &val) == 0) {
2764 ocs_log_debug(ocs, "invalid property request %d\n", prop);
2769 * @ingroup scsi_api_base
2770 * @brief Return a property pointer.
2773 * This function is called by a target-server or initiator-client to
2774 * retrieve a pointer to the requested property.
2776 * @param ocs Pointer to the ocs.
2777 * @param prop Property value to return.
2779 * @return Returns pointer to the requested property, or NULL otherwise.
2781 void *ocs_scsi_get_property_ptr(ocs_t *ocs, ocs_scsi_property_e prop)
2787 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
2790 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
2792 case OCS_SCSI_PORTNUM:
2793 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_PORTNUM);
2795 case OCS_SCSI_BIOS_VERSION_STRING:
2796 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_BIOS_VERSION_STRING);
2798 #if defined(OCS_ENABLE_VPD_SUPPORT)
2799 case OCS_SCSI_SERIALNUMBER:
2804 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
2805 ocs_log_test(ocs, "Can't get VPD length\n");
2806 rc = "\012sn-unknown";
2810 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
2812 rc = ocs_find_vpd(pvpd, vpd_len, "SN");
2816 ocs_strlen(rc) == 0) {
2817 /* Note: VPD is missing, using wwnn for serial number */
2818 scsi_log(ocs, "Note: VPD is missing, using wwnn for serial number\n");
2819 /* Use the last 32 bits of the WWN */
2820 if ((ocs == NULL) || (ocs->domain == NULL) || (ocs->domain->sport == NULL)) {
2821 rc = "\011(Unknown)";
2823 rc = &ocs->domain->sport->wwnn_str[8];
2828 case OCS_SCSI_PARTNUMBER:
2833 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
2834 ocs_log_test(ocs, "Can't get VPD length\n");
2835 rc = "\012pn-unknown";
2838 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
2840 rc = ocs_find_vpd(pvpd, vpd_len, "PN");
2842 rc = "\012pn-unknown";
2845 rc = "\012pn-unknown";
2855 ocs_log_debug(ocs, "invalid property request %d\n", prop);
2861 * @ingroup scsi_api_base
2862 * @brief Notify that delete initiator is complete.
2865 * Sent by the target-server to notify the base driver that the work started from
2866 * ocs_scsi_del_initiator() is now complete and that it is safe for the node to
2867 * release the rest of its resources.
2869 * @param node Pointer to the node.
2874 ocs_scsi_del_initiator_complete(ocs_node_t *node)
2876 /* Notify the node to resume */
2877 ocs_node_post_event(node, OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
2881 * @ingroup scsi_api_base
2882 * @brief Notify that delete target is complete.
2885 * Sent by the initiator-client to notify the base driver that the work started from
2886 * ocs_scsi_del_target() is now complete and that it is safe for the node to
2887 * release the rest of its resources.
2889 * @param node Pointer to the node.
2894 ocs_scsi_del_target_complete(ocs_node_t *node)
2896 /* Notify the node to resume */
2897 ocs_node_post_event(node, OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
2901 * @brief Update transferred count
2904 * Updates io->transferred, as required when using first burst, when the amount
2905 * of first burst data processed differs from the amount of first burst
2908 * @param io Pointer to the io object.
2909 * @param transferred Number of bytes transferred out of first burst buffers.
2914 ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred)
2916 io->transferred = transferred;
2920 * @brief Register bounce callback for multi-threading.
2923 * Register the back end bounce function.
2925 * @param ocs Pointer to device object.
2926 * @param fctn Function pointer of bounce function.
2931 ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void(*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id,
2936 rc = ocs_hw_callback(&ocs->hw, OCS_HW_CB_BOUNCE, fctn, NULL);
2938 ocs_log_test(ocs, "ocs_hw_callback(OCS_HW_CB_BOUNCE) failed: %d\n", rc);