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