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