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 #include "ocs.h"
39 #include "ocs_iscsi_spec.h"
40 #include "ocs_vpd.h"
41 #include "sli4_iscsi.h"
42 #include "ocs_login.h"
43 #include "ocs_dif.h"
44 
45 static int32_t
46 ocs_scsi_build_sgls(ocs_hal_t *hal, ocs_io_t *io, ocs_hal_dif_info_t *hal_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hal_io_type_e type);
47 static int32_t
48 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info,
49  ocs_hal_dif_info_t *hal_dif_info);
50 static int32_t ocs_scsi_check_pending(ocs_t *ocs);
51 static int32_t ocs_scsi_io_dispatch_hal_io(ocs_io_t *io, ocs_hal_io_t *hio, uint8_t lock_held);
52 
53 /**
54  * @brief This function sends a target nop.
55  *
56  * @par Description
57  * This function sends a target nop, if it is not already active. We use this
58  * to ensure that the TCP ACK is complete before re-using the ICD.
59  *
60  * @param cxn Pointer to the connection object.
61  */
62 static void ocs_target_nop_check(ocs_cxn_t *cxn)
63 {
64  ocs_iscsi_t *iscsi = cxn->iscsi;
65  ocs_t *ocs = iscsi->os;
66 
67  /*
68  * We need to issue a NOP to force a TCP-ACK. Since the ICD is already
69  * started, just push the NOP down now.
70  */
71  if (cxn->cxn_state == CONN_STATE_FULL_FEATURE &&
72  !cxn->nop_sent_for_tm &&
73  !ocs_list_empty(&cxn->aborted_ios)) {
74  if (ocs_iscsi_send_nop_in(cxn,
75  ocs_be64toh(0),
76  0xffffffff,
77  0xffffffff, /* not a ping */
78  NULL,
79  0)) {
80  ocs_log_test(ocs, "sending nop-in failed\n");
81  } else {
82  cxn->nop_sent_for_tm = TRUE;
83  ocs_atomic_add_return(&cxn->nop_abort_counter, 1);
84  }
85  }
86 }
87 
88 /**
89  * @brief This function is called when an IO is aborted.
90  *
91  * @par Description
92  * We need to hold the IO until we receive a TCP ACK for a packet sent after
93  * this IO to ensure that the IO is available to be re-used. Hold this IO in
94  * the iSCSI transport to prevent it being re-used.
95  *
96  * @param io Pointer to the io object.
97  * @param cxn Pointer to the connection object.
98  */
99 static void ocs_target_io_aborted(ocs_io_t *io, ocs_cxn_t *cxn)
100 {
101  ocs_node_lock(cxn);
102  ocs_list_remove(&cxn->active_ios, io);
103  io->on_abort_list = 1;
104  io->nop_abort_counter = ocs_atomic_read(&cxn->nop_abort_counter);
105  ocs_list_add_tail(&cxn->aborted_ios, io);
106  ocs_node_unlock(cxn);
107 
109 }
110 
111 /**
112  * @brief This function is called whenever a target NOP completes.
113  *
114  * @par Description
115  * Once a TCP ACK is received, the NOP request completes. We can now free any
116  * aborted IOs and they are also TCP ACKed.
117  *
118  * @param cxn Pointer to the connection object.
119  */
120 void ocs_target_io_aborted_nop_cmpl(ocs_cxn_t *cxn)
121 {
122  ocs_iscsi_t *iscsi = cxn->iscsi;
123  ocs_io_t *io, *io_next;
124  uint32_t abort_counter;
125 
126  abort_counter = ocs_atomic_read(&cxn->nop_abort_counter);
127  ocs_node_lock(cxn);
128  ocs_list_foreach_safe(&cxn->aborted_ios, io, io_next) {
129  /*
130  * Note: This code relies on the fact that there is only 1
131  * target nop oustanding, so this should clear all IOs
132  * with a count less than the current value.
133  */
134  if (io->nop_abort_counter < abort_counter) {
135  if (io->scsi_io_cb) {
136 
137  ocs_scsi_io_cb_t cb = io->scsi_io_cb;
138  uint32_t flags = OCS_SCSI_IO_CMPL;
140 
141  /* Clear the callback before invoking the callback */
142  io->scsi_io_cb = NULL;
143 
144  io_trace(io, "IO completed with status 0x%x (flags 0x%x)\n",
145  cb_status, flags);
146  ocs_node_unlock(cxn);
147  cb(io, cb_status, flags, io->scsi_io_cb_arg);
148  ocs_node_lock(cxn);
149  }
150  }
151  }
152  ocs_node_unlock(cxn);
153 
155 }
156 
157 
158 /**
159  * @brief This function is the callback for a target IO.
160  *
161  * @param hio Pointer to the HAL io object.
162  * @param cxn Pointer to the connection object.
163  * @param status Status of the command.
164  * @param ini_fields Pointer to the initiator completion fields.
165  * @param ul_arg Points to the io object.
166  */
167 static int32_t ocs_target_io_cb(struct ocs_hal_io_s *hio,
168  ocs_cxn_t *cxn,
169  int32_t status,
170  ocs_ini_cmpl_fields_t *ini_fields,
171  void *ul_arg)
172 {
173  ocs_io_t *io = ul_arg;
174  ocs_iscsi_t *iscsi;
175  ocs_t *ocs;
176 
177  ocs_assert(io, -1);
178 
179  ocs = io->ocs;
180  ocs_assert(ocs, -1);
181  iscsi = &ocs->iscsi;
182  ocs_assert(iscsi, -1);
183 
184  if (!ocs_list_empty(&iscsi->login_retry_busy)) {
186  }
187 
188  /*
189  * Increment io->scsi_xxx_offset in case we are forced into multiple
190  * start calls because of the max number of SGLs we can handle.
191  */
192  io->scsi_mem_offset += (io->scsi_mem_xfer_size);
193  io->scsi_wire_offset += (io->scsi_wire_xfer_size);
194 
195  if (status == SLI_STATUS_HOST_CMD_INVALID_NOTIFY) {
196  ocs_target_io_aborted(io, cxn);
197  return 0;
198  }
199 
200  /* Call target server completion */
201  if (io->scsi_io_cb) {
202  ocs_scsi_io_cb_t cb = io->scsi_io_cb;
203  uint32_t flags = 0;
205 
206  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
207  cb_status = OCS_SCSI_STATUS_NEXUS_LOST;
208  } else if(status == SLI_STATUS_SOL_CMD_CMPL_NORMAL ||
209  status == SLI_STATUS_TCP_ACK_NOTIFY) {
210  cb_status = OCS_SCSI_STATUS_GOOD;
211 
212  /*
213  * If we send an unassisted response with good status,
214  * we must send the expected data SN. We do not receive
215  * this information from the firmware. So, calculate the
216  * data_SN sent for this phase based on the expected
217  * pdu size. For BE3 it should be 8K, for Skyhawk, it
218  * should the negotiated max receive data segment
219  * length (up to 64K).
220  */
221  if (io->is_read) {
222  uint32_t pdu_size = (iscsi->hal->sli.is_skyhawk ? cxn->max_xmit_dsl : 8192);
223 
224  if ((io->scsi_wire_xfer_size % pdu_size) > 0) {
225  io->data_sn += 1;
226  }
227  io->data_sn += (io->scsi_wire_xfer_size / pdu_size);
228  }
229  } else if (status == SLI_STATUS_DIF_ERROR) {
231  /* TODO - OCS_SCSI_STATUS_DIF_REF_TAG_ERROR &&
232  * OCS_SCSI_STATUS_DIF_APP_TAG_ERROR
233  */
234  } else if (status == SLI_STATUS_SOL_CMD_DATA_DIGEST_ERROR) {
236  }
237 
238  /* Clear the callback before invoking the callback */
239  io->scsi_io_cb = NULL;
240 
241  /* if status was good, and auto-good-response was set, then callback
242  * target-server with IO_CMPL_RSP_SENT, otherwise send IO_CMPL
243  */
244  if (cb_status == OCS_SCSI_STATUS_GOOD && io->auto_resp) {
245  flags |= OCS_SCSI_IO_CMPL_RSP_SENT;
246  } else {
247  flags |= OCS_SCSI_IO_CMPL;
248  }
249 
250  io_trace(io, "IO completed with status 0x%x (flags 0x%x)\n",
251  cb_status, flags);
252  cb(io, cb_status, flags, io->scsi_io_cb_arg);
253  }
254 
255  /* Signal IO completions to the state machine if we are cleaning up */
256  if (cxn != NULL && (cxn->cxn_state == CONN_STATE_CLEANUP ||
257  cxn->cxn_state == CONN_STATE_LOGOUT_REQUESTED)) {
258  ocs_sm_post_event(&cxn->sm, OCS_EVT_IO_CMPL, NULL);
259  }
260 
262  return 0;
263 }
264 
265 /**
266  * @brief This function logs the SGLs for an IO.
267  *
268  * @param io Pointer to IO context.
269  */
270 static void ocs_log_sgl(ocs_io_t *io)
271 {
272  sli4_sge_t *data = NULL;
273  uint32_t *dword = NULL;
274  ocs_hal_sgl_info_t *sgl_info;
275  uint32_t sgl_count;
276  uint32_t sgl_offset;
277 #if defined(OCS_INCLUDE_DEBUG)
278  ocs_t *ocs = io->ocs;
279  ocs_iscsi_t *iscsi = &ocs->iscsi;
280 #endif
281 
282  sgl_info = ocs_list_get_head(&io->hio->sgl_list);
283  sgl_count = 0;
284  sgl_offset = 0;
285  while (sgl_info != NULL &&
286  sgl_count < io->hio->n_sge) {
287  data = &((sli4_sge_t *)sgl_info->sgl)[sgl_offset];
288  dword = (uint32_t*)data;
289 
290  io_trace(io, "SGL %d 0x%08x 0x%08x 0x%08x 0x%08x",
291  sgl_count, dword[0], dword[1], dword[2], dword[3]);
292  sgl_count++;
293  sgl_offset++;
294  if (sgl_offset >= sgl_info->num_entries) {
295  sgl_info = ocs_list_next(&io->hio->sgl_list, sgl_info);
296  sgl_offset = 0;
297  if (sgl_info != NULL) {
298  io_trace(io, "Move to SGL ICD 0x%x", sgl_info->icd);
299  }
300  }
301  }
302 }
303 
304 /**
305  * @brief Check pending error asynchronous callback function/
306  *
307  * @par Description
308  * Invoke the HAL callback function for a given IO. This function is called
309  * from the NOP mailbox completion context.
310  *
311  * @param hal Pointer to HAL object.
312  * @param status Completion status.
313  * @param arg General purpose argument.
314  *
315  * @return Returns 0.
316  */
317 static int32_t
318 ocs_scsi_check_pending_async_cb(ocs_hal_t *hal, int32_t status, void *arg)
319 {
320  ocs_io_t *io = arg;
321 
322  if (io != NULL) {
323  if (io->hal_cb != NULL) {
324  io_cb_t *cb = io->hal_cb;
325 
326  io->hal_cb = NULL;
327  cb(io->hio, io->node, SLI_STATUS_DISPATCH_ERROR, NULL, io);
328  }
329  }
330  return 0;
331 }
332 
333 /**
334  * @brief Check for pending IOs to dispatch.
335  *
336  * @par Description
337  * If there are IOs on the pending list, and a HAL IO is available, then
338  * dispatch the IOs.
339  *
340  * @param ocs Pointer to the OCS structure.
341  *
342  * @return Returns 0 for success, or -1 if no IO could be dispatched.
343  */
344 
345 static int32_t
347 {
348  ocs_hal_t *hal = &ocs->hal;
349  ocs_io_t *io;
350  ocs_io_t *next;
351  ocs_hal_io_t *hio = NULL;
352  int32_t status;
353  int32_t rc = 0;
354 
355  /* Guard against recursion */
356  if (ocs_atomic_add_return(&ocs->io_pending_recursing, 1)) {
357  /* This function is already running, decrement and return. */
358  ocs_atomic_sub_return(&ocs->io_pending_recursing, 1);
359  return rc;
360  }
361 
362  /* Check the IO pending list */
363  ocs_device_lock(ocs);
364  for (;;) {
365  if (ocs_list_empty(&ocs->io_pending_list)) {
366  break;
367  }
368 
369  /* Allocate a HAL IO */
370  hio = ocs_hal_io_alloc(hal);
371  if (hio == NULL) {
372  break;
373  }
374 
375  /*
376  * Pop the next IO off the pending list that has space on the
377  * WQ and submit it
378  */
379  ocs_list_foreach_safe(&ocs->io_pending_list, io, next) {
380  if (ocs_hal_cxn_get_free_wq_cnt(hal, io->node) > 0) {
381  ocs_list_remove(&ocs->io_pending_list, io);
382  ocs_atomic_sub_return(&ocs->io_pending_count, 1);
383 
384  if ((io->cmd_tgt == 0) && (io->cmd_ini == 0)) {
385  ocs_log_err(ocs, "assertion failed: niether io->cmd_tgt nor io->cmd_ini set\n");
386  ocs_hal_io_free(hal, hio);
387  ocs_device_unlock(ocs);
388  ocs_atomic_sub_return(&ocs->io_pending_recursing, 1);
389  return -1;
390  }
391 
392  /*
393  * Because we can queue because of insufficent
394  * space on the WQ, there may already be an
395  * hio assigned.
396  */
397  if (io->hio == NULL) {
398  io->hio = hio;
399  hio = ocs_hal_io_alloc(hal);
400  }
401 
402  status = ocs_scsi_io_dispatch_hal_io(io, io->hio, TRUE);
403  if (status) {
404  /*
405  * Invoke the HAL callback, but do so in the separate execution context,
406  * provided by the NOP mailbox completion processing context by using
407  * ocs_hal_async_call()
408  */
410  ocs_log_test(ocs, "call to ocs_hal_async_call() failed\n");
411  }
412  }
413  if (hio == NULL) {
414  break;
415  }
416  }
417  } /* Pending list loop */
418 
419  if (hio != NULL) {
420  break;
421  }
422  } /* for (;;) */
423  ocs_device_unlock(ocs);
424 
425  /* If the hio was not used, then free it now. */
426  if (hio) {
427  ocs_hal_io_free(hal, hio);
428  }
429 
430  ocs_atomic_sub_return(&ocs->io_pending_recursing, 1);
431 
432  return rc;
433 }
434 
435 /**
436  * @brief Place an IO on the pending list to retry later when resources are
437  * available.
438  *
439  * @param ocs Pointer to the ocs structure.
440  * @param io Pointer to the IO structure.
441  * @param lock_held inform this function if the ocs lock is already held
442  */
443 static void
444 ocs_scsi_io_add_to_pending(ocs_t *ocs, ocs_io_t *io, uint8_t lock_held)
445 {
446  if (!lock_held) {
447  ocs_device_lock(ocs);
448  }
449  ocs_list_add_tail(&ocs->io_pending_list, io);
450  if (!lock_held) {
451  ocs_device_unlock(ocs);
452  }
453  ocs_atomic_add_return(&ocs->io_total_pending, 1);
454  ocs_atomic_add_return(&ocs->io_pending_count, 1);
455 }
456 
457 /**
458  * @brief Attempt to dispatch an IO.
459  *
460  * @par Description
461  * An IO is dispatched. The steps are as follows:
462  * 1. Try to allocate a HAL IO. If none is available, place this IO at the tail
463  * of the pending IO list.
464  * 2. With a HAL IO in hand, if there are IOs on the pending IO list, push this IO
465  * on the tail of the pending list and pop the head of the pending list.
466  * 3. Attach this IO to the HAL IO and submit it.
467  *
468  * @param io Pointer to IO structure.
469  * @param cb Callback function.
470  *
471  * @return Returns 0 for success, or a negative error code value for failure.
472  */
473 
474 int32_t
475 ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
476 {
477  ocs_hal_io_t *hio;
478  ocs_t *ocs = io->ocs;
479  ocs_cxn_t *cxn = io->node;
480  ocs_hal_t *hal = &ocs->hal;
481 
482  ocs_assert(io->cmd_tgt || io->cmd_ini, -1);
483 
484  io->hal_cb = cb;
485 
486  /* If the WQ for this IO is FULL, then put it on the pending list. */
487  if (ocs_hal_cxn_get_free_wq_cnt(hal, cxn) == 0) {
488  ocs_scsi_io_add_to_pending(ocs, io, FALSE);
489 
490  /*
491  * It is OK to return here, because anything already pended is
492  * either waiting for space on the WQ or a HAL IO. This function
493  * is called for either new IO or a pended IO with space on the
494  * WQ and the pended will ensure space before calling.
495  */
496  return 0;
497  }
498 
499  /*
500  * if this IO already has a HAL IO, then this is not the first phase of
501  * the IO. Send it to the HAL.
502  */
503  if (io->hio != NULL) {
504  return ocs_scsi_io_dispatch_hal_io(io, io->hio, FALSE);
505  }
506 
507  /*
508  * We don't already have a HAL IO associated with the IO. First check
509  * the pending list. If not empty, add IO to the tail and process the
510  * pending list.
511  */
512  ocs_device_lock(ocs);
513  if (!ocs_list_empty(&ocs->io_pending_list)) {
514  ocs_scsi_io_add_to_pending(ocs, io, TRUE);
515 
516  ocs_device_unlock(ocs);
517 
518  /* process pending list */
520  return 0;
521  }
522  ocs_device_unlock(ocs);
523 
524  /*
525  * We don't have a HAL IO associated with the IO and there's nothing
526  * on the pending list. Attempt to allocate a HAL IO and dispatch it.
527  */
528  hio = ocs_hal_io_alloc(&io->ocs->hal);
529  if (hio == NULL) {
530  /* Couldn't get a HAL IO. Save this IO on the pending list */
531  ocs_scsi_io_add_to_pending(ocs, io, FALSE);
532  return 0;
533  }
534 
535  /* We successfully allocated a HAL IO; dispatch to HAL */
536  return ocs_scsi_io_dispatch_hal_io(io, hio, FALSE);
537 }
538 
539 /**
540  * @brief Dispatch IO
541  *
542  * @par Description
543  * An IO and its associated HAL IO is dispatched to the HAL.
544  *
545  * @param io Pointer to IO structure.
546  * @param hio Pointer to HAL IO structure from which IO will be
547  * dispatched.
548  * @param lock_held inform this function if the ocs lock is already held
549  *
550  * @return Returns 0 on success, a negative error code value on failure.
551  */
552 
553 static int32_t
554 ocs_scsi_io_dispatch_hal_io(ocs_io_t *io, ocs_hal_io_t *hio, uint8_t lock_held)
555 {
556  int32_t rc;
557  ocs_t *ocs = io->ocs;
558  ocs_hal_t *hal = &ocs->hal;
559  ocs_hal_rtn_e hal_rtn;
560 
561  /* Got a HAL IO; update ini/tgt_task_tag with HAL IO info and dispatch */
562  io->hio = hio;
563  io->hw_tag = hio->tag;
564 
565  /* Copy the BHS to the DMA buffer */
566  ocs_memcpy(io->hio->bhs.virt, io->bhs, 48);
567 
568  if (io->io_type == OCS_HAL_IO_UNASSISTED) {
569  io->iparam.unassisted.bhs = &io->hio->bhs;
570  }
571 
572  rc = ocs_scsi_build_sgls(hal, io, &io->hal_dif, io->sgl, io->sgl_count, io->io_type);
573  if (rc) {
574  return rc;
575  }
576 
578  ocs_log_sgl(io);
579  }
580 
581  hal_rtn = ocs_hal_io_send(hal, io->io_type, io->hio, io->hal_io_size,
582  &io->iparam, io->node, io->hal_cb, io);
583  if (hal_rtn == OCS_HAL_RTN_NO_RESOURCES) {
584  ocs_scsi_io_add_to_pending(ocs, io, lock_held);
585  rc = 0;
586  } else if (hal_rtn != OCS_HAL_RTN_SUCCESS) {
587  rc = -1;
588  }
589  return rc;
590 }
591 
592 /**
593  * @brief Clean up any IOs on the pending list when a connection goes down.
594  *
595  * @param node Pointer to node structure.
596  */
597 void
598 ocs_scsi_pending_cleanup(ocs_node_t *node)
599 {
600  ocs_t *ocs = node->ocs;
601  ocs_io_t *io;
602  ocs_io_t *next;
603 
604  ocs_device_lock(ocs);
605  ocs_list_foreach_safe(&ocs->io_pending_list, io, next) {
606  if (io->node == node) {
607  ocs_list_remove(&ocs->io_pending_list, io);
608  ocs_atomic_sub_return(&ocs->io_pending_count, 1);
609 
610  (void)ocs_target_io_cb(io->hio,
611  io->node,
613  NULL,
614  io);
615  }
616  }
617  ocs_device_unlock(ocs);
618 }
619 
620 /**
621  * @brief Build the SGLs for the IO.
622  *
623  * @param hal Pointer to HAL object.
624  * @param io Pointer to IO context.
625  * @param sgl Pointer to payload scatter-gather list.
626  * @param sgl_count Count of scatter-gather list elements.
627  * @param type IO type.
628  * @param hal_dif Pointer to the HAL DIF structure.
629  *
630  * @return Returns 0 on success, or a negative error code value on failure.
631  */
632 static int32_t
633 ocs_scsi_build_sgls(ocs_hal_t *hal, ocs_io_t *io, ocs_hal_dif_info_t *hal_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hal_io_type_e type)
634 {
635  int32_t rc;
636  uint32_t i;
637  ocs_hal_io_t *hio = io->hio;
638  ocs_t *ocs = io->ocs;
639  uint32_t blocksize = 0;
640  uint32_t blockcount;
641  ocs_hal_dif_info_t hal_dif_temp = *hal_dif;
642 
643  /* Initialize HAL SGL */
644  rc = ocs_hal_io_init_sges(&ocs->hal, hio, type, io->scsi_mem_offset);
645  if (rc) {
646  ocs_log_err(ocs, "ocs_hal_io_init_sges failed: %d\n", rc);
647  return -1;
648  }
649 
650  /* Convert DIF Information */
651  if (hal_dif_temp.dif_oper != OCS_HAL_DIF_OPER_DISABLED) {
652 
653  /* If we're not DIF separate, then emit a seed SGE */
654  if (!hal_dif_temp.dif_separate) {
655  rc = ocs_hal_io_add_seed_sge(hal, hio, &hal_dif_temp);
656  if (rc) {
657  return rc;
658  }
659  }
660 
661  /* if we are doing DIF separate, then figure out the block size so that we
662  * can update the ref tag in the DIF seed SGE. Also verify that the
663  * the sgl lengths are all multiples of the blocksize
664  */
665  if (hal_dif_temp.dif_separate) {
666  switch(hal_dif_temp.blk_size) {
667  case OCS_HAL_DIF_BK_SIZE_512: blocksize = 512; break;
668  case OCS_HAL_DIF_BK_SIZE_1024: blocksize = 1024; break;
669  case OCS_HAL_DIF_BK_SIZE_2048: blocksize = 2048; break;
670  case OCS_HAL_DIF_BK_SIZE_4096: blocksize = 4096; break;
671  case OCS_HAL_DIF_BK_SIZE_520: blocksize = 520; break;
672  case OCS_HAL_DIF_BK_SIZE_4104: blocksize = 4104; break;
673  default:
674  ocs_log_err(hal->os, "Invalid hal_dif blocksize %d\n", hal_dif_temp.blk_size);
675  return -1;
676  }
677  for (i = 0; i < sgl_count; i++) {
678  if ((sgl[i].len % blocksize) != 0) {
679  ocs_log_err(hal->os, "sgl[%d] len of %ld is not multiple of blocksize\n",
680  i, sgl[i].len);
681  return -1;
682  }
683  }
684  }
685 
686  for (i = 0; i < sgl_count; i++) {
687  ocs_assert(sgl[i].addr, -1);
688  ocs_assert(sgl[i].len, -1);
689 
690  /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
691  if (hal_dif_temp.dif_separate) {
692  rc = ocs_hal_io_add_seed_sge(hal, hio, &hal_dif_temp);
693  if (rc) {
694  return rc;
695  }
696  rc = ocs_hal_io_add_dif_sge(hal, hio, sgl[i].dif_addr);
697  if (rc) {
698  return rc;
699  }
700  /* Update the ref_tag for the next DIF seed SGE */
701  blockcount = sgl[i].len / blocksize;
702  if (hal_dif_temp.dif_oper == OCS_HAL_DIF_OPER_INSERT) {
703  hal_dif_temp.ref_tag_repl += blockcount;
704  } else {
705  hal_dif_temp.ref_tag_cmp += blockcount;
706  }
707  }
708 
709  /* Add data SGE */
710  rc = ocs_hal_io_add_sge(hal, hio, sgl[i].addr, sgl[i].len);
711  if (rc) {
712  ocs_log_err(ocs, "ocs_hal_io_add_sge failed: count=%d rc=%d\n",
713  sgl_count, rc);
714  return rc;
715  }
716  }
717  } else {
718  for (i = 0; i < sgl_count; i++) {
719  ocs_assert(sgl[i].addr, -1);
720  ocs_assert(sgl[i].len, -1);
721 
722  /* Add data SGE */
723  rc = ocs_hal_io_add_sge(hal, hio, sgl[i].addr, sgl[i].len);
724  if (rc) {
725  ocs_log_err(ocs, "ocs_hal_io_add_sge failed: count=%d rc=%d\n",
726  sgl_count, rc);
727  return rc;
728  }
729 
730  }
731  }
732  return 0;
733 }
734 
735 /**
736  * @ingroup scsi_api_base
737  * @brief Send read data.
738  *
739  * @par Description
740  * This call is made by a target-server to initiate a SCSI read dataphase, transferring
741  * data from the target to the remote initiator. The payload is specified by the
742  * scatter-gather list @c sgl of length @c sgl_count. The @c len argument
743  * specifies the payload length (independent of the scatter-gather list cumulative length).
744  * @n @n
745  * The c flags argument has one bit: OCS_SCSI_LAST_DATAPHASE, which is a hint to the base
746  * driver that it may use auto SCSI response features if the hardware supports it.
747  * @n @n
748  * Upon completion the callback function @c cb is called with flags indicating that the
749  * IO has completed (OCS_SCSI_IO_COMPL) and another dataphase or response may be sent,
750  * the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP), or that
751  * the IO was aborted (OCS_SCSI_IO_ABORTED).
752  *
753  * @param io Pointer to IO context.
754  * @param flags Flags controlling the sending of data.
755  * @param dif_info Pointer to a T10 PI (DIF) information structure.
756  * @param sgl Pointer to payload scatter-gather list.
757  * @param sgl_count Number of scatter-gather list elements.
758  * @param wire_len Length of the payload on wire, in bytes.
759  * @param cb Completion callback.
760  * @param arg Application supplied callback data.
761  *
762  * @return Returns 0 for success, a negative error code value for failure.
763  */
764 int32_t ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags,
765  ocs_scsi_dif_info_t *dif_info,
766  ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
767  uint64_t wire_len,
768  ocs_scsi_io_cb_t cb, void *arg)
769 {
770  int32_t rc;
771  ocs_t *ocs;
772  ocs_cxn_t *cxn;
773  ocs_iscsi_t *iscsi;
774  ocs_session_t *session;
775  iscsi_data_in_hdr_t *hdr;
776  int blocksize = 0;
777  int wire_blocksize = 0;
778  int num_blocks;
779 
780  ocs_assert(io, -1);
781 
782  if (dif_info && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) {
783  dif_info = NULL;
784  }
785 
786  ocs_assert(io, -1);
787 
788  io->sgl_count = sgl_count;
789 
790  /* If needed, copy SGL */
791  if (sgl && (sgl != io->sgl)) {
792  ocs_assert(sgl_count <= io->sgl_allocated, -1);
793  ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl));
794  }
795 
796  ocs = io->ocs;
797  ocs_assert(ocs, -1);
798 
799  cxn = io->node;
800  ocs_assert(cxn, -1);
801  iscsi = &ocs->iscsi;
802  session = cxn->session;
803 
804  io_trace(io, "send wire_len %d\n", wire_len);
805 
806  /* Verify that we are in the correct state to start IO. */
807  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
808  return -1;
809  }
810 
811  ocs_assert(sgl, -1);
812  ocs_assert(sgl_count > 0, -1);
813 
814  io->io_type = OCS_HAL_IO_TARGET_READ;
815  io->scsi_io_cb = cb;
816  io->scsi_io_cb_arg = arg;
817  io->scsi_wire_xfer_size = wire_len;
818  io->is_read = 1;
819 
820  /* Calculate memory size */
821 
822  if (dif_info == NULL) {
823  io->scsi_mem_xfer_size = wire_len;
824  } else {
825  /* Get the size of a data block */
826  switch(dif_info->blk_size) {
828  blocksize = 512;
829  break;
831  blocksize = 1024;
832  break;
834  blocksize = 2048;
835  break;
837  blocksize = 4096;
838  break;
840  blocksize = 520;
841  break;
843  blocksize = 4104;
844  break;
845  }
846 
847  /* Get the size of a block on the wire */
848  wire_blocksize = ocs_scsi_dif_wire_blocksize(dif_info, !io->tgt_io.is_read);
849 
850  /* Given the total wire length and the wire blocksize,
851  * calculate the number of blocks
852  */
853  num_blocks = wire_len / wire_blocksize;
854 
855  /* With DIF separate the mem_xfer_size is based on the data blocksize
856  * excluding the DIF data. This is true whether or not the
857  * DIF goes on the wire.
858  */
859  if (dif_info->dif_separate) {
860  io->scsi_mem_xfer_size = num_blocks * blocksize;
861  } else {
862  /* With inline DIF the mem_xfer_size is based on the blocksize
863  * includeing the DIF data, regardless of the wire length
864  */
865  io->scsi_mem_xfer_size = num_blocks * (blocksize + 8);
866  }
867  }
868 
869 
870  rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hal_dif);
871  if (rc) {
872  return rc;
873  }
874 
875  /*
876  * Adjust the wire size if required. We can't exceed expected transfer
877  * size for the io.
878  */
879  if ((io->exp_xfer_len - io->scsi_wire_offset) < wire_len) {
880  wire_len = io->exp_xfer_len - io->scsi_wire_offset;
881  }
882 
883  /*
884  * Setup the iSCSI header.
885  */
886  hdr = (iscsi_data_in_hdr_t *)io->bhs;
887  ocs_memset(hdr, 0, sizeof(iscsi_data_in_hdr_t));
888  hdr->opcode = ISCSI_RESP_DATAIN;
889  hdr->lun.lun_64 = io->iscsi_lun; /* already BE */
890  hdr->itt = ocs_htobe32(io->init_task_tag);
891  hdr->ttt = 0xFFFFFFFF;
892  hdr->expCmdSN = ocs_htobe32(session->exp_cmd_sn);
893  hdr->maxCmdSN = ocs_htobe32(session->max_cmd_sn);
894 
895 
896  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
897  io->iparam.tgt_read.data_sn = io->data_sn;
898  io->iparam.tgt_read.dif_info = (dif_info ? &io->hal_dif : NULL);
899 
900  /* if this is the last sequence in the data phase then enable
901  * auto-good-response
902  */
903  if ((flags & OCS_SCSI_LAST_DATAPHASE)) {
904  io->iparam.tgt_read.piggy_back_status = 1;
905  if (wire_len + io->scsi_wire_offset < io->exp_xfer_len) {
906  io->iparam.tgt_read.underrun = 1;
907  hdr->residualCount = ocs_htobe32(io->exp_xfer_len - (wire_len + io->scsi_wire_offset));
908  io_trace(io, "set underflow for %d bytes, exp_xfer_len=%d, scsi_wire_offset= %d, wire_=%d\n",
909  io->exp_xfer_len - (wire_len + io->scsi_wire_offset),
910  io->exp_xfer_len,
911  io->scsi_wire_offset,
912  wire_len);
913  } else if (wire_len + io->scsi_wire_offset > io->exp_xfer_len) {
914  io->iparam.tgt_read.overrun = 1;
915  hdr->residualCount = ocs_htobe32((wire_len + io->scsi_wire_offset) - io->exp_xfer_len);
916  io_trace(io, "set overflow for %d bytes, exp_xfer_len=%d, scsi_wire_offset=%d, wire_len=%d\n",
917  (wire_len + io->scsi_wire_offset) - io->exp_xfer_len,
918  io->exp_xfer_len,
919  io->scsi_wire_offset,
920  wire_len);
921  }
922  io->auto_resp = 1;
923  } else {
924  io->auto_resp = 0;
925  }
926 
927  io->hal_io_size = wire_len;
929 }
930 
931 
932 /**
933  * @ingroup scsi_api_base
934  * @brief Prepare to receive write data
935  *
936  * This function is used by the target-server to set up a SCSI write data phase, transferring
937  * data from the remote initiator to the target. The payload is specified by the
938  * scatter-gather list @c sgl of length @c sgl_count. The @c len argument
939  * specifies the payload length (independent of the scatter-gather list cumulative length).
940  * @n @n
941  * The @c flags argument has one bit: OCS_SCSI_LAST_DATAPHASE, which is a hint to the base
942  * driver that it may use auto SCSI response features if the hardware supports it.
943  * @n @n
944  * Upon completion the callback function @c cb is called with flags indicating that the
945  * IO has completed (OCS_SCSI_IO_COMPL) and another dataphase or response may be sent,
946  * the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP), or that
947  * the IO was aborted (OCS_SCSI_IO_ABORTED).
948  *
949  * @param io Pointer to IO context.
950  * @param flags Flags controlling the receipt of data.
951  * @param dif_info Pointer to a T10 PI (DIF) information structure.
952  * @param sgl Pointer to payload scatter-gather list.
953  * @param sgl_count Number of scatter-gather list elements.
954  * @param wire_len Length of the payload on wire, in bytes.
955  * @param cb Completion callback.
956  * @param arg Application supplied callback data.
957  *
958  * @return Returns 0 for success, a negative error code value for failure.
959  */
960 int32_t ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags,
961  ocs_scsi_dif_info_t *dif_info,
962  ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
963  uint64_t wire_len,
964  ocs_scsi_io_cb_t cb, void *arg)
965 {
966  ocs_t *ocs;
967  ocs_cxn_t *cxn;
968  ocs_iscsi_t *iscsi;
969  ocs_session_t *session;
970  iscsi_r2t_hdr_t *hdr;
971  int32_t rc;
972  iscsi_lun_t *lun = (iscsi_lun_t*)&io->iscsi_lun;
973 
974  ocs_assert(io, -1);
975 
976  if (dif_info && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) {
977  dif_info = NULL;
978  }
979 
980  ocs_assert(io, -1);
981 
982  io->sgl_count = sgl_count;
983 
984  /* If needed, copy SGL */
985  if (sgl && (sgl != io->sgl)) {
986  ocs_assert(sgl_count <= io->sgl_allocated, -1);
987  ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl));
988  }
989 
990  ocs = io->ocs;
991  ocs_assert(ocs, -1);
992 
993  cxn = io->node;
994  ocs_assert(cxn, -1);
995  iscsi = &ocs->iscsi;
996  session = cxn->session;
997 
998  /* Verify that we are in the correct state to start IO. */
999  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
1000  return -1;
1001  }
1002 
1003  io_trace(io, "recv wire_len %d\n", wire_len);
1004 
1005  ocs_assert(sgl, -1);
1006  ocs_assert(sgl_count > 0, -1);
1007 
1008  rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hal_dif);
1009  if (rc) {
1010  return rc;
1011  }
1012 
1013  io->io_type = OCS_HAL_IO_TARGET_WRITE;
1014  io->scsi_io_cb = cb;
1015  io->scsi_io_cb_arg = arg;
1016  io->scsi_mem_xfer_size = io->scsi_wire_xfer_size = wire_len;
1017  io->auto_resp = 0;
1018  io->is_read = 0;
1019 
1020  /*
1021  * Adjust the wire size if required. We can't exceed expected transfer
1022  * size for the io.
1023  */
1024  if ((io->exp_xfer_len - io->scsi_wire_offset) < wire_len) {
1025  wire_len = io->exp_xfer_len - io->scsi_wire_offset;
1026  }
1027 
1028  /*
1029  * Setup the iSCSI header.
1030  *
1031  * Note: The target transfer tag is set in the HAL based on the WRB index
1032  * and the icd.
1033  */
1034  hdr = (iscsi_r2t_hdr_t *)io->bhs;
1035  ocs_memset(hdr, 0, sizeof(iscsi_r2t_hdr_t));
1036  hdr->final = 1;
1037  hdr->opcode = ISCSI_RESP_R2T;
1038  hdr->lun.lun_64 = io->iscsi_lun; /* already BE */
1039  hdr->itt = ocs_htobe32(io->init_task_tag);
1040  hdr->ExpCmdSN = ocs_htobe32(session->exp_cmd_sn);
1041  hdr->MaxCmdSN = ocs_htobe32(session->max_cmd_sn);
1042  hdr->R2TSN = ocs_htobe32(io->r2tsn++);
1043  hdr->bufferOffset= ocs_htobe32(io->scsi_wire_offset);
1044  hdr->desiredDataTransferLength = ocs_htobe32(wire_len);
1045 
1046  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1047  // TODO handle multi-phase IO when the target API supports it
1048  io->iparam.tgt_write.lun = (((ocs_be32toh(lun->lun_32[0])) >> 16) & 0x3fff);
1049  io->iparam.tgt_write.exp_data_sn = 0;
1050  io->iparam.tgt_write.itt = io->init_task_tag;
1051  io->iparam.tgt_write.r2t_offset = io->scsi_wire_offset;
1052  io->iparam.tgt_write.dif_info = (dif_info ? &io->hal_dif : NULL);
1053 
1054  io->hal_io_size = wire_len;
1056 }
1057 
1058 /**
1059  * @ingroup scsi_api_base
1060  * @brief Send response data.
1061  *
1062  * @par Description
1063  * This function is used by a target-server to send SCSI response data to a remote
1064  * initiator node. The target-server populates the <b>ocs_scsi_cmd_resp_t</b>
1065  * argument with scsi status, status qualifier, sense data and response data as
1066  * needed.
1067  * @n @n
1068  * Upon completion the callback function @c cb . The target-server will generally
1069  * clean up its IO context resources and call ocs_scsi_io_complete().
1070  *
1071  * @param io Pointer to IO context.
1072  * @param flags Flags to control sending of SCSI response.
1073  * @param rsp Pointer to response data populated by caller.
1074  * @param cb Completion callback.
1075  * @param arg Application specified completion callback argument.
1076 
1077  * @return Returns 0 for success, a negative error code value for failure.
1078  */
1079 int32_t ocs_scsi_send_resp(ocs_io_t *io, uint32_t flags,
1080  ocs_scsi_cmd_resp_t *rsp,
1081  ocs_scsi_io_cb_t cb, void *arg)
1082 {
1083  ocs_t *ocs;
1084  ocs_cxn_t *cxn;
1085  ocs_iscsi_t *iscsi;
1086  ocs_session_t *session;
1087  iscsi_response_hdr_t *hdr;
1088  uint32_t dsl = 0;
1089  uint8_t *rsp_bytes;
1090 
1091  /* Fields that come in rsp if not NULL */
1092  uint8_t scsi_status = 0;
1093  uint32_t sense_data_length = 0;
1094  uint8_t *sense_data = NULL;
1095 
1096  ocs_assert(io, -1);
1097 
1098  ocs = io->ocs;
1099  ocs_assert(ocs, -1);
1100 
1101  cxn = io->node;
1102  ocs_assert(cxn, -1);
1103  iscsi = &ocs->iscsi;
1104  session = cxn->session;
1105 
1106  /* Verify that we are in the correct state to start IO. */
1107  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
1108  return -1;
1109  }
1110 
1111  ocs_scsi_convert_dif_info(ocs, NULL, &io->hal_dif);
1112 
1113  if (rsp != NULL) {
1114  scsi_status = rsp->scsi_status;
1115  sense_data = rsp->sense_data;
1116  sense_data_length = rsp->sense_data_length;
1117  }
1118 
1119  io->io_type = OCS_HAL_IO_TARGET_RSP;
1120  io->scsi_io_cb = cb;
1121  io->scsi_io_cb_arg = arg;
1122 
1123  /*
1124  * Setup the iSCSI header.
1125  *
1126  * Note: The target transfer tag is set in the HAL based on the WRB index
1127  * and the icd.
1128  */
1129  hdr = (iscsi_response_hdr_t *)io->bhs;
1130  ocs_memset(hdr, 0, sizeof(iscsi_response_hdr_t));
1131  hdr->final = 1;
1132  hdr->opcode = ISCSI_RESP_RESP;
1134  hdr->status = scsi_status;
1135  hdr->itt = ocs_htobe32(io->init_task_tag);
1136  hdr->ExpCmdSN = ocs_htobe32(session->exp_cmd_sn);
1137  hdr->MaxCmdSN = ocs_htobe32(session->max_cmd_sn);
1138 
1139  if (io->is_read) {
1140  hdr->ExpDataSN = ocs_htobe32(io->data_sn);
1141  } else {
1142  hdr->ExpDataSN = ocs_htobe32(io->r2tsn);
1143  }
1144 
1145  /* Set residual */
1146  if (io->scsi_wire_offset < io->exp_xfer_len) {
1147  hdr->underflow = 1;
1148  hdr->ResidualCnt = ocs_htobe32(io->exp_xfer_len - io->scsi_wire_offset);
1149  io_trace(io, "set underflow for %d bytes, exp_xfer_len=%d, len=%d\n",
1150  io->exp_xfer_len - io->scsi_wire_offset, io->exp_xfer_len, io->scsi_wire_offset);
1151  } else if (io->scsi_wire_offset > io->exp_xfer_len) {
1152  hdr->overflow = 1;
1153  hdr->ResidualCnt = ocs_htobe32(io->scsi_wire_offset - io->exp_xfer_len);
1154  io_trace(io, "set overflow for %d bytes, exp_xfer_len=%d, len=%d\n",
1155  io->scsi_wire_offset - io->exp_xfer_len, io->exp_xfer_len, io->scsi_wire_offset);
1156  }
1157 
1158 
1159  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1160  io->iparam.tgt_rsp.payload1 = NULL;
1161  io->iparam.tgt_rsp.payload2 = NULL;
1162 
1163  if (OCS_SCSI_SNS_BUF_VALID(sense_data) && sense_data_length) {
1164  dsl = sense_data_length + 2;
1165  hdr->dw2.data_segment_length[0] = (dsl >> 16) & 0xff;
1166  hdr->dw2.data_segment_length[1] = (dsl >> 8) & 0xff;
1167  hdr->dw2.data_segment_length[2] = dsl & 0xff;
1168 
1169  if (io->sensebuf.virt == NULL) {
1170  ocs_log_err(ocs, "NULL response buffer\n");
1171  return -1;
1172  }
1173  io->iparam.tgt_rsp.payload1 = &io->sensebuf;
1174 
1175  rsp_bytes = (uint8_t*)io->sensebuf.virt;
1176  rsp_bytes[0] = (sense_data_length >> 8) & 0xff;
1177  rsp_bytes[1] = sense_data_length & 0xff;
1178  ocs_memcpy(&rsp_bytes[2], sense_data, dsl - 2);
1179  }
1180 
1181  io_trace(io, "send rsp\n");
1182  io->hal_io_size = dsl;
1184 }
1185 
1186 /**
1187  * @ingroup scsi_api_base
1188  * @brief Abort a target IO.
1189  *
1190  * @par Description
1191  * This routine is called from a SCSI target-server and initiates an abort of a
1192  * previously issued target data phase or response request.
1193  *
1194  * @param io IO context.
1195  * @param cb SCSI target server callback.
1196  * @param arg SCSI target server supplied callback argument.
1197  *
1198  * @return Returns 0 on success, or a non-zero value otherwise.
1199  */
1200 int32_t
1201 ocs_scsi_tgt_abort_io(ocs_io_t *io, bool send_abts, ocs_scsi_io_cb_t cb, void *arg)
1202 {
1203  ocs_t *ocs = io->ocs;
1204  ocs_hal_rtn_e rc = 0;
1205 
1206  io->scsi_io_cb = cb;
1207  io->scsi_io_cb_arg = arg;
1208 
1209  /*
1210  * See if the IO is on the pending list, if so then remove it and
1211  * send the IO completion for it.
1212  */
1213  if (ocs_list_on_list(&io->io_pending_link)) {
1214  ocs_device_lock(ocs);
1215  ocs_list_remove(&ocs->io_pending_list, io);
1216  ocs_device_unlock(ocs);
1217  ocs_atomic_sub_return(&ocs->io_pending_count, 1);
1218 
1219  ocs_node_lock(io->node);
1220  ocs_node_unlock(io->node);
1221  (void)ocs_target_io_cb(io->hio,
1222  io->node,
1224  NULL,
1225  io);
1226  } else if (io->hio == NULL) {
1227  (void)ocs_target_io_cb(io->hio,
1228  io->node,
1230  NULL,
1231  io);
1232  } else {
1234 
1235  if (rc == OCS_HAL_RTN_SUCCESS) {
1236  ocs_log_debug(ocs, "abort ICD %d\n", io->hio->icd);
1237  } else if (rc == OCS_HAL_RTN_ERROR) { /* IO is not active in the HAL */
1238  rc = 0;
1239  (void)ocs_target_io_cb(io->hio,
1240  io->node,
1242  NULL,
1243  io);
1244  }
1245  }
1246  return rc;
1247 }
1248 
1249 
1250 /**
1251  * @ingroup scsi_api_base
1252  * @brief Send TMF response data.
1253  *
1254  * @par Description
1255  * This function is used by a target-server to send SCSI TMF response data to a remote
1256  * initiator node.
1257  * @n @n
1258  * Upon completion the callback function @c cb. The target-server will generally
1259  * clean up its IO context resources and call ocs_scsi_io_complete().
1260  *
1261  * @param io Pointer to IO context.
1262  * @param rspcode TMF response code.
1263  * @param addl_rsp_info Additional TMF response information (may be NULL for zero data).
1264  * @param cb Completion callback.
1265  * @param arg Application specified completion callback argument.
1266 
1267  * @return Returns 0 for success, a negative error code value for failure.
1268  */
1269 int32_t
1271  uint8_t *addl_rsp_info,
1272  ocs_scsi_io_cb_t cb, void *arg)
1273 {
1274  uint8_t response;
1275  int32_t rc;
1276 
1277  switch (rspcode) {
1281  break;
1284  break;
1287  break;
1290  default:
1292  break;
1293  }
1294 
1295  rc = ocs_iscsi_send_tmf_resp(io,
1296  response,
1297  cb,
1298  arg);
1299  return rc;
1300 }
1301 
1302 /**
1303  * @ingroup scsi_api_base
1304  * @brief send TMF response data
1305  *
1306  * @par Description
1307  * This function is to send an iSCSI TMF response data to a remote
1308  * initiator node.
1309  * @n @n
1310  * Upon completion the callback function <b>cb</b> is called.
1311  *
1312  * @param io Pointer to IO context.
1313  * @param response The iSCSI task management response code.
1314  * @param cb Completion callback.
1315  * @param arg Application specified completion callback argument.
1316 
1317  * @return Returns 0 for success, a negative error code value for failure.
1318  */
1319 int32_t
1320 ocs_iscsi_send_tmf_resp(ocs_io_t *io, uint8_t response,
1321  ocs_scsi_io_cb_t cb, void *arg)
1322 {
1323  ocs_cxn_t *cxn = io->node;
1324  ocs_session_t *session = cxn->session;
1326 #if defined(OCS_INCLUDE_DEBUG)
1327  ocs_t *ocs = io->ocs;
1328  ocs_iscsi_t *iscsi = &ocs->iscsi;
1329 #endif
1330 
1331  /* Verify that we are in the correct state to start IO. */
1332  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
1333  return -1;
1334  }
1335 
1336  io->io_type = OCS_HAL_IO_UNASSISTED;
1337  io->scsi_io_cb = cb;
1338  io->scsi_io_cb_arg = arg;
1339 
1340  /*
1341  * Setup the iSCSI header.
1342  *
1343  * Note: The target transfer tag is set in the HAL based on the WRB index
1344  * and the icd.
1345  */
1346  hdr = (iscsi_task_mgmt_response_t *)io->bhs;
1347  ocs_memset(hdr, 0, sizeof(iscsi_task_mgmt_response_t));
1348  hdr->final = 1;
1349  hdr->opcode = ISCSI_RESP_TASK;
1350  hdr->itt = ocs_htobe32(io->init_task_tag);
1351  hdr->ExpCmdSN = ocs_htobe32(session->exp_cmd_sn);
1352  hdr->MaxCmdSN = ocs_htobe32(session->max_cmd_sn);
1353  hdr->response = response;
1354 
1355  /* Set residual */
1356  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1357  io->iparam.unassisted.set_dm = TRUE;
1358  io->iparam.unassisted.is_login = FALSE;
1359  io->iparam.unassisted.incr_statsn = TRUE;
1360  io->iparam.unassisted.bhs = NULL;
1361  io->iparam.unassisted.payload1 = NULL;
1362  io->iparam.unassisted.payload2 = NULL;
1363 
1364  io_trace(io, "send tm rsp\n");
1365 
1366  io->hal_io_size = 0;
1368 }
1369 
1370 
1371 /**
1372  * @brief This function is the callback for a initiator IO.
1373  *
1374  * @param hio Pointer to the HAL io object.
1375  * @param cxn Pointer to the connection object.
1376  * @param status Status of the command
1377  * @param ini_fields Pointer to the initiator completion fields
1378  * @param ul_arg Points to the io object
1379  */
1380 static int32_t ocs_initiator_io_cb(struct ocs_hal_io_s *hio,
1381  ocs_cxn_t *cxn,
1382  int32_t status,
1383  ocs_ini_cmpl_fields_t *ini_fields,
1384  void *ul_arg)
1385 {
1386  ocs_io_t *io = ul_arg;
1387  ocs_iscsi_t *iscsi;
1388  ocs_session_t *session = cxn->session;
1389  ocs_t *ocs;
1390  ocs_scsi_cmd_resp_t rsp;
1391 
1392  ocs_assert(io, -1);
1393  ocs_assert(io->scsi_io_cb, -1);
1394 
1395  ocs = io->ocs;
1396  ocs_assert(ocs, -1);
1397  iscsi = &ocs->iscsi;
1398  ocs_assert(iscsi, -1);
1399 
1400  if (!ocs_list_empty(&iscsi->login_retry_busy)) {
1401  ocs_iscsi_login_retry(cxn);
1402  }
1403 
1404  ocs_memset(&rsp, 0, sizeof(ocs_scsi_cmd_resp_t));
1405  if (ini_fields != NULL &&
1406  status == SLI_STATUS_SOL_CMD_CMPL_NORMAL) {
1407  /* Do not update the session's exp_cmd_sn if it would go backwards */
1408  if (GT_WRAP(ini_fields->exp_cmdsn, session->exp_cmd_sn)) {
1409  session->exp_cmd_sn = ini_fields->exp_cmdsn;
1410  session->cmd_window = ini_fields->cmd_window;
1411  }
1412 
1413  /* build the response */
1414  rsp.scsi_status = ini_fields->status;
1415  rsp.sense_data = ini_fields->sense_data;
1416  rsp.sense_data_length = ini_fields->sense_len;
1417  rsp.residual = ini_fields->residual_cnt;
1418  }
1419 
1420  /* Clear the idle count */
1421  cxn->idle_count = 0;
1422 
1423  /* Call initiator server completion */
1424  if (io->scsi_io_cb) {
1425  ocs_scsi_rsp_io_cb_t cb = io->scsi_io_cb;
1426  uint32_t flags = 0;
1428 
1429  if (cxn->cxn_state != CONN_STATE_FULL_FEATURE) {
1430  cb_status = OCS_SCSI_STATUS_NEXUS_LOST;
1431  } else if(status == SLI_STATUS_SOL_CMD_CMPL_NORMAL ||
1432  status == SLI_STATUS_TCP_ACK_NOTIFY) {
1433  cb_status = OCS_SCSI_STATUS_GOOD;
1434  } else if (status == SLI_STATUS_HOST_CMD_INVALID_NOTIFY) {
1435  cb_status = OCS_SCSI_STATUS_ABORTED;
1436  } else if (status == SLI_STATUS_CMD_OVERRUN ||
1437  status == SLI_STATUS_CMD_UNDERRUN) {
1438  cb_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
1439  } else if (status == SLI_STATUS_DIF_ERROR) {
1441  } else if (status == SLI_STATUS_HOST_CXN_INVALID_NOTIFY) {
1442  cb_status = OCS_SCSI_STATUS_NEXUS_LOST;
1443 
1444  /* TODO - OCS_SCSI_STATUS_DIF_REF_TAG_ERROR &&
1445  * OCS_SCSI_STATUS_DIF_APP_TAG_ERROR
1446  */
1447  }
1448 
1449  /* Clear the callback before invoking the callback */
1450  io->scsi_io_cb = NULL;
1451 
1452  io_trace(io, "IO completed with status 0x%x (flags 0x%x)\n",
1453  cb_status, flags);
1454 
1455  cb(io, cb_status, &rsp, flags, io->scsi_io_cb_arg);
1456  }
1457 
1458  /* Signal IO completions to the state machine if we are cleaning up */
1459  if (cxn->cxn_state == CONN_STATE_CLEANUP ||
1460  cxn->cxn_state == CONN_STATE_LOGOUT_REQUESTED) {
1461  ocs_sm_post_event(&cxn->sm, OCS_EVT_IO_CMPL, NULL);
1462  }
1464  return 0;
1465 }
1466 
1467 
1468 /**
1469  * @brief This function is the callback for a initiator TM IO
1470  *
1471  * @param hio Pointer to the io object.
1472  * @param cxn Pointer to the connection object.
1473  * @param status Status of the command.
1474  * @param ini_fields Pointer to the initiator completion fields.
1475  * @param ul_arg Points to the io object.
1476  */
1477 static int32_t ocs_initiator_io_tm_cb(struct ocs_hal_io_s *hio,
1478  ocs_cxn_t *cxn,
1479  int32_t status,
1480  ocs_ini_cmpl_fields_t *ini_fields,
1481  void *ul_arg)
1482 {
1483  ocs_iscsi_t *iscsi;
1484  ocs_t *ocs;
1485  ocs_io_t *io = ul_arg;
1486 
1487  ocs_assert(io, -1);
1488 
1489  ocs = io->ocs;
1490  ocs_assert(ocs, -1);
1491  iscsi = &ocs->iscsi;
1492  ocs_assert(iscsi, -1);
1493 
1494  if (!ocs_list_empty(&iscsi->login_retry_busy)) {
1495  ocs_iscsi_login_retry(cxn);
1496  }
1497 
1498  /*
1499  * For task management, the IO completion is received when the TCP
1500  * ACK acknowledges the TM PDU. We need to wait for the TM response
1501  * before notifying the SCSI backend that the IO is complete.
1502  */
1503 
1504  /* Signal IO completions to the state machine if we are cleaning up */
1505  if (cxn->cxn_state == CONN_STATE_CLEANUP ||
1506  cxn->cxn_state == CONN_STATE_LOGOUT_REQUESTED) {
1507  ocs_sm_post_event(&cxn->sm, OCS_EVT_IO_CMPL, NULL);
1508  }
1510  return 0;
1511 }
1512 
1513 /**
1514  * @brief Sends an initiator command to the chip.
1515  *
1516  * @param lun 32-bit LUN for this IO.
1517  * @param ocs Pointer to the ocs structure.
1518  *
1519  */
1520 static uint64_t
1521 ocs_scsi_convert_lun(ocs_t *ocs, uint32_t lun)
1522 {
1523  uint64_t iscsi_lun = 0;
1524  uint8_t *iscsi_lun_byte = (uint8_t*)&iscsi_lun;
1525 
1526  lun &= 0xffffff;
1527 
1528  if (lun <= ISCSI_LUN_ADDR_SIMPLE_MAX) {
1529  iscsi_lun_byte[1] = lun & 0xff;
1530  } else if (lun <= ISCSI_LUN_ADDR_FLAT_MAX) {
1531  /*
1532  * Use single level, flat space LUN
1533  */
1535  ((lun >> 8) & ISCSI_LUN_ADDRESS_METHOD_MASK);
1536  iscsi_lun_byte[1] = lun & 0xff;
1537  } else {
1538  ocs_log_test(ocs, "unsupported LU %08X\n", lun);
1539  iscsi_lun = 0xFFFFFFFFFFFFFFFF;
1540  }
1541  return iscsi_lun;
1542 }
1543 
1544 
1545 /**
1546  * @brief Sends an initiator command to the chip.
1547  *
1548  * @param node Pointer to the node object.
1549  * @param io Pointer to the io object.
1550  * @param io_type HAL io type for this initiator command.
1551  * @param lun 32-bit LUN for this IO.
1552  * @param cdb Pointer to the SCSI CDB.
1553  * @param cdb_len Length of the SCSI CDB in bytes.
1554  * @param dif_info Pointer to a T10 PI (DIF) information structure.
1555  * @param sgl Pointer to the SGL list for this IO.
1556  * @param sgl_count Number of SGLs for the IO.
1557  * @param wire_len Number of bytes being transferred for this IO.
1558  * @param cb Callback function to call upon completion.
1559  * @param arg Argument to call the callback function.
1560  */
1561 static int32_t
1562 ocs_scsi_send_ini_io(ocs_node_t *node, ocs_io_t *io, ocs_hal_io_type_e io_type,
1563  uint32_t lun, void *cdb, uint32_t cdb_len,
1564  ocs_scsi_dif_info_t *dif_info,
1565  ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
1566  uint32_t wire_len, ocs_scsi_rsp_io_cb_t cb, void *arg)
1567 {
1568  int32_t rc;
1569  ocs_iscsi_t *iscsi = node->iscsi;
1570  ocs_session_t *session = node->session;
1571  ocs_t *ocs = iscsi->os;
1572  iscsi_cmd_hdr_t *hdr;
1573  iscsi_lun_t *iscsi_lun = (iscsi_lun_t*)&io->iscsi_lun;
1574 
1575  ocs_assert(io, -1);
1576 
1577  /* Verify that we are in the correct state to start IO. */
1578  if (node->cxn_state != CONN_STATE_FULL_FEATURE) {
1579  ocs_log_test(ocs, "cxn not ready, state is %d\n", node->cxn_state);
1580  return -1;
1581  }
1582 
1583  /*
1584  * Ensure that the CDB is 16 bytes or less since our chips don't
1585  * support additional header segments.
1586  */
1587  if (cdb_len > 16) {
1588  ocs_log_test(ocs, "CDB len %d is not supported\n", cdb_len);
1589  return -1;
1590  }
1591 
1592  /*
1593  * Check the iSCSI command window to ensure that it is OK to send this
1594  * command.
1595  */
1596  if (!GT_NOTWRAPPED(session->exp_cmd_sn + session->cmd_window,
1597  session->cmd_sn)) {
1598  ocs_log_test(ocs, "iSCSI cmd window closed, exp_cmd_sn 0x%x, window 0x%x, cmd_sn 0x%x\n",
1599  session->exp_cmd_sn, session->cmd_window, session->cmd_sn);
1600  return -1;
1601  }
1602 
1603  io->sgl_count = sgl_count;
1604 
1605  /* Copy SGL if needed */
1606  if (sgl != io->sgl) {
1607  ocs_assert(sgl_count <= io->sgl_allocated, -1);
1608  ocs_memcpy(io->sgl, sgl, sizeof(*io->sgl) * sgl_count);
1609  }
1610 
1611  rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hal_dif);
1612  if (rc) {
1613  return rc;
1614  }
1615 
1616  io->iscsi_lun = ocs_scsi_convert_lun(ocs, lun);
1617  io->node = node;
1618  io->ocs = iscsi->os;
1619  io->auto_resp = 0;
1620  io->init_task_tag = 0;
1621  io->exp_xfer_len = wire_len;
1622  io->io_type = io_type;
1623  io->scsi_io_cb = cb;
1624  io->scsi_io_cb_arg = arg;
1625  io->scsi_mem_xfer_size = io->scsi_wire_xfer_size = wire_len;
1626  io->is_read = ((io_type == OCS_HAL_IO_INITIATOR_READ) ? 1 : 0);
1627  io->cmd_sn = session->cmd_sn++;
1628 
1629  /*
1630  * Setup the iSCSI header.
1631  */
1632  hdr = (iscsi_cmd_hdr_t*)io->bhs;
1633  ocs_memset(hdr, 0, sizeof(iscsi_cmd_hdr_t));
1634  hdr->opcode = ISCSI_CMD_CMD;
1635  hdr->final = 1;
1636  hdr->rd = ((io_type == OCS_HAL_IO_INITIATOR_READ) ? 1 : 0);
1637  hdr->wr = ((io_type == OCS_HAL_IO_INITIATOR_WRITE) ? 1 : 0);
1639  hdr->lun.lun_64 = io->iscsi_lun; /* already BE */
1640  hdr->ExpectedDataTransferLength = ocs_htobe32(wire_len);
1641  hdr->CmdSN = ocs_htobe32(io->cmd_sn);
1642  ocs_memcpy(hdr->cdb, cdb, (cdb_len < 16 ? cdb_len : 16));
1643 
1644  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1645  io->iparam.ini_io.lun = (((ocs_be32toh(iscsi_lun->lun_32[0])) >> 16) & 0x3fff);
1646  io->iparam.ini_io.cmdsn = io->cmd_sn;
1647  io->iparam.ini_io.dif_info = (dif_info ? &io->hal_dif : NULL);
1648 
1649  io_trace(io, "start INI Io, CmdSn=%d, instance=0x%x, size=0x%x, DIF=%s, oper=%s\n",
1650  io->cmd_sn, io->instance_index, wire_len,
1651  (io->iparam.ini_io.dif_info == NULL ? "Non-DIF" : "DIF"),
1652  (io->is_read ? "READ" : "WRITE"));
1653 
1654  io->hal_io_size = wire_len;
1656 
1657  if (rc == 0) {
1658  /* Clear the idle count */
1659  node->idle_count = 0;
1660  }
1661 
1662  return rc;
1663 }
1664 
1665 
1666 /**
1667  * @ingroup scsi_api_base
1668  * @brief Initiate initiator read IO.
1669  *
1670  * @par Description
1671  * This call is made by an initiator-client to send a SCSI read command. The payload
1672  * for the command is given by a scatter-gather list @c sgl for @c sgl_count
1673  * entries.
1674  * @n @n
1675  * Upon completion, the callback cb is invoked and passed request status. If the command
1676  * completed successfully, the callback is given SCSI response data.
1677  *
1678  * @param node Pointer to node.
1679  * @param io Pointer to IO context.
1680  * @param lun LUN value.
1681  * @param cdb Pointer to CDB.
1682  * @param cdb_len Length of CDB.
1683  * @param dif_info Pointer to a T10 PI (DIF) information structure.
1684  * @param sgl Pointer to scatter-gather list.
1685  * @param sgl_count Count of scatter-gather list elements.
1686  * @param len Length of payload.
1687  * @param cb Completion callback.
1688  * @param arg Application-specified completion callback argument.
1689  *
1690  * @return returns 0 for success, a negative error code value for failure.
1691  */
1692 int32_t
1693 ocs_scsi_send_rd_io(ocs_node_t *node, ocs_io_t *io, uint32_t lun, void *cdb,
1694  uint32_t cdb_len, ocs_scsi_dif_info_t *dif_info,
1695  ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
1696  uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg)
1697 {
1698  return ocs_scsi_send_ini_io(node, io,
1700  lun, cdb, cdb_len, dif_info, sgl, sgl_count,
1701  len, cb, arg);
1702 }
1703 
1704 /**
1705  * @ingroup scsi_api_base
1706  * @brief Initiate initiator SCSI command with no data.
1707  *
1708  * @par Description
1709  * This call is made by an initiator-client to send a SCSI command with no data.
1710  * @n @n
1711  * Upon completion, the callback cb is invoked and passed request status. If the command
1712  * completed successfully, the callback is given SCSI response data.
1713  *
1714  * @param node Pointer to node.
1715  * @param io Pointer to IO context.
1716  * @param lun LUN value.
1717  * @param cdb Pointer to CDB.
1718  * @param cdb_len Length of CDB.
1719  * @param cb Completion callback.
1720  * @param arg Application specified completion callback argument.
1721  *
1722  * @return Returns 0 on success, or a negative error code value on failure.
1723  */
1724 int32_t ocs_scsi_send_nodata_io(ocs_node_t *node, ocs_io_t *io, uint32_t lun, void *cdb, uint32_t cdb_len,
1725  ocs_scsi_rsp_io_cb_t cb, void *arg)
1726 {
1727  return ocs_scsi_send_ini_io(node, io,
1729  lun, cdb, cdb_len, NULL, NULL, 0,0,
1730  cb, arg);
1731 }
1732 
1733 
1734 /**
1735  * @ingroup scsi_api_base
1736  * @brief Initiate initiator write IO.
1737  *
1738  * @par Description
1739  * This call is made by an initiator-client to send a SCSI write command. The payload
1740  * for the command is given by a scatter-gather list @c sgl for @c sgl_count.
1741  * entries.
1742  * @n @n
1743  * Upon completion, the callback cb is invoked and passed request status. If the command
1744  * completed successfully, the callback is given SCSI response data.
1745  *
1746  * @param node Pointer to node.
1747  * @param io Pointer to IO context.
1748  * @param lun LUN value.
1749  * @param cdb Pointer to CDB.
1750  * @param cdb_len Length of CDB.
1751  * @param dif_info Pointer to a T10 PI (DIF) information structure.
1752  * @param sgl Pointer to scatter-gather list.
1753  * @param sgl_count Count of scatter-gather list elements.
1754  * @param len Length of payload.
1755  * @param cb Completion callback.
1756  * @param arg Application specified completion callback argument.
1757  *
1758  * @return Returns 0 for success, a negative error code value for failure.
1759  */
1760 int32_t
1761 ocs_scsi_send_wr_io(ocs_node_t *node, ocs_io_t *io, uint32_t lun, void *cdb,
1762  uint32_t cdb_len, ocs_scsi_dif_info_t *dif_info,
1763  ocs_scsi_sgl_t *sgl, uint32_t sgl_count,
1764  uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg)
1765 {
1767  lun, cdb, cdb_len, dif_info, sgl, sgl_count,
1768  len, cb, arg);
1769 }
1770 
1771 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,
1772  ocs_scsi_dif_info_t *dif_info,
1773  ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
1774  ocs_scsi_rsp_io_cb_t cb, void *arg)
1775 {
1776  ocs_log_test(node->ocs, "First burst not implemented\n");
1777  return -1;
1778 }
1779 
1780 
1781 /**
1782  * @brief Sends a task management command on an initiator (internal).
1783  *
1784  * @param node Pointer to the node object.
1785  * @param io Pointer to the io object.
1786  * @param ref_io Pointer to the referenced io object (for abort task).
1787  * @param lun 32-bit LUN for this IO.
1788  * @param tmf Defines the type of TM request.
1789  * @param cb Callback function to call upon completion.
1790  * @param arg Argument to call the callback function.
1791  */
1792 static int32_t
1793 ocs_scsi_send_tmf_internal(ocs_node_t *node, ocs_io_t *io, ocs_io_t *ref_io,
1794  uint32_t lun, ocs_scsi_tmf_cmd_e tmf,
1795  ocs_scsi_rsp_io_cb_t cb, void *arg)
1796 {
1797  int32_t rc;
1798  ocs_iscsi_t *iscsi = node->iscsi;
1799  ocs_session_t *session = node->session;
1800  ocs_t *ocs = iscsi->os;
1801  iscsi_task_mgmt_hdr_t *hdr;
1802  iscsi_lun_t *iscsi_lun = (iscsi_lun_t*)&io->iscsi_lun;
1803  io_cb_t *io_cb = ocs_initiator_io_cb;
1804 
1805  ocs_assert(io, -1);
1806 
1807  /* Verify that we are in the correct state to start IO. */
1808  if (node->cxn_state != CONN_STATE_FULL_FEATURE) {
1809  return -1;
1810  }
1811 
1812  io->node = node;
1813  io->ocs = ocs;
1814  io->auto_resp = 0;
1815  io->init_task_tag = 0;
1816  io->exp_xfer_len = 0;
1817  io->iscsi_lun = ocs_scsi_convert_lun(ocs, lun);
1818  io->io_type = OCS_HAL_IO_INITIATOR_TMF;
1819  io->sgl_count = 0;
1820  io->scsi_io_cb = cb;
1821  io->scsi_io_cb_arg = arg;
1822  io->scsi_mem_xfer_size = 0;
1823  io->scsi_wire_xfer_size = 0;
1824  io->is_read = 0;
1825  io->cmd_sn = session->cmd_sn;
1826 
1827  /*
1828  * Setup the iSCSI header.
1829  */
1830  hdr = (iscsi_task_mgmt_hdr_t*)io->bhs;
1831  ocs_memset(hdr, 0, sizeof(iscsi_task_mgmt_hdr_t));
1832  hdr->opcode = ISCSI_CMD_TASK;
1833  hdr->final = 1;
1834  hdr->immediate = 1;
1835  hdr->ref_task_tag = 0xffffffff;
1836 
1837  /* Convert the TMF function */
1838  switch (tmf) {
1840  hdr->function = ISCSI_ABORT_TASK;
1841  break;
1844  break;
1846  hdr->function = ISCSI_LUN_RESET;
1847  break;
1849  hdr->function = ISCSI_CLEAR_ACA;
1850  break;
1852  hdr->function = ISCSI_ABORT_TASK;
1853  hdr->ref_task_tag = (ref_io->hio == NULL ? ref_io->init_task_tag : ref_io->hio->itt);
1854  hdr->ref_cmd_sn = ref_io->cmd_sn;
1855  break;
1856  default:
1857  ocs_log_test(ocs, "unsupported TMF %d\n", tmf);
1858  return -1;
1859  }
1860 
1861  hdr->lun.lun_64 = io->iscsi_lun; /* already BE */
1862  hdr->cmd_sn = ocs_htobe32(io->cmd_sn);
1863 
1864  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1865  io->iparam.ini_tmf.lun = (((ocs_be32toh(iscsi_lun->lun_32[0])) >> 16) & 0x3fff);
1866  io->iparam.ini_tmf.cmdsn = io->cmd_sn;
1867 
1868  io_trace(io, "start INI TMF (CmdSn %d)\n", io->cmd_sn);
1869 
1870  if (iscsi->hal->sli.is_skyhawk) {
1871  io_cb = ocs_initiator_io_tm_cb;
1872  }
1873 
1874  io->hal_io_size = 0;
1875  rc = ocs_scsi_io_dispatch(io, io_cb);
1876 
1877  if (rc == 0) {
1878  /* Clear the idle count */
1879  node->idle_count = 0;
1880  }
1881  return rc;
1882 }
1883 
1884 
1885 /**
1886  * @ingroup scsi_api_base
1887  * @brief initiate initiator task management operation
1888  *
1889  * @par Description
1890  * This command is used to send a SCSI task management function command. If the command
1891  * requires it (QUERY_TASK_SET for example), a payload may be associated with the command.
1892  * If no payload is required, then @c sgl_count may be zero and @c sgl is ignored.
1893  * @n @n
1894  * Upon completion cb is invoked with status and SCSI response data.
1895  *
1896  * @param node Pointer to node.
1897  * @param io Pointer to IO context.
1898  * @param io_to_abort Pointer to IO context to be aborted.
1899  * @param lun LUN value.
1900  * @param tmf Task management function.
1901  * @param sgl Pointer to scatter-gather list.
1902  * @param sgl_count Count of scatter-gather list elements.
1903  * @param len Length of payload.
1904  * @param cb Completion callback.
1905  * @param arg Application specified completion callback argument.
1906  *
1907  * @return Returns 0 for success, a negative error code value for failure.
1908  */
1909 int32_t
1910 ocs_scsi_send_tmf(ocs_node_t *node, ocs_io_t *io, ocs_io_t *io_to_abort, uint32_t lun,
1912  uint32_t sgl_count, uint32_t len,
1913  ocs_scsi_rsp_io_cb_t cb, void *arg)
1914 {
1915  return ocs_scsi_send_tmf_internal(node, io, NULL,
1916  lun, tmf, cb, arg);
1917 }
1918 
1919 
1920 /**
1921  * @ingroup scsi_api_base
1922  * @brief Convert SCSI API T10 DIF information into the FC HAL format.
1923  *
1924  * @param ocs Pointer to the ocs structure for logging.
1925  * @param scsi_dif_info Pointer to the SCSI API T10 DIF fields.
1926  * @param hal_dif_info Pointer to the FC HAL API T10 DIF fields.
1927  *
1928  * @return Returns 0 on success, or a negative error code value on failure.
1929  */
1930 
1931 static int32_t
1932 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, ocs_hal_dif_info_t *hal_dif_info)
1933 {
1934  ocs_memset(hal_dif_info, 0, sizeof(ocs_hal_dif_info_t));
1935 
1936  if (scsi_dif_info == NULL) {
1937  hal_dif_info->dif_oper = OCS_HAL_DIF_OPER_DISABLED;
1938  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_NA;
1939  return 0;
1940  }
1941 
1942  /* Convert the DIF operation */
1943  switch(scsi_dif_info->dif_oper) {
1945  hal_dif_info->dif_oper = OCS_HAL_DIF_OPER_DISABLED;
1946  break;
1948  //wr_dif_bytes = 8;
1949  hal_dif_info->dif_oper = OCS_HAL_DIF_OPER_PASS_THRU;
1950  break;
1952  //wr_dif_bytes = 8;
1953  hal_dif_info->dif_oper = OCS_HAL_DIF_OPER_STRIP;
1954  break;
1956  hal_dif_info->dif_oper = OCS_HAL_DIF_OPER_INSERT;
1957  break;
1958  default:
1959  ocs_log_test(ocs, "unhandled SCSI DIF operation %d\n",
1960  scsi_dif_info->dif_oper);
1961  return -1;
1962  }
1963 
1964  switch(scsi_dif_info->blk_size) {
1966  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_512;
1967  break;
1969  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_1024;
1970  break;
1972  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_2048;
1973  break;
1975  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_4096;
1976  break;
1978  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_520;
1979  break;
1981  hal_dif_info->blk_size = OCS_HAL_DIF_BK_SIZE_4104;
1982  break;
1983  default:
1984  ocs_log_test(ocs, "unhandled SCSI DIF block size %d\n",
1985  scsi_dif_info->blk_size);
1986  return -1;
1987  }
1988 
1989  // If the operation is an INSERT the tags provided are the ones that should be
1990  // inserted, otherwise they're the ones to be checked against.
1991  if (scsi_dif_info->dif_oper == OCS_SCSI_DIF_OPER_INSERT) {
1992  hal_dif_info->ref_tag_repl = scsi_dif_info->ref_tag;
1993  hal_dif_info->app_tag_repl = scsi_dif_info->app_tag;
1994  } else {
1995  hal_dif_info->ref_tag_cmp = scsi_dif_info->ref_tag;
1996  hal_dif_info->app_tag_cmp = scsi_dif_info->app_tag;
1997  }
1998 
1999  hal_dif_info->check_ref_tag = scsi_dif_info->check_ref_tag;
2000  hal_dif_info->check_app_tag = scsi_dif_info->check_app_tag;
2001  hal_dif_info->check_guard = scsi_dif_info->check_guard;
2002  hal_dif_info->auto_incr_ref_tag = 1;
2003  hal_dif_info->dif_separate = scsi_dif_info->dif_separate;
2004  hal_dif_info->disable_app_ffff = scsi_dif_info->disable_app_ffff;
2005  hal_dif_info->disable_app_ref_ffff = scsi_dif_info->disable_app_ref_ffff;
2006 
2007  return 0;
2008 }
2009 
2010 /**
2011  * @ingroup scsi_api_base
2012  * @brief Notify base that IO is complete.
2013  *
2014  * @par Description
2015  * This function is called by a target-server to notify the base driver that an IO
2016  * has completed, allowing for the base driver to free resources. Note, that it is
2017  * not called by initiator-clients.
2018  *
2019  * @param io Pointer to IO context.
2020  *
2021  * @return None.
2022  */
2023 void ocs_scsi_io_complete(ocs_io_t *io)
2024 {
2025  ocs_assert(io);
2026 
2027  if (!ocs_io_busy(io)) {
2028  ocs_log_test(io->ocs, "Got completion for non-busy io with tag 0x%x\n", io->tag);
2029  return;
2030  }
2031 
2032  ocs_scsi_io_free(io);
2033 }
2034 
2035 /**
2036  * @ingroup scsi_api_base
2037  * @brief Return SCSI API integer valued property.
2038  *
2039  * @par Description
2040  * This function is called by a target-server or initiator-client to
2041  * retrieve an integer valued property.
2042  *
2043  * @param ocs Pointer to ocs.
2044  * @param prop Property value to return.
2045  *
2046  * @return Returns a property value, or 0 if an invalid property was requested.
2047  */
2048 uint32_t ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop)
2049 {
2050  uint32_t sgl_chain_capable;
2051  uint32_t max_sge;
2052  uint32_t max_sgl;
2053  uint32_t num_sges;
2054  uint32_t dif_capable;
2055 
2056  switch (prop) {
2057  case OCS_SCSI_MAX_SGE:
2058  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_MAX_SGE, &max_sge)) {
2059  return (max_sge < ocs->max_sge_size ? max_sge : ocs->max_sge_size);
2060  }
2061  break;
2062  case OCS_SCSI_MAX_SGL:
2063  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_NUM_SGES_PER_ICD, &num_sges)) {
2064  max_sgl = num_sges - SLI4_SGE_MAX_RESERVED;
2065  if (ocs->enable_sgl_chaining &&
2066  (0 == ocs_hal_get(&ocs->hal,
2068  &sgl_chain_capable))) {
2069  /* SGL chaing mode, use default SGL count */
2070  if (sgl_chain_capable) {
2072  }
2073  }
2074  return max_sgl;
2075  }
2076  break;
2077  case OCS_SCSI_MAX_IOS:
2078  return ocs_io_pool_allocated(ocs->io_pool);
2079  case OCS_SCSI_DIF_CAPABLE:
2080  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_DIF_CAPABLE, &dif_capable)) {
2081  return dif_capable;
2082  }
2083  break;
2087  /* Skyhawk only supports a single DIF separate SGE */
2088  return FALSE;
2090  uint32_t val;
2091 
2092  /* Return FALSE if we are send frame capable */
2093  if (ocs_hal_get(&ocs->hal, OCS_HAL_SEND_FRAME_CAPABLE, &val) == 0) {
2094  return ! val;
2095  }
2096  break;
2097  }
2098  default:
2099  break;
2100  }
2101 
2102  ocs_log_test(ocs, "invalid property request %d\n", prop);
2103  return 0;
2104 }
2105 
2106 /**
2107  * @ingroup scsi_api_base
2108  * @brief return a property pointer.
2109  *
2110  * @par Description
2111  * This function is called by a target-server or initiator-client to
2112  * retrieve a pointer to the requested property.
2113  *
2114  * @param ocs Pointer to ocs.
2115  * @param prop Property value to return.
2116  *
2117  * @return Returns pointer to the requested property, otherwise NULL.
2118  */
2120 {
2121  void * rc = NULL;
2122 
2123  switch (prop) {
2124  case OCS_SCSI_WWNN:
2125  case OCS_SCSI_WWPN:
2126  rc = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_MAC_ADDR);
2127  break;
2128  case OCS_SCSI_SERIALNUMBER:
2129  {
2130  uint8_t *pvpd;
2131 
2132  pvpd = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_VPD);
2133  if (pvpd) {
2134  rc = ocs_find_vpd(pvpd, 256, "SN");
2135  }
2136 
2137  if (rc == NULL ||
2138  ocs_strlen(rc) == 0) {
2139  /* Use the last MAC address as the serial # */
2140  rc = ocs->sport[0].mac_str;
2141  }
2142  break;
2143  }
2144  case OCS_SCSI_PARTNUMBER:
2145  {
2146  uint8_t *pvpd;
2147 
2148  pvpd = ocs_hal_get_ptr(&ocs->hal, OCS_HAL_VPD);
2149  if (pvpd) {
2150  rc = ocs_find_vpd(pvpd, 256, "PN");
2151  }
2152 
2153  if (rc == NULL) {
2154  rc = "Unknown";
2155  }
2156 
2157  break;
2158  }
2159  default:
2160  break;
2161  }
2162 
2163  if (rc == NULL) {
2164  ocs_log_test(ocs, "invalid property request %d\n", prop);
2165  }
2166  return rc;
2167 }
2168 
2169 /**
2170  * @ingroup scsi_api_base
2171  * @brief allocate a SCSI IO context.
2172  *
2173  * @par Description
2174  * A SCSI IO context is allocated and associated with @c node. This function
2175  * is called by initiator-clients when issuing SCSI commands to remote
2176  * target devices. On completion, ocs_scsi_io_free() is called.
2177  * @n @n
2178  * The returned ocs_io_t structure has an element of type ocs_scsi_ini_io_t named
2179  * ini_io that is declared and used by a initiator-client for private information.
2180  *
2181  * @param node Pointer to associated node structure.
2182  * @param role Role for IO (originator/responder).
2183  *
2184  * @return Returns pointer to IO context or NULL.
2185  *
2186  */
2187 ocs_io_t *ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
2188 {
2189  ocs_t *ocs;
2190  ocs_iscsi_t *iscsi;
2191  ocs_io_t *io;
2192 
2193  ocs_assert(node, NULL);
2194  ocs_assert(node->ocs, NULL);
2195 
2196  ocs = node->ocs;
2197  iscsi = node->iscsi;
2198 
2199  io = ocs_io_alloc(ocs);
2200  if (io == NULL) {
2201  ocs_atomic_add_return(&ocs->io_alloc_failed_count, 1);
2202  return NULL;
2203  }
2204 
2205  ocs_assert(io->hio == NULL, NULL);
2206 
2207  io->ocs = ocs;
2208  io->node = node;
2209  io->auto_resp = 0;
2210  io->scsi_mem_xfer_size = 0;
2211  io->scsi_wire_xfer_size = 0;
2212  io->scsi_mem_offset = 0;
2213  io->scsi_wire_offset = 0;
2214  io->cmd_sn = 0;
2215  io->init_task_tag = 0;
2216  io->exp_xfer_len = 0;
2217  io->iscsi_lun = 0;
2218  io->data_sn = 0;
2219  io->r2tsn = 0;
2220  io->ppdu = 0;
2221  io->on_abort_list = 0;
2222 
2223  /* Always initialize refcount to 1.
2224  * Not used by iscsi, needed to handle common tmf abort in ramd*/
2225  ocs_ref_init(&io->ref, NULL, NULL);
2226 
2227 
2228  switch (role) {
2230  io->cmd_ini = TRUE;
2231  io->cmd_tgt = FALSE;
2232  break;
2234  io->cmd_ini = FALSE;
2235  io->cmd_tgt = TRUE;
2236  break;
2237  }
2238 
2239  /* Add to node's active_ios list */
2240  ocs_node_lock(node);
2241  ocs_list_add_tail(&node->active_ios, io);
2242  ocs_node_unlock(node);
2243 
2244  ocs_atomic_add_return(&ocs->io_active_count, 1);
2245  ocs_atomic_add_return(&ocs->io_total_alloc, 1);
2246 
2247  io_trace(io, "allocating io 0x%p %s\n", io, io->display_name);
2248 
2249  return io;
2250 }
2251 
2252 
2253 /**
2254  * @ingroup scsi_api_base
2255  * @brief Free a SCSI IO context.
2256  *
2257  * @par Description
2258  * The IO context previously allocated using ocs_scsi_io_alloc() is freed.
2259  *
2260  * @param io Pointer to IO context.
2261  *
2262  * @return None.
2263  */
2264 void ocs_scsi_io_free(ocs_io_t *io)
2265 {
2266  if (io) {
2267  ocs_t *ocs = io->ocs;
2268  ocs_node_t *node = io->node;
2269  ocs_iscsi_t *iscsi = node->iscsi;
2270 
2271  io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
2272 
2273  ocs_assert(ocs);
2274  ocs_assert(ocs_io_busy(io));
2275 
2276  ocs_node_lock(node);
2277  if (io->on_abort_list) {
2278  ocs_list_remove(&io->node->aborted_ios, io);
2279  } else {
2280  ocs_list_remove(&io->node->active_ios, io);
2281  }
2282  ocs_node_unlock(node);
2283 
2284  ocs_atomic_sub_return(&ocs->io_active_count, 1);
2285  ocs_atomic_sub_return(&ocs->io_total_free, 1);
2286 
2287  /* clear from the pending list */
2288  ocs_device_lock(ocs);
2289  if (ocs_list_on_list(&io->io_pending_link)) {
2290  ocs_list_remove(&ocs->io_pending_list, io);
2291  }
2292  ocs_device_unlock(ocs);
2293 
2294  io->node = NULL;
2295  ocs_io_free(ocs, io);
2296  }
2297 }
2298 
2299 /**
2300  * @brief Update transferred count.
2301  *
2302  * @par Description
2303  * Updates io->transferred, as required when using first burst, when the amount
2304  * of first burst data processed differs from the amount of first burst
2305  * data received.
2306  *
2307  * @param io Pointer to the io object.
2308  * @param transferred Number of bytes transferred out of first burst buffers.
2309  *
2310  * @return None.
2311  */
2312 void
2313 ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred)
2314 {
2315  io->scsi_mem_offset = transferred;
2316  io->scsi_wire_offset = transferred;
2317 }
2318 
2319 /**
2320  * @brief Register bounce callback for multi-threading.
2321  *
2322  * @par Description
2323  * Register the back end bounce function.
2324  *
2325  * @param ocs Pointer to device object.
2326  * @param fctn Function pointer of bounce function.
2327  *
2328  * @return None.
2329  */
2330 void
2331 ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void (*fctn)(void *arg), void *arg, uint32_t s_id,
2332  uint32_t d_id, uint32_t ox_id))
2333 {
2334  ocs_hal_rtn_e rc;
2335 
2336  rc = ocs_hal_callback(&ocs->hal, OCS_HAL_CB_BOUNCE, fctn, NULL);
2337  if (rc) {
2338  ocs_log_test(ocs, "ocs_hal_callback(OCS_HAL_CB_BOUNCE) failed: %d\n", rc);
2339  }
2340 }
2341 
2343  ocs_hal_abort_type_e abort_type)
2344 {
2345  int rc;
2346 
2347  rc = ocs_hal_io_abort(hal, hio,
2349  abort_type);
2350 
2351  if (rc != OCS_HAL_RTN_SUCCESS) {
2352  ocs_log_test(hal->os, "received rc %d aborting IOs\n", rc);
2353  } else {
2354  uint32_t inters = 10;
2355 
2356  /* Wait for completion */
2357  do {
2358  ocs_delay_usec(10000);
2359  inters--;
2360  }while(inters);
2361  }
2362 
2363  return rc;
2364 }
2365 
2366 /**
2367  * @brief Check Connection WQ's full status
2368  *
2369  * @param ocs Pointer to OCS object
2370  * @param cxn Pointer to connection object
2371  *
2372  * @return true if connection WQ is full, otherwise false
2373  */
2374 bool ocs_scsi_check_cxn_wq_full(ocs_t *ocs, ocs_cxn_t *cxn)
2375 {
2376  if (ocs_hal_cxn_get_free_wq_cnt(&ocs->hal, cxn) == 0)
2377  return true;
2378  else
2379  return false;
2380 }
2381 
2382 /*
2383  * Exported OCS SCSI API functions.
2384  */
2385 
2386 #if !defined(OCS_EXPORT)
2387 #define OCS_EXPORT(...)
2388 #endif
2389 
2392 //OCS_EXPORT(ocs_io_get_instance); // iscsi needs to add this
2401 //OCS_EXPORT(ocs_scsi_del_initiator_complete); // iscsi needs to add this
2402 //OCS_EXPORT(ocs_scsi_del_target_complete); // iscsi needs to add this
uint8_t is_skyhawk
Definition: sli4.h:2208
uint32_t check_guard
Definition: ocs_scsi.h:233
Defines the iSCSI response PDU header.
Defines the iSCSI command PDU header.
#define ISCSI_RESP_DATAIN
uint32_t disable_app_ffff
Definition: ocs_scsi.h:233
uint8_t scsi_status
Definition: ocs_scsi.h:92
ocs_os_handle_t os
Definition: ocs_hal.h:725
SGL information structure.
Definition: ocs_hal.h:451
uint32_t ocs_hal_cxn_get_free_wq_cnt(ocs_hal_t *hal, ocs_cxn_t *cxn)
Returns the number of free entries on the work queue for this connection.
Definition: ocs_hal.c:5013
static int32_t ocs_io_busy(ocs_io_t *io)
Test if IO object is busy.
Definition: ocs_io.h:129
static int32_t ocs_list_on_list(ocs_list_link_t *link)
Test if object is on a list.
Definition: ocs_list.h:460
ocs_scsi_tmf_cmd_e
Definition: ocs_scsi.h:138
#define OCS_ISCSI_LOGIN_MAX_BURST_LEN
ocs_scsi_tmf_resp_e
Definition: ocs_scsi.h:150
uint16_t tag
Definition: ocs_hal.h:486
uint32_t ref_tag_repl
Definition: ocs_hal.h:205
#define ISCSI_LUN_RESET
uint32_t ExpectedDataTransferLength
ocs_hal_t * hal
Definition: ocs_iscsi.h:295
uint8_t data_segment_length[3]
void ocs_scsi_pending_cleanup(ocs_node_t *node)
Clean up any IOs on the pending list when a connection goes down.
Definition: ocs_scsi.c:598
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)
Prepare to receive write data.
Definition: ocs_scsi.c:960
static void ocs_target_nop_check(ocs_cxn_t *cxn)
This function sends a target nop.
Definition: ocs_scsi.c:62
#define ISCSI_LUN_ADDRESS_METHOD_MASK
Definition: ocs_iscsi.h:55
static int32_t ocs_scsi_check_pending_async_cb(ocs_hal_t *hal, int32_t status, void *arg)
Check pending error asynchronous callback function/.
Definition: ocs_scsi.c:318
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
#define ISCSI_LUN_ADDRESS_METHOD_SHIFT
Definition: ocs_iscsi.h:54
T10 DIF information passed to the transport.
Definition: ocs_scsi.h:229
#define ISCSI_RESP_TASK
T10 DIF information passed to the transport.
Definition: ocs_hal.h:201
uint32_t n_sge
Definition: ocs_hal.h:459
static int32_t ocs_scsi_send_tmf_internal(ocs_node_t *node, ocs_io_t *io, ocs_io_t *ref_io, uint32_t lun, ocs_scsi_tmf_cmd_e tmf, ocs_scsi_rsp_io_cb_t cb, void *arg)
Sends a task management command on an initiator (internal).
Definition: ocs_scsi.c:1793
static void ocs_log_sgl(ocs_io_t *io)
This function logs the SGLs for an IO.
Definition: ocs_scsi.c:270
#define ISCSI_LUN_ADDR_FLAT_MAX
Definition: ocs_iscsi.h:62
uint32_t app_tag_cmp
Definition: ocs_hal.h:206
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
uint32_t sense_data_length
Definition: ocs_scsi.h:97
uint16_t sense_len
Definition: ocs_hal.h:424
static int32_t ocs_scsi_check_pending(ocs_t *ocs)
Check for pending IOs to dispatch.
Definition: ocs_scsi.c:346
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:5793
ocs_hal_rtn_e
defines common HAL return statuses.
Definition: ocs_hal.h:78
ocs_hal_rtn_e ocs_hal_io_init_sges(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_type_e type, uint32_t offset)
Initialize the Scatter Gather List entries of an IO.
Definition: ocs_hal.c:5562
#define GT_WRAP(a, b)
Definition: ocs_iscsi.h:87
Defines the iSCSI task management PDU header.
sli4_t sli
Definition: ocs_hal.h:726
ocs_hal_abort_type_e
HAL abort types.
Definition: ocs_hal.h:675
uint32_t dif_separate
Definition: ocs_scsi.h:233
#define GT_NOTWRAPPED(a, b)
Definition: ocs_iscsi.h:79
uint32_t desiredDataTransferLength
static void ocs_device_lock(ocs_t *ocs)
Definition: ocs_drv_fc.h:218
bool ocs_scsi_check_cxn_wq_full(ocs_t *ocs, ocs_cxn_t *cxn)
Check Connection WQ&#39;s full status.
Definition: ocs_scsi.c:2374
#define OCS_SCSI_DIF_OPER_PASS_THRU
Definition: ocs_scsi.h:198
HAL object.
Definition: ocs_hal.h:724
iscsi_hdr_dw2_t dw2
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:5732
static int32_t ocs_initiator_io_cb(struct ocs_hal_io_s *hio, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
This function is the callback for a initiator IO.
Definition: ocs_scsi.c:1380
generic scatter-gather list structure
Definition: ocs_scsi.h:218
int32_t ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
Attempt to dispatch an IO.
Definition: ocs_scsi.c:475
uint32_t dif_separate
Definition: ocs_hal.h:208
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:2203
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:2264
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:1693
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
#define ISCSI_TASK_MGMT_FUNCTION_REJECTED
#define ISCSI_TASK_MGMT_TASK_DOES_NOT_EXIST
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)
Send read data.
Definition: ocs_scsi.c:764
uint32_t check_app_tag
Definition: ocs_scsi.h:233
ocs_hal_io_t * ocs_hal_io_alloc(ocs_hal_t *hal)
Allocate a HAL IO object.
Definition: ocs_hal.c:5170
ocs_hal_io_type_e
enum identifying IO types.
Definition: ocs_hal.h:227
SCSI command response.
Definition: ocs_scsi.h:91
#define ISCSI_TASK_MGMT_LUN_DOES_NOT_EXIST
#define ISCSI_RESPONSE_CMD_COMPLETED
uint8_t cdb[16]
static int32_t ocs_target_io_cb(struct ocs_hal_io_s *hio, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
This function is the callback for a target IO.
Definition: ocs_scsi.c:167
uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool)
Definition: ocs_io.c:220
#define ISCSI_CLEAR_TASK_SET
uint32_t num_entries
Definition: ocs_hal.h:456
#define OCS_SCSI_IO_CMPL_RSP_SENT
Definition: ocs_scsi.h:134
ocs_hal_rtn_e ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_abort_scope_e abort_scope, ocs_hal_abort_type_e abort_type)
Abort a currently running IO.
Definition: ocs_hal.c:6148
iscsi_lun_t lun
void ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred)
Update transferred count.
Definition: ocs_scsi.c:2313
ocs_scsi_dif_blk_size_e blk_size
Definition: ocs_scsi.h:231
#define ISCSI_CMD_CMD
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:2331
uint32_t check_ref_tag
Definition: ocs_scsi.h:233
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
int ocs_scsi_abort_io(ocs_hal_t *hal, ocs_hal_io_t *hio, ocs_hal_abort_type_e abort_type)
Definition: ocs_scsi.c:2342
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_cxn_t *cxn, io_cb_t cb, void *arg)
Send a read, write, or response IO.
Definition: ocs_hal.c:5370
static void ocs_device_unlock(ocs_t *ocs)
Definition: ocs_drv_fc.h:223
void ocs_target_io_aborted_nop_cmpl(ocs_cxn_t *cxn)
This function is called whenever a target NOP completes.
Definition: ocs_scsi.c:120
Defines the iSCSI task management response PDU header.
#define OCS_SCSI_LAST_DATAPHASE
Definition: ocs_scsi.h:58
static void ocs_target_io_aborted(ocs_io_t *io, ocs_cxn_t *cxn)
This function is called when an IO is aborted.
Definition: ocs_scsi.c:99
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:5880
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:2666
#define CONN_STATE_LOGOUT_REQUESTED
uint32_t disable_app_ffff
Definition: ocs_hal.h:208
#define OCS_SCSI_IO_CMPL
Definition: ocs_scsi.h:133
#define ISCSI_RESP_RESP
Defines the iSCSI data-in PDU header.
#define OCS_SCSI_SNS_BUF_VALID(sense)
Definition: ocs_scsi.h:63
iSCSI object
Definition: ocs_iscsi.h:293
#define io_trace(io, fmt,...)
Definition: ocs_debug.h:187
#define ISCSI_ABORT_TASK
HAL IO object.
Definition: ocs_hal.h:471
uint32_t disable_app_ref_ffff
Definition: ocs_scsi.h:233
static void ocs_scsi_io_add_to_pending(ocs_t *ocs, ocs_io_t *io, uint8_t lock_held)
Place an IO on the pending list to retry later when resources are available.
Definition: ocs_scsi.c:444
ocs_os_handle_t os
Definition: ocs_iscsi.h:294
#define OCS_EXPORT(...)
Definition: ocs_ddump.c:842
#define OCS_DEBUG_ENABLE_IO_TRACE
Definition: ocs_debug.h:158
#define ISCSI_SIMPLE_TAG
int32_t ocs_iscsi_send_nop_in(ocs_cxn_t *cxn, uint64_t lun, uint32_t itt, uint32_t ttt, char *data_ptr, uint32_t data_len)
Send NOP-In from a target.
Definition: ocs_login.c:4404
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_cxn_t * node
Definition: ocs_hal.h:475
ocs_scsi_io_role_e
Definition: ocs_scsi.h:254
uint8_t * sense_data
Definition: ocs_scsi.h:96
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)
Definition: ocs_scsi.c:1771
Defines a union to decode the SCSI LUN field in various ways.
#define ISCSI_TASK_MGMT_FUNCTION_COMPLETE
uint32_t residual_cnt
Definition: ocs_hal.h:417
#define ISCSI_CLEAR_ACA
static int32_t ocs_initiator_io_tm_cb(struct ocs_hal_io_s *hio, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
This function is the callback for a initiator TM IO.
Definition: ocs_scsi.c:1477
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:1724
int ocs_sm_post_event(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Post an event to a context.
Definition: ocs_sm.c:59
uint16_t icd
Definition: ocs_hal.h:454
ocs_list_t login_retry_busy
Definition: ocs_iscsi.h:327
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
void ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously allocated HAL IO object.
Definition: ocs_hal.c:5231
ocs_scsi_property_e
property names for ocs_scsi_get_property() functions
Definition: ocs_scsi.h:163
Defines the iSCSI R2T PDU header.
uint32_t auto_incr_ref_tag
Definition: ocs_hal.h:208
uint32_t ref_tag_cmp
Definition: ocs_hal.h:204
ocs_hal_dif_oper_e dif_oper
Definition: ocs_hal.h:202
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_common.h:432
void ocs_iscsi_login_retry(ocs_cxn_t *cxn)
Attempt to start a request on the retry queue.
Definition: ocs_login.c:402
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:1910
defines a structure to contain the fields specific to an initiator IO completion. ...
Definition: ocs_hal.h:416
int32_t ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
Return wire block size given SCSI DIF API.
Definition: ocs_dif.c:237
static void * ocs_list_next(ocs_list_t *list, void *item)
Get the next item on the list.
Definition: ocs_list.h:339
uint32_t check_app_tag
Definition: ocs_hal.h:208
#define SLI4_SGE_MAX_RESERVED
Definition: sli4.h:456
size_t len
Definition: ocs_scsi.h:221
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:1201
#define ISCSI_LUN_ADDR_SIMPLE_MAX
Definition: ocs_iscsi.h:61
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_common.h:437
#define OCS_SCSI_DIF_OPER_INSERT
Definition: ocs_scsi.h:200
int32_t residual
Definition: ocs_scsi.h:98
static int32_t ocs_scsi_build_sgls(ocs_hal_t *hal, ocs_io_t *io, ocs_hal_dif_info_t *hal_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hal_io_type_e type)
Build the SGLs for the IO.
Definition: ocs_scsi.c:633
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:1079
int ocs_debug_is_enabled(uint32_t mask)
return true if debug bits are enabled
Definition: ocs_debug.c:122
uint32_t check_ref_tag
Definition: ocs_hal.h:208
#define OCS_DEFAULT_SGL_COUNT
Definition: ocs_hal.h:74
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:7518
uint32_t app_tag
Definition: ocs_scsi.h:233
iscsi_lun_t lun
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
static uint64_t ocs_scsi_convert_lun(ocs_t *ocs, uint32_t lun)
Sends an initiator command to the chip.
Definition: ocs_scsi.c:1521
int32_t io_cb_t(struct ocs_hal_io_s *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
IO Completion function prototype.
Definition: ocs_hal.h:432
Scatter-Gather Entry (SGE)
Definition: sli4.h:379
static int32_t ocs_scsi_io_dispatch_hal_io(ocs_io_t *io, ocs_hal_io_t *hio, uint8_t lock_held)
Dispatch IO.
Definition: ocs_scsi.c:554
#define CONN_STATE_FULL_FEATURE
static void ocs_io_free(ocs_t *ocs, ocs_io_t *io)
Definition: ocs_drv_fc.h:238
uint32_t bufferOffset
#define ISCSI_LUN_ADDR_METHOD_FLAT
Definition: ocs_iscsi.h:57
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:1761
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2753
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:1932
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:2187
ocs_scsi_io_status_e
Definition: ocs_scsi.h:105
ocs_hal_dif_blk_size_e blk_size
Definition: ocs_hal.h:203
#define ISCSI_RESP_R2T
uint64_t lun_64
uint32_t app_tag_repl
Definition: ocs_hal.h:206
#define ISCSI_CMD_TASK
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)
uint32_t check_guard
Definition: ocs_hal.h:208
uint32_t exp_cmdsn
Definition: ocs_hal.h:418
void * ocs_scsi_get_property_ptr(ocs_t *ocs, ocs_scsi_property_e prop)
return a property pointer.
Definition: ocs_scsi.c:2119
uint32_t disable_app_ref_ffff
Definition: ocs_hal.h:208
ocs_scsi_dif_oper_e dif_oper
Definition: ocs_scsi.h:230
static ocs_io_t * ocs_io_alloc(ocs_t *ocs)
Definition: ocs_drv_fc.h:232
int32_t ocs_iscsi_send_tmf_resp(ocs_io_t *io, uint8_t response, ocs_scsi_io_cb_t cb, void *arg)
send TMF response data
Definition: ocs_scsi.c:1320
uint32_t ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop)
Return SCSI API integer valued property.
Definition: ocs_scsi.c:2048
void ocs_scsi_io_complete(ocs_io_t *io)
Notify base that IO is complete.
Definition: ocs_scsi.c:2023
uint32_t lun_32[2]
#define OCS_SCSI_DIF_OPER_STRIP
Definition: ocs_scsi.h:199
#define CONN_STATE_CLEANUP
static int32_t ocs_scsi_send_ini_io(ocs_node_t *node, ocs_io_t *io, ocs_hal_io_type_e io_type, 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)
Sends an initiator command to the chip.
Definition: ocs_scsi.c:1562