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