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