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