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