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