Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_unsol.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  * Code to handle unsolicited received FC frames.
36  */
37 
38 /*!
39  * @defgroup unsol Unsolicited Frame Handling
40  */
41 
42 #include "ocs.h"
43 #include "ocs_els.h"
44 #include "ocs_fabric.h"
45 #include "ocs_device.h"
46 #include "scsi_cmds.h"
47 
48 
49 #define frame_printf(ocs, hdr, fmt, ...) \
50  do { \
51  char s_id_text[16]; \
52  ocs_node_fcid_display(fc_be24toh((hdr)->s_id), s_id_text, sizeof(s_id_text)); \
53  ocs_log_debug(ocs, "[%06x.%s] %02x/%04x/%04x: " fmt, fc_be24toh((hdr)->d_id), s_id_text, \
54  (hdr)->r_ctl, ocs_be16toh((hdr)->ox_id), ocs_be16toh((hdr)->rx_id), ##__VA_ARGS__); \
55  } while(0)
56 
57 static int32_t ocs_unsol_process(ocs_t *ocs, ocs_hal_sequence_t *seq);
58 static int32_t ocs_dispatch_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq);
59 static int32_t ocs_dispatch_tow_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq);
60 static int32_t ocs_dispatch_fcp_data(ocs_node_t *node, ocs_hal_sequence_t *seq);
61 static uint32_t ocs_fc_decode_lun(uint8_t *lu);
62 static int32_t ocs_domain_dispatch_frame(void *arg, ocs_hal_sequence_t *seq);
63 static int32_t ocs_node_dispatch_frame(void *arg, ocs_hal_sequence_t *seq);
64 static int32_t ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg);
65 static uint8_t ocs_node_frames_held(void *arg);
66 static uint8_t ocs_domain_frames_held(void *arg);
67 static int32_t ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock);
68 static int32_t ocs_sframe_send_task_set_full_or_busy(ocs_node_t *node, ocs_hal_sequence_t *seq);
69 ocs_hal_sequence_t *ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock);
70 
71 #define OCS_MAX_FRAMES_BEFORE_YEILDING 10000
72 
73 /**
74  * @brief Process the RQ circular buffer and process the incoming frames.
75  *
76  * @param mythread Pointer to thread object.
77  *
78  * @return Returns 0 on success, or a non-zero value on failure.
79  */
80 int32_t
81 ocs_unsol_rq_thread(ocs_thread_t *mythread)
82 {
83  ocs_xport_rq_thread_info_t *thread_data = mythread->arg;
84  ocs_t *ocs = thread_data->ocs;
85  ocs_hal_sequence_t *seq;
86  uint32_t yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
87 
88  ocs_log_debug(ocs, "%s running\n", mythread->name);
89  while (!ocs_thread_terminate_requested(mythread)) {
90  seq = ocs_cbuf_get(thread_data->seq_cbuf, 100000);
91  if (seq == NULL) {
92  /* Prevent soft lockups by yielding the CPU */
93  ocs_thread_yield(&thread_data->thread);
94  yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
95  continue;
96  }
97  /* Note: Always returns 0 */
98  ocs_unsol_process((ocs_t*)seq->hal->os, seq);
99 
100  /* We have to prevent CPU soft lockups, so just yield the CPU after x frames. */
101  if (--yield_count == 0) {
102  ocs_thread_yield(&thread_data->thread);
103  yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
104  }
105  }
106  ocs_log_debug(ocs, "%s exiting\n", mythread->name);
107  thread_data->thread_started = FALSE;
108  return 0;
109 }
110 
111 /**
112  * @ingroup unsol
113  * @brief Callback function when aborting a port owned XRI
114  * exchanges.
115  *
116  * @return Returns 0.
117  */
118 static int32_t
119 ocs_unsol_abort_cb (ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, uint32_t ext, void *arg)
120 {
121  ocs_t *ocs = arg;
122  ocs_assert(hio, -1);
123  ocs_assert(arg, -1);
124  ocs_log_debug(ocs, "xri=0x%x tag=0x%x\n", hio->indicator, hio->reqtag);
125  ocs_hal_io_free(&ocs->hal, hio);
126  return 0;
127 }
128 
129 
130 /**
131  * @ingroup unsol
132  * @brief Abort either a RQ Pair auto XFER RDY XRI.
133  * @return Returns None.
134  */
135 static void
136 ocs_port_owned_abort(ocs_t *ocs, ocs_hal_io_t *hio)
137 {
138  ocs_hal_rtn_e hal_rc;
139  hal_rc = ocs_hal_io_abort(&ocs->hal, hio, FALSE,
140  ocs_unsol_abort_cb, ocs);
141  if((hal_rc == OCS_HAL_RTN_IO_ABORT_IN_PROGRESS) ||
143  ocs_log_debug(ocs, "already aborted XRI 0x%x\n", hio->indicator);
144  } else if(hal_rc != OCS_HAL_RTN_SUCCESS) {
145  ocs_log_debug(ocs, "Error aborting XRI 0x%x status %d\n",
146  hio->indicator, hal_rc);
147  }
148 }
149 
150 /**
151  * @ingroup unsol
152  * @brief Handle unsolicited FC frames.
153  *
154  * <h3 class="desc">Description</h3>
155  * This function is called from the HAL with unsolicited FC frames (FCP, ELS, BLS, etc.).
156  *
157  * @param arg Application-specified callback data.
158  * @param seq Header/payload sequence buffers.
159  *
160  * @return Returns 0 on success; or a negative error value on failure.
161  */
162 
163 int32_t
165 {
166  ocs_t *ocs = arg;
167  ocs_xport_t *xport = ocs->xport;
168  int32_t rc;
169 
170  CPUTRACE("");
171 
172  if (ocs->rq_threads == 0) {
173  rc = ocs_unsol_process(ocs, seq);
174  } else {
175  /* use the ox_id to dispatch this IO to a thread */
176  fc_header_t *hdr = seq->header->dma.virt;
177  uint32_t ox_id = ocs_be16toh(hdr->ox_id);
178  uint32_t thr_index = ox_id % ocs->rq_threads;
179 
180  rc = ocs_cbuf_put(xport->rq_thread_info[thr_index].seq_cbuf, seq);
181  }
182 
183  if (rc) {
184  ocs_hal_sequence_free(&ocs->hal, seq);
185  }
186 
187  return 0;
188 }
189 
190 /**
191  * @ingroup unsol
192  * @brief Handle unsolicited FC frames.
193  *
194  * <h3 class="desc">Description</h3>
195  * This function is called either from ocs_unsolicited_cb() or ocs_unsol_rq_thread().
196  *
197  * @param ocs Pointer to the ocs structure.
198  * @param seq Header/payload sequence buffers.
199  *
200  * @return Returns 0 on success, or a negative error value on failure.
201  */
202 static int32_t
204 {
205  ocs_xport_fcfi_t *xport_fcfi = NULL;
206  ocs_domain_t *domain;
207  uint8_t seq_fcfi = seq->fcfi;
208 
209  /* HAL_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
210  if (ocs->hal.workaround.override_fcfi) {
211  if (ocs->hal.first_domain_idx > -1) {
212  seq_fcfi = ocs->hal.first_domain_idx;
213  }
214  }
215 
216  /* Range check seq->fcfi */
217  if (seq_fcfi < ARRAY_SIZE(ocs->xport->fcfi)) {
218  xport_fcfi = &ocs->xport->fcfi[seq_fcfi];
219  }
220 
221  /* If the transport FCFI entry is NULL, then drop the frame */
222  if (xport_fcfi == NULL) {
223  ocs_log_test(ocs, "FCFI %d is not valid, dropping frame\n", seq->fcfi);
224  if (seq->hio != NULL) {
225  ocs_port_owned_abort(ocs, seq->hio);
226  }
227 
228  ocs_hal_sequence_free(&ocs->hal, seq);
229  return 0;
230  }
231  domain = ocs_hal_domain_get(&ocs->hal, seq_fcfi);
232 
233  /*
234  * If we are holding frames or the domain is not yet registered or
235  * there's already frames on the pending list,
236  * then add the new frame to pending list
237  */
238  if (domain == NULL ||
239  xport_fcfi->hold_frames ||
240  !ocs_list_empty(&xport_fcfi->pend_frames)) {
241  ocs_lock(&xport_fcfi->pend_frames_lock);
242  ocs_list_add_tail(&xport_fcfi->pend_frames, seq);
243  ocs_unlock(&xport_fcfi->pend_frames_lock);
244 
245  if (domain != NULL) {
246  /* immediately process pending frames */
248  }
249  } else {
250  /*
251  * We are not holding frames and pending list is empty, just process frame.
252  * A non-zero return means the frame was not handled - so cleanup
253  */
254  if (ocs_domain_dispatch_frame(domain, seq)) {
255  if (seq->hio != NULL) {
256  ocs_port_owned_abort(ocs, seq->hio);
257  }
258  ocs_hal_sequence_free(&ocs->hal, seq);
259  }
260  }
261  return 0;
262 }
263 
264 /**
265  * @ingroup unsol
266  * @brief Process pending frames queued to the given node.
267  *
268  * <h3 class="desc">Description</h3>
269  * Frames that are queued for the \c node are dispatched and returned
270  * to the RQ.
271  *
272  * @param node Node of the queued frames that are to be dispatched.
273  *
274  * @return Returns 0 on success, or a negative error value on failure.
275  */
276 
277 int32_t
278 ocs_process_node_pending(ocs_node_t *node)
279 {
280  ocs_t *ocs = node->ocs;
281  ocs_hal_sequence_t *seq = NULL;
282  uint32_t pend_frames_processed = 0;
283 
284  for (;;) {
285  /* need to check for hold frames condition after each frame processed
286  * because any given frame could cause a transition to a state that
287  * holds frames
288  */
289  if (ocs_node_frames_held(node)) {
290  break;
291  }
292 
293  /* Get next frame/sequence */
294  ocs_lock(&node->pend_frames_lock);
295  seq = ocs_list_remove_head(&node->pend_frames);
296  if (seq == NULL) {
297  pend_frames_processed = node->pend_frames_processed;
298  node->pend_frames_processed = 0;
299  ocs_unlock(&node->pend_frames_lock);
300  break;
301  }
302  node->pend_frames_processed++;
303  ocs_unlock(&node->pend_frames_lock);
304 
305  /* now dispatch frame(s) to dispatch function */
306  if (ocs_node_dispatch_frame(node, seq)) {
307  if (seq->hio != NULL) {
308  ocs_port_owned_abort(ocs, seq->hio);
309  }
310  ocs_hal_sequence_free(&ocs->hal, seq);
311  }
312  }
313 
314  if (pend_frames_processed != 0) {
315  ocs_log_debug(ocs, "%u node frames held and processed\n", pend_frames_processed);
316  }
317 
318  return 0;
319 }
320 
321 /**
322  * @ingroup unsol
323  * @brief Process pending frames queued to the given domain.
324  *
325  * <h3 class="desc">Description</h3>
326  * Frames that are queued for the \c domain are dispatched and
327  * returned to the RQ.
328  *
329  * @param domain Domain of the queued frames that are to be
330  * dispatched.
331  *
332  * @return Returns 0 on success, or a negative error value on failure.
333  */
334 
335 int32_t
336 ocs_domain_process_pending(ocs_domain_t *domain)
337 {
338  ocs_t *ocs = domain->ocs;
339  ocs_xport_fcfi_t *xport_fcfi;
340  ocs_hal_sequence_t *seq = NULL;
341  uint32_t pend_frames_processed = 0;
342 
343  ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, -1);
344  xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
345 
346  for (;;) {
347  /* need to check for hold frames condition after each frame processed
348  * because any given frame could cause a transition to a state that
349  * holds frames
350  */
351  if (ocs_domain_frames_held(domain)) {
352  break;
353  }
354 
355  /* Get next frame/sequence */
356  ocs_lock(&xport_fcfi->pend_frames_lock);
357  seq = ocs_list_remove_head(&xport_fcfi->pend_frames);
358  if (seq == NULL) {
359  pend_frames_processed = xport_fcfi->pend_frames_processed;
360  xport_fcfi->pend_frames_processed = 0;
361  ocs_unlock(&xport_fcfi->pend_frames_lock);
362  break;
363  }
364  xport_fcfi->pend_frames_processed++;
365  ocs_unlock(&xport_fcfi->pend_frames_lock);
366 
367  /* now dispatch frame(s) to dispatch function */
368  if (ocs_domain_dispatch_frame(domain, seq)) {
369  if (seq->hio != NULL) {
370  ocs_port_owned_abort(ocs, seq->hio);
371  }
372  ocs_hal_sequence_free(&ocs->hal, seq);
373  }
374  }
375  if (pend_frames_processed != 0) {
376  ocs_log_debug(ocs, "%u domain frames held and processed\n", pend_frames_processed);
377  }
378  return 0;
379 }
380 
381 /**
382  * @ingroup unsol
383  * @brief Purge given pending list
384  *
385  * <h3 class="desc">Description</h3>
386  * Frames that are queued on the given pending list are
387  * discarded and returned to the RQ.
388  *
389  * @param ocs Pointer to ocs object.
390  * @param pend_list Pending list to be purged.
391  * @param list_lock Lock that protects pending list.
392  *
393  * @return Returns 0 on success, or a negative error value on failure.
394  */
395 
396 static int32_t
397 ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock)
398 {
399  ocs_hal_sequence_t *frame;
400 
401  for (;;) {
402  frame = ocs_frame_next(pend_list, list_lock);
403  if (frame == NULL) {
404  break;
405  }
406 
407  frame_printf(ocs, (fc_header_t*) frame->header->dma.virt, "Discarding held frame\n");
408  if (frame->hio != NULL) {
409  ocs_port_owned_abort(ocs, frame->hio);
410  }
411  ocs_hal_sequence_free(&ocs->hal, frame);
412  }
413 
414  return 0;
415 }
416 
417 /**
418  * @ingroup unsol
419  * @brief Purge node's pending (queued) frames.
420  *
421  * <h3 class="desc">Description</h3>
422  * Frames that are queued for the \c node are discarded and returned
423  * to the RQ.
424  *
425  * @param node Node of the queued frames that are to be discarded.
426  *
427  * @return Returns 0 on success, or a negative error value on failure.
428  */
429 
430 int32_t
431 ocs_node_purge_pending(ocs_node_t *node)
432 {
433  return ocs_purge_pending(node->ocs, &node->pend_frames, &node->pend_frames_lock);
434 }
435 
436 /**
437  * @ingroup unsol
438  * @brief Purge xport's pending (queued) frames.
439  *
440  * <h3 class="desc">Description</h3>
441  * Frames that are queued for the \c xport are discarded and
442  * returned to the RQ.
443  *
444  * @param domain Pointer to domain object.
445  *
446  * @return Returns 0 on success; or a negative error value on failure.
447  */
448 
449 int32_t
450 ocs_domain_purge_pending(ocs_domain_t *domain)
451 {
452  ocs_t *ocs = domain->ocs;
453  ocs_xport_fcfi_t *xport_fcfi;
454 
455  ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, -1);
456  xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
457  return ocs_purge_pending(domain->ocs,
458  &xport_fcfi->pend_frames,
459  &xport_fcfi->pend_frames_lock);
460 }
461 
462 /**
463  * @ingroup unsol
464  * @brief Check if node's pending frames are held.
465  *
466  * @param arg Node for which the pending frame hold condition is
467  * checked.
468  *
469  * @return Returns 1 if node is holding pending frames, or 0
470  * if not.
471  */
472 
473 static uint8_t
475 {
476  ocs_node_t *node = (ocs_node_t *)arg;
477  return node->hold_frames;
478 }
479 
480 /**
481  * @ingroup unsol
482  * @brief Check if domain's pending frames are held.
483  *
484  * @param arg Domain for which the pending frame hold condition is
485  * checked.
486  *
487  * @return Returns 1 if domain is holding pending frames, or 0
488  * if not.
489  */
490 
491 static uint8_t
493 {
494  ocs_domain_t *domain = (ocs_domain_t *)arg;
495  ocs_t *ocs = domain->ocs;
496  ocs_xport_fcfi_t *xport_fcfi;
497 
498  ocs_assert(domain != NULL, 1);
499  ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, 1);
500  xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
501  return xport_fcfi->hold_frames;
502 }
503 
504 /**
505  * @ingroup unsol
506  * @brief Globally (at xport level) hold unsolicited frames.
507  *
508  * <h3 class="desc">Description</h3>
509  * This function places a hold on processing unsolicited FC
510  * frames queued to the xport pending list.
511  *
512  * @param domain Pointer to domain object.
513  *
514  * @return Returns None.
515  */
516 
517 void
518 ocs_domain_hold_frames(ocs_domain_t *domain)
519 {
520  ocs_t *ocs = domain->ocs;
521  ocs_xport_fcfi_t *xport_fcfi;
522 
523  ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI);
524  xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
525  if (!xport_fcfi->hold_frames) {
526  ocs_log_debug(domain->ocs, "hold frames set for FCFI %d\n",
527  domain->fcf_indicator);
528  xport_fcfi->hold_frames = 1;
529  }
530 }
531 
532 /**
533  * @ingroup unsol
534  * @brief Clear hold on unsolicited frames.
535  *
536  * <h3 class="desc">Description</h3>
537  * This function clears the hold on processing unsolicited FC
538  * frames queued to the domain pending list.
539  *
540  * @param domain Pointer to domain object.
541  *
542  * @return Returns None.
543  */
544 
545 void
546 ocs_domain_accept_frames(ocs_domain_t *domain)
547 {
548  ocs_t *ocs = domain->ocs;
549  ocs_xport_fcfi_t *xport_fcfi;
550 
551  ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI);
552  xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
553  if (xport_fcfi->hold_frames == 1) {
554  ocs_log_debug(domain->ocs, "hold frames cleared for FCFI %d\n",
555  domain->fcf_indicator);
556  }
557  xport_fcfi->hold_frames = 0;
559 }
560 
561 
562 /**
563  * @ingroup unsol
564  * @brief Dispatch unsolicited FC frame.
565  *
566  * <h3 class="desc">Description</h3>
567  * This function processes an unsolicited FC frame queued at the
568  * domain level.
569  *
570  * @param arg Pointer to ocs object.
571  * @param seq Header/payload sequence buffers.
572  *
573  * @return Returns 0 if frame processed and RX buffers cleaned
574  * up appropriately, -1 if frame not handled.
575  */
576 
577 static __inline int32_t
579 {
580  ocs_domain_t *domain = (ocs_domain_t *)arg;
581  ocs_t *ocs = domain->ocs;
582  fc_header_t *hdr;
583  uint32_t s_id;
584  uint32_t d_id;
585  ocs_node_t *node = NULL;
586  ocs_sport_t *sport = NULL;
587 
588  ocs_assert(seq->header, -1);
589  ocs_assert(seq->header->dma.virt, -1);
590  ocs_assert(seq->payload->dma.virt, -1);
591 
592  hdr = seq->header->dma.virt;
593 
594  /* extract the s_id and d_id */
595  s_id = fc_be24toh(hdr->s_id);
596  d_id = fc_be24toh(hdr->d_id);
597 
598  sport = domain->sport;
599  if (sport == NULL) {
600  frame_printf(ocs, hdr, "phy sport for FC ID 0x%06x is NULL, dropping frame\n", d_id);
601  return -1;
602  }
603 
604  if (sport->fc_id != d_id) {
605  /* Not a physical port IO lookup sport associated with the npiv port */
606  sport = ocs_sport_find(domain, d_id); /* Look up without lock */
607  if (sport == NULL) {
608  if (hdr->type == FC_TYPE_FCP) {
609  /* Drop frame */
610  ocs_log_warn(ocs, "unsolicited FCP frame with invalid d_id x%x, dropping\n",
611  d_id);
612  return -1;
613  } else {
614  /* p2p will use this case */
615  sport = domain->sport;
616  }
617  }
618  }
619 
620  /* Lookup the node given the remote s_id */
621  node = ocs_node_find(sport, s_id);
622 
623  /* If not found, then create a new node */
624  if (node == NULL) {
625  /* If this is solicited data or control based on R_CTL and there is no node context,
626  * then we can drop the frame
627  */
628  if ((hdr->r_ctl == FC_RCTL_FC4_DATA) && (
629  (hdr->info == FC_RCTL_INFO_SOL_DATA) || (hdr->info == FC_RCTL_INFO_SOL_CTRL))) {
630  ocs_log_debug(ocs, "solicited data/ctrl frame without node, dropping\n");
631  return -1;
632  }
633  node = ocs_node_alloc(sport, s_id, FALSE, FALSE);
634  if (node == NULL) {
635  ocs_log_err(ocs, "ocs_node_alloc() failed\n");
636  return -1;
637  }
638  /* don't send PLOGI on ocs_d_init entry */
639  ocs_node_init_device(node, FALSE);
640  }
641 
642  if (node->hold_frames || !ocs_list_empty((&node->pend_frames))) {
643  /*
644  * Drop the FC command frame that is received when remote node being shutdown.
645  * Determine the node shutdown state based on io_alloc_enabled flag.
646  */
647  if ((hdr->r_ctl == FC_RCTL_FC4_DATA) &&
648  !ocs_scsi_io_alloc_enabled(node)) {
649  return -1;
650  }
651 
652  /* TODO: info log level
653  frame_printf(ocs, hdr, "Holding frame\n");
654  */
655  /* add frame to node's pending list */
656  ocs_lock(&node->pend_frames_lock);
657  ocs_list_add_tail(&node->pend_frames, seq);
658  ocs_unlock(&node->pend_frames_lock);
659 
660  return 0;
661  }
662 
663  /* now dispatch frame to the node frame handler */
664  return ocs_node_dispatch_frame(node, seq);
665 }
666 
667 /**
668  * @ingroup unsol
669  * @brief Dispatch a frame.
670  *
671  * <h3 class="desc">Description</h3>
672  * A frame is dispatched from the \c node to the handler.
673  *
674  * @param arg Node that originated the frame.
675  * @param seq Header/payload sequence buffers.
676  *
677  * @return Returns 0 if frame processed and RX buffers cleaned
678  * up appropriately, -1 if frame not handled.
679  */
680 static int32_t
682 {
683 
684  fc_header_t *hdr = seq->header->dma.virt;
685  uint32_t port_id;
686  ocs_node_t *node = (ocs_node_t *)arg;
687  int32_t rc = -1;
688  int32_t sit_set = 0;
689 
690  port_id = fc_be24toh(hdr->s_id);
691  ocs_assert(port_id == node->rnode.fc_id, -1);
692 
693  if (fc_be24toh(hdr->f_ctl) & FC_FCTL_END_SEQUENCE) {
694  /*if SIT is set */
696  sit_set = 1;
697  }
698  switch (hdr->r_ctl) {
699  case FC_RCTL_ELS:
700  if (sit_set) {
701  rc = ocs_node_recv_els_frame(node, seq);
702  }
703  break;
704 
705  case FC_RCTL_BLS:
706  if (sit_set) {
707  rc = ocs_node_recv_abts_frame(node, seq);
708  }else {
709  rc = ocs_node_recv_bls_no_sit(node, seq);
710  }
711  break;
712 
713  case FC_RCTL_FC4_DATA:
714  switch(hdr->type) {
715  case FC_TYPE_FCP:
716  if (hdr->info == FC_RCTL_INFO_UNSOL_CMD) {
717  if (node->fcp_enabled) {
718  if (sit_set) {
719  rc = ocs_dispatch_fcp_cmd(node, seq);
720  }else {
721  rc = ocs_dispatch_tow_fcp_cmd(node, seq);
722  }
723  } else {
724  rc = ocs_node_recv_fcp_cmd(node, seq);
725  }
726  } else if (hdr->info == FC_RCTL_INFO_SOL_DATA) {
727  if (sit_set) {
728  rc = ocs_dispatch_fcp_data(node, seq);
729  }
730  }
731  break;
732  case FC_TYPE_GS:
733  if (sit_set) {
734  rc = ocs_node_recv_ct_frame(node, seq);
735  }
736  break;
737  default:
738  break;
739  }
740  break;
741  }
742  } else {
743  node_printf(node, "Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n",
744  ocs_htobe32(((uint32_t *)hdr)[0]),
745  ocs_htobe32(((uint32_t *)hdr)[1]),
746  ocs_htobe32(((uint32_t *)hdr)[2]),
747  ocs_htobe32(((uint32_t *)hdr)[3]),
748  ocs_htobe32(((uint32_t *)hdr)[4]),
749  ocs_htobe32(((uint32_t *)hdr)[5]));
750  }
751  return rc;
752 }
753 
754 /**
755  * @ingroup unsol
756  * @brief Dispatch unsolicited FCP frames (RQ Pair).
757  *
758  * <h3 class="desc">Description</h3>
759  * Dispatch unsolicited FCP frames (called from the device node state machine).
760  *
761  * @param io Pointer to the IO context.
762  * @param task_management_flags Task management flags from the FCP_CMND frame.
763  * @param node Node that originated the frame.
764  * @param lun 32-bit LUN from FCP_CMND frame.
765  *
766  * @return Returns None.
767  */
768 
769 static void
770 ocs_dispatch_unsolicited_tmf(ocs_io_t *io, uint8_t task_management_flags, ocs_node_t *node, uint32_t lun)
771 {
772  uint32_t i;
773  struct {
774  uint32_t mask;
775  ocs_scsi_tmf_cmd_e cmd;
776  } tmflist[] = {
784 
785  io->exp_xfer_len = 0; /* BUG 32235 */
786 
787  for (i = 0; i < ARRAY_SIZE(tmflist); i ++) {
788  if (tmflist[i].mask & task_management_flags) {
789  io->tmf_cmd = tmflist[i].cmd;
790  ocs_log_info(io->ocs, "Process Unsol TMF cmd %d lun %d\n", tmflist[i].cmd, lun);
791  ocs_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0);
792  break;
793  }
794  }
795  if (i == ARRAY_SIZE(tmflist)) {
796  /* Not handled */
797  node_printf(node, "TMF x%x rejected\n", task_management_flags);
799  }
800 }
801 
802 static int32_t
804 {
805  size_t exp_payload_len = 0;
806  fcp_cmnd_iu_t *cmnd = seq->payload->dma.virt;
807  exp_payload_len = sizeof(fcp_cmnd_iu_t) - 16 + cmnd->additional_fcp_cdb_length;
808 
809  /*
810  * If we received less than FCP_CMND_IU bytes, assume that the frame is
811  * corrupted in some way and drop it. This was seen when jamming the FCTL
812  * fill bytes field.
813  */
814  if (seq->payload->dma.len < exp_payload_len) {
815  fc_header_t *fchdr = seq->header->dma.virt;
816  ocs_log_debug(ocs, "dropping ox_id %04x with payload length (%zd) less than expected (%zd)\n",
817  ocs_be16toh(fchdr->ox_id), seq->payload->dma.len,
818  exp_payload_len);
819  return -1;
820  }
821  return 0;
822 
823 }
824 
825 static void
826 ocs_populate_io_fcp_cmd(ocs_io_t *io, fcp_cmnd_iu_t *cmnd, fc_header_t *fchdr, uint8_t sit)
827 {
828  uint32_t *fcp_dl;
829  io->init_task_tag = ocs_be16toh(fchdr->ox_id);
830  /* note, tgt_task_tag, hw_tag set when HAL io is allocated */
831  fcp_dl = (uint32_t*)(&(cmnd->fcp_cdb_and_dl));
832  fcp_dl += cmnd->additional_fcp_cdb_length;
833  io->exp_xfer_len = ocs_be32toh(*fcp_dl);
834  io->transferred = 0;
835 
836  /* The upper 7 bits of CS_CTL is the frame priority thru the SAN.
837  * Our assertion here is, the priority given to a frame containing
838  * the FCP cmd should be the priority given to ALL frames contained
839  * in that IO. Thus we need to save the incoming CS_CTL here.
840  */
841  if (fc_be24toh(fchdr->f_ctl) & FC_FCTL_PRIORITY_ENABLE) {
842  io->cs_ctl = fchdr->cs_ctl;
843  } else {
844  io->cs_ctl = 0;
845  }
846  io->seq_init = sit;
847 }
848 
849 static uint32_t
851 {
852  uint32_t flags = 0;
853  switch (cmnd->task_attribute) {
855  flags |= OCS_SCSI_CMD_SIMPLE;
856  break;
859  break;
861  flags |= OCS_SCSI_CMD_ORDERED;
862  break;
863  case FCP_TASK_ATTR_ACA:
864  flags |= OCS_SCSI_CMD_ACA;
865  break;
867  flags |= OCS_SCSI_CMD_UNTAGGED;
868  break;
869  }
870  if (cmnd->wrdata)
871  flags |= OCS_SCSI_CMD_DIR_IN;
872  if (cmnd->rddata)
873  flags |= OCS_SCSI_CMD_DIR_OUT;
874 
875  return flags;
876 }
877 
878 /**
879  * @ingroup unsol
880  * @brief Dispatch unsolicited FCP_CMND frame.
881  *
882  * <h3 class="desc">Description</h3>
883  * Dispatch unsolicited FCP_CMND frame. RQ Pair mode - always
884  * used for RQ Pair mode since first burst is not supported.
885  *
886  * @param node Node that originated the frame.
887  * @param seq Header/payload sequence buffers.
888  *
889  * @return Returns 0 if frame processed and RX buffers cleaned
890  * up appropriately, -1 if frame not handled and RX buffers need
891  * to be returned.
892  */
893 static int32_t
895 {
896  ocs_t *ocs = node->ocs;
897  fc_header_t *fchdr = seq->header->dma.virt;
898  fcp_cmnd_iu_t *cmnd = NULL;
899  ocs_io_t *io = NULL;
900  fc_vm_header_t *vhdr;
901  uint8_t df_ctl;
902  uint32_t lun = UINT32_MAX;
903  int32_t rc = 0;
904 
905  ocs_assert(seq->payload, -1);
906  cmnd = seq->payload->dma.virt;
907 
908  /* perform FCP_CMND validation check(s) */
909  if (ocs_validate_fcp_cmd(ocs, seq)) {
910  return -1;
911  }
912 
913  lun = ocs_fc_decode_lun(cmnd->fcp_lun);
914  if (lun == UINT32_MAX) {
915  return -1;
916  }
917 
919  if (io == NULL) {
920  uint32_t send_frame_capable;
921 
922  /* If we have SEND_FRAME capability, then use it to send task set full or busy */
923  rc = ocs_hal_get(&ocs->hal, OCS_HAL_SEND_FRAME_CAPABLE, &send_frame_capable);
924  if ((rc == 0) && send_frame_capable) {
926  if (rc) {
927  ocs_log_test(ocs, "ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
928  }
929  return rc;
930  }
931 
932  ocs_log_err(ocs, "IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->ox_id));
933  return -1;
934  }
935  io->hal_priv = seq->hal_priv;
936 
937  /* Check if the CMD has vmheader. */
938  io->app_id = 0;
939  df_ctl = fchdr->df_ctl;
940  if (df_ctl & FC_DFCTL_DEVICE_HDR_16_MASK) {
941  uint32_t vmhdr_offset = 0;
942  /* Presence of VMID. Get the vm header offset. */
943  if (df_ctl & FC_DFCTL_ESP_HDR_MASK) {
944  vmhdr_offset += FC_DFCTL_ESP_HDR_SIZE;
945  ocs_log_err(ocs, "ESP Header present. Fix ESP Size.\n");
946  }
947 
948  if (df_ctl & FC_DFCTL_NETWORK_HDR_MASK) {
949  vmhdr_offset += FC_DFCTL_NETWORK_HDR_SIZE;
950  }
951  vhdr = (fc_vm_header_t *) ((char *)fchdr + sizeof(fc_header_t) + vmhdr_offset);
952  io->app_id = ocs_be32toh(vhdr->src_vmid);
953  }
954 
955  /* RQ pair, if we got here, SIT=1 */
956  ocs_populate_io_fcp_cmd(io, cmnd, fchdr, TRUE);
957 
958  if (cmnd->task_management_flags) {
960  } else {
961  uint32_t flags = ocs_get_flags_fcp_cmd(cmnd);
962 
963  /* can return failure for things like task set full and UAs,
964  * no need to treat as a dropped frame if rc != 0
965  */
966  ocs_scsi_recv_cmd(io, lun, cmnd->fcp_cdb,
967  sizeof(cmnd->fcp_cdb) +
968  (cmnd->additional_fcp_cdb_length * sizeof(uint32_t)),
969  flags);
970  }
971 
972  /* successfully processed, now return RX buffer to the chip */
973  ocs_hal_sequence_free(&ocs->hal, seq);
974  return 0;
975 }
976 
977 /**
978  * @ingroup unsol
979  * @brief Dispatch unsolicited FCP_CMND frame.
980  *
981  * <h3 class="desc">Description</h3>
982  * Dispatch unsolicited FCP_CMND frame that is assisted with TOW.
983  *
984  * @param node Node that originated the frame.
985  * @param seq Header/payload sequence buffers.
986  *
987  * @return Returns 0 if frame processed and RX buffers cleaned
988  * up appropriately, -1 if frame not handled and RX buffers need
989  * to be returned.
990  */
991 static int32_t ocs_dispatch_tow_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
992 {
993  ocs_t *ocs = node->ocs;
994  fc_header_t *fchdr = seq->header->dma.virt;
995  fcp_cmnd_iu_t *cmnd = NULL;
996  ocs_io_t *io = NULL;
997  uint32_t lun = UINT32_MAX;
998  int32_t rc = 0;
999 
1000  ocs_assert(seq->payload, -1);
1001  cmnd = seq->payload->dma.virt;
1002 
1003  /* perform FCP_CMND validation check(s) */
1004  if (ocs_validate_fcp_cmd(ocs, seq)) {
1005  return -1;
1006  }
1007 
1008  /* make sure first burst or auto xfer_rdy is enabled */
1009  if (!seq->tow) {
1010  node_printf(node, "IO is not optimized write assisted, dropping FCP_CMND\n");
1011  return -1;
1012  }
1013 
1014  lun = ocs_fc_decode_lun(cmnd->fcp_lun);
1015 
1016  // TODO should there be a check here for an error? Why do any of the
1017  // below if the LUN decode failed?
1019  if (io == NULL) {
1020  uint32_t send_frame_capable;
1021 
1022  /* If we have SEND_FRAME capability, then use it to send task set full or busy */
1023  rc = ocs_hal_get(&ocs->hal, OCS_HAL_SEND_FRAME_CAPABLE, &send_frame_capable);
1024  if ((rc == 0) && send_frame_capable) {
1025  rc = ocs_sframe_send_task_set_full_or_busy(node, seq);
1026  if (rc) {
1027  ocs_log_test(ocs, "ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
1028  }
1029  return rc;
1030  }
1031 
1032  ocs_log_err(ocs, "IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->ox_id));
1033  return -1;
1034  }
1035  io->hal_priv = seq->hal_priv;
1036 
1037  /* RQ pair, if we got here, SIT=0 */
1038  ocs_populate_io_fcp_cmd(io, cmnd, fchdr, FALSE);
1039 
1040  if (cmnd->task_management_flags) {
1041  /* first burst command better not be a TMF */
1042  ocs_log_err(ocs, "TMF flags set 0x%x\n", cmnd->task_management_flags);
1043  ocs_scsi_io_free(io);
1044  return -1;
1045  } else {
1046  uint32_t flags = ocs_get_flags_fcp_cmd(cmnd);
1047 
1048  /* activate HAL IO */
1049  ocs_hal_io_activate_port_owned(&ocs->hal, seq->hio);
1050  io->hio = seq->hio;
1051  seq->hio->ul_io = io;
1052  io->tgt_task_tag = seq->hio->indicator;
1053 
1054  /* Note: Data buffers are received in another call */
1055  ocs_scsi_recv_cmd_first_burst(io, lun, cmnd->fcp_cdb,
1056  sizeof(cmnd->fcp_cdb) +
1057  (cmnd->additional_fcp_cdb_length * sizeof(uint32_t)),
1058  flags, NULL, 0);
1059  }
1060 
1061  /* FCP_CMND processed, return RX buffer to the chip */
1062  ocs_hal_sequence_free(&ocs->hal, seq);
1063  return 0;
1064 }
1065 
1066 /**
1067  * @ingroup unsol
1068  * @brief Dispatch FCP data frames for TOW.
1069  *
1070  * <h3 class="desc">Description</h3>
1071  * Dispatch unsolicited FCP data frames
1072  * containing sequence initiative transferred (SIT=1).
1073  *
1074  * @param node Node that originated the frame.
1075  * @param seq Header/payload sequence buffers.
1076  *
1077  * @return Returns 0 if frame processed and RX buffers cleaned
1078  * up appropriately, -1 if frame not handled.
1079  */
1080 
1081 static int32_t
1083 {
1084  ocs_t *ocs = node->ocs;
1085  ocs_hal_t *hal = &ocs->hal;
1086  ocs_hal_io_t *hio = seq->hio;
1087  ocs_io_t *io;
1088  ocs_dma_t fburst[1];
1089 
1090  ocs_assert(seq->payload, -1);
1091  ocs_assert(hio, -1);
1092 
1093  io = hio->ul_io;
1094  if (io == NULL) {
1095  ocs_log_err(ocs, "data received for NULL io, xri=0x%x\n",
1096  hio->indicator);
1097  return -1;
1098  }
1099 
1100  /*
1101  * We only support data completions for TOW. Make sure
1102  * this is a port owned XRI.
1103  */
1104  if (!ocs_hal_is_io_port_owned(hal, seq->hio)) {
1105  ocs_log_err(ocs, "data received for host owned XRI, xri=0x%x\n",
1106  hio->indicator);
1107  return -1;
1108  }
1109 
1110  /* For error statuses, pass the error to the target back end */
1111  if (seq->status != OCS_HAL_UNSOL_SUCCESS) {
1112  ocs_log_err(ocs, "data with status 0x%x received, xri=0x%x\n",
1113  seq->status, hio->indicator);
1114 
1115  /*
1116  * In this case, there is an existing, in-use HAL IO that
1117  * first may need to be aborted. Then, the backend will be
1118  * notified of the error while waiting for the data.
1119  */
1120  ocs_port_owned_abort(ocs, seq->hio);
1121 
1122  /*
1123  * HAL IO has already been allocated and is waiting for data.
1124  * Need to tell backend that an error has occurred.
1125  */
1126  ocs_scsi_recv_cmd_first_burst(io, 0, NULL, 0, OCS_SCSI_FIRST_BURST_ERR, NULL, 0);
1127  return -1;
1128  }
1129 
1130  /* sequence initiative has been transferred */
1131  io->seq_init = 1;
1132 
1133  /* convert the array of pointers to the correct type, to send to backend */
1134  fburst[0] = seq->payload->dma;
1135 
1136  /* the amount of first burst data was saved as "acculated sequence length" */
1137  io->transferred = seq->payload->dma.len;
1138  if (ocs_scsi_recv_cmd_first_burst(io, 0, NULL, 0, 0,
1139  fburst, io->transferred)) {
1140  ocs_log_err(ocs, "error passing first burst, xri=0x%x, oxid=0x%x\n",
1141  hio->indicator, io->init_task_tag);
1142  }
1143 
1144  /* Free the header and all the accumulated payload buffers */
1145  ocs_hal_sequence_free(&ocs->hal, seq);
1146  return 0;
1147 }
1148 
1149 
1150 /**
1151  * @ingroup unsol
1152  * @brief Handle the callback for the TMF FUNCTION_REJECTED response.
1153  *
1154  * <h3 class="desc">Description</h3>
1155  * Handle the callback of a send TMF FUNCTION_REJECTED response request.
1156  *
1157  * @param io Pointer to the IO context.
1158  * @param scsi_status Status of the response.
1159  * @param flags Callback flags.
1160  * @param arg Callback argument.
1161  *
1162  * @return Returns 0 on success, or a negative error value on failure.
1163  */
1164 
1165 static int32_t
1166 ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
1167 {
1168  ocs_scsi_io_free(io);
1169  return 0;
1170 }
1171 
1172 /**
1173  * @ingroup unsol
1174  * @brief Decode a LU Number according to SAM.
1175  *
1176  * <h3 class="desc">Description</h3>
1177  * Decode a LU Number according to SAM.
1178  * \b Note: Only handles a single-level LU.
1179  *
1180  * @param lu Pointer to the LU data.
1181  *
1182  * @return Returns the LU Number; or the maximum integer on error.
1183  *
1184  * @todo move to generic FC file
1185  */
1186 
1187 static uint32_t
1188 ocs_fc_decode_lun(uint8_t *lu)
1189 {
1190  uint32_t lun = UINT32_MAX;
1191  uint8_t address_method = -1;
1192 
1193  address_method = lu[0] >> FCP_LUN_ADDRESS_METHOD_SHIFT;
1194 
1195  switch (address_method) {
1197  {
1198  uint8_t bus_identifier = lu[0] & ~FCP_LUN_ADDRESS_METHOD_MASK;
1199 
1200  if (0 == bus_identifier) {
1201  lun = lu[1];
1202  } else {
1203  ocs_log_test(NULL, "unsupported bus identifier %#02x (LU %02x %02x %02x %02x ...\n",
1204  bus_identifier, lu[0], lu[1], lu[2], lu[3]);
1205  }
1206  break;
1207  }
1209  {
1210  lun = (lu[0] & ~FCP_LUN_ADDRESS_METHOD_MASK) << 8 | lu[1];
1211  break;
1212  }
1214  {
1215  uint8_t length, extended_address_method;
1216 
1217  length = (lu[0] & 0x30) >> 4;
1218  extended_address_method = lu[0] & 0xf;
1219 
1220  if ((1 == length) && (2 == extended_address_method)) {
1221  lun = (lu[1] << 16) | (lu[2] << 8) | lu[3];
1222  } else {
1223  ocs_log_test(NULL, "unsupported extended addressing method (length=%#x method=%#x)\n",
1224  length, extended_address_method);
1225  }
1226  break;
1227  }
1228  default:
1229  ocs_log_test(NULL, "unsupported LU address method %#02x\n", address_method);
1230  }
1231 
1232  return lun;
1233 }
1234 
1235 /**
1236  * @brief Return next FC frame on node->pend_frames list
1237  *
1238  * The next FC frame on the node->pend_frames list is returned, or NULL
1239  * if the list is empty.
1240  *
1241  * @param pend_list Pending list to be purged.
1242  * @param list_lock Lock that protects pending list.
1243  *
1244  * @return Returns pointer to the next FC frame, or NULL if the pending frame list
1245  * is empty.
1246  */
1248 ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock)
1249 {
1250  ocs_hal_sequence_t *frame = NULL;
1251 
1252  ocs_lock(list_lock);
1253  frame = ocs_list_remove_head(pend_list);
1254  ocs_unlock(list_lock);
1255  return frame;
1256 }
1257 
1258 /**
1259  * @brief Process send fcp response frame callback
1260  *
1261  * The function is called when the send FCP response posting has completed. Regardless
1262  * of the outcome, the sequence is freed.
1263  *
1264  * @param arg Pointer to originator frame sequence.
1265  * @param cqe Pointer to completion queue entry.
1266  * @param status Status of operation.
1267  *
1268  * @return None.
1269  */
1270 static void
1271 ocs_sframe_common_send_cb(void *arg, uint8_t *cqe, int32_t status)
1272 {
1273  ocs_hal_send_frame_context_t *ctx = arg;
1274  ocs_hal_t *hal = ctx->hal;
1275 
1276  /* Free WQ completion callback */
1277  ocs_hal_reqtag_free(hal, ctx->wqcb);
1278 
1279  /* Free sequence */
1280  ocs_hal_sequence_free(hal, ctx->seq);
1281 }
1282 
1283 /**
1284  * @brief Send a frame, common code
1285  *
1286  * A frame is sent using SEND_FRAME, the R_CTL/F_CTL/TYPE may be specified, the payload is
1287  * sent as a single frame.
1288  *
1289  * Memory resources are allocated from RQ buffers contained in the passed in sequence data.
1290  *
1291  * @param node Pointer to node object.
1292  * @param seq Pointer to sequence object.
1293  * @param r_ctl R_CTL value to place in FC header.
1294  * @param info INFO value to place in FC header.
1295  * @param f_ctl F_CTL value to place in FC header.
1296  * @param type TYPE value to place in FC header.
1297  * @param payload Pointer to payload data
1298  * @param payload_len Length of payload in bytes.
1299  *
1300  * @return Returns 0 on success, or a negative error code value on failure.
1301  */
1302 static int32_t
1303 ocs_sframe_common_send(ocs_node_t *node, ocs_hal_sequence_t *seq, uint8_t r_ctl, uint8_t info, uint32_t f_ctl,
1304  uint8_t type, void *payload, uint32_t payload_len)
1305 {
1306  ocs_t *ocs = node->ocs;
1307  ocs_hal_t *hal = &ocs->hal;
1308  ocs_hal_rtn_e rc = 0;
1309  fc_header_t *behdr = seq->header->dma.virt;
1310  fc_header_le_t hdr;
1311  uint32_t s_id = fc_be24toh(behdr->s_id);
1312  uint32_t d_id = fc_be24toh(behdr->d_id);
1313  uint16_t ox_id = ocs_be16toh(behdr->ox_id);
1314  uint16_t rx_id = ocs_be16toh(behdr->rx_id);
1316 
1317  uint32_t heap_size = seq->payload->dma.size;
1318  uintptr_t heap_phys_base = seq->payload->dma.phys;
1319  uint8_t *heap_virt_base = seq->payload->dma.virt;
1320  uint32_t heap_offset = 0;
1321 
1322  /* Build the FC header reusing the RQ header DMA buffer */
1323  ocs_memset(&hdr, 0, sizeof(hdr));
1324  hdr.d_id = s_id; /* send it back to whomever sent it to us */
1325  hdr.r_ctl = r_ctl;
1326  hdr.info = info;
1327  hdr.s_id = d_id;
1328  hdr.cs_ctl = 0;
1329  hdr.f_ctl = f_ctl;
1330  hdr.type = type;
1331  hdr.seq_cnt = 0;
1332  hdr.df_ctl = 0;
1333 
1334  /*
1335  * send_frame_seq_id is an atomic, we just let it increment, while storing only
1336  * the low 8 bits to hdr->seq_id
1337  */
1338  hdr.seq_id = (uint8_t) ocs_atomic_add_return(&hal->send_frame_seq_id, 1);
1339 
1340  hdr.rx_id = rx_id;
1341  hdr.ox_id = ox_id;
1342  hdr.parameter = 0;
1343 
1344  /* Allocate and fill in the send frame request context */
1345  ctx = (void*)(heap_virt_base + heap_offset);
1346  heap_offset += sizeof(*ctx);
1347  ocs_assert(heap_offset < heap_size, -1);
1348  ocs_memset(ctx, 0, sizeof(*ctx));
1349 
1350  /* Save sequence */
1351  ctx->seq = seq;
1352 
1353  /* Allocate a response payload DMA buffer from the heap */
1354  ctx->payload.phys = heap_phys_base + heap_offset;
1355  ctx->payload.virt = heap_virt_base + heap_offset;
1356  ctx->payload.size = payload_len;
1357  ctx->payload.len = payload_len;
1358  heap_offset += payload_len;
1359  ocs_assert(heap_offset <= heap_size, -1);
1360 
1361  /* Copy the payload in */
1362  ocs_memcpy(ctx->payload.virt, payload, payload_len);
1363 
1364  /* Send */
1365  rc = ocs_hal_send_frame(&ocs->hal, (void*)&hdr, FC_SOFI3, FC_EOFT, &ctx->payload, ctx,
1367  if (rc) {
1368  ocs_log_test(ocs, "ocs_hal_send_frame failed: %d\n", rc);
1369  }
1370 
1371  return rc ? -1 : 0;
1372 }
1373 
1374 /**
1375  * @brief Send FCP response using SEND_FRAME
1376  *
1377  * The FCP response is send using the SEND_FRAME function.
1378  *
1379  * @param node Pointer to node object.
1380  * @param seq Pointer to inbound sequence.
1381  * @param rsp Pointer to response data.
1382  * @param rsp_len Length of response data, in bytes.
1383  *
1384  * @return Returns 0 on success, or a negative error code value on failure.
1385  */
1386 static int32_t
1387 ocs_sframe_send_fcp_rsp(ocs_node_t *node, ocs_hal_sequence_t *seq, void *rsp, uint32_t rsp_len)
1388 {
1389  return ocs_sframe_common_send(node, seq,
1396  FC_TYPE_FCP,
1397  rsp, rsp_len);
1398 }
1399 
1400 /**
1401  * @brief Send task set full response
1402  *
1403  * Return a task set full or busy response using send frame.
1404  *
1405  * @param node Pointer to node object.
1406  * @param seq Pointer to originator frame sequence.
1407  *
1408  * @return Returns 0 on success, or a negative error code value on failure.
1409  */
1410 static int32_t
1412 {
1413  fcp_rsp_iu_t fcprsp;
1414  fcp_cmnd_iu_t *fcpcmd = seq->payload->dma.virt;
1415  uint32_t *fcp_dl_ptr;
1416  uint32_t fcp_dl;
1417  int32_t rc = 0;
1418 
1419  /* extract FCP_DL from FCP command*/
1420  fcp_dl_ptr = (uint32_t*)(&(fcpcmd->fcp_cdb_and_dl));
1421  fcp_dl_ptr += fcpcmd->additional_fcp_cdb_length;
1422  fcp_dl = ocs_be32toh(*fcp_dl_ptr);
1423 
1424  /* construct task set full or busy response */
1425  ocs_memset(&fcprsp, 0, sizeof(fcprsp));
1426  ocs_lock(&node->active_ios_lock);
1427  fcprsp.scsi_status = ocs_list_empty(&node->active_ios) ? SCSI_STATUS_BUSY : SCSI_STATUS_TASK_SET_FULL;
1428  ocs_unlock(&node->active_ios_lock);
1429  *((uint32_t*)&fcprsp.fcp_resid) = fcp_dl;
1430 
1431  /* send it using send_frame */
1432  rc = ocs_sframe_send_fcp_rsp(node, seq, &fcprsp, sizeof(fcprsp) - sizeof(fcprsp.data));
1433  if (rc) {
1434  ocs_log_test(node->ocs, "ocs_sframe_send_fcp_rsp failed: %d\n", rc);
1435  }
1436  return rc;
1437 }
1438 
1439 /**
1440  * @brief Send BA_ACC using sent frame
1441  *
1442  * A BA_ACC is sent using SEND_FRAME
1443  *
1444  * @param node Pointer to node object.
1445  * @param seq Pointer to originator frame sequence.
1446  *
1447  * @return Returns 0 on success, or a negative error code value on failure.
1448  */
1449 int32_t
1451 {
1452  fc_header_t *behdr = seq->header->dma.virt;
1453  uint16_t ox_id = ocs_be16toh(behdr->ox_id);
1454  uint16_t rx_id = ocs_be16toh(behdr->rx_id);
1455  fc_ba_acc_payload_t acc = {0};
1456 
1457  acc.ox_id = ocs_htobe16(ox_id);
1458  acc.rx_id = ocs_htobe16(rx_id);
1459  acc.low_seq_cnt = UINT16_MAX;
1460  acc.high_seq_cnt = UINT16_MAX;
1461 
1462  return ocs_sframe_common_send(node, seq,
1463  FC_RCTL_BLS,
1469  &acc, sizeof(acc));
1470 }
void ocs_domain_accept_frames(ocs_domain_t *domain)
Clear hold on unsolicited frames.
Definition: ocs_unsol.c:546
uint8_t additional_fcp_cdb_length
Definition: ocs_fcp.h:838
uint32_t info
Definition: ocs_fcp.h:179
uint32_t r_ctl
Definition: ocs_fcp.h:158
#define OCS_SCSI_FIRST_BURST_ERR
Definition: ocs_scsi.h:54
uint32_t low_seq_cnt
Definition: ocs_fcp.h:300
int32_t ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously-allocated HAL IO object.
Definition: ocs_hal.c:4001
static int32_t ocs_sframe_send_task_set_full_or_busy(ocs_node_t *node, ocs_hal_sequence_t *seq)
Send task set full response.
Definition: ocs_unsol.c:1411
#define OCS_MAX_FRAMES_BEFORE_YEILDING
Definition: ocs_unsol.c:71
ocs_sport_t * ocs_sport_find(ocs_domain_t *domain, uint32_t d_id)
Find a SLI port object, given an FC_ID.
Definition: ocs_sport.c:365
#define SCSI_STATUS_BUSY
Definition: scsi_cmds.h:267
ocs_scsi_tmf_cmd_e
Definition: ocs_scsi.h:138
int32_t ocs_scsi_recv_tmf(ocs_io_t *tmfio, uint32_t lun, ocs_scsi_tmf_cmd_e cmd, ocs_io_t *abortio, uint32_t flags)
Receive a TMF command IO.
Definition: ocs_ramd.c:2682
int32_t ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hal_sequence_t *seq)
Stub handler for non-ABTS BLS frames.
Definition: ocs_node.c:2549
uint8_t ocs_hal_is_io_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Determine if HAL IO is owned by the port.
Definition: ocs_hal.c:12789
void ocs_hal_reqtag_free(ocs_hal_t *hal, hal_wq_callback_t *wqcb)
Free a WQ request tag.
Definition: ocs_hal.c:13406
uint32_t cs_ctl
Definition: ocs_fcp.h:182
#define OCS_SCSI_CMD_HEAD_OF_QUEUE
Definition: ocs_scsi.h:50
FC VM header in big-endian order.
Definition: ocs_fcp.h:200
int32_t ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ABTS frame (RQ Pair/sequence coalescing).
Definition: ocs_node.c:2342
uint32_t pend_frames_processed
Definition: ocs_xport.h:48
uint32_t df_ctl
Definition: ocs_fcp.h:165
int32_t ocs_domain_purge_pending(ocs_domain_t *domain)
Purge xport&#39;s pending (queued) frames.
Definition: ocs_unsol.c:450
ocs_hal_rq_buffer_t * header
Definition: ocs_hal.h:790
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
int32_t ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a CT frame.
Definition: ocs_node.c:2420
#define FC_RCTL_INFO_UNSOL_DATA
Definition: ocs_fcp.h:221
#define FC_FCTL_SEQUENCE_INITIATIVE
Definition: ocs_fcp.h:233
#define FC_EOFT
Definition: ocs_fcp.h:152
#define FCP_TASK_ATTR_ORDERED
Definition: ocs_fcp.h:857
static void ocs_dispatch_unsolicited_tmf(ocs_io_t *io, uint8_t task_management_flags, ocs_node_t *node, uint32_t lun)
Dispatch unsolicited FCP frames (RQ Pair).
Definition: ocs_unsol.c:770
uint32_t parameter
Definition: ocs_fcp.h:191
ocs_hal_rtn_e ocs_hal_send_frame(ocs_hal_t *hal, fc_header_le_t *hdr, uint8_t sof, uint8_t eof, ocs_dma_t *payload, ocs_hal_send_frame_context_t *ctx, void(*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
Send a raw frame.
Definition: ocs_hal.c:4817
#define FCP_TARGET_RESET
Definition: ocs_fcp.h:866
int32_t ocs_domain_process_pending(ocs_domain_t *domain)
Process pending frames queued to the given domain.
Definition: ocs_unsol.c:336
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
uint32_t seq_id
Definition: ocs_fcp.h:186
uint32_t f_ctl
Definition: ocs_fcp.h:184
uint32_t r_ctl
Definition: ocs_fcp.h:179
uint32_t d_id
Definition: ocs_fcp.h:179
#define FCP_TASK_ATTR_UNTAGGED
Definition: ocs_fcp.h:859
uint32_t ox_id
Definition: ocs_fcp.h:168
ocs_hal_rtn_e
Definition: ocs_hal.h:159
hal_wq_callback_t * wqcb
Definition: ocs_hal.h:1450
static uint32_t ocs_fc_decode_lun(uint8_t *lu)
Decode a LU Number according to SAM.
Definition: ocs_unsol.c:1188
uint8_t fcp_lun[8]
Definition: ocs_fcp.h:832
ocs_hal_io_t * hio
Definition: ocs_hal.h:796
#define FC_TYPE_FCP
Definition: ocs_fcp.h:56
#define frame_printf(ocs, hdr, fmt,...)
Definition: ocs_unsol.c:49
static void ocs_sframe_common_send_cb(void *arg, uint8_t *cqe, int32_t status)
Process send fcp response frame callback.
Definition: ocs_unsol.c:1271
#define FC_TYPE_BASIC_LINK
Definition: ocs_fcp.h:55
uint32_t type
Definition: ocs_fcp.h:184
#define FCP_TASK_ATTR_SIMPLE
Definition: ocs_fcp.h:855
uint32_t s_id
Definition: ocs_fcp.h:182
#define FCP_LUN_ADDRESS_METHOD_MASK
Definition: ocs_fcp.h:846
int32_t ocs_node_purge_pending(ocs_node_t *node)
Purge node&#39;s pending (queued) frames.
Definition: ocs_unsol.c:431
ocs_hal_sequence_t * ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock)
Return next FC frame on node-&gt;pend_frames list.
Definition: ocs_unsol.c:1248
ocs_list_t pend_frames
Definition: ocs_xport.h:46
ocs_node_t * ocs_node_find(ocs_sport_t *sport, uint32_t port_id)
Find an FC node structure given the FC port ID.
Definition: ocs_node.c:202
#define FC_RCTL_INFO_CMD_STATUS
Definition: ocs_fcp.h:224
void ocs_scsi_io_free(ocs_io_t *io)
Free a SCSI IO context.
Definition: ocs_scsi.c:317
#define OCS_SCSI_CMD_ACA
Definition: ocs_scsi.h:53
uint32_t rx_id
Definition: ocs_fcp.h:189
void ocs_node_init_device(ocs_node_t *node, int send_plogi)
Initialize device node.
Definition: ocs_device.c:781
#define OCS_SCSI_CMD_DIR_OUT
Definition: ocs_scsi.h:48
#define FCP_LUN_ADDR_METHOD_PERIPHERAL
Definition: ocs_fcp.h:847
uint32_t seq_cnt
Definition: ocs_fcp.h:186
#define FC_FCTL_END_SEQUENCE
Definition: ocs_fcp.h:230
#define FCP_TASK_ATTR_ACA
Definition: ocs_fcp.h:858
static uint8_t ocs_domain_frames_held(void *arg)
Check if domain&#39;s pending frames are held.
Definition: ocs_unsol.c:492
ocs_lock_t pend_frames_lock
Definition: ocs_xport.h:45
static ocs_hal_rtn_e ocs_hal_sequence_free(ocs_hal_t *hal, ocs_hal_sequence_t *seq)
Definition: ocs_hal.h:1512
static int32_t ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock)
Purge given pending list.
Definition: ocs_unsol.c:397
#define FCP_QUERY_ASYNCHRONOUS_EVENT
Definition: ocs_fcp.h:864
uint32_t ox_id
Definition: ocs_fcp.h:189
#define CPUTRACE(...)
Definition: ocs_hal.h:1537
uint32_t cs_ctl
Definition: ocs_fcp.h:161
uint32_t d_id
Definition: ocs_fcp.h:158
#define FC_DFCTL_ESP_HDR_MASK
Definition: ocs_fcp.h:209
FC header in big-endian order.
Definition: ocs_fcp.h:157
int32_t ocs_unsolicited_cb(void *arg, ocs_hal_sequence_t *seq)
Handle unsolicited FC frames.
Definition: ocs_unsol.c:164
#define FC_RCTL_INFO_UNSOL_CMD
Definition: ocs_fcp.h:223
static int32_t ocs_dispatch_fcp_data(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch FCP data frames for TOW.
Definition: ocs_unsol.c:1082
uint32_t hold_frames
Definition: ocs_xport.h:47
#define FC_SOFI3
Definition: ocs_fcp.h:149
static void ocs_populate_io_fcp_cmd(ocs_io_t *io, fcp_cmnd_iu_t *cmnd, fc_header_t *fchdr, uint8_t sit)
Definition: ocs_unsol.c:826
#define OCS_SCSI_CMD_UNTAGGED
Definition: ocs_scsi.h:52
#define FCP_ABORT_TASK_SET
Definition: ocs_fcp.h:862
#define FCP_QUERY_TASK_SET
Definition: ocs_fcp.h:861
#define FC_DFCTL_NETWORK_HDR_SIZE
Definition: ocs_fcp.h:210
#define OCS_SCSI_CMD_SIMPLE
Definition: ocs_scsi.h:49
uint8_t fcp_cdb[16]
Definition: ocs_fcp.h:841
FC header in little-endian order.
Definition: ocs_fcp.h:177
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:1840
static int32_t ocs_node_dispatch_frame(void *arg, ocs_hal_sequence_t *seq)
Dispatch a frame.
Definition: ocs_unsol.c:681
#define FC_RCTL_INFO_SOL_CTRL
Definition: ocs_fcp.h:220
uint8_t data[FCP_MAX_RSP_INFO_LEN]
Definition: ocs_fcp.h:886
static int32_t ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
Handle the callback for the TMF FUNCTION_REJECTED response.
Definition: ocs_unsol.c:1166
#define OCS_SCSI_CMD_ORDERED
Definition: ocs_scsi.h:51
static int32_t ocs_dispatch_tow_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch unsolicited FCP_CMND frame.
Definition: ocs_unsol.c:991
uint8_t task_attribute
Definition: ocs_fcp.h:834
static uint32_t ocs_get_flags_fcp_cmd(fcp_cmnd_iu_t *cmnd)
Definition: ocs_unsol.c:850
ocs_hal_t * hal
Definition: ocs_hal.h:785
#define FC_TYPE_GS
Definition: ocs_fcp.h:58
static void ocs_port_owned_abort(ocs_t *ocs, ocs_hal_io_t *hio)
Abort either a RQ Pair auto XFER RDY XRI.
Definition: ocs_unsol.c:136
void * ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
Get pointer to buffer.
Definition: ocs_cbuf.c:126
ocs_node_t * ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
Allocate an fc node structure and add to node list.
Definition: ocs_node.c:415
#define FC_FCTL_PRIORITY_ENABLE
Definition: ocs_fcp.h:232
int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
ocs_domain_t * ocs_hal_domain_get(ocs_hal_t *hal, uint16_t fcfi)
Definition: ocs_hal.c:9692
uint32_t df_ctl
Definition: ocs_fcp.h:186
uint8_t rddata
Definition: ocs_fcp.h:838
static int32_t ocs_unsol_process(ocs_t *ocs, ocs_hal_sequence_t *seq)
Handle unsolicited FC frames.
Definition: ocs_unsol.c:203
int32_t ocs_node_recv_els_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ELS frame.
Definition: ocs_node.c:2231
uint32_t f_ctl
Definition: ocs_fcp.h:163
uint8_t fcp_cdb_and_dl[20]
Definition: ocs_fcp.h:842
static int32_t ocs_validate_fcp_cmd(ocs_t *ocs, ocs_hal_sequence_t *seq)
Definition: ocs_unsol.c:803
#define SCSI_STATUS_TASK_SET_FULL
Definition: scsi_cmds.h:269
#define FC_FCTL_EXCHANGE_RESPONDER
Definition: ocs_fcp.h:226
ocs_hal_unsol_status_e status
Definition: ocs_hal.h:794
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_domain_hold_frames(ocs_domain_t *domain)
Globally (at xport level) hold unsolicited frames.
Definition: ocs_unsol.c:518
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
ocs_hal_io_t * ocs_hal_io_activate_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Allocate/Activate a port owned HAL IO object.
Definition: ocs_hal.c:3867
int32_t ocs_sframe_send_bls_acc(ocs_node_t *node, ocs_hal_sequence_t *seq)
Send BA_ACC using sent frame.
Definition: ocs_unsol.c:1450
static int32_t ocs_sframe_common_send(ocs_node_t *node, ocs_hal_sequence_t *seq, uint8_t r_ctl, uint8_t info, uint32_t f_ctl, uint8_t type, void *payload, uint32_t payload_len)
Send a frame, common code.
Definition: ocs_unsol.c:1303
#define OCS_SCSI_CMD_DIR_IN
Definition: ocs_scsi.h:47
static int32_t ocs_sframe_send_fcp_rsp(ocs_node_t *node, ocs_hal_sequence_t *seq, void *rsp, uint32_t rsp_len)
Send FCP response using SEND_FRAME.
Definition: ocs_unsol.c:1387
uint32_t uint32_t ox_id
Definition: ocs_fcp.h:295
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
Definition: ocs_hal.h:784
#define FC_DFCTL_DEVICE_HDR_16_MASK
Definition: ocs_fcp.h:207
#define FCP_LUN_ADDR_METHOD_FLAT
Definition: ocs_fcp.h:848
#define FC_RCTL_BLS
Definition: ocs_fcp.h:215
#define FCP_LOGICAL_UNIT_RESET
Definition: ocs_fcp.h:865
FCFI lookup/pending frames.
Definition: ocs_xport.h:44
uint32_t rx_id
Definition: ocs_fcp.h:168
ocs_dma_t dma
Definition: ocs_hal.h:328
uint32_t info
Definition: ocs_fcp.h:158
uint32_t type
Definition: ocs_fcp.h:163
int32_t ocs_process_node_pending(ocs_node_t *node)
Process pending frames queued to the given node.
Definition: ocs_unsol.c:278
uint8_t fcp_resid[4]
Definition: ocs_fcp.h:883
#define node_printf(node, fmt,...)
Definition: ocs_node.h:48
#define FC_DFCTL_ESP_HDR_SIZE
Definition: ocs_fcp.h:211
#define SLI4_MAX_FCFI
Maximum value for a FCFI.
Definition: sli4_fc.h:52
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
#define FC_RCTL_FC4_DATA
Definition: ocs_fcp.h:213
int32_t ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
write a buffer
Definition: ocs_cbuf.c:153
static int32_t ocs_unsol_abort_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, uint32_t ext, void *arg)
Callback function when aborting a port owned XRI exchanges.
Definition: ocs_unsol.c:119
uint32_t uint32_t rx_id
Definition: ocs_fcp.h:295
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
ocs_hal_sequence_t * seq
Definition: ocs_hal.h:1456
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
uint32_t s_id
Definition: ocs_fcp.h:161
ocs_scsi_io_status_e
Definition: ocs_scsi.h:105
int32_t ocs_unsol_rq_thread(ocs_thread_t *mythread)
Process the RQ circular buffer and process the incoming frames.
Definition: ocs_unsol.c:81
int32_t ocs_scsi_recv_cmd_first_burst(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags, ocs_dma_t first_burst_buffers[], uint32_t first_burst_bytes)
Receive an FCP SCSI command with the first burst data.
Definition: ocs_ramd.c:1230
#define FC_RCTL_INFO_SOL_DATA
Definition: ocs_fcp.h:218
#define FCP_CLEAR_ACA
Definition: ocs_fcp.h:867
int32_t ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a FCP command frame when the node is not ready.
Definition: ocs_node.c:2522
uint8_t scsi_status
Definition: ocs_fcp.h:882
uint8_t uint8_t task_management_flags
Definition: ocs_fcp.h:834
uint32_t high_seq_cnt
Definition: ocs_fcp.h:300
#define FC_RCTL_ELS
Definition: ocs_fcp.h:214
static int32_t ocs_dispatch_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch unsolicited FCP_CMND frame.
Definition: ocs_unsol.c:894
int32_t ocs_scsi_io_alloc_enabled(ocs_node_t *node)
Get state of IO allocation.
Definition: ocs_scsi.c:160
static int32_t ocs_domain_dispatch_frame(void *arg, ocs_hal_sequence_t *seq)
Dispatch unsolicited FC frame.
Definition: ocs_unsol.c:578
#define FCP_LUN_ADDRESS_METHOD_SHIFT
Definition: ocs_fcp.h:845
ocs_hal_rq_buffer_t * payload
Definition: ocs_hal.h:791
static uint8_t ocs_node_frames_held(void *arg)
Check if node&#39;s pending frames are held.
Definition: ocs_unsol.c:474
uint8_t wrdata
Definition: ocs_fcp.h:838
#define FC_DFCTL_NETWORK_HDR_MASK
Definition: ocs_fcp.h:208
Structure to hold the information related to an RQ processing thread used to increase 40G performance...
Definition: ocs_xport.h:55
#define FC_FCTL_LAST_SEQUENCE
Definition: ocs_fcp.h:229
#define FCP_TASK_ATTR_HEAD_OF_QUEUE
Definition: ocs_fcp.h:856
#define FCP_LUN_ADDR_METHOD_EXTENDED
Definition: ocs_fcp.h:850
uint32_t src_vmid
Definition: ocs_fcp.h:202