Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_els.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  * Functions to build and send ELS/CT/BLS commands and responses.
36  */
37 
38 /*!
39 @defgroup els_api ELS/BLS/CT Command and Response Functions
40 */
41 
42 #include "ocs.h"
43 #include "ocs_els.h"
44 #include "ocs_scsi_fc.h"
45 #include "ocs_device.h"
46 #include "ocs_fabric.h"
47 
48 #define ELS_IOFMT "[i:%04x t:%04x h:%04x]"
49 #define ELS_IOFMT_ARGS(els) els->init_task_tag, els->tgt_task_tag, els->hw_tag
50 
51 #define node_els_trace() \
52  do { \
53  if (OCS_LOG_ENABLE_ELS_TRACE(ocs)) \
54  ocs_log_info(ocs, "[%s] %-20s\n", node->display_name, __func__); \
55  } while (0)
56 
57 #define els_io_printf(els, fmt, ...) \
58  ocs_log_debug(els->node->ocs, "[%s]" ELS_IOFMT " %-8s " fmt, els->node->display_name, ELS_IOFMT_ARGS(els), els->display_name, ##__VA_ARGS__);
59 
60 static int32_t ocs_els_send(ocs_io_t *els, uint32_t reqlen, uint32_t timeout_sec, ocs_hal_srrs_cb_t cb);
61 static int32_t ocs_els_send_rsp(ocs_io_t *els, uint32_t rsplen);
62 static int32_t ocs_els_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg);
63 static ocs_io_t *ocs_bls_send_acc(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id);
64 static ocs_io_t *ocs_bls_send_rjt(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id);
65 static int32_t ocs_bls_send_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
66  int32_t status, uint32_t ext_status, void *app);
67 static int32_t ocs_bls_send_rjt_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
68  int32_t status, uint32_t ext_status, void *app);
69 static void ocs_io_transition(ocs_io_t *els, ocs_sm_function_t state, void *data);
70 static ocs_io_t *ocs_els_abort_io(ocs_io_t *els, int send_abts);
71 static void _ocs_els_io_free(void *arg);
72 static void ocs_els_delay_timer_cb(void *arg);
73 
74 /* RHBA attribute jump table */
75 int (*ocs_fdmi_hba_action[])(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad) = {
76  /* Action routine Mask bit Attribute type */
77  ocs_fdmi_hba_attr_wwnn, /* bit0 RHBA_NODENAME */
78  ocs_fdmi_hba_attr_manufacturer, /* bit1 RHBA_MANUFACTURER */
79  ocs_fdmi_hba_attr_sn, /* bit2 RHBA_SERIAL_NUMBER */
80  ocs_fdmi_hba_attr_model, /* bit3 RHBA_MODEL */
81  ocs_fdmi_hba_attr_description, /* bit4 RHBA_MODEL_DESCRIPTION */
82  ocs_fdmi_hba_attr_drvr_ver, /* bit5 RHBA_DRIVER_VERSION */
83  ocs_fdmi_hba_attr_rom_ver, /* bit6 RHBA_OPTION_ROM_VERSION */
84  ocs_fdmi_hba_attr_fmw_ver, /* bit7 RHBA_FIRMWARE_VERSION */
85  ocs_fdmi_hba_attr_os_ver, /* bit8 RHBA_OS_NAME_VERSION */
86  ocs_fdmi_hba_attr_ct_len, /* bit9 RHBA_MAX_CT_PAYLOAD_LEN */
87  ocs_fdmi_hba_attr_symbolic_name, /* bit10 RHBA_SYM_NODENAME */
88  ocs_fdmi_hba_attr_vendor_info, /* bit11 RHBA_VENDOR_INFO */
89  ocs_fdmi_hba_attr_num_ports, /* bit12 RHBA_NUM_PORTS */
90  ocs_fdmi_hba_attr_fabric_wwnn, /* bit13 RHBA_FABRIC_WWNN */
91  ocs_fdmi_hba_attr_bios_ver, /* bit14 RHBA_BIOS_VERSION */
92  ocs_fdmi_hba_attr_bios_state, /* bit15 RHBA_BIOS_STATE */
93  ocs_fdmi_hba_attr_vendor_id, /* bit16 RHBA_VENDOR_ID */
94  NULL,
95 };
96 
97 /* RPA / RPRT attribute jump table */
98 int (*ocs_fdmi_port_action[])(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad) = {
99  /* Action routine Mask bit Attribute type */
100  ocs_fdmi_port_attr_fc4type, /* bit0 RPRT_SUPPORT_FC4_TYPES */
101  ocs_fdmi_port_attr_support_speed, /* bit1 RPRT_SUPPORTED_SPEED */
102  ocs_fdmi_port_attr_speed, /* bit2 RPRT_PORT_SPEED */
103  ocs_fdmi_port_attr_max_frame, /* bit3 RPRT_MAX_FRAME_SIZE */
104  ocs_fdmi_port_attr_os_devname, /* bit4 RPRT_OS_DEVICE_NAME */
105  ocs_fdmi_port_attr_host_name, /* bit5 RPRT_HOST_NAME */
106  ocs_fdmi_port_attr_wwnn, /* bit6 RPRT_NODENAME */
107  ocs_fdmi_port_attr_wwpn, /* bit7 RPRT_PORTNAME */
108  ocs_fdmi_port_attr_symbolic_name, /* bit8 RPRT_SYM_PORTNAME */
109  ocs_fdmi_port_attr_port_type, /* bit9 RPRT_PORT_TYPE */
110  ocs_fdmi_port_attr_class, /* bit10 RPRT_SUPPORTED_CLASS */
111  ocs_fdmi_port_attr_fabric_wwpn, /* bit11 RPRT_FABRICNAME */
112  ocs_fdmi_port_attr_active_fc4type, /* bit12 RPRT_ACTIVE_FC4_TYPES */
113  ocs_fdmi_port_attr_port_state, /* bit13 RPRT_PORT_STATE */
114  ocs_fdmi_port_attr_nportid, /* bit14 RPRT_PORT_ID */
115  NULL,
116 };
117 
118 #define OCS_ELS_RSP_LEN 1024
119 #define OCS_ELS_FDMI_REG_LEN 2048
120 #define OCS_ELS_FDMI_RSP_LEN 4096
121 #define OCS_ELS_GID_FT_RSP_LEN 8096 /* Enough for 2K remote target nodes */
122 #define OCS_ELS_GID_PT_RSP_LEN 8096 /* Enough for 2K remote target nodes */
123 
124 #define MAX_FDMI_ATTRIBUTE_SIZE 256
125 /**
126  * @ingroup els_api
127  * @brief ELS state machine transition wrapper.
128  *
129  * <h3 class="desc">Description</h3>
130  * This function is the transition wrapper for the ELS state machine. It grabs
131  * the node lock prior to making the transition to protect
132  * against multiple threads accessing a particular ELS. For example,
133  * one thread transitioning from __els_init to
134  * __ocs_els_wait_resp and another thread (tasklet) handling the
135  * completion of that ELS request.
136  *
137  * @param els Pointer to the IO context.
138  * @param state State to transition to.
139  * @param data Data to pass in with the transition.
140  *
141  * @return None.
142  */
143 static void
144 ocs_io_transition(ocs_io_t *els, ocs_sm_function_t state, void *data)
145 {
146  /* protect ELS events with node lock */
147  ocs_node_t *node = els->node;
148  ocs_node_lock(node);
149  ocs_sm_transition(&els->els_sm, state, data);
150  ocs_node_unlock(node);
151 }
152 
153 /**
154  * @ingroup els_api
155  * @brief ELS state machine post event wrapper.
156  *
157  * <h3 class="desc">Description</h3>
158  * Post an event wrapper for the ELS state machine. This function grabs
159  * the node lock prior to posting the event.
160  *
161  * @param els Pointer to the IO context.
162  * @param evt Event to process.
163  * @param data Data to pass in with the transition.
164  *
165  * @return None.
166  */
167 void
168 ocs_els_post_event(ocs_io_t *els, ocs_sm_event_t evt, void *data)
169 {
170  /* protect ELS events with node lock */
171  ocs_node_t *node = els->node;
172  ocs_node_lock(node);
173  els->els_evtdepth ++;
174  ocs_sm_post_event(&els->els_sm, evt, data);
175  els->els_evtdepth --;
176  ocs_node_unlock(node);
177  if (els->els_evtdepth == 0 && els->els_req_free) {
178  ocs_els_io_free(els);
179  }
180 }
181 
182 /**
183  * @ingroup els_api
184  * @brief Allocate an IO structure for an ELS IO context.
185  *
186  * <h3 class="desc">Description</h3>
187  * Allocate an IO for an ELS context. Uses OCS_ELS_RSP_LEN as response size.
188  *
189  * @param node node to associate ELS IO with
190  * @param reqlen Length of ELS request
191  * @param role Role of ELS (originator/responder)
192  *
193  * @return pointer to IO structure allocated
194  */
195 
196 ocs_io_t *
197 ocs_els_io_alloc(ocs_node_t *node, uint32_t reqlen, ocs_els_role_e role)
198 {
199  return ocs_els_io_alloc_size(node, reqlen, OCS_ELS_RSP_LEN, role);
200 }
201 
202 /**
203  * @ingroup els_api
204  * @brief Allocate an IO structure for an ELS IO context.
205  *
206  * <h3 class="desc">Description</h3>
207  * Allocate an IO for an ELS context, allowing the caller to specify the size of the response.
208  *
209  * @param node node to associate ELS IO with
210  * @param reqlen Length of ELS request
211  * @param rsplen Length of ELS response
212  * @param role Role of ELS (originator/responder)
213  *
214  * @return pointer to IO structure allocated
215  */
216 
217 ocs_io_t *
218 ocs_els_io_alloc_size(ocs_node_t *node, uint32_t reqlen, uint32_t rsplen, ocs_els_role_e role)
219 {
220 
221  int32_t rc;
222  ocs_t *ocs;
223  ocs_xport_t *xport;
224  ocs_io_t *els;
225  ocs_dma_t els_req;
226  ocs_dma_t els_rsp;
227  ocs_assert(node, NULL);
228  ocs_assert(node->ocs, NULL);
229  ocs = node->ocs;
230  ocs_assert(ocs->xport, NULL);
231  xport = ocs->xport;
232 
233  /* now allocate DMA for request and response */
234  rc = ocs_dma_alloc(ocs, &els_req, reqlen, OCS_MIN_DMA_ALIGNMENT);
235  if (rc == 0) {
236  rc = ocs_dma_alloc(ocs, &els_rsp, rsplen, OCS_MIN_DMA_ALIGNMENT);
237  if (rc != 0) {
238  ocs_log_err(ocs, "ocs_dma_alloc rsp\n");
239  ocs_dma_free(ocs, &els_req);
240  return NULL;
241  }
242  } else {
243  ocs_log_err(ocs, "ocs_dma_alloc req\n");
244  return NULL;
245  }
246 
247  ocs_lock(&node->active_ios_lock);
248  if (!node->io_alloc_enabled) {
249  ocs_log_debug(ocs, "called with io_alloc_enabled = FALSE\n");
250  ocs_unlock(&node->active_ios_lock);
251  goto els_io_alloc_err;
252  }
253 
254  els = ocs_io_alloc(ocs);
255  if (els == NULL) {
256  ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
257  ocs_unlock(&node->active_ios_lock);
258  goto els_io_alloc_err;
259  }
260 
261  /* initialize refcount */
262  ocs_ref_init(&els->ref, _ocs_els_io_free, els);
263 
264  switch (role) {
266  els->cmd_ini = TRUE;
267  els->cmd_tgt = FALSE;
268  break;
270  els->cmd_ini = FALSE;
271  els->cmd_tgt = TRUE;
272  break;
273  }
274 
275  /* IO should not have an associated HAL IO yet. Assigned below. */
276  if (els->hio != NULL) {
277  ocs_log_err(ocs, "assertion failed. HIO is not null\n");
278  ocs_io_free(ocs, els);
279  ocs_unlock(&node->active_ios_lock);
280  goto els_io_alloc_err;
281  }
282 
283  /* populate generic io fields */
284  els->ocs = ocs;
285  els->node = node;
286 
287  /* set type and ELS-specific fields */
288  els->io_type = OCS_IO_TYPE_ELS;
289  els->display_name = "pending";
290 
291 
292  if (els != NULL) {
293  ocs_memset(&els->els_sm, 0, sizeof(els->els_sm));
294  els->els_sm.app = els;
295 
296  /* initialize fields */
297  els->els_retries_remaining = OCS_FC_ELS_DEFAULT_RETRIES;
298  els->els_evtdepth = 0;
299  els->els_pend = 0;
300  els->els_active = 0;
301  els->els_req = els_req;
302  els->els_rsp = els_rsp;
303 
304  /* add els structure to ELS IO list */
305  ocs_list_add_tail(&node->els_io_pend_list, els);
306  els->els_pend = 1;
307  }
308  ocs_unlock(&node->active_ios_lock);
309  return els;
310 
311 els_io_alloc_err:
312  ocs_dma_free(ocs, &els_req);
313  ocs_dma_free(ocs, &els_rsp);
314  return NULL;
315 }
316 
317 /**
318  * @ingroup els_api
319  * @brief Free IO structure for an ELS IO context.
320  *
321  * <h3 class="desc">Description</h3> Free IO for an ELS
322  * IO context
323  *
324  * @param els ELS IO structure for which IO is allocated
325  *
326  * @return None
327  */
328 
329 void
330 ocs_els_io_free(ocs_io_t *els)
331 {
332  ocs_ref_put(&els->ref);
333 }
334 
335 /**
336  * @ingroup els_api
337  * @brief Free IO structure for an ELS IO context.
338  *
339  * <h3 class="desc">Description</h3> Free IO for an ELS
340  * IO context
341  *
342  * @param arg ELS IO structure for which IO is allocated
343  *
344  * @return None
345  */
346 
347 static void
349 {
350  ocs_io_t *els = (ocs_io_t *)arg;
351  ocs_t *ocs;
352  ocs_node_t *node;
353  int send_empty_event = FALSE;
354 
355  ocs_assert(els);
356  ocs_assert(els->node);
357  ocs_assert(els->node->ocs);
358  ocs = els->node->ocs;
359 
360  node = els->node;
361  ocs = node->ocs;
362 
363  ocs_lock(&node->active_ios_lock);
364  if (els->els_active) {
365  /* if active, remove from active list and check empty */
366  ocs_list_remove(&node->els_io_active_list, els);
367  /* Send list empty event if the IO allocator is disabled, and the list is empty
368  * If node->io_alloc_enabled was not checked, the event would be posted continually
369  */
370  send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->els_io_active_list);
371  els->els_active = 0;
372  } else if (els->els_pend) {
373  /* if pending, remove from pending list; node shutdown isn't
374  * gated off the pending list (only the active list), so no
375  * need to check if pending list is empty
376  */
377  ocs_list_remove(&node->els_io_pend_list, els);
378  els->els_pend = 0;
379  } else {
380  ocs_log_err(ocs, "assertion failed: niether els->els_pend nor els->active set\n");
381  ocs_unlock(&node->active_ios_lock);
382  return;
383  }
384 
385  ocs_unlock(&node->active_ios_lock);
386 
387  /* free ELS request and response buffers */
388  ocs_dma_free(ocs, &els->els_rsp);
389  ocs_dma_free(ocs, &els->els_req);
390 
391  ocs_io_free(ocs, els);
392 
393  if (send_empty_event) {
395  }
396 
398 }
399 
400 /**
401  * @ingroup els_api
402  * @brief Make ELS IO active
403  *
404  * @param els Pointer to the IO context to make active.
405  *
406  * @return Returns 0 on success; or a negative error code value on failure.
407  */
408 
409 static void
410 ocs_els_make_active(ocs_io_t *els)
411 {
412  ocs_node_t *node = els->node;
413 
414  /* move ELS from pending list to active list */
415  ocs_lock(&node->active_ios_lock);
416  if (els->els_pend) {
417  if (els->els_active) {
418  ocs_log_err(node->ocs, "assertion failed: both els->els_pend and els->active set\n");
419  ocs_unlock(&node->active_ios_lock);
420  return;
421  } else {
422 
423  /* remove from pending list */
424  ocs_list_remove(&node->els_io_pend_list, els);
425  els->els_pend = 0;
426 
427  /* add els structure to ELS IO list */
428  ocs_list_add_tail(&node->els_io_active_list, els);
429  els->els_active = 1;
430  }
431  } else {
432  /* must be retrying; make sure it's already active */
433  if (!els->els_active) {
434  ocs_log_err(node->ocs, "assertion failed: niether els->els_pend nor els->active set\n");
435  }
436  }
437  ocs_unlock(&node->active_ios_lock);
438 }
439 
440 /**
441  * @ingroup els_api
442  * @brief Send the ELS command.
443  *
444  * <h3 class="desc">Description</h3>
445  * The command, given by the \c els IO context, is sent to the node that the IO was
446  * configured with, using ocs_hal_srrs_send(). Upon completion,
447  * the \c cb callback is invoked,
448  * with the application-specific argument set to the \c els IO context.
449  *
450  * @param els Pointer to the IO context.
451  * @param reqlen Byte count in the payload to send.
452  * @param timeout_sec Command timeout, in seconds (0 -> 2*R_A_TOV).
453  * @param cb Completion callback.
454  *
455  * @return Returns 0 on success; or a negative error code value on failure.
456  */
457 
458 static int32_t
459 ocs_els_send(ocs_io_t *els, uint32_t reqlen, uint32_t timeout_sec, ocs_hal_srrs_cb_t cb)
460 {
461  ocs_node_t *node = els->node;
462 
463  /* update ELS request counter */
464  node->els_req_cnt++;
465 
466  /* move ELS from pending list to active list */
467  ocs_els_make_active(els);
468 
469  els->wire_len = reqlen;
470  return ocs_scsi_io_dispatch(els, cb);
471 }
472 
473 /**
474  * @ingroup els_api
475  * @brief Send the ELS response.
476  *
477  * <h3 class="desc">Description</h3>
478  * The ELS response, given by the \c els IO context, is sent to the node
479  * that the IO was configured with, using ocs_hal_srrs_send().
480  *
481  * @param els Pointer to the IO context.
482  * @param rsplen Byte count in the payload to send.
483  *
484  * @return Returns 0 on success; or a negative error value on failure.
485  */
486 
487 static int32_t
488 ocs_els_send_rsp(ocs_io_t *els, uint32_t rsplen)
489 {
490  ocs_node_t *node = els->node;
491 
492  /* increment ELS completion counter */
493  node->els_cmpl_cnt++;
494 
495  /* move ELS from pending list to active list */
496  ocs_els_make_active(els);
497 
498  els->wire_len = rsplen;
500 }
501 
502 /**
503  * @ingroup els_api
504  * @brief Handle ELS IO request completions.
505  *
506  * <h3 class="desc">Description</h3>
507  * This callback is used for several ELS send operations.
508  *
509  * @param hio Pointer to the HAL IO context that completed.
510  * @param rnode Pointer to the remote node.
511  * @param length Length of the returned payload data.
512  * @param status Status of the completion.
513  * @param ext_status Extended status of the completion.
514  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
515  *
516  * @return Returns 0 on success; or a negative error value on failure.
517  */
518 
519 static int32_t
520 ocs_els_req_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
521 {
522  ocs_io_t *els;
523  ocs_node_t *node;
524  ocs_t *ocs;
525  ocs_node_cb_t cbdata;
526  ocs_sport_t *sport;
527 
528  ocs_assert(arg, -1);
529  els = arg;
530 
531  ocs_assert(els->node, -1);
532  node = els->node;
533 
534  ocs_assert(node->ocs, -1);
535  ocs = node->ocs;
536 
537  ocs_assert(node->sport, -1);
538  sport = node->sport;
539 
540  ocs_assert(els->hio, -1);
541  ocs_assert(hio == els->hio, -1);
542 
543  if (status)
544  els_io_printf(els, "status x%x ext x%x\n", status, ext_status);
545 
546  /* Set the response len element of els->rsp */
547  els->els_rsp.len = length;
548 
549  cbdata.status = status;
550  cbdata.ext_status = ext_status;
551  cbdata.header = NULL;
552  cbdata.els = els;
553 
554  /* Take a refcount here so that this sport will not get freed while processing the ELS WQE completion */
555  if (!ocs_ref_get_unless_zero(&sport->ref))
556  ocs_assert(FALSE, -1);
557 
558  /**
559  * For ELS WQE completions, we seem to acquire the sport and node locks in a different order
560  * when compared to other code paths. So, acquire the sport lock here to avoid the deadlock.
561  */
562  ocs_sport_lock(sport);
563 
564  /**
565  * FW returns the number of bytes received on the link in the WCQE, not the amount
566  * placed in the buffer. So, use this info to check if there was an overrun.
567  */
568  if (length > els->els_rsp.size) {
569  ocs_log_warn(ocs, "ELS response returned len=%d > buflen=%zu\n", length, els->els_rsp.size);
571  goto exit_els_req_cb;
572  }
573 
574  /* Post event to ELS IO object */
575  switch (status) {
578  break;
579 
582  break;
583 
585  switch (ext_status) {
588  break;
591  break;
592  default:
594  break;
595  }
596  break;
597 
598  default:
599  ocs_log_warn(ocs, "els req complete: failed status x%x, ext_status, x%x\n", status, ext_status);
601  break;
602  }
603 
604 exit_els_req_cb:
605  /* Release the sport lock and put the refcount */
606  ocs_sport_unlock(sport);
607  ocs_ref_put(&sport->ref); /* ocs_ref_get(): same function */
608  return 0;
609 }
610 
611 /**
612  * @ingroup els_api
613  * @brief Handle ELS IO accept/response completions.
614  *
615  * <h3 class="desc">Description</h3>
616  * This callback is used for several ELS send operations.
617  *
618  * @param hio Pointer to the HAL IO context that completed.
619  * @param rnode Pointer to the remote node.
620  * @param length Length of the returned payload data.
621  * @param status Status of the completion.
622  * @param ext_status Extended status of the completion.
623  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
624  *
625  * @return Returns 0 on success; or a negative error value on failure.
626  */
627 
628 static int32_t
629 ocs_els_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
630 {
631  ocs_io_t *els;
632  ocs_node_t *node;
633  ocs_t *ocs;
634  ocs_node_cb_t cbdata;
635  ocs_io_t *io;
636 
637  ocs_assert(arg, -1);
638  io = arg;
639  els = io;
640  ocs_assert(els, -1);
641  ocs_assert(els->node, -1);
642  node = els->node;
643  ocs_assert(node->ocs, -1);
644  ocs = node->ocs;
645 
646  ocs_assert(io->hio, -1);
647  ocs_assert(hio == io->hio, -1);
648 
649  cbdata.status = status;
650  cbdata.ext_status = ext_status;
651  cbdata.header = NULL;
652  cbdata.els = els;
653 
654  /* Post node event */
655  switch (status) {
658  break;
659 
660  default: // Other error
661  ocs_log_warn(ocs, "[%s] %-8s failed status x%x, ext_status x%x\n",
662  node->display_name, els->display_name, status, ext_status);
663  ocs_log_warn(ocs, "els acc complete: failed status x%x, ext_status, x%x\n", status, ext_status);
665  break;
666  }
667 
668  /* If this IO has a callback, invoke it */
669  if (els->els_callback) {
670  (*els->els_callback)(node, &cbdata, els->els_callback_arg);
671  }
672 
673  ocs_els_io_free(els);
674 
675  return 0;
676 }
677 
678 /**
679  * @ingroup els_api
680  * @brief Format and send a PLOGI ELS command.
681  *
682  * <h3 class="desc">Description</h3>
683  * Construct a PLOGI payload using the domain SLI port service parameters,
684  * and send to the \c node.
685  *
686  * @param node Node to which the PLOGI is sent.
687  * @param timeout_sec Command timeout, in seconds.
688  * @param retries Number of times to retry errors before reporting a failure.
689  * @param cb Callback function.
690  * @param cbarg Callback function argument.
691  *
692  * @return Returns pointer to IO object, or NULL if error.
693  */
694 
695 ocs_io_t *
696 ocs_send_plogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
697  void (*cb)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg), void *cbarg)
698 {
699  ocs_io_t *els;
700  ocs_t *ocs = node->ocs;
701  fc_plogi_payload_t *plogi;
702  uint32_t suppress_rsp = false;
703  node_els_trace();
704 
705  els = ocs_els_io_alloc(node, sizeof(*plogi), OCS_ELS_ROLE_ORIGINATOR);
706  if (els == NULL) {
707  ocs_log_err(ocs, "IO alloc failed\n");
708  } else {
709  els->els_timeout_sec = timeout_sec;
710  els->els_retries_remaining = retries;
711  els->els_callback = cb;
712  els->els_callback_arg = cbarg;
713  els->display_name = "plogi";
714 
715  /* Build PLOGI request */
716  plogi = els->els_req.virt;
717 
718  ocs_memcpy(plogi, node->sport->service_params, sizeof(*plogi));
719 
721  plogi->resv1 = 0;
722 
723  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
725  /*
726  * If FW suppress_rsp feature, then indicate the same to the target
727  * using the vendor version field in service parameters.
728  */
729  ocs_hal_get(&ocs->hal, OCS_HAL_SUPPRESS_RSP_CAPABLE, &suppress_rsp);
730  if (suppress_rsp) {
731  /* Set valid vendor version level bit */
732  plogi->common_service_parameters[1] |=
734  plogi->vendor_version_level[0] =
736  plogi->vendor_version_level[1] = ocs_htobe32(suppress_rsp);
737  } else {
738  plogi->common_service_parameters[1] &=
740  plogi->vendor_version_level[0] = 0;
741  plogi->vendor_version_level[1] = 0;
742  plogi->vendor_version_level[2] = 0;
743  plogi->vendor_version_level[3] = 0;
744  }
745 
746  ocs_display_sparams(node->display_name, "plogi send req", 0, NULL, plogi->common_service_parameters);
747 
748  els->hio_type = OCS_HAL_ELS_REQ;
749  els->iparam.els.timeout = timeout_sec;
750 
751  ocs_io_transition(els, __ocs_els_init, NULL);
752  }
753  return els;
754 }
755 
756 /**
757  * @ingroup els_api
758  * @brief Format and send a FLOGI ELS command.
759  *
760  * <h3 class="desc">Description</h3>
761  * Construct an FLOGI payload, and send to the \c node.
762  *
763  * @param node Node to which the FLOGI is sent.
764  * @param timeout_sec Command timeout, in seconds.
765  * @param retries Number of times to retry errors before reporting a failure.
766  * @param cb Callback function.
767  * @param cbarg Callback function argument.
768  *
769  * @return Returns pointer to IO object, or NULL if error.
770  */
771 
772 ocs_io_t *
773 ocs_send_flogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
774  els_cb_t cb, void *cbarg)
775 {
776  ocs_io_t *els;
777  ocs_t *ocs;
778  fc_plogi_payload_t *flogi;
779 
780  ocs_assert(node, NULL);
781  ocs_assert(node->ocs, NULL);
782  ocs_assert(node->sport, NULL);
783  ocs = node->ocs;
784 
785  node_els_trace();
786 
787  els = ocs_els_io_alloc(node, sizeof(*flogi), OCS_ELS_ROLE_ORIGINATOR);
788  if (els == NULL) {
789  ocs_log_err(ocs, "IO alloc failed\n");
790  } else {
791  els->els_timeout_sec = timeout_sec;
792  els->els_retries_remaining = retries;
793  els->els_callback = cb;
794  els->els_callback_arg = cbarg;
795  els->display_name = "flogi";
796 
797  /* Build FLOGI request */
798  flogi = els->els_req.virt;
799 
800  ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
802  flogi->resv1 = 0;
803 
804  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
806 
807  /* BBCR support */
808  if (ocs_bbcr_enabled(ocs)) {
809  /* Set the BB_SC_N field to 'bbscn_def' */
810  flogi->common_service_parameters[1] |= ocs_htobe32(ocs->hal.sli.config.bbscn_def << 12);
811  }
812 
813  /* Priority tagging support */
814  flogi->common_service_parameters[1] |= ocs_htobe32(1U << 23);
815 
816  ocs_display_sparams(node->display_name, "flogi send req", 0, NULL, flogi->common_service_parameters);
817 
818  els->hio_type = OCS_HAL_ELS_REQ;
819  els->iparam.els.timeout = timeout_sec;
820  ocs_io_transition(els, __ocs_els_init, NULL);
821  }
822  return els;
823 }
824 
825 /**
826  * @ingroup els_api
827  * @brief Format and send a FDISC ELS command.
828  *
829  * <h3 class="desc">Description</h3>
830  * Construct an FDISC payload, and send to the \c node.
831  *
832  * @param node Node to which the FDISC is sent.
833  * @param timeout_sec Command timeout, in seconds.
834  * @param retries Number of times to retry errors before reporting a failure.
835  * @param cb Callback function.
836  * @param cbarg Callback function argument.
837  *
838  * @return Returns pointer to IO object, or NULL if error.
839  */
840 
841 ocs_io_t *
842 ocs_send_fdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
843  els_cb_t cb, void *cbarg)
844 {
845  ocs_io_t *els;
846  ocs_t *ocs;
847  fc_plogi_payload_t *fdisc;
848 
849  ocs_assert(node, NULL);
850  ocs_assert(node->ocs, NULL);
851  ocs = node->ocs;
852 
853  node_els_trace();
854 
855  els = ocs_els_io_alloc(node, sizeof(*fdisc), OCS_ELS_ROLE_ORIGINATOR);
856  if (els == NULL) {
857  ocs_log_err(ocs, "IO alloc failed\n");
858  } else {
859  els->els_timeout_sec = timeout_sec;
860  els->els_retries_remaining = retries;
861  els->els_callback = cb;
862  els->els_callback_arg = cbarg;
863  els->display_name = "fdisc";
864 
865  /* Build FDISC request */
866  fdisc = els->els_req.virt;
867 
868  ocs_memcpy(fdisc, node->sport->service_params, sizeof(*fdisc));
870  fdisc->resv1 = 0;
871 
872  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
874 
875  /* Clear VVL valid and VVL values */
876  fdisc->common_service_parameters[1] &=
878  fdisc->vendor_version_level[0] = 0;
879  fdisc->vendor_version_level[1] = 0;
880  fdisc->vendor_version_level[2] = 0;
881  fdisc->vendor_version_level[3] = 0;
882 
883  ocs_display_sparams(node->display_name, "fdisc send req", 0, NULL, fdisc->common_service_parameters);
884 
885  els->hio_type = OCS_HAL_ELS_REQ;
886  els->iparam.els.timeout = timeout_sec;
887  ocs_io_transition(els, __ocs_els_init, NULL);
888  }
889  return els;
890 }
891 
892 /**
893  * @ingroup els_api
894  * @brief Send a PRLI ELS command.
895  *
896  * <h3 class="desc">Description</h3>
897  * Construct a PRLI ELS command, and send to the \c node.
898  *
899  * @param node Node to which the PRLI is sent.
900  * @param timeout_sec Command timeout, in seconds.
901  * @param retries Number of times to retry errors before reporting a failure.
902  * @param cb Callback function.
903  * @param cbarg Callback function argument.
904  *
905  * @return Returns pointer to IO object, or NULL if error.
906  */
907 
908 ocs_io_t *
909 ocs_send_prli(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
910  els_cb_t cb, void *cbarg)
911 {
912  ocs_t *ocs = node->ocs;
913  ocs_io_t *els;
914  fc_prli_payload_t *prli;
915 
916  node_els_trace();
917 
918  els = ocs_els_io_alloc(node, sizeof(*prli), OCS_ELS_ROLE_ORIGINATOR);
919  if (els == NULL) {
920  ocs_log_err(ocs, "IO alloc failed\n");
921  } else {
922  els->els_timeout_sec = timeout_sec;
923  els->els_retries_remaining = retries;
924  els->els_callback = cb;
925  els->els_callback_arg = cbarg;
926  els->display_name = "prli";
927 
928  /* Build PRLI request */
929  prli = els->els_req.virt;
930 
931  ocs_memset(prli, 0, sizeof(*prli));
932 
934  prli->page_length = 16;
935  prli->payload_length = ocs_htobe16(sizeof(fc_prli_payload_t));
936  prli->type = FC_TYPE_FCP;
937  prli->type_ext = 0;
938  prli->flags = ocs_htobe16(FC_PRLI_ESTABLISH_IMAGE_PAIR);
939  prli->service_params = ocs_htobe16(FC_PRLI_READ_XRDY_DISABLED |
940  (node->sport->enable_ini ? FC_PRLI_INITIATOR_FUNCTION : 0) |
941  (node->sport->enable_tgt ? FC_PRLI_TARGET_FUNCTION : 0));
942 
943  els->hio_type = OCS_HAL_ELS_REQ;
944  els->iparam.els.timeout = timeout_sec;
945  ocs_io_transition(els, __ocs_els_init, NULL);
946  }
947 
948  return els;
949 }
950 
951 /**
952  * @ingroup els_api
953  * @brief Send a PRLO ELS command.
954  *
955  * <h3 class="desc">Description</h3>
956  * Construct a PRLO ELS command, and send to the \c node.
957  *
958  * @param node Node to which the PRLO is sent.
959  * @param timeout_sec Command timeout, in seconds.
960  * @param retries Number of times to retry errors before reporting a failure.
961  * @param cb Callback function.
962  * @param cbarg Callback function argument.
963  *
964  * @return Returns pointer to IO object, or NULL if error.
965  */
966 
967 ocs_io_t *
968 ocs_send_prlo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
969  els_cb_t cb, void *cbarg)
970 {
971  ocs_t *ocs = node->ocs;
972  ocs_io_t *els;
973  fc_prlo_payload_t *prlo;
974 
975  node_els_trace();
976 
977  els = ocs_els_io_alloc(node, sizeof(*prlo), OCS_ELS_ROLE_ORIGINATOR);
978  if (els == NULL) {
979  ocs_log_err(ocs, "IO alloc failed\n");
980  } else {
981  els->els_timeout_sec = timeout_sec;
982  els->els_retries_remaining = retries;
983  els->els_callback = cb;
984  els->els_callback_arg = cbarg;
985  els->display_name = "prlo";
986 
987  /* Build PRLO request */
988  prlo = els->els_req.virt;
989 
990  ocs_memset(prlo, 0, sizeof(*prlo));
992  prlo->page_length = 16;
993  prlo->payload_length = ocs_htobe16(sizeof(fc_prlo_payload_t));
994  prlo->type = FC_TYPE_FCP;
995  prlo->type_ext = 0;
996 
997  els->hio_type = OCS_HAL_ELS_REQ;
998  els->iparam.els.timeout = timeout_sec;
999  ocs_io_transition(els, __ocs_els_init, NULL);
1000  }
1001  return els;
1002 }
1003 
1004 /**
1005  * @ingroup els_api
1006  * @brief Send a LOGO ELS command.
1007  *
1008  * <h3 class="desc">Description</h3>
1009  * Format a LOGO, and send to the \c node.
1010  *
1011  * @param node Node to which the LOGO is sent.
1012  * @param timeout_sec Command timeout, in seconds.
1013  * @param retries Number of times to retry errors before reporting a failure.
1014  * @param cb Callback function.
1015  * @param cbarg Callback function argument.
1016  *
1017  * @return Returns pointer to IO object, or NULL if error.
1018  */
1019 
1020 ocs_io_t *
1021 ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1022  els_cb_t cb, void *cbarg)
1023 {
1024  ocs_io_t *els;
1025  ocs_t *ocs;
1026  fc_logo_payload_t *logo;
1027  fc_plogi_payload_t *sparams;
1028 
1029 
1030  ocs = node->ocs;
1031 
1032  node_els_trace();
1033 
1034  sparams = (fc_plogi_payload_t*) node->sport->service_params;
1035 
1036  els = ocs_els_io_alloc(node, sizeof(*logo), OCS_ELS_ROLE_ORIGINATOR);
1037  if (els == NULL) {
1038  ocs_log_err(ocs, "IO alloc failed\n");
1039  } else {
1040  els->els_timeout_sec = timeout_sec;
1041  els->els_retries_remaining = retries;
1042  els->els_callback = cb;
1043  els->els_callback_arg = cbarg;
1044  els->display_name = "logo";
1045 
1046  /* Build LOGO request */
1047 
1048  logo = els->els_req.virt;
1049 
1050  ocs_memset(logo, 0, sizeof(*logo));
1051  logo->command_code = FC_ELS_CMD_LOGO;
1052  logo->resv1 = 0;
1053  logo->port_id = fc_htobe24(node->rnode.sport->fc_id);
1054  logo->port_name_hi = sparams->port_name_hi;
1055  logo->port_name_lo = sparams->port_name_lo;
1056 
1057  els->hio_type = OCS_HAL_ELS_REQ;
1058  els->iparam.els.timeout = timeout_sec;
1059  ocs_io_transition(els, __ocs_els_init, NULL);
1060  }
1061  return els;
1062 }
1063 
1064 /**
1065  * @ingroup els_api
1066  * @brief Send an ADISC ELS command.
1067  *
1068  * <h3 class="desc">Description</h3>
1069  * Construct an ADISC ELS command, and send to the \c node.
1070  *
1071  * @param node Node to which the ADISC is sent.
1072  * @param timeout_sec Command timeout, in seconds.
1073  * @param retries Number of times to retry errors before reporting a failure.
1074  * @param cb Callback function.
1075  * @param cbarg Callback function argument.
1076  *
1077  * @return Returns pointer to IO object, or NULL if error.
1078  */
1079 
1080 ocs_io_t *
1081 ocs_send_adisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1082  els_cb_t cb, void *cbarg)
1083 {
1084  ocs_io_t *els;
1085  ocs_t *ocs;
1086  fc_adisc_payload_t *adisc;
1087  fc_plogi_payload_t *sparams;
1088  ocs_sport_t *sport = node->sport;
1089 
1090  ocs = node->ocs;
1091 
1092  node_els_trace();
1093 
1094  sparams = (fc_plogi_payload_t*) node->sport->service_params;
1095 
1096  els = ocs_els_io_alloc(node, sizeof(*adisc), OCS_ELS_ROLE_ORIGINATOR);
1097  if (els == NULL) {
1098  ocs_log_err(ocs, "IO alloc failed\n");
1099  } else {
1100  els->els_timeout_sec = timeout_sec;
1101  els->els_retries_remaining = retries;
1102  els->els_callback = cb;
1103  els->els_callback_arg = cbarg;
1104  els->display_name = "adisc";
1105 
1106  /* Build ADISC request */
1107 
1108  adisc = els->els_req.virt;
1109 
1110  ocs_memset(adisc, 0, sizeof(*adisc));
1111  adisc->command_code = FC_ELS_CMD_ADISC;
1112  adisc->hard_address = fc_htobe24(sport->fc_id);
1113  adisc->port_name_hi = sparams->port_name_hi;
1114  adisc->port_name_lo = sparams->port_name_lo;
1115  adisc->node_name_hi = sparams->node_name_hi;
1116  adisc->node_name_lo = sparams->node_name_lo;
1117  adisc->port_id = fc_htobe24(node->rnode.sport->fc_id);
1118 
1119  els->hio_type = OCS_HAL_ELS_REQ;
1120  els->iparam.els.timeout = timeout_sec;
1121  ocs_io_transition(els, __ocs_els_init, NULL);
1122  }
1123  return els;
1124 }
1125 
1126 /**
1127  * @ingroup els_api
1128  * @brief Send a PDISC ELS command.
1129  *
1130  * <h3 class="desc">Description</h3>
1131  * Construct a PDISC ELS command, and send to the \c node.
1132  *
1133  * @param node Node to which the PDISC is sent.
1134  * @param timeout_sec Command timeout, in seconds.
1135  * @param retries Number of times to retry errors before reporting a failure.
1136  * @param cb Callback function.
1137  * @param cbarg Callback function argument.
1138  *
1139  * @return Returns pointer to IO object, or NULL if error.
1140  */
1141 
1142 ocs_io_t *
1143 ocs_send_pdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1144  els_cb_t cb, void *cbarg)
1145 {
1146  ocs_io_t *els;
1147  ocs_t *ocs = node->ocs;
1148  fc_plogi_payload_t *pdisc;
1149 
1150  node_els_trace();
1151 
1152  els = ocs_els_io_alloc(node, sizeof(*pdisc), OCS_ELS_ROLE_ORIGINATOR);
1153  if (els == NULL) {
1154  ocs_log_err(ocs, "IO alloc failed\n");
1155  } else {
1156  els->els_timeout_sec = timeout_sec;
1157  els->els_retries_remaining = retries;
1158  els->els_callback = cb;
1159  els->els_callback_arg = cbarg;
1160  els->display_name = "pdisc";
1161 
1162  pdisc = els->els_req.virt;
1163 
1164  ocs_memcpy(pdisc, node->sport->service_params, sizeof(*pdisc));
1165 
1166  pdisc->command_code = FC_ELS_CMD_PDISC;
1167  pdisc->resv1 = 0;
1168 
1169  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
1171 
1172  els->hio_type = OCS_HAL_ELS_REQ;
1173  els->iparam.els.timeout = timeout_sec;
1174  ocs_io_transition(els, __ocs_els_init, NULL);
1175  }
1176  return els;
1177 }
1178 
1179 /**
1180  * @ingroup els_api
1181  * @brief Send an SCR ELS command.
1182  *
1183  * <h3 class="desc">Description</h3>
1184  * Format an SCR, and send to the \c node.
1185  *
1186  * @param node Node to which the SCR is sent.
1187  * @param timeout_sec Command timeout, in seconds.
1188  * @param retries Number of times to retry errors before reporting a failure.
1189  * @param cb Callback function
1190  * @param cbarg Callback function arg
1191  *
1192  * @return Returns pointer to IO object, or NULL if error.
1193  */
1194 
1195 ocs_io_t *
1196 ocs_send_scr(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1197  els_cb_t cb, void *cbarg)
1198 {
1199  ocs_io_t *els;
1200  ocs_t *ocs = node->ocs;
1201  fc_scr_payload_t *req;
1202 
1203  node_els_trace();
1204 
1205  els = ocs_els_io_alloc(node, sizeof(*req), OCS_ELS_ROLE_ORIGINATOR);
1206  if (els == NULL) {
1207  ocs_log_err(ocs, "IO alloc failed\n");
1208  } else {
1209  els->els_timeout_sec = timeout_sec;
1210  els->els_retries_remaining = retries;
1211  els->els_callback = cb;
1212  els->els_callback_arg = cbarg;
1213  els->display_name = "scr";
1214 
1215  req = els->els_req.virt;
1216 
1217  ocs_memset(req, 0, sizeof(*req));
1219  req->function = FC_SCR_REG_FULL;
1220 
1221  els->hio_type = OCS_HAL_ELS_REQ;
1222  els->iparam.els.timeout = timeout_sec;
1223  ocs_io_transition(els, __ocs_els_init, NULL);
1224  }
1225  return els;
1226 }
1227 
1228 /**
1229  * @ingroup els_api
1230  * @brief Send an RRQ ELS command.
1231  *
1232  * <h3 class="desc">Description</h3>
1233  * Format an RRQ, and send to the \c node.
1234  *
1235  * @param node Node to which the RRQ is sent.
1236  * @param timeout_sec Command timeout, in seconds.
1237  * @param retries Number of times to retry errors before reporting a failure.
1238  * @param cb Callback function
1239  * @param cbarg Callback function arg
1240  *
1241  * @return Returns pointer to IO object, or NULL if error.
1242  */
1243 
1244 ocs_io_t *
1245 ocs_send_rrq(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1246  els_cb_t cb, void *cbarg)
1247 {
1248  ocs_io_t *els;
1249  ocs_t *ocs = node->ocs;
1250  fc_scr_payload_t *req;
1251 
1252  node_els_trace();
1253 
1254  els = ocs_els_io_alloc(node, sizeof(*req), OCS_ELS_ROLE_ORIGINATOR);
1255  if (els == NULL) {
1256  ocs_log_err(ocs, "IO alloc failed\n");
1257  } else {
1258  els->els_timeout_sec = timeout_sec;
1259  els->els_retries_remaining = retries;
1260  els->els_callback = cb;
1261  els->els_callback_arg = cbarg;
1262  els->display_name = "scr";
1263 
1264  req = els->els_req.virt;
1265 
1266  ocs_memset(req, 0, sizeof(*req));
1268  req->function = FC_SCR_REG_FULL;
1269 
1270  els->hio_type = OCS_HAL_ELS_REQ;
1271  els->iparam.els.timeout = timeout_sec;
1272  ocs_io_transition(els, __ocs_els_init, NULL);
1273  }
1274  return els;
1275 }
1276 
1277 /**
1278  * @ingroup els_api
1279  * @brief Send an RSCN ELS command.
1280  *
1281  * <h3 class="desc">Description</h3>
1282  * Format an RSCN, and send to the \c node.
1283  *
1284  * @param node Node to which the RRQ is sent.
1285  * @param timeout_sec Command timeout, in seconds.
1286  * @param retries Number of times to retry errors before reporting a failure.
1287  * @param port_ids Pointer to port IDs
1288  * @param port_ids_count Count of port IDs
1289  * @param cb Callback function
1290  * @param cbarg Callback function arg
1291  *
1292  * @return Returns pointer to IO object, or NULL if error.
1293  */
1294 ocs_io_t *
1295 ocs_send_rscn(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1296  void *port_ids, uint32_t port_ids_count, els_cb_t cb, void *cbarg)
1297 {
1298  ocs_io_t *els;
1299  ocs_t *ocs = node->ocs;
1300  fc_rscn_payload_t *req;
1301  uint32_t payload_length = sizeof(fc_rscn_affected_port_id_page_t)*(port_ids_count - 1) +
1302  sizeof(fc_rscn_payload_t);
1303 
1304  node_els_trace();
1305 
1306  els = ocs_els_io_alloc(node, payload_length, OCS_ELS_ROLE_ORIGINATOR);
1307  if (els == NULL) {
1308  ocs_log_err(ocs, "IO alloc failed\n");
1309  } else {
1310  els->els_timeout_sec = timeout_sec;
1311  els->els_retries_remaining = retries;
1312  els->els_callback = cb;
1313  els->els_callback_arg = cbarg;
1314  els->display_name = "rscn";
1315 
1316  req = els->els_req.virt;
1317 
1320  req->payload_length = ocs_htobe16(sizeof(*req) +
1321  sizeof(fc_rscn_affected_port_id_page_t)*(port_ids_count-1));
1322 
1323  els->hio_type = OCS_HAL_ELS_REQ;
1324  els->iparam.els.timeout = timeout_sec;
1325 
1326  /* copy in the payload */
1327  ocs_memcpy(req->port_list, port_ids, port_ids_count*sizeof(fc_rscn_affected_port_id_page_t));
1328 
1329  /* Submit the request */
1330  ocs_io_transition(els, __ocs_els_init, NULL);
1331  }
1332  return els;
1333 }
1334 
1335 /**
1336  * @brief Send an LS_RJT ELS response.
1337  *
1338  * <h3 class="desc">Description</h3>
1339  * Send an LS_RJT ELS response.
1340  *
1341  * @param io Pointer to a SCSI IO object.
1342  * @param ox_id Originator exchange ID being responded to.
1343  * @param reason_code Reason code value for LS_RJT.
1344  * @param reason_code_expl Reason code explanation value for LS_RJT.
1345  * @param vendor_unique Vendor-unique value for LS_RJT.
1346  * @param cb Callback function.
1347  * @param cbarg Callback function argument.
1348  *
1349  * @return Returns pointer to IO object, or NULL if error.
1350  */
1351 
1352 ocs_io_t *
1353 ocs_send_ls_rjt(ocs_io_t *io, uint32_t ox_id, uint32_t reason_code, uint32_t reason_code_expl,
1354  uint32_t vendor_unique, els_cb_t cb, void *cbarg)
1355 {
1356  ocs_node_t *node = io->node;
1357  int32_t rc;
1358  ocs_t *ocs = node->ocs;
1359  fc_ls_rjt_payload_t *rjt;
1360 
1361  node_els_trace();
1362 
1363  io->els_callback = cb;
1364  io->els_callback_arg = cbarg;
1365  io->display_name = "ls_rjt";
1366  io->init_task_tag = ox_id;
1367 
1368  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1369  io->iparam.els.ox_id = ox_id;
1370 
1371  rjt = io->els_req.virt;
1372  ocs_memset(rjt, 0, sizeof(*rjt));
1373 
1375  rjt->reason_code = reason_code;
1376  rjt->reason_code_exp = reason_code_expl;
1377 
1378  io->hio_type = OCS_HAL_ELS_RSP;
1379  if ((rc = ocs_els_send_rsp(io, sizeof(*rjt)))) {
1380  ocs_els_io_free(io);
1381  io = NULL;
1382  }
1383 
1384  return io;
1385 }
1386 
1387 /**
1388  * @ingroup els_api
1389  * @brief Send a PLOGI accept response.
1390  *
1391  * <h3 class="desc">Description</h3>
1392  * Construct a PLOGI LS_ACC, and send to the \c node, using the originator exchange ID
1393  * \c ox_id.
1394  *
1395  * @param io Pointer to a SCSI IO object.
1396  * @param ox_id Originator exchange ID being responsed to.
1397  * @param cb Callback function.
1398  * @param cbarg Callback function argument.
1399  *
1400  * @return Returns pointer to IO object, or NULL if error.
1401  */
1402 ocs_io_t *
1403 ocs_send_plogi_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1404 {
1405  ocs_node_t *node = io->node;
1406  int32_t rc;
1407  uint32_t suppress_rsp;
1408  ocs_t *ocs = node->ocs;
1409  fc_plogi_payload_t *plogi;
1410  fc_plogi_payload_t *req = (fc_plogi_payload_t *)node->service_params;
1411 
1412  node_els_trace();
1413 
1414  io->els_callback = cb;
1415  io->els_callback_arg = cbarg;
1416  io->display_name = "plog_acc";
1417  io->init_task_tag = ox_id;
1418 
1419  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1420  io->iparam.els.ox_id = ox_id;
1421 
1422  plogi = io->els_req.virt;
1423 
1424  /* copy our port's service paramters to payload */
1425  ocs_memcpy(plogi, node->sport->service_params, sizeof(*plogi));
1426  plogi->command_code = FC_ELS_CMD_ACC;
1427  plogi->resv1 = 0;
1428 
1429  ocs_hal_get(&ocs->hal, OCS_HAL_SUPPRESS_RSP_CAPABLE, &suppress_rsp);
1430  if (suppress_rsp && node->suppress_rsp) {
1431  /* Set valid vendor version level bit */
1432  plogi->common_service_parameters[1] |=
1434  plogi->vendor_version_level[0] =
1436  plogi->vendor_version_level[1] = ocs_htobe32(suppress_rsp);
1437  } else {
1438  plogi->common_service_parameters[1] &=
1440  plogi->vendor_version_level[0] = 0;
1441  plogi->vendor_version_level[1] = 0;
1442  plogi->vendor_version_level[2] = 0;
1443  plogi->vendor_version_level[3] = 0;
1444  node->suppress_rsp = false;
1445  }
1446 
1447  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
1449 
1450  /* Set Application header support bit if requested */
1451  if (req->common_service_parameters[1] & ocs_htobe32(1U << 24)) {
1452  plogi->common_service_parameters[1] |= ocs_htobe32(1U << 24);
1453  }
1454 
1455  /* Priority tagging support. */
1456  if (req->common_service_parameters[1] & ocs_htobe32(1U << 23)) {
1457  plogi->common_service_parameters[1] |= ocs_htobe32(1U << 23);
1458  }
1459 
1460  ocs_display_sparams(node->display_name, "plogi send resp", 0, NULL, plogi->common_service_parameters);
1461 
1462  io->hio_type = OCS_HAL_ELS_RSP;
1463  if ((rc = ocs_els_send_rsp(io, sizeof(*plogi)))) {
1464  ocs_els_io_free(io);
1465  io = NULL;
1466  }
1467 
1468  ocs_log_info(ocs, "ELS PLOGI (0x%x) ACK sent %s; OX_ID: %04x, D_ID: %06x, WWPN: %016" PRIX64"\n",
1469  FC_ELS_CMD_PLOGI, rc ? "failed" : "successfully",
1470  ox_id, node->rnode.fc_id, ocs_node_get_wwpn(node));
1471  return io;
1472 }
1473 
1474 /**
1475  * @ingroup els_api
1476  * @brief Send an FLOGI accept response for point-to-point negotiation.
1477  *
1478  * <h3 class="desc">Description</h3>
1479  * Construct an FLOGI accept response, and send to the \c node using the originator
1480  * exchange id \c ox_id. The \c s_id is used for the response frame source FC ID.
1481  *
1482  * @param io Pointer to a SCSI IO object.
1483  * @param ox_id Originator exchange ID for the response.
1484  * @param s_id Source FC ID to be used in the response frame.
1485  * @param cb Callback function.
1486  * @param cbarg Callback function argument.
1487  *
1488  * @return Returns pointer to IO object, or NULL if error.
1489  */
1490 ocs_io_t *
1491 ocs_send_flogi_p2p_acc(ocs_io_t *io, uint32_t ox_id, uint32_t s_id, els_cb_t cb, void *cbarg)
1492 {
1493  ocs_node_t *node = io->node;
1494  int32_t rc;
1495  ocs_t *ocs = node->ocs;
1496  fc_plogi_payload_t *flogi;
1497 
1498  node_els_trace();
1499 
1500  io->els_callback = cb;
1501  io->els_callback_arg = cbarg;
1502  io->display_name = "flogi_p2p_acc";
1503  io->init_task_tag = ox_id;
1504 
1505  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1506  io->iparam.els_sid.ox_id = ox_id;
1507  io->iparam.els_sid.s_id = s_id;
1508 
1509  flogi = io->els_req.virt;
1510 
1511  /* copy our port's service paramters to payload */
1512  ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
1513  flogi->command_code = FC_ELS_CMD_ACC;
1514  flogi->resv1 = 0;
1515 
1516  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
1518 
1519  ocs_memset(flogi->class1_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1520  ocs_memset(flogi->class2_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1521  ocs_memset(flogi->class3_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1522  ocs_memset(flogi->class4_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1523 
1524  io->hio_type = OCS_HAL_ELS_RSP_SID;
1525  if ((rc = ocs_els_send_rsp(io, sizeof(*flogi)))) {
1526  ocs_els_io_free(io);
1527  io = NULL;
1528  }
1529 
1530  return io;
1531 }
1532 
1533 ocs_io_t *
1534 ocs_send_flogi_acc(ocs_io_t *io, uint32_t ox_id, uint32_t is_fport, els_cb_t cb, void *cbarg)
1535 {
1536  ocs_node_t *node = io->node;
1537  int32_t rc;
1538  ocs_t *ocs = node->ocs;
1539  fc_plogi_payload_t *flogi;
1540 
1541  node_els_trace();
1542 
1543  io->els_callback = cb;
1544  io->els_callback_arg = cbarg;
1545  io->display_name = "flogi_acc";
1546  io->init_task_tag = ox_id;
1547 
1548  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1549  io->iparam.els_sid.ox_id = ox_id;
1550  io->iparam.els_sid.s_id = io->node->sport->fc_id;
1551 
1552  flogi = io->els_req.virt;
1553 
1554  /* copy our port's service paramters to payload */
1555  ocs_memcpy(flogi, node->sport->service_params, sizeof(*flogi));
1556 
1557  /* Set F_port */
1558  if (is_fport) {
1559  /* Set F_PORT and Multiple N_PORT_ID Assignment */
1560  flogi->common_service_parameters[1] |= ocs_be32toh(3U << 28);
1561  }
1562 
1563  flogi->command_code = FC_ELS_CMD_ACC;
1564  flogi->resv1 = 0;
1565 
1566  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
1568 
1569  ocs_display_sparams(node->display_name, "flogi send resp", 0, NULL, flogi->common_service_parameters);
1570 
1571  ocs_memset(flogi->class1_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1572  ocs_memset(flogi->class2_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1573  ocs_memset(flogi->class3_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1574  ocs_memset(flogi->class4_service_parameters, 0, sizeof(flogi->class1_service_parameters));
1575 
1576  io->hio_type = OCS_HAL_ELS_RSP_SID;
1577  if ((rc = ocs_els_send_rsp(io, sizeof(*flogi)))) {
1578  ocs_els_io_free(io);
1579  io = NULL;
1580  }
1581 
1582  return io;
1583 }
1584 
1585 static inline int32_t
1587 {
1588  return node->first_burst;
1589 }
1590 
1591 static ocs_io_t *
1593 {
1594  ocs_node_t *node = io->node;
1595  int32_t rc;
1596  ocs_t *ocs = node->ocs;
1597  fc_nvme_prli_payload_t *prli;
1598 
1599  prli = io->els_req.virt;
1600  ocs_memset(prli, 0, sizeof(*prli));
1601 
1602  prli->type = FC_TYPE_NVME;
1603  prli->command_code = FC_ELS_CMD_ACC;
1604  prli->flags = ocs_htobe16(FC_PRLI_REQUEST_EXECUTED);
1605  prli->service_params = ocs_htobe16(FC_PRLI_TARGET_FUNCTION |
1607  prli->payload_length = ocs_htobe16(sizeof(*prli));
1609  prli->type_ext = 0;
1610 
1611  io->hio_type = OCS_HAL_ELS_RSP;
1612  if ((rc = ocs_els_send_rsp(io, sizeof(*prli)))) {
1613  ocs_els_io_free(io);
1614  io = NULL;
1615  }
1616 
1617  ocs_log_info(ocs, "ELS NVMe PRLI (0x%x) ACK sent %s; OX_ID: %04x, D_ID: %06x, WWPN: %016" PRIX64"\n",
1618  FC_ELS_CMD_PRLI, rc ? "failed" : "successfully",
1619  io->init_task_tag, node->rnode.fc_id, ocs_node_get_wwpn(node));
1620 
1621  return io;
1622 }
1623 
1624 static ocs_io_t *
1626 {
1627  ocs_node_t *node = io->node;
1628  int32_t rc;
1629  int32_t first_burst = 0;
1630  ocs_t *ocs = node->ocs;
1631  fc_prli_payload_t *prli;
1632 
1633  prli = io->els_req.virt;
1634  ocs_memset(prli, 0, sizeof(fc_prli_payload_t));
1635 
1636  prli->type = FC_TYPE_FCP;
1637  prli->command_code = FC_ELS_CMD_ACC;
1639 #if defined(OCS_ENABLE_FIRST_BURST)
1640  /*
1641  * Determine node first_burst capability based on the support at both sides.
1642  */
1643  first_burst = ocs_node_first_burst_enabled(node) && ocs_first_burst_enabled(ocs);
1644  if (first_burst)
1645  ocs_log_info(ocs, "Target negotiated first burst\n");
1646 #endif
1647  prli->service_params = ocs_htobe16(FC_PRLI_READ_XRDY_DISABLED |
1648  (first_burst ? FC_PRLI_WRITE_XRDY_DISABLED : 0) |
1649  (node->sport->enable_ini ? FC_PRLI_INITIATOR_FUNCTION : 0) |
1650  (node->sport->enable_tgt ? FC_PRLI_TARGET_FUNCTION : 0));
1652  prli->payload_length = ocs_htobe16(sizeof(fc_prli_payload_t));
1653  prli->type_ext = 0;
1654 
1655  io->hio_type = OCS_HAL_ELS_RSP;
1656  if ((rc = ocs_els_send_rsp(io, sizeof(*prli)))) {
1657  ocs_els_io_free(io);
1658  io = NULL;
1659  }
1660 
1661  ocs_log_info(ocs, "ELS FCP PRLI (0x%x) ACK sent %s; OX_ID: %04x, D_ID: %06x, WWPN: %016" PRIX64"\n",
1662  FC_ELS_CMD_PRLI, rc ? "failed" : "successfully",
1663  io->init_task_tag, node->rnode.fc_id, ocs_node_get_wwpn(node));
1664 
1665  return io;
1666 }
1667 
1668 /**
1669  * @ingroup els_api
1670  * @brief Send a PRLI accept response
1671  *
1672  * <h3 class="desc">Description</h3>
1673  * Construct a PRLI LS_ACC response, and send to the \c node, using the originator
1674  * \c ox_id exchange ID.
1675  *
1676  * @param io Pointer to a SCSI IO object.
1677  * @param ox_id Originator exchange ID.
1678  * @param fc_type FC4 type: FCP or NVME.
1679  * @param cb Callback function.
1680  * @param cbarg Callback function argument.
1681  *
1682  * @return Returns pointer to IO object, or NULL if error.
1683  */
1684 
1685 ocs_io_t *
1686 ocs_send_prli_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
1687 {
1688  ocs_node_t *node = io->node;
1689  ocs_t *ocs = node->ocs;
1690 
1691  node_els_trace();
1692 
1693  io->els_callback = cb;
1694  io->els_callback_arg = cbarg;
1695  io->display_name = "prli_acc";
1696  io->init_task_tag = ox_id;
1697 
1698  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1699  io->iparam.els.ox_id = ox_id;
1700 
1701  switch (fc_type) {
1702  case FC_TYPE_NVME:
1703  return ocs_send_nvme_prli_acc(io);
1704  case FC_TYPE_FCP:
1705  return ocs_send_fcp_prli_acc(io);
1706  default:
1707  ocs_log_err(ocs, "prli response failed, invalid protocol type (%#x)\n", fc_type);
1708  ocs_assert(NULL, NULL);
1709  }
1710 
1711  return NULL;
1712 }
1713 
1714 /**
1715  * @ingroup els_api
1716  * @brief Send a PRLO accept response.
1717  *
1718  * <h3 class="desc">Description</h3>
1719  * Construct a PRLO LS_ACC response, and send to the \c node, using the originator
1720  * exchange ID \c ox_id.
1721  *
1722  * @param io Pointer to a SCSI IO object.
1723  * @param ox_id Originator exchange ID.
1724  * @param cb Callback function.
1725  * @param cbarg Callback function argument.
1726  *
1727  * @return Returns pointer to IO object, or NULL if error.
1728  */
1729 
1730 ocs_io_t *
1731 ocs_send_prlo_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
1732 {
1733  ocs_node_t *node = io->node;
1734  int32_t rc;
1735  ocs_t *ocs = node->ocs;
1736  fc_prlo_acc_payload_t *prlo_acc;
1737 
1738  node_els_trace();
1739 
1740  io->els_callback = cb;
1741  io->els_callback_arg = cbarg;
1742  io->display_name = "prlo_acc";
1743  io->init_task_tag = ox_id;
1744 
1745  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1746  io->iparam.els.ox_id = ox_id;
1747 
1748  prlo_acc = io->els_req.virt;
1749  ocs_memset(prlo_acc, 0, sizeof(*prlo_acc));
1750 
1751  if (fc_type == FC_TYPE_NVME) {
1752  prlo_acc->type = FC_TYPE_NVME;
1753  } else {
1754  prlo_acc->type = FC_TYPE_FCP;
1755  }
1756  prlo_acc->command_code = FC_ELS_CMD_ACC;
1757  prlo_acc->page_length = 16;
1758  prlo_acc->payload_length = ocs_htobe16(sizeof(fc_prlo_acc_payload_t));
1759  prlo_acc->type_ext = 0;
1761 
1762  io->hio_type = OCS_HAL_ELS_RSP;
1763  if ((rc = ocs_els_send_rsp(io, sizeof(*prlo_acc)))) {
1764  ocs_els_io_free(io);
1765  io = NULL;
1766  }
1767 
1768  return io;
1769 }
1770 
1771 /**
1772  * @ingroup els_api
1773  * @brief Send a generic LS_ACC response without a payload.
1774  *
1775  * <h3 class="desc">Description</h3>
1776  * A generic LS_ACC response is sent to the \c node using the originator exchange ID
1777  * \c ox_id.
1778  *
1779  * @param io Pointer to a SCSI IO object.
1780  * @param ox_id Originator exchange id.
1781  * @param cb Callback function.
1782  * @param cbarg Callback function argument.
1783  *
1784  * @return Returns pointer to IO object, or NULL if error.
1785  */
1786 ocs_io_t *
1787 ocs_send_ls_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1788 {
1789  ocs_node_t *node = io->node;
1790  int32_t rc;
1791  ocs_t *ocs = node->ocs;
1792  fc_acc_payload_t *acc;
1793 
1794  node_els_trace();
1795 
1796  io->els_callback = cb;
1797  io->els_callback_arg = cbarg;
1798  io->display_name = "ls_acc";
1799  io->init_task_tag = ox_id;
1800 
1801  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1802  io->iparam.els.ox_id = ox_id;
1803 
1804  acc = io->els_req.virt;
1805  ocs_memset(acc, 0, sizeof(*acc));
1806 
1808 
1809  io->hio_type = OCS_HAL_ELS_RSP;
1810  if ((rc = ocs_els_send_rsp(io, sizeof(*acc)))) {
1811  ocs_els_io_free(io);
1812  io = NULL;
1813  }
1814 
1815  return io;
1816 }
1817 
1818 /**
1819  * @ingroup els_api
1820  * @brief Send a LOGO accept response.
1821  *
1822  * <h3 class="desc">Description</h3>
1823  * Construct a LOGO LS_ACC response, and send to the \c node, using the originator
1824  * exchange ID \c ox_id.
1825  *
1826  * @param io Pointer to a SCSI IO object.
1827  * @param ox_id Originator exchange ID.
1828  * @param cb Callback function.
1829  * @param cbarg Callback function argument.
1830  *
1831  * @return Returns pointer to IO object, or NULL if error.
1832  */
1833 ocs_io_t *
1834 ocs_send_logo_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1835 {
1836  ocs_node_t *node = io->node;
1837  int32_t rc;
1838  ocs_t *ocs = node->ocs;
1839  fc_acc_payload_t *logo;
1840 
1841  node_els_trace();
1842 
1843  io->els_callback = cb;
1844  io->els_callback_arg = cbarg;
1845  io->display_name = "logo_acc";
1846  io->init_task_tag = ox_id;
1847 
1848  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1849  io->iparam.els.ox_id = ox_id;
1850 
1851  logo = io->els_req.virt;
1852  ocs_memset(logo, 0, sizeof(*logo));
1853 
1854  logo->command_code = FC_ELS_CMD_ACC;
1855  logo->resv1 = 0;
1856 
1857  io->hio_type = OCS_HAL_ELS_RSP;
1858  if ((rc = ocs_els_send_rsp(io, sizeof(*logo)))) {
1859  ocs_els_io_free(io);
1860  io = NULL;
1861  }
1862 
1863  return io;
1864 }
1865 
1866 /**
1867  * @ingroup els_api
1868  * @brief Send an ADISC accept response.
1869  *
1870  * <h3 class="desc">Description</h3>
1871  * Construct an ADISC LS__ACC, and send to the \c node, using the originator
1872  * exchange id \c ox_id.
1873  *
1874  * @param io Pointer to a SCSI IO object.
1875  * @param ox_id Originator exchange ID.
1876  * @param cb Callback function.
1877  * @param cbarg Callback function argument.
1878  *
1879  * @return Returns pointer to IO object, or NULL if error.
1880  */
1881 
1882 ocs_io_t *
1883 ocs_send_adisc_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
1884 {
1885  ocs_node_t *node = io->node;
1886  int32_t rc;
1887  fc_adisc_payload_t *adisc;
1888  fc_plogi_payload_t *sparams;
1889  ocs_t *ocs;
1890 
1891  ocs_assert(node, NULL);
1892  ocs_assert(node->ocs, NULL);
1893  ocs = node->ocs;
1894 
1895  node_els_trace();
1896 
1897  io->els_callback = cb;
1898  io->els_callback_arg = cbarg;
1899  io->display_name = "adisc_acc";
1900  io->init_task_tag = ox_id;
1901 
1902  /* Go ahead and send the ELS_ACC */
1903  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1904  io->iparam.els.ox_id = ox_id;
1905 
1906  sparams = (fc_plogi_payload_t*) node->sport->service_params;
1907  adisc = io->els_req.virt;
1908  ocs_memset(adisc, 0, sizeof(fc_adisc_payload_t));
1909  adisc->command_code = FC_ELS_CMD_ACC;
1910  adisc->hard_address = 0;
1911  adisc->port_name_hi = sparams->port_name_hi;
1912  adisc->port_name_lo = sparams->port_name_lo;
1913  adisc->node_name_hi = sparams->node_name_hi;
1914  adisc->node_name_lo = sparams->node_name_lo;
1915  adisc->port_id = fc_htobe24(node->rnode.sport->fc_id);
1916 
1917  io->hio_type = OCS_HAL_ELS_RSP;
1918  if ((rc = ocs_els_send_rsp(io, sizeof(*adisc)))) {
1919  ocs_els_io_free(io);
1920  io = NULL;
1921  }
1922 
1923  return io;
1924 }
1925 
1926 /**
1927  * @ingroup els_api
1928  * @brief Send a RFTID CT request.
1929  *
1930  * <h3 class="desc">Description</h3>
1931  * Construct an RFTID CT request, and send to the \c node.
1932  *
1933  * @param node Node to which the RFTID request is sent.
1934  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
1935  * @param retries Number of times to retry errors before reporting a failure.
1936  * @param cb Callback function.
1937  * @param cbarg Callback function argument.
1938  *
1939  * @return Returns pointer to IO object, or NULL if error.
1940  */
1941 ocs_io_t *
1942 ocs_ns_send_rftid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
1943  els_cb_t cb, void *cbarg)
1944 {
1945  ocs_io_t *els;
1946  ocs_t *ocs = node->ocs;
1947  fcct_rftid_req_t *rftid;
1948 
1949  node_els_trace();
1950 
1951  els = ocs_els_io_alloc(node, sizeof(*rftid), OCS_ELS_ROLE_ORIGINATOR);
1952  if (els == NULL) {
1953  ocs_log_err(ocs, "IO alloc failed\n");
1954  } else {
1955 
1956  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
1957  els->iparam.fc_ct.type = FC_TYPE_GS;
1958  els->iparam.fc_ct.df_ctl = 0;
1959  els->iparam.fc_ct.timeout = timeout_sec;
1960 
1961  els->els_callback = cb;
1962  els->els_callback_arg = cbarg;
1963  els->display_name = "rftid";
1964 
1965  rftid = els->els_req.virt;
1966 
1967  ocs_memset(rftid, 0, sizeof(*rftid));
1970  (OCS_ELS_RSP_LEN - sizeof(rftid->hdr)));
1971 
1972  rftid->port_id = ocs_htobe32(node->rnode.sport->fc_id);
1973 
1974  if (ocs->enable_nvme_tgt) { // Word 1
1975  rftid->fc4_types[FC_GS_TYPE_WORD(FC_TYPE_NVME)] = ocs_htobe32(1 << FC_GS_TYPE_BIT(FC_TYPE_NVME));
1976  }
1977 
1978  if (node->sport->enable_ini || node->sport->enable_tgt) { // Word 0
1979  rftid->fc4_types[FC_GS_TYPE_WORD(FC_TYPE_FCP)] = ocs_htobe32(1 << FC_GS_TYPE_BIT(FC_TYPE_FCP));
1980  }
1981 
1982  els->hio_type = OCS_HAL_FC_CT;
1983 
1984  ocs_io_transition(els, __ocs_els_init, NULL);
1985  }
1986  return els;
1987 }
1988 
1989 /**
1990  * @ingroup els_api
1991  * @brief Send a RFFID CT request.
1992  *
1993  * <h3 class="desc">Description</h3>
1994  * Construct an RFFID CT request, and send to the \c node.
1995  *
1996  * @param node Node to which the RFFID request is sent.
1997  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
1998  * @param retries Number of times to retry errors before reporting a failure.
1999  * @param cb Callback function
2000  * @param cbarg Callback function argument.
2001  *
2002  * @return Returns pointer to IO object, or NULL if error.
2003  */
2004 ocs_io_t *
2005 ocs_ns_send_rffid(ocs_node_t *node, uint8_t fc_type, uint32_t timeout_sec, uint32_t retries,
2006  els_cb_t cb, void *cbarg)
2007 {
2008  ocs_io_t *els;
2009  ocs_t *ocs = node->ocs;
2010  fcct_rffid_req_t *rffid;
2011 
2012  node_els_trace();
2013 
2014  els = ocs_els_io_alloc(node, sizeof(*rffid), OCS_ELS_ROLE_ORIGINATOR);
2015  if (els == NULL) {
2016  ocs_log_err(ocs, "IO alloc failed\n");
2017  } else {
2018 
2019  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2020  els->iparam.fc_ct.type = FC_TYPE_GS;
2021  els->iparam.fc_ct.df_ctl = 0;
2022  els->iparam.fc_ct.timeout = timeout_sec;
2023 
2024  els->els_callback = cb;
2025  els->els_callback_arg = cbarg;
2026  els->display_name = "rffid";
2027 
2028  rffid = els->els_req.virt;
2029 
2030  ocs_memset(rffid, 0, sizeof(*rffid));
2031 
2034  (OCS_ELS_RSP_LEN - sizeof(rffid->hdr)));
2035  rffid->port_id = ocs_htobe32(node->rnode.sport->fc_id);
2036  if (fc_type == FC_TYPE_NVME) {
2037  rffid->type = FC_TYPE_NVME;
2038  if (ocs->enable_nvme_tgt) {
2041  }
2042  } else { // SCSI
2043  rffid->type = FC_TYPE_FCP;
2044  if (node->sport->enable_ini) {
2046  }
2047  if (node->sport->enable_tgt) {
2049  }
2050  }
2051 
2052  els->hio_type = OCS_HAL_FC_CT;
2053 
2054  ocs_io_transition(els, __ocs_els_init, NULL);
2055  }
2056  return els;
2057 }
2058 
2059 /**
2060  * @ingroup els_api
2061  * @brief Send a GIDPT CT request.
2062  *
2063  * <h3 class="desc">Description</h3>
2064  * Construct a GIDPT CT request, and send to the \c node.
2065  *
2066  * @param node Node to which the GIDPT request is sent.
2067  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2068  * @param retries Number of times to retry errors before reporting a failure.
2069  * @param cb Callback function.
2070  * @param cbarg Callback function argument.
2071  *
2072  * @return Returns pointer to IO object, or NULL if error.
2073  */
2074 
2075 ocs_io_t *
2076 ocs_ns_send_gidpt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
2077  els_cb_t cb, void *cbarg)
2078 {
2079  ocs_io_t *els;
2080  ocs_t *ocs = node->ocs;
2081  fcct_gidpt_req_t *gidpt;
2082 
2083  node_els_trace();
2084 
2086  if (els == NULL) {
2087  ocs_log_err(ocs, "%s: IO alloc failed\n", __func__);
2088  } else {
2089 
2090  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2091  els->iparam.fc_ct.type = FC_TYPE_GS;
2092  els->iparam.fc_ct.df_ctl = 0;
2093  els->iparam.fc_ct.timeout = timeout_sec;
2094 
2095  els->els_callback = cb;
2096  els->els_callback_arg = cbarg;
2097  els->display_name = "gidpt";
2098 
2099  gidpt = els->els_req.virt;
2100 
2101  ocs_memset(gidpt, 0, sizeof(*gidpt));
2104  (OCS_ELS_GID_PT_RSP_LEN - sizeof(gidpt->hdr)) );
2105  gidpt->domain_id_scope = 0;
2106  gidpt->area_id_scope = 0;
2107  gidpt->port_type = 0x7f;
2108 
2109  els->hio_type = OCS_HAL_FC_CT;
2110 
2111  ocs_io_transition(els, __ocs_els_init, NULL);
2112  }
2113  return els;
2114 }
2115 
2116 
2117 ocs_io_t *
2118 ocs_ns_send_loopback_frame(ocs_node_t *node, void *buf, uint32_t size, void *rx_buf, uint32_t rx_buf_size,
2119  uint32_t timeout_sec, uint32_t retries,
2120  els_cb_t cb, void *cbarg)
2121 {
2122  ocs_io_t *els;
2123  ocs_t *ocs = node->ocs;
2124  fcct_iu_header_t *fcct_header;
2125  uint32_t total_size;
2126  void *ptr = NULL;
2127 
2128  node_els_trace();
2129 
2130  if (rx_buf == NULL) {
2131  ocs_log_err(ocs, "failed to allocate RX buff data\n");
2132  return NULL;
2133  }
2134  total_size = size + sizeof(fcct_iu_header_t);
2136  if (els == NULL) {
2137  ocs_log_err(ocs, "%s: IO alloc failed\n", __func__);
2138  } else {
2139 
2140  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2141  els->iparam.fc_ct.type = FC_TYPE_GS;
2142  els->iparam.fc_ct.df_ctl = 0;
2143  els->iparam.fc_ct.timeout = timeout_sec;
2144 
2145  els->els_callback = cb;
2146  els->els_callback_arg = cbarg;
2147  els->els_retries_remaining = retries;
2148  els->display_name = "loopback_frame";
2149 
2150  ptr = els->els_req.virt;
2151  fcct_header = (fcct_iu_header_t *)ptr;
2152 
2153  els->loopback_evt_data.is_loopback_frame = 1;
2154  els->loopback_evt_data.loopback_rx_data = rx_buf;
2155  els->loopback_evt_data.loopback_rx_data_len = rx_buf_size;
2156  ocs_sem_init(&els->loopback_evt_data.wait_io_sem, 0, "loopback_frame_sem");
2157 
2158  ocs_memset(fcct_header, 0, sizeof(*fcct_header));
2160  ptr = (uint8_t *)ptr + sizeof(fcct_iu_header_t);
2161  ocs_memcpy(ptr, buf, size);
2162 
2163  els->hio_type = OCS_HAL_FC_CT;
2164 
2165  ocs_ref_get(&els->ref);
2166  ocs_io_transition(els, __ocs_els_init, NULL);
2167  }
2168  return els;
2169 }
2170 
2171 /**
2172  * @ingroup els_api
2173  * @brief Send a GA_NEXT CT request.
2174  *
2175  * <h3 class="desc">Description</h3>
2176  * Construct a GA_NEXT CT request, and send to the \c node.
2177  *
2178  * @param node Node to which the GIDFT request is sent.
2179  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2180  * @param retries Number of times to retry errors before reporting a failure.
2181  * @param cb Callback function.
2182  * @param cbarg Callback function argument.
2183  *
2184  * @return Returns pointer to IO object, or NULL if error.
2185  */
2186 ocs_io_t *
2187 ocs_ns_send_ganxt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
2188  els_cb_t cb, void *cbarg, uint32_t port_id)
2189 {
2190  ocs_io_t *els;
2191  ocs_t *ocs = node->ocs;
2192  fcct_ganxt_req_t *ganxt;
2193 
2194  node_els_trace();
2195 
2196  els = ocs_els_io_alloc_size(node, sizeof(*ganxt), OCS_ELS_RSP_LEN, OCS_ELS_ROLE_ORIGINATOR);
2197  if (els == NULL) {
2198  ocs_log_err(ocs, "%s: IO alloc failed\n", __func__);
2199  } else {
2200 
2201  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2202  els->iparam.fc_ct.type = FC_TYPE_GS;
2203  els->iparam.fc_ct.df_ctl = 0;
2204  els->iparam.fc_ct.timeout = timeout_sec;
2205 
2206  els->els_callback = cb;
2207  els->els_callback_arg = cbarg;
2208  els->display_name = "ganxt";
2209 
2210  ganxt = els->els_req.virt;
2211 
2212  ocs_memset(ganxt, 0, sizeof(*ganxt));
2215  (OCS_ELS_RSP_LEN - sizeof(ganxt->hdr)));
2216 
2217  if (!port_id) {
2218  port_id = fc_htobe24(node->sport->fc_id);
2219  }
2220 
2221  ganxt->port_id = port_id;
2222 
2223  els->hio_type = OCS_HAL_FC_CT;
2224 
2225  ocs_io_transition(els, __ocs_els_init, NULL);
2226  }
2227  return els;
2228 }
2229 
2230 /**
2231  * @ingroup els_api
2232  * @brief Send a RHBA CT request.
2233  *
2234  * <h3 class="desc">Description</h3>
2235  * Construct an RHBA CT request, and send to the \c node.
2236  *
2237  * @param node Node to which the RHBA request is sent.
2238  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2239  * @param retries Number of times to retry errors before reporting a failure.
2240  * @param cb Callback function.
2241  * @param cbarg Callback function argument.
2242  *
2243  * @return Returns pointer to IO object, or NULL if error.
2244  */
2245 ocs_io_t *
2246 ocs_fdmi_send_rhba(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries,
2247  els_cb_t cb, void *cbarg)
2248 {
2249  ocs_io_t *els;
2250  ocs_t *ocs = node->ocs;
2251  fcct_fdmi_rhba_req_t *rhba;
2252  int (*func)(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad);
2253 
2254  node_els_trace();
2255 
2257  if (els == NULL) {
2258  ocs_log_err(ocs, "IO alloc failed\n");
2259  } else {
2260  uint32_t index = 0, size = 0;
2261  uint32_t num_port_entries = 0, mask = 0;
2262  ocs_fdmi_attr_block_t *ab = NULL;
2263 
2264 
2265  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2266  els->iparam.fc_ct.type = FC_TYPE_GS;
2267  els->iparam.fc_ct.df_ctl = 0;
2268  els->iparam.fc_ct.timeout = timeout_sec;
2269 
2270  els->els_callback = cb;
2271  els->els_callback_arg = cbarg;
2272  els->display_name = "rhba";
2273  els->els_retries_remaining = retries;
2274 
2275  rhba = (fcct_fdmi_rhba_req_t *)els->els_req.virt;
2276 
2277  ocs_memset(rhba, 0, sizeof(*rhba));
2280  (OCS_ELS_FDMI_REG_LEN - sizeof(rhba->hdr)));
2281  size += sizeof(rhba->hdr);
2282 
2283  /* HBA identifier */
2284  memcpy(&rhba->hba_identifier, &node->sport->sli_wwpn, sizeof(node->sport->sli_wwpn));
2285  size += sizeof(rhba->hba_identifier);
2286  num_port_entries = 1;
2287  rhba->port_list.entry_count = ocs_htobe32(num_port_entries);
2288  memcpy(&rhba->port_list.port_entry[0], &node->sport->sli_wwpn, sizeof(node->sport->sli_wwpn));
2289  size += sizeof(rhba->port_list) + num_port_entries * sizeof(node->sport->sli_wwpn);
2290  /* point to the HBA attribute block */
2291  ab = (ocs_fdmi_attr_block_t *)((uint8_t *)rhba + size);
2292  ab->num_entries = 0;
2293  size += sizeof(ab->num_entries);
2294 
2295  func = ocs_fdmi_hba_action[index];
2296  mask = node->sport->fdmi_hba_mask;
2297  /* Build all required HBA info in the request */
2298  while (func && mask) {
2299  size += func(node->sport, (ocs_fdmi_attr_def_t *)((uint8_t *)rhba + size));
2300  ab->num_entries++;
2302  goto hba_reg_exit;
2303  mask = mask >> 1;
2304  func = ocs_fdmi_hba_action[++index];
2305  }
2306 hba_reg_exit:
2307  ab->num_entries = ocs_htobe32(ab->num_entries);
2308  els->hio_type = OCS_HAL_FC_CT;
2309 
2310  ocs_io_transition(els, __ocs_els_init, NULL);
2311  }
2312 
2313  return els;
2314 }
2315 
2316 /**
2317  * @ingroup els_api
2318  * @brief Send a FDMI dereg CT request.
2319  *
2320  * <h3 class="desc">Description</h3>
2321  * Construct an DHBA/DPRT CT request, and send to the \c node.
2322  *
2323  * @param node Node to which the dereg request is sent.
2324  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2325  * @param retries Number of times to retry errors before reporting a failure.
2326  * @param cb Callback function.
2327  * @param cbarg Callback function argument.
2328  *
2329  * @return Returns pointer to IO object, or NULL if error.
2330  */
2331 ocs_io_t *
2332 ocs_fdmi_send_dereg_cmd(ocs_node_t *node, uint16_t dereg_code, uint32_t timeout_sec,
2333  uint32_t retries, els_cb_t cb, void *cbarg)
2334 {
2335  ocs_io_t *els;
2336  ocs_t *ocs = node->ocs;
2337  fcct_fdmi_dereg_req_t *dereg_req;
2338 
2339  node_els_trace();
2340 
2341  els = ocs_els_io_alloc(node, sizeof(*dereg_req), OCS_ELS_ROLE_ORIGINATOR);
2342  if (els == NULL) {
2343  ocs_log_err(ocs, "IO alloc failed\n");
2344  } else {
2345  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2346  els->iparam.fc_ct.type = FC_TYPE_GS;
2347  els->iparam.fc_ct.df_ctl = 0;
2348  els->iparam.fc_ct.timeout = timeout_sec;
2349 
2350  els->els_callback = cb;
2351  els->els_callback_arg = cbarg;
2352 
2353  els->display_name = "dereg_cmd";
2354  els->els_retries_remaining = retries;
2355 
2356  dereg_req = (fcct_fdmi_dereg_req_t *)els->els_req.virt;
2357 
2358  ocs_memset(dereg_req, 0, sizeof(*dereg_req));
2359  fcct_build_req_header(&dereg_req->hdr, dereg_code, FC_GS_TYPE_MANAGEMENT_SERVICE,
2361  (OCS_ELS_FDMI_RSP_LEN - sizeof(dereg_req->hdr)));
2362  /* HBA identifier */
2363  dereg_req->identifier = node->sport->sli_wwpn;
2364  els->hio_type = OCS_HAL_FC_CT;
2365  ocs_io_transition(els, __ocs_els_init, NULL);
2366  }
2367 
2368  return els;
2369 }
2370 
2371 /**
2372  * @ingroup els_api
2373  * @brief Send a RPRT/RPA CT request.
2374  *
2375  * <h3 class="desc">Description</h3>
2376  * Construct an RPRT/RPA CT request, and send to the \c node.
2377  *
2378  * @param node Node to which the RPRT/RPA request is sent.
2379  * @req_code command code(RPRT/RPA)
2380  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2381  * @param retries Number of times to retry errors before reporting a failure.
2382  * @param cb Callback function.
2383  * @param cbarg Callback function argument.
2384  *
2385  * @return Returns pointer to IO object, or NULL if error.
2386  */
2387 ocs_io_t *
2388 ocs_fdmi_send_reg_port(ocs_node_t *node, int req_code, uint32_t timeout_sec,
2389  uint32_t retries, els_cb_t cb, void *cbarg)
2390 {
2391  ocs_io_t *els;
2392  ocs_t *ocs = node->ocs;
2393  int (*func)(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad);
2394 
2395  node_els_trace();
2396 
2398  if (els == NULL) {
2399  ocs_log_err(ocs, "IO alloc failed\n");
2400  } else {
2401  uint32_t index = 0, size = 0, mask;
2402  ocs_fdmi_attr_block_t *pab = NULL;
2403 
2404  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2405  els->iparam.fc_ct.type = FC_TYPE_GS;
2406  els->iparam.fc_ct.df_ctl = 0;
2407  els->iparam.fc_ct.timeout = timeout_sec;
2408 
2409  els->els_callback = cb;
2410  els->els_callback_arg = cbarg;
2411  els->els_retries_remaining = retries;
2412  if (req_code == FC_GS_FDMI_RPRT) {
2413  fcct_fdmi_rprt_req_t *rprt;
2414 
2415  els->display_name = "rprt";
2416  rprt = (fcct_fdmi_rprt_req_t *)els->els_req.virt;
2417  ocs_memset(rprt, 0, sizeof(*rprt));
2420  (OCS_ELS_FDMI_REG_LEN - sizeof(rprt->hdr)));
2421  size += sizeof(rprt->hdr);
2422  /* Physical port HBA identifier */
2423  memcpy(&rprt->hba_identifier, &ocs->domain->sport->sli_wwpn,
2424  sizeof(ocs->domain->sport->sli_wwpn));
2425  size += sizeof(ocs->domain->sport->sli_wwpn);
2426 
2427  /* Port name */
2428  memcpy(&rprt->port_name, &node->sport->sli_wwpn,
2429  sizeof(node->sport->sli_wwpn));
2430  size += sizeof(node->sport->sli_wwpn);
2431 
2432  } else {
2433  fcct_fdmi_rpa_req_t *rpa;
2434 
2435  els->display_name = "rpa";
2436  rpa = (fcct_fdmi_rpa_req_t *)els->els_req.virt;
2437  ocs_memset(rpa, 0, sizeof(*rpa));
2439  FC_GS_SUBTYPE_FDMI, (OCS_ELS_FDMI_REG_LEN - sizeof(rpa->hdr)));
2440  size += sizeof(rpa->hdr);
2441  /* Port name */
2442  memcpy(&rpa->port_name[0], &node->sport->sli_wwpn,
2443  sizeof(node->sport->sli_wwpn));
2444  size += sizeof(node->sport->sli_wwpn);
2445  }
2446 
2447  /* Now point to port attribute block */
2448  pab = (ocs_fdmi_attr_block_t *)((uint8_t *)els->els_req.virt + size);
2449 
2450  pab->num_entries = 0;
2451  size += sizeof(pab->num_entries);
2452 
2453  func = ocs_fdmi_port_action[index];
2454  mask = node->sport->fdmi_port_mask;
2455  /* Mask will dictate what attributes to build in the request */
2456  while (func && mask) {
2457  size += func(node->sport, (ocs_fdmi_attr_def_t *)
2458  ((uint8_t *)els->els_req.virt + size));
2459  pab->num_entries++;
2461  goto reg_port_exit;
2462  mask = mask >> 1;
2463  func = ocs_fdmi_port_action[++index];
2464  }
2465 reg_port_exit:
2466  pab->num_entries = ocs_htobe32(pab->num_entries);
2467  els->hio_type = OCS_HAL_FC_CT;
2468 
2469  ocs_io_transition(els, __ocs_els_init, NULL);
2470  }
2471 
2472  return els;
2473 }
2474 
2475 /**
2476  * @ingroup els_api
2477  * @brief Send a GHRL CT request.
2478  *
2479  * <h3 class="desc">Description</h3>
2480  * Construct a GHRL CT request, and send to the \c node.
2481  *
2482  * @param node Node to which the GHRL request is sent.
2483  * @param timeout_sec Time, in seconds, to wait before timing out the ELS.
2484  * @param retries Number of times to retry errors before reporting a failure.
2485  * @param cb Callback function.
2486  * @param cbarg Callback function argument.
2487  *
2488  * @return Returns pointer to IO object, or NULL if error.
2489  */
2490 
2491 ocs_io_t *
2492 ocs_fdmi_send_get_cmd(ocs_node_t *node, uint32_t timeout_sec,
2493  uint32_t retries, els_cb_t cb,
2494  void *cbarg, ocs_fdmi_get_cmd_req_info_t *req_info)
2495 {
2496  ocs_io_t *els;
2497  ocs_t *ocs = node->ocs;
2498  fcct_iu_header_t *fcct_header = NULL;
2499  node_els_trace();
2500 
2501  els = ocs_els_io_alloc_size(node, req_info->ct_cmd_req_size,
2503  if (els == NULL) {
2504  ocs_log_err(ocs, "ELS IO alloc failed\n");
2505  } else {
2506  els->iparam.fc_ct.r_ctl = FC_RCTL_ELS;
2507  els->iparam.fc_ct.type = FC_TYPE_GS;
2508  els->iparam.fc_ct.df_ctl = 0;
2509  els->iparam.fc_ct.timeout = timeout_sec;
2510 
2511  els->els_callback = cb;
2512  els->els_callback_arg = cbarg;
2513  els->els_retries_remaining = retries;
2514 
2515  fcct_header = (fcct_iu_header_t *)els->els_req.virt;
2516 
2520 
2521  els->hio_type = OCS_HAL_FC_CT;
2522  switch (req_info->cmd_code) {
2523  case FC_GS_FDMI_GRHL:
2524  els->display_name = "grhl";
2525  break;
2526  case FC_GS_FDMI_GRPL: {
2527  fcct_fdmi_grpl_req_t *grpl_req = els->els_req.virt;
2528 
2529  els->display_name = "grpl";
2530  grpl_req->hba_identifier = ocs_htobe64(req_info->identifier);
2531  }
2532  break;
2533  case FC_GS_FDMI_GHAT: {
2534  fcct_fdmi_ghat_req_t *ghat_req = els->els_req.virt;
2535 
2536  els->display_name = "ghat";
2537  ghat_req->hba_identifier = ocs_htobe64(req_info->identifier);
2538  }
2539  break;
2540  case FC_GS_FDMI_GPAT: {
2541  fcct_fdmi_gpat_req_t *gpat_req = els->els_req.virt;
2542 
2543  els->display_name = "gpat";
2544  gpat_req->port_identifier = ocs_htobe64(req_info->identifier);
2545  }
2546  break;
2547  default:
2548  ocs_log_err(ocs, "Unhandled FDMI cmd code: 0x%x\n", req_info->cmd_code);
2549  ocs_ref_put(&els->ref);
2550  return NULL;
2551  }
2552  ocs_io_transition(els, __ocs_els_init, NULL);
2553  }
2554 
2555  return els;
2556 }
2557 
2558 
2559 /**
2560  * @ingroup els_api
2561  * @brief Send a BA_ACC given the request's FC header
2562  *
2563  * <h3 class="desc">Description</h3>
2564  * Using the S_ID/D_ID from the request's FC header, generate a BA_ACC.
2565  *
2566  * @param io Pointer to a SCSI IO object.
2567  * @param hdr Pointer to the FC header.
2568  *
2569  * @return Returns pointer to IO object, or NULL if error.
2570  */
2571 
2572 ocs_io_t *
2574 {
2575  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
2576  uint16_t rx_id = ocs_be16toh(hdr->rx_id);
2577  uint32_t d_id = fc_be24toh(hdr->d_id);
2578 
2579  return ocs_bls_send_acc(io, d_id, ox_id, rx_id);
2580 }
2581 
2582 /**
2583  * @ingroup els_api
2584  * @brief Send a BLS BA_ACC response.
2585  *
2586  * <h3 class="desc">Description</h3>
2587  * Construct a BLS BA_ACC response, and send to the \c node.
2588  *
2589  * @param io Pointer to a SCSI IO object.
2590  * @param s_id S_ID to use for the response. If UINT32_MAX, then use our SLI port
2591  * (sport) S_ID.
2592  * @param ox_id Originator exchange ID.
2593  * @param rx_id Responder exchange ID.
2594  *
2595  * @return Returns pointer to IO object, or NULL if error.
2596  */
2597 
2598 static ocs_io_t *
2599 ocs_bls_send_acc(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id)
2600 {
2601  ocs_node_t *node = io->node;
2602  int32_t rc;
2603  fc_ba_acc_payload_t *acc;
2604  ocs_t *ocs;
2605 
2606  ocs_assert(node, NULL);
2607  ocs_assert(node->ocs, NULL);
2608  ocs = node->ocs;
2609 
2610  if (node->rnode.sport->fc_id == s_id) {
2611  s_id = UINT32_MAX;
2612  }
2613 
2614  /* fill out generic fields */
2615  io->ocs = ocs;
2616  io->node = node;
2617  io->cmd_tgt = TRUE;
2618 
2619  /* fill out BLS Response-specific fields */
2620  io->io_type = OCS_IO_TYPE_BLS_RESP;
2621  io->display_name = "ba_acc";
2622  io->hio_type = OCS_HAL_BLS_ACC_SID;
2623  io->init_task_tag = ox_id;
2624 
2625  /* fill out iparam fields */
2626  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
2627  io->iparam.bls_sid.s_id = s_id;
2628  io->iparam.bls_sid.ox_id = ox_id;
2629  io->iparam.bls_sid.rx_id = rx_id;
2630 
2631  acc = (void *)io->iparam.bls_sid.payload;
2632 
2633  ocs_memset(io->iparam.bls_sid.payload, 0, sizeof(io->iparam.bls_sid.payload));
2634  acc->ox_id = io->iparam.bls_sid.ox_id;
2635  acc->rx_id = io->iparam.bls_sid.rx_id;
2636  acc->high_seq_cnt = UINT16_MAX;
2637 
2638  if ((rc = ocs_scsi_io_dispatch(io, ocs_bls_send_acc_cb))) {
2639  ocs_log_err(ocs, "ocs_scsi_io_dispatch() failed: %d\n", rc);
2640  ocs_scsi_io_free(io);
2641  io = NULL;
2642  }
2643  return io;
2644 }
2645 
2646 /**
2647  * @brief Handle the BLS accept completion.
2648  *
2649  * <h3 class="desc">Description</h3>
2650  * Upon completion of sending a BA_ACC, this callback is invoked by the HAL.
2651  *
2652  * @param hio Pointer to the HAL IO object.
2653  * @param rnode Pointer to the HAL remote node.
2654  * @param length Length of the response payload, in bytes.
2655  * @param status Completion status.
2656  * @param ext_status Extended completion status.
2657  * @param app Callback private argument.
2658  *
2659  * @return Returns 0 on success; or a negative error value on failure.
2660  */
2661 
2662 static int32_t
2663 ocs_bls_send_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
2664 {
2665  ocs_io_t *io = app;
2666 
2667  ocs_assert(io, -1);
2668 
2669  ocs_scsi_io_free(io);
2670  return 0;
2671 }
2672 
2673 /**
2674  * @ingroup els_ap
2675  * @brief Send a BA_RJT given the request's FC heade
2676  * <h3 class="desc">Description</h3>
2677  * Using the S_ID/D_ID from the request's FC header, generate a BA_RJT.
2678  *
2679  * @param io Pointer to a SCSI IO object.
2680  * @param hdr Pointer to the FC header.
2681  *
2682  * @return Returns pointer to IO object, or NULL if error.
2683  */
2684 ocs_io_t *
2686 {
2687  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
2688  uint16_t rx_id = ocs_be16toh(hdr->rx_id);
2689  uint32_t d_id = fc_be24toh(hdr->d_id);
2690 
2691  return ocs_bls_send_rjt(io, d_id, ox_id, rx_id);
2692 }
2693 /**
2694  * @ingroup els_api
2695  * @brief Send a BLS BA_RJT response.
2696  *
2697  * <h3 class="desc">Description</h3>
2698  * Construct a BLS BA_RJT response, and send to the \c node.
2699  *
2700  * @param io Pointer to a SCSI IO object.
2701  * @param s_id S_ID to use for the response. If UINT32_MAX, then use our SLI port
2702  * (sport) S_ID.
2703  * @param ox_id Originator exchange ID.
2704  * @param rx_id Responder exchange ID.
2705  *
2706  * @return Returns pointer to IO object, or NULL if error.
2707  */
2708 static ocs_io_t *
2709 ocs_bls_send_rjt(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id)
2710 {
2711  ocs_node_t *node = io->node;
2712  int32_t rc;
2713  fc_ba_rjt_payload_t *acc;
2714  ocs_t *ocs;
2715 
2716  ocs_assert(node, NULL);
2717  ocs_assert(node->ocs, NULL);
2718  ocs = node->ocs;
2719 
2720  if (node->rnode.sport->fc_id == s_id) {
2721  s_id = UINT32_MAX;
2722  }
2723 
2724  /* fill out generic fields */
2725  io->ocs = ocs;
2726  io->node = node;
2727  io->cmd_tgt = TRUE;
2728 
2729  /* fill out BLS Response-specific fields */
2730  io->io_type = OCS_IO_TYPE_BLS_RESP;
2731  io->display_name = "ba_rjt";
2732  io->hio_type = OCS_HAL_BLS_RJT;
2733  io->init_task_tag = ox_id;
2734 
2735  /* fill out iparam fields */
2736  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
2737  io->iparam.bls.ox_id = ox_id;
2738  io->iparam.bls.rx_id = rx_id;
2739 
2740  acc = (void *)io->iparam.bls.payload;
2741 
2742  ocs_memset(io->iparam.bls.payload, 0, sizeof(io->iparam.bls.payload));
2745 
2746  if ((rc = ocs_scsi_io_dispatch(io, ocs_bls_send_rjt_cb))) {
2747  ocs_log_err(ocs, "%s: ocs_scsi_io_dispatch() failed: %d\n", __func__, rc);
2748  ocs_scsi_io_free(io);
2749  io = NULL;
2750  }
2751  return io;
2752 }
2753 
2754 /**
2755  * @brief Handle the BLS reject completion.
2756  *
2757  * <h3 class="desc">Description</h3>
2758  * Upon completion of sending a BA_RJT, this callback is invoked by the HAL.
2759  *
2760  * @param hio Pointer to the HAL IO object.
2761  * @param rnode Pointer to the HAL remote node.
2762  * @param length Length of the response payload, in bytes.
2763  * @param status Completion status.
2764  * @param ext_status Extended completion status.
2765  * @param app Callback private argument.
2766  *
2767  * @return Returns 0 on success; or a negative error value on failure.
2768  */
2769 static int32_t
2770 ocs_bls_send_rjt_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
2771  int32_t status, uint32_t ext_status, void *app)
2772 {
2773  ocs_io_t *io = app;
2774 
2775  ocs_assert(io, -1);
2776 
2777  ocs_scsi_io_free(io);
2778 
2779  return 0;
2780 }
2781 
2782 /**
2783  * @brief ELS abort callback.
2784  *
2785  * <h3 class="desc">Description</h3>
2786  * This callback is invoked by the HAL when an ELS IO is aborted.
2787  *
2788  * @param hio Pointer to the HAL IO object.
2789  * @param rnode Pointer to the HAL remote node.
2790  * @param length Length of the response payload, in bytes.
2791  * @param status Completion status.
2792  * @param ext_status Extended completion status.
2793  * @param app Callback private argument.
2794  *
2795  * @return Returns 0 on success; or a negative error value on failure.
2796  */
2797 
2798 static int32_t
2799 ocs_els_abort_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
2800 {
2801  ocs_io_t *els;
2802  ocs_io_t *abort_io = NULL; /* IO structure used to abort ELS */
2803  ocs_t *ocs;
2804 
2805  ocs_assert(app, -1);
2806  abort_io = app;
2807  els = abort_io->io_to_abort;
2808  ocs_assert(els->node, -1);
2809  ocs_assert(els->node->ocs, -1);
2810 
2811  ocs = els->node->ocs;
2812 
2813  if (status != 0) {
2814  ocs_log_warn(ocs, "status x%x ext x%x\n", status, ext_status);
2815  }
2816 
2817  /* now free the abort IO */
2818  ocs_io_free(ocs, abort_io);
2819 
2820  /* send completion event to indicate abort process is complete
2821  * Note: The ELS SM will already be receiving ELS_REQ_OK/FAIL/RJT/ABORTED
2822  */
2824 
2825  /* done with ELS IO to abort */
2826  ocs_ref_put(&els->ref); /* ocs_ref_get(): ocs_els_abort_io() */
2827  return 0;
2828 }
2829 
2830 /**
2831  * @brief Abort an ELS IO.
2832  *
2833  * <h3 class="desc">Description</h3>
2834  * The ELS IO is aborted by making a HAL abort IO request,
2835  * optionally requesting that an ABTS is sent.
2836  *
2837  * \b Note: This function allocates a HAL IO, and associates the HAL IO
2838  * with the ELS IO that it is aborting. It does not associate
2839  * the HAL IO with the node directly, like for ELS requests. The
2840  * abort completion is propagated up to the node once the
2841  * original WQE and the abort WQE are complete (the original WQE
2842  * completion is not propagated up to node).
2843  *
2844  * @param els Pointer to the ELS IO.
2845  * @param send_abts Boolean to indicate if hardware will automatically generate an ABTS.
2846  *
2847  * @return Returns pointer to Abort IO object, or NULL if error.
2848  */
2849 
2850 static ocs_io_t *
2851 ocs_els_abort_io(ocs_io_t *els, int send_abts)
2852 {
2853  ocs_t *ocs;
2854  ocs_xport_t *xport;
2855  int32_t rc;
2856  ocs_io_t *abort_io = NULL;
2857 
2858  ocs_assert(els, NULL);
2859  ocs_assert(els->node, NULL);
2860  ocs_assert(els->node->ocs, NULL);
2861 
2862  ocs = els->node->ocs;
2863  ocs_assert(ocs->xport, NULL);
2864  xport = ocs->xport;
2865 
2866  /* take a reference on IO being aborted */
2867  if ((ocs_ref_get_unless_zero(&els->ref) == 0)) {
2868  /* command no longer active */
2869  ocs_log_debug(ocs, "els no longer active\n");
2870  return NULL;
2871  }
2872 
2873  /* allocate IO structure to send abort */
2874  abort_io = ocs_io_alloc(ocs);
2875  if (abort_io == NULL) {
2876  ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
2877  } else {
2878  ocs_assert(abort_io->hio == NULL, NULL);
2879 
2880  /* set generic fields */
2881  abort_io->ocs = ocs;
2882  abort_io->node = els->node;
2883  abort_io->cmd_ini = TRUE;
2884 
2885  /* set type and ABORT-specific fields */
2886  abort_io->io_type = OCS_IO_TYPE_ABORT;
2887  abort_io->display_name = "abort_els";
2888  abort_io->io_to_abort = els;
2889  abort_io->send_abts = send_abts;
2890 
2891  /* now dispatch IO */
2892  if ((rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_els_abort_cb))) {
2893  ocs_log_err(ocs, "ocs_scsi_io_dispatch failed: %d\n", rc);
2894  ocs_io_free(ocs, abort_io);
2895  abort_io = NULL;
2896  }
2897  }
2898 
2899  /* if something failed, put reference on ELS to abort */
2900  if (abort_io == NULL) {
2901  ocs_ref_put(&els->ref); /* ocs_ref_get(): same function */
2902  }
2903  return abort_io;
2904 }
2905 
2906 
2907 /*
2908  * ELS IO State Machine
2909  */
2910 
2911 #define std_els_state_decl(...) \
2912  ocs_io_t *els = NULL; \
2913  ocs_node_t *node = NULL; \
2914  ocs_t *ocs = NULL; \
2915  ocs_assert(ctx != NULL, NULL); \
2916  els = ctx->app; \
2917  ocs_assert(els != NULL, NULL); \
2918  node = els->node; \
2919  ocs_assert(node != NULL, NULL); \
2920  ocs = node->ocs; \
2921  ocs_assert(ocs != NULL, NULL);
2922 
2923 #define els_sm_trace(...) \
2924  do { \
2925  if (OCS_LOG_ENABLE_ELS_TRACE(ocs)) \
2926  ocs_log_info(ocs, "[%s] %-8s %-20s %-20s\n", node->display_name, els->display_name, \
2927  __func__, ocs_sm_event_name(evt)); \
2928  } while (0)
2929 
2930 
2931 /**
2932  * @brief Cleanup an ELS IO
2933  *
2934  * <h3 class="desc">Description</h3>
2935  * Cleans up an ELS IO by posting the requested event to the owning node object;
2936  * invoking the callback, if one is provided; and then freeing the
2937  * ELS IO object.
2938  *
2939  * @param els Pointer to the ELS IO.
2940  * @param node_evt Node SM event to post.
2941  * @param arg Node SM event argument.
2942  *
2943  * @return None.
2944  */
2945 
2946 void
2947 ocs_els_io_cleanup(ocs_io_t *els, ocs_sm_event_t node_evt, void *arg)
2948 {
2949  ocs_assert(els);
2950 
2951  /* don't want further events that could come; e.g. abort requests
2952  * from the node state machine; thus, disable state machine
2953  */
2954  ocs_sm_disable(&els->els_sm);
2955  ocs_node_post_event(els->node, node_evt, arg);
2956 
2957  /* If this IO has a callback, invoke it */
2958  if (els->els_callback) {
2959  (*els->els_callback)(els->node, arg, els->els_callback_arg);
2960  }
2961  els->els_req_free = 1;
2962 }
2963 
2964 
2965 /**
2966  * @brief Common event handler for the ELS IO state machine.
2967  *
2968  * <h3 class="desc">Description</h3>
2969  * Provide handler for events for which default actions are desired.
2970  *
2971  * @param funcname Name of the calling function (for logging).
2972  * @param ctx Remote node SM context.
2973  * @param evt Event to process.
2974  * @param arg Per event optional argument.
2975  *
2976  * @return Returns NULL.
2977  */
2978 
2979 void *
2980 __ocs_els_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2981 {
2983 
2984  switch(evt) {
2985  case OCS_EVT_ENTER:
2986  case OCS_EVT_REENTER:
2987  case OCS_EVT_EXIT:
2988  break;
2989 
2990  /* If ELS_REQ_FAIL is not handled in state, then we'll terminate this ELS and
2991  * pass the event to the node
2992  */
2994  ocs_log_warn(els->node->ocs, "[%s] %-20s %-20s not handled - terminating ELS\n", node->display_name, funcname,
2995  ocs_sm_event_name(evt));
2997  break;
2998  default:
2999  ocs_log_warn(els->node->ocs, "[%s] %-20s %-20s not handled\n", node->display_name, funcname,
3000  ocs_sm_event_name(evt));
3001  break;
3002  }
3003  return NULL;
3004 }
3005 
3006 /**
3007  * @brief Initial ELS IO state
3008  *
3009  * <h3 class="desc">Description</h3>
3010  * This is the initial ELS IO state. Upon entry, the requested ELS/CT is submitted to
3011  * the hardware.
3012  *
3013  * @param ctx Remote node SM context.
3014  * @param evt Event to process.
3015  * @param arg Per event optional argument.
3016  *
3017  * @return Returns NULL.
3018  */
3019 
3020 void *
3021 __ocs_els_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3022 {
3023  int32_t rc = 0;
3025 
3026  els_sm_trace();
3027 
3028  switch(evt) {
3029  case OCS_EVT_ENTER: {
3030  rc = ocs_els_send(els, els->els_req.size, els->els_timeout_sec, ocs_els_req_cb);
3031  if (rc) {
3032  ocs_node_cb_t cbdata;
3033  cbdata.status = cbdata.ext_status = (~0);
3034  cbdata.els = els;
3035  ocs_log_err(ocs, "ocs_els_send failed: %d\n", rc);
3037  } else {
3039  }
3040  break;
3041  }
3042  default:
3043  __ocs_els_common(__func__, ctx, evt, arg);
3044  break;
3045  }
3046 
3047  return NULL;
3048 }
3049 
3050 /**
3051  * @brief Wait for the ELS request to complete.
3052  *
3053  * <h3 class="desc">Description</h3>
3054  * This is the ELS IO state that waits for the submitted ELS event to complete.
3055  * If an error completion event is received, the requested ELS is aborted.
3056  *
3057  * @param ctx Remote node SM context.
3058  * @param evt Event to process.
3059  * @param arg Per event optional argument.
3060  *
3061  * @return Returns NULL.
3062  */
3063 
3064 void *
3065 __ocs_els_wait_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3066 {
3067  ocs_io_t *io;
3069 
3070  els_sm_trace();
3071 
3072  switch(evt) {
3073  case OCS_EVT_SRRS_ELS_REQ_OK: {
3075  break;
3076  }
3077 
3080  break;
3081  }
3082 
3083  case OCS_EVT_ELS_REQ_TIMEOUT: {
3084  els_io_printf(els, "Timed out, retry (%d tries remaining)\n",
3085  els->els_retries_remaining-1);
3086  ocs_io_transition(els, __ocs_els_retry, NULL);
3087  break;
3088  }
3089 
3090  case OCS_EVT_SRRS_ELS_REQ_RJT: {
3091  ocs_node_cb_t *cbdata = arg;
3092  uint8_t reason_code = (cbdata->ext_status >> 16) & 0xFF;
3093  uint8_t reason_code_expl = (cbdata->ext_status >> 8) & 0xFF;
3094  fc_els_gen_t *buf = els->els_req.virt;
3095 
3096  /* delay and retry if reason code is Logical Busy */
3097  switch (reason_code) {
3099  els->node->els_req_cnt--;
3100  els_io_printf(els, "LS_RJT Logical Busy response, delay and retry\n");
3102  break;
3104  if (FC_ELS_CMD_FLOGI == buf->command_code && FC_EXPL_NO_ADDITIONAL == reason_code_expl) {
3105  /**
3106  * Disable BBCR by setting the BB_SC_N field in the Common Service
3107  * Parameters to zero while retrying the FLOGI. Keep the BB_SC_N field
3108  * set to zero for any additional retries while the link remains up.
3109  * This is to work around a bug in the older Brocade switch firmware
3110  * (FOS versions prior to 7.1.0). During subsequent linkup processing,
3111  * if BBCR is enabled, attempt to enable BBCR again.
3112  */
3113  fc_plogi_payload_t *flogi = els->els_req.virt;
3114 
3115  /* Zero-out the BB_SC_N field (word 1, bits 15:12) */
3117  els_io_printf(els, "BBCR disabled until the next link toggle\n");
3118  }
3119 
3120  /* For now, fall through since we are not retrying this ELS request */
3121  default:
3122  ocs_els_io_cleanup(els, evt, arg);
3123  break;
3124  }
3125  break;
3126  }
3127 
3128  case OCS_EVT_ABORT_ELS: {
3129  /* request to abort this ELS without an ABTS */
3130  els_io_printf(els, "ELS abort requested\n");
3131  els->els_retries_remaining = 0; /* Set retries to zero, we are done */
3132  io = ocs_els_abort_io(els, FALSE);
3133  if (io == NULL) {
3134  ocs_log_err(ocs, "ocs_els_send failed\n");
3136  } else {
3138  }
3139  break;
3140  }
3141 
3142  default:
3143  __ocs_els_common(__func__, ctx, evt, arg);
3144  break;
3145  }
3146  return NULL;
3147 }
3148 
3149 /**
3150  * @brief Wait for the ELS IO abort request to complete, and retry the ELS.
3151  *
3152  * <h3 class="desc">Description</h3>
3153  * This state is entered when waiting for an abort of an ELS
3154  * request to complete so the request can be retried.
3155  *
3156  * @param ctx Remote node SM context.
3157  * @param evt Event to process.
3158  * @param arg Per event optional argument.
3159  *
3160  * @return Returns NULL.
3161  */
3162 
3163 void *
3164 __ocs_els_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3165 {
3166  int32_t rc = 0;
3168 
3169  els_sm_trace();
3170 
3171  switch(evt) {
3172  case OCS_EVT_ENTER: {
3173  /* handle event for ABORT_XRI WQE
3174  * once abort is complete, retry if retries left;
3175  * don't need to wait for OCS_EVT_SRRS_ELS_REQ_* event because we got
3176  * by receiving OCS_EVT_ELS_REQ_TIMEOUT
3177  */
3178  ocs_node_cb_t node_cbdata;
3179  node_cbdata.status = node_cbdata.ext_status = (~0);
3180  node_cbdata.els = els;
3181  if (els->els_retries_remaining && --els->els_retries_remaining) {
3182  /* Use a different XRI for the retry (would like a new oxid),
3183  * so free the HAL IO (dispatch will allocate a new one). It's an
3184  * optimization to only free the HAL IO here and not the ocs_io_t;
3185  * Freeing the ocs_io_t object would require copying all the necessary
3186  * info from the old ocs_io_t object to the * new one; and allocating
3187  * a new ocs_io_t could fail.
3188  */
3189  ocs_assert(els->hio, NULL);
3190  ocs_hal_io_free(&ocs->hal, els->hio);
3191  els->hio = NULL;
3192 
3193  /* result isn't propagated up to node sm, need to decrement req cnt */
3194  ocs_assert(els->node->els_req_cnt, NULL);
3195  els->node->els_req_cnt--;
3196  rc = ocs_els_send(els, els->els_req.size, els->els_timeout_sec, ocs_els_req_cb);
3197  if (rc) {
3198  ocs_log_err(ocs, "ocs_els_send failed: %d\n", rc);
3199  ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &node_cbdata);
3200  }
3202  } else {
3203  els_io_printf(els, "Retries exhausted\n");
3204  ocs_els_io_cleanup(els, OCS_EVT_SRRS_ELS_REQ_FAIL, &node_cbdata);
3205  }
3206  break;
3207  }
3208 
3209  default:
3210  __ocs_els_common(__func__, ctx, evt, arg);
3211  break;
3212  }
3213  return NULL;
3214 }
3215 
3216 /**
3217  * @brief Wait for a retry timer to expire having received an abort request
3218  *
3219  * <h3 class="desc">Description</h3>
3220  * This state is entered when waiting for a timer event, after having received
3221  * an abort request, to avoid a race condition with the timer handler
3222  *
3223  * @param ctx Remote node SM context.
3224  * @param evt Event to process.
3225  * @param arg Per event optional argument.
3226  *
3227  * @return Returns NULL.
3228  */
3229 void *
3230 __ocs_els_aborted_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3231 {
3233 
3234  els_sm_trace();
3235 
3236  switch(evt) {
3237  case OCS_EVT_ENTER:
3238  /* mod/resched the timer for a short duration */
3239  ocs_mod_timer(&els->delay_timer, 1);
3240  break;
3241  case OCS_EVT_TIMER_EXPIRED:
3242  /* Cancel the timer, skip post node event, and free the io */
3243  node->els_req_cnt++;
3245  break;
3246  default:
3247  __ocs_els_common(__func__, ctx, evt, arg);
3248  break;
3249  }
3250  return NULL;
3251 }
3252 
3253 /**
3254  * @brief Wait for a retry timer to expire
3255  *
3256  * <h3 class="desc">Description</h3>
3257  * This state is entered when waiting for a timer event, so that
3258  * the ELS request can be retried.
3259  *
3260  * @param ctx Remote node SM context.
3261  * @param evt Event to process.
3262  * @param arg Per event optional argument.
3263  *
3264  * @return Returns NULL.
3265  */
3266 void *
3267 __ocs_els_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3268 {
3270 
3271  els_sm_trace();
3272 
3273  switch(evt) {
3274  case OCS_EVT_ENTER:
3275  ocs_setup_timer(ocs, &els->delay_timer, ocs_els_delay_timer_cb, els, 5000, false);
3276  break;
3277  case OCS_EVT_TIMER_EXPIRED:
3278  /* Retry delay timer expired, retry the ELS request, Free the HAL IO so
3279  * that a new oxid is used.
3280  */
3281  if (els->hio != NULL) {
3282  ocs_hal_io_free(&ocs->hal, els->hio);
3283  els->hio = NULL;
3284  }
3285  ocs_io_transition(els, __ocs_els_init, NULL);
3286  break;
3287  case OCS_EVT_ABORT_ELS:
3289  break;
3290  default:
3291  __ocs_els_common(__func__, ctx, evt, arg);
3292  break;
3293  }
3294  return NULL;
3295 }
3296 
3297 /**
3298  * @brief Wait for the ELS IO abort request to complete.
3299  *
3300  * <h3 class="desc">Description</h3>
3301  * This state is entered after we abort an ELS WQE and are
3302  * waiting for either the original ELS WQE request or the abort
3303  * to complete.
3304  *
3305  * @param ctx Remote node SM context.
3306  * @param evt Event to process.
3307  * @param arg Per event optional argument.
3308  *
3309  * @return Returns NULL.
3310  */
3311 
3312 void *
3313 __ocs_els_aborting(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3314 {
3316 
3317  els_sm_trace();
3318 
3319  switch(evt) {
3324  case OCS_EVT_ELS_REQ_ABORTED: {
3325  /* completion for ELS received first, transition to wait for abort cmpl */
3326  els_io_printf(els, "request cmpl evt=%s\n", ocs_sm_event_name(evt));
3328  break;
3329  }
3330  case OCS_EVT_ELS_ABORT_CMPL: {
3331  /* completion for abort was received first, transition to wait for req cmpl */
3332  els_io_printf(els, "abort cmpl evt=%s\n", ocs_sm_event_name(evt));
3334  break;
3335  }
3336  case OCS_EVT_ABORT_ELS:
3337  /* nothing we can do but wait */
3338  break;
3339 
3340  default:
3341  __ocs_els_common(__func__, ctx, evt, arg);
3342  break;
3343  }
3344  return NULL;
3345 }
3346 
3347 /**
3348  * @brief cleanup ELS after abort
3349  *
3350  * @param els ELS IO to cleanup
3351  *
3352  * @return Returns None.
3353  */
3354 
3355 static void
3357 {
3358  /* handle event for ABORT_WQE
3359  * whatever state ELS happened to be in, propagate aborted event up
3360  * to node state machine in lieu of OCS_EVT_SRRS_ELS_* event
3361  */
3362  ocs_node_cb_t cbdata;
3363  cbdata.status = cbdata.ext_status = 0;
3364  cbdata.els = els;
3365  els_io_printf(els, "Request aborted\n");
3367 }
3368 
3369 /**
3370  * @brief Wait for the ELS IO abort request to complete.
3371  *
3372  * <h3 class="desc">Description</h3>
3373  * This state is entered after we abort an ELS WQE, we received
3374  * the abort completion first and are waiting for the original
3375  * ELS WQE request to complete.
3376  *
3377  * @param ctx Remote node SM context.
3378  * @param evt Event to process.
3379  * @param arg Per event optional argument.
3380  *
3381  * @return Returns NULL.
3382  */
3383 
3384 void *
3385 __ocs_els_aborting_wait_req_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3386 {
3388 
3389  els_sm_trace();
3390 
3391  switch(evt) {
3396  case OCS_EVT_ELS_REQ_ABORTED: {
3397  /* completion for ELS that was aborted */
3398  ocs_els_abort_cleanup(els);
3399  break;
3400  }
3401  case OCS_EVT_ABORT_ELS:
3402  /* nothing we can do but wait */
3403  break;
3404 
3405  default:
3406  __ocs_els_common(__func__, ctx, evt, arg);
3407  break;
3408  }
3409  return NULL;
3410 }
3411 
3412 /**
3413  * @brief Wait for the ELS IO abort request to complete.
3414  *
3415  * <h3 class="desc">Description</h3>
3416  * This state is entered after we abort an ELS WQE, we received
3417  * the original ELS WQE request completion first and are waiting
3418  * for the abort to complete.
3419  *
3420  * @param ctx Remote node SM context.
3421  * @param evt Event to process.
3422  * @param arg Per event optional argument.
3423  *
3424  * @return Returns NULL.
3425  */
3426 
3427 void *
3428 __ocs_els_aborting_wait_abort_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
3429 {
3431 
3432  els_sm_trace();
3433 
3434  switch(evt) {
3435  case OCS_EVT_ELS_ABORT_CMPL: {
3436  ocs_els_abort_cleanup(els);
3437  break;
3438  }
3439  case OCS_EVT_ABORT_ELS:
3440  /* nothing we can do but wait */
3441  break;
3442 
3443  default:
3444  __ocs_els_common(__func__, ctx, evt, arg);
3445  break;
3446  }
3447  return NULL;
3448 }
3449 
3450 /**
3451  * @brief Generate ELS context ddump data.
3452  *
3453  * <h3 class="desc">Description</h3>
3454  * Generate the ddump data for an ELS context.
3455  *
3456  * @param textbuf Pointer to the text buffer.
3457  * @param els Pointer to the ELS context.
3458  *
3459  * @return None.
3460  */
3461 
3462 void
3463 ocs_ddump_els(ocs_textbuf_t *textbuf, ocs_io_t *els)
3464 {
3465  ocs_ddump_section(textbuf, "els", -1);
3466  ocs_ddump_value(textbuf, "req_free", "%d", els->els_req_free);
3467  ocs_ddump_value(textbuf, "evtdepth", "%d", els->els_evtdepth);
3468  ocs_ddump_value(textbuf, "pend", "%d", els->els_pend);
3469  ocs_ddump_value(textbuf, "active", "%d", els->els_active);
3470  ocs_ddump_io(textbuf, els);
3471  ocs_ddump_endsection(textbuf, "els", -1);
3472 }
3473 
3474 
3475 /**
3476  * @brief return TRUE if given ELS list is empty (while taking proper locks)
3477  *
3478  * Test if given ELS list is empty while holding the node->active_ios_lock.
3479  *
3480  * @param node pointer to node object
3481  * @param list pointer to list
3482  *
3483  * @return TRUE if els_io_list is empty
3484  */
3485 
3486 int32_t
3487 ocs_els_io_list_empty(ocs_node_t *node, ocs_list_t *list)
3488 {
3489  int empty;
3490  ocs_lock(&node->active_ios_lock);
3491  empty = ocs_list_empty(list);
3492  ocs_unlock(&node->active_ios_lock);
3493  return empty;
3494 }
3495 
3496 /**
3497  * @brief Handle CT send response completion
3498  *
3499  * Called when CT response completes, free IO
3500  *
3501  * @param hio Pointer to the HAL IO context that completed.
3502  * @param rnode Pointer to the remote node.
3503  * @param length Length of the returned payload data.
3504  * @param status Status of the completion.
3505  * @param ext_status Extended status of the completion.
3506  * @param arg Application-specific argument (generally a pointer to the ELS IO context).
3507  *
3508  * @return returns 0
3509  */
3510 static int32_t
3511 ocs_ct_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
3512 {
3513  ocs_io_t *io = arg;
3514 
3515  ocs_els_io_free(io);
3516 
3517  return 0;
3518 }
3519 
3520 /**
3521  * @brief Send CT response
3522  *
3523  * Sends a CT response frame with payload
3524  *
3525  * @param io Pointer to the IO context.
3526  * @param ox_id Originator exchange ID
3527  * @param ct_hdr Pointer to the CT IU
3528  * @param cmd_rsp_code CT response code
3529  * @param reason_code Reason code
3530  * @param reason_code_explanation Reason code explanation
3531  *
3532  * @return returns 0 for success, a negative error code value for failure.
3533  */
3534 int32_t
3535 ocs_send_ct_rsp(ocs_io_t *io, uint32_t ox_id, fcct_iu_header_t *ct_hdr, uint32_t cmd_rsp_code, uint32_t reason_code, uint32_t reason_code_explanation)
3536 {
3537  fcct_iu_header_t *rsp = io->els_rsp.virt;
3538 
3539  io->io_type = OCS_IO_TYPE_CT_RESP;
3540 
3541  *rsp = *ct_hdr;
3542 
3545  rsp->reason_code = reason_code;
3546  rsp->reason_code_explanation = reason_code_explanation;
3547 
3548  io->display_name = "ct response";
3549  io->init_task_tag = ox_id;
3550  io->wire_len += sizeof(*rsp);
3551 
3552  ocs_memset(&io->iparam, 0, sizeof(io->iparam));
3553 
3554  io->io_type = OCS_IO_TYPE_CT_RESP;
3555  io->hio_type = OCS_HAL_FC_CT_RSP;
3556  io->iparam.fc_ct_rsp.ox_id = ocs_htobe16(ox_id);
3557  io->iparam.fc_ct_rsp.r_ctl = 3;
3558  io->iparam.fc_ct_rsp.type = FC_TYPE_GS;
3559  io->iparam.fc_ct_rsp.df_ctl = 0;
3560  io->iparam.fc_ct_rsp.timeout = 5;
3561 
3562  if (ocs_scsi_io_dispatch(io, ocs_ct_acc_cb) < 0) {
3563  ocs_els_io_free(io);
3564  return -1;
3565  }
3566  return 0;
3567 }
3568 
3569 
3570 /**
3571  * @brief Handle delay retry timeout
3572  *
3573  * Callback is invoked when the delay retry timer expires.
3574  *
3575  * @param arg pointer to the ELS IO object
3576  *
3577  * @return none
3578  */
3579 static void
3581 {
3582  ocs_io_t *els = arg;
3583  ocs_node_t *node = els->node;
3584 
3585  /*
3586  * There is a potential deadlock here since is Linux executes timers
3587  * in a soft IRQ context. The lock may be aready locked by the interrupt
3588  * thread. Handle this case by attempting to take the node lock and reset the
3589  * timer if we fail to acquire the lock.
3590  *
3591  * Note: This code relies on the fact that the node lock is recursive.
3592  */
3593  if (ocs_node_lock_try(node)) {
3595  ocs_node_unlock(node);
3596  } else {
3597  ocs_setup_timer(els->ocs, &els->delay_timer, ocs_els_delay_timer_cb, els, 1, false);
3598  }
3599 }
uint32_t type_ext
Definition: ocs_fcp.h:365
#define FC_GS_NAMESERVER_GA_NXT
Definition: ocs_fcp.h:91
uint32_t payload_length
Definition: ocs_fcp.h:375
ocs_io_t * ocs_fdmi_send_rhba(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a RHBA CT request.
Definition: ocs_els.c:2246
ocs_io_t * ocs_send_scr(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send an SCR ELS command.
Definition: ocs_els.c:1196
#define std_els_state_decl(...)
Definition: ocs_els.c:2911
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
int ocs_fdmi_port_attr_fabric_wwpn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3584
int ocs_fdmi_port_attr_active_fc4type(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3608
#define OCS_ELS_RSP_LEN
Definition: ocs_els.c:118
int ocs_fdmi_hba_attr_num_ports(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3030
#define MAX_FDMI_ATTRIBUTE_SIZE
Definition: ocs_els.c:124
uint32_t port_id
Definition: ocs_fcp.h:643
static void ocs_io_transition(ocs_io_t *els, ocs_sm_function_t state, void *data)
ELS state machine transition wrapper.
Definition: ocs_els.c:144
ocs_io_t * ocs_send_pdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a PDISC ELS command.
Definition: ocs_els.c:1143
fcct_iu_header_t hdr
Definition: ocs_fcp.h:688
#define FC_ELS_CMD_RRQ
Definition: ocs_fcp.h:46
int ocs_fdmi_hba_attr_bios_ver(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3063
#define FC_GS_FDMI_RPRT
Definition: ocs_fcp.h:113
fcct_iu_header_t hdr
Definition: ocs_fcp.h:753
uint32_t type
Definition: ocs_fcp.h:393
int ocs_fdmi_hba_attr_model(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2858
#define FC_GS_NAMESERVER_RFT_ID
Definition: ocs_fcp.h:97
uint32_t reason_code
Definition: ocs_fcp.h:305
uint32_t payload_length
Definition: ocs_fcp.h:402
uint32_t command_code
Definition: ocs_fcp.h:312
uint32_t command_code
Definition: ocs_fcp.h:390
ocs_io_t * ocs_els_io_alloc(ocs_node_t *node, uint32_t reqlen, ocs_els_role_e role)
Allocate an IO structure for an ELS IO context.
Definition: ocs_els.c:197
uint64_t port_identifier
Definition: ocs_fcp.h:731
void * __ocs_els_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Initial ELS IO state.
Definition: ocs_els.c:3021
#define FC_PRLI_ACC_NVME_PAGE_LENGTH
Definition: ocs_fcp.h:447
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static void ocs_els_make_active(ocs_io_t *els)
Make ELS IO active.
Definition: ocs_els.c:410
void * __ocs_els_aborting_wait_abort_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for the ELS IO abort request to complete.
Definition: ocs_els.c:3428
#define FC_REASON_LOGICAL_BUSY
Definition: ocs_fcp.h:250
#define FC4_FEATURE_TARGET
Definition: ocs_fcp.h:637
uint32_t node_name_hi
Definition: ocs_fcp.h:326
void * __ocs_els_aborting_wait_req_cmpl(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for the ELS IO abort request to complete.
Definition: ocs_els.c:3385
static int32_t ocs_bls_send_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
Handle the BLS accept completion.
Definition: ocs_els.c:2663
uint32_t port_id
Definition: ocs_fcp.h:754
static ocs_io_t * ocs_send_fcp_prli_acc(ocs_io_t *io)
Definition: ocs_els.c:1625
int32_t ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb)
Attempt to dispatch an Abort IO.
Definition: ocs_scsi.c:1243
void ocs_ddump_els(ocs_textbuf_t *textbuf, ocs_io_t *els)
Generate ELS context ddump data.
Definition: ocs_els.c:3463
uint64_t hba_identifier
Definition: ocs_fcp.h:707
#define FC_ELS_CMD_RSCN
Definition: ocs_fcp.h:52
int ocs_fdmi_port_attr_class(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3570
#define FC_GS_TYPE_MANAGEMENT_SERVICE
Definition: ocs_fcp.h:69
int(* ocs_fdmi_port_action[])(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_els.c:98
uint64_t port_name
Definition: ocs_fcp.h:683
#define FC_PRLI_TARGET_FUNCTION
Definition: ocs_fcp.h:441
#define SLI4_FC_WCQE_STATUS_LOCAL_REJECT
Definition: sli4_fc.h:1641
static int32_t ocs_els_req_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
Handle ELS IO request completions.
Definition: ocs_els.c:520
uint32_t port_name_lo
Definition: ocs_fcp.h:343
#define FC_GS_NAMESERVER_GID_PT
Definition: ocs_fcp.h:90
#define FC_GS_TYPE_WORD(type)
Definition: ocs_fcp.h:79
uint32_t command_code
Definition: ocs_fcp.h:453
int ocs_fdmi_hba_attr_fmw_ver(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2940
void * __ocs_els_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Common event handler for the ELS IO state machine.
Definition: ocs_els.c:2980
uint32_t payload_length
Definition: ocs_fcp.h:471
void ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg)
Post event to node state machine context.
Definition: ocs_node.c:1498
#define FC_TYPE_NVME
Definition: ocs_fcp.h:57
#define FC_GS_FDMI_GHAT
Definition: ocs_fcp.h:107
#define FC_GS_FDMI_GRHL
Definition: ocs_fcp.h:106
uint64_t identifier
Definition: ocs_fcp.h:677
static int32_t ocs_bls_send_rjt_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
Handle the BLS reject completion.
Definition: ocs_els.c:2770
uint32_t command_code
Definition: ocs_fcp.h:416
ocs_io_t * ocs_send_plogi_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a PLOGI accept response.
Definition: ocs_els.c:1403
#define OCS_ELS_FDMI_RSP_LEN
Definition: ocs_els.c:120
#define FC_GS_SUBTYPE_FDMI
Definition: ocs_fcp.h:74
ocs_io_t * ocs_send_prli(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a PRLI ELS command.
Definition: ocs_els.c:909
uint32_t ox_id
Definition: ocs_fcp.h:168
uint32_t port_id
Definition: ocs_fcp.h:633
#define FC_ELS_CMD_FDISC
Definition: ocs_fcp.h:50
ocs_io_t * ocs_ns_send_rftid(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a RFTID CT request.
Definition: ocs_els.c:1942
ocs_io_t * ocs_send_ls_rjt(ocs_io_t *io, uint32_t ox_id, uint32_t reason_code, uint32_t reason_code_expl, uint32_t vendor_unique, els_cb_t cb, void *cbarg)
Send an LS_RJT ELS response.
Definition: ocs_els.c:1353
uint32_t command_code
Definition: ocs_fcp.h:338
int ocs_fdmi_port_attr_nportid(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3650
void ocs_els_post_event(ocs_io_t *els, ocs_sm_event_t evt, void *data)
ELS state machine post event wrapper.
Definition: ocs_els.c:168
int32_t ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
Attempt to dispatch a non-abort IO.
Definition: ocs_scsi.c:1162
uint32_t command_code
Definition: ocs_fcp.h:353
#define FC4_FEATURE_INITIATOR
Definition: ocs_fcp.h:638
uint32_t reason_code
Definition: ocs_fcp.h:355
#define FC_TYPE_FCP
Definition: ocs_fcp.h:56
#define SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED
Definition: sli4_fc.h:1697
int ocs_fdmi_port_attr_wwpn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3515
uint32_t reason_code_explanation
Definition: ocs_fcp.h:487
ocs_io_t * ocs_send_prli_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
Send a PRLI accept response.
Definition: ocs_els.c:1686
uint32_t page_length
Definition: ocs_fcp.h:362
int ocs_fdmi_port_attr_os_devname(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3457
uint32_t command_code
Definition: ocs_fcp.h:375
static int32_t ocs_els_send(ocs_io_t *els, uint32_t reqlen, uint32_t timeout_sec, ocs_hal_srrs_cb_t cb)
Send the ELS command.
Definition: ocs_els.c:459
ocs_io_t * ocs_send_plogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, void(*cb)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg), void *cbarg)
Format and send a PLOGI ELS command.
Definition: ocs_els.c:696
static uint32_t fc_htobe24(uint32_t x)
Definition: ocs_fcp.h:147
static ocs_io_t * ocs_bls_send_acc(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id)
Send a BLS BA_ACC response.
Definition: ocs_els.c:2599
uint32_t page_length
Definition: ocs_fcp.h:390
ocs_io_t * ocs_bls_send_rjt_hdr(ocs_io_t *io, fc_header_t *hdr)
Send a BA_RJT given the request&#39;s FC heade.
Definition: ocs_els.c:2685
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
int ocs_fdmi_hba_attr_bios_state(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3082
int ocs_fdmi_port_attr_max_frame(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3432
fcct_iu_header_t hdr
Definition: ocs_fcp.h:670
void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section start data.
Definition: ocs_ddumplib.c:90
void ocs_scsi_io_free(ocs_io_t *io)
Free a SCSI IO context.
Definition: ocs_scsi.c:317
uint32_t node_name_hi
Definition: ocs_fcp.h:422
int32_t ocs_els_io_list_empty(ocs_node_t *node, ocs_list_t *list)
return TRUE if given ELS list is empty (while taking proper locks)
Definition: ocs_els.c:3487
ocs_io_t * ocs_fdmi_send_dereg_cmd(ocs_node_t *node, uint16_t dereg_code, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a FDMI dereg CT request.
Definition: ocs_els.c:2332
uint32_t port_entry[0]
Definition: ocs_fcp.h:666
uint32_t area_id_scope
Definition: ocs_fcp.h:774
void ocs_els_io_free(ocs_io_t *els)
Free IO structure for an ELS IO context.
Definition: ocs_els.c:330
#define FC_GS_NAMESERVER_RFF_ID
Definition: ocs_fcp.h:98
uint32_t type
Definition: ocs_fcp.h:644
#define FC_ELS_CMD_LOGO
Definition: ocs_fcp.h:45
ocs_els_role_e
Definition: ocs_els.h:42
static int32_t ocs_node_first_burst_enabled(ocs_node_t *node)
Definition: ocs_els.c:1586
static int32_t ocs_node_lock_try(ocs_node_t *node)
Definition: ocs_node.h:143
#define FC_ELS_CMD_RJT
Definition: ocs_fcp.h:41
ocs_io_t * ocs_els_io_alloc_size(ocs_node_t *node, uint32_t reqlen, uint32_t rsplen, ocs_els_role_e role)
Allocate an IO structure for an ELS IO context.
Definition: ocs_els.c:218
#define SLI4_FC_WCQE_STATUS_SUCCESS
FC/FCoE Completion Status Codes.
Definition: sli4_fc.h:1638
static int32_t ocs_els_abort_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
ELS abort callback.
Definition: ocs_els.c:2799
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
uint32_t port_id
Definition: ocs_fcp.h:424
uint32_t page_length
Definition: ocs_fcp.h:402
uint32_t port_name_lo
Definition: ocs_fcp.h:421
static void ocs_els_delay_timer_cb(void *arg)
Handle delay retry timeout.
Definition: ocs_els.c:3580
int(* ocs_fdmi_hba_action[])(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_els.c:75
ocs_io_t * ocs_fdmi_send_get_cmd(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg, ocs_fdmi_get_cmd_req_info_t *req_info)
Send a GHRL CT request.
Definition: ocs_els.c:2492
#define SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT
Definition: sli4_fc.h:1680
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
uint32_t type
Definition: ocs_fcp.h:365
void * __ocs_els_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for the ELS IO abort request to complete, and retry the ELS.
Definition: ocs_els.c:3164
#define FC_PLOGI_CSP_W1_VALID_VENDOR_VER_LEVEL
Definition: ocs_fcp.h:317
uint32_t reason_code
Definition: ocs_fcp.h:487
uint32_t d_id
Definition: ocs_fcp.h:158
int ocs_fdmi_hba_attr_ct_len(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2979
void(* els_cb_t)(ocs_node_t *node, ocs_node_cb_t *cbdata, void *arg)
Definition: ocs_els.h:58
#define FC_GS_FDMI_RHBA
Definition: ocs_fcp.h:111
void * __ocs_els_wait_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for the ELS request to complete.
Definition: ocs_els.c:3065
fcct_iu_header_t hdr
Definition: ocs_fcp.h:773
#define FC_ELS_CMD_ADISC
Definition: ocs_fcp.h:51
FC header in big-endian order.
Definition: ocs_fcp.h:157
uint32_t command_code
Definition: ocs_fcp.h:402
static ocs_io_t * ocs_bls_send_rjt(ocs_io_t *io, uint32_t s_id, uint16_t ox_id, uint16_t rx_id)
Send a BLS BA_RJT response.
Definition: ocs_els.c:2709
void * __ocs_els_aborting(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for the ELS IO abort request to complete.
Definition: ocs_els.c:3313
uint32_t fc4_feature_bits
Definition: ocs_fcp.h:644
#define FC_PRLI_NVME_DISC_FUNCTION
Definition: ocs_fcp.h:444
uint32_t node_name_lo
Definition: ocs_fcp.h:327
void *(* ocs_sm_function_t)(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_sm.h:188
#define FC_ELX_LOOPBACK_DATA
Definition: ocs_fcp.h:120
fc_rscn_affected_port_id_page_t port_list[1]
Definition: ocs_fcp.h:474
uint32_t resv1
Definition: ocs_fcp.h:321
int ocs_fdmi_hba_attr_symbolic_name(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2994
#define OCS_ELS_GID_PT_RSP_LEN
Definition: ocs_els.c:122
int ocs_fdmi_hba_attr_rom_ver(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2920
int ocs_fdmi_hba_attr_drvr_ver(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2899
ocs_io_t * ocs_ns_send_gidpt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a GIDPT CT request.
Definition: ocs_els.c:2076
int ocs_fdmi_hba_attr_fabric_wwnn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3046
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:1840
void ocs_els_io_cleanup(ocs_io_t *els, ocs_sm_event_t node_evt, void *arg)
Cleanup an ELS IO.
Definition: ocs_els.c:2947
fcct_iu_header_t hdr
Definition: ocs_fcp.h:642
#define FC_PRLI_WRITE_XRDY_DISABLED
Definition: ocs_fcp.h:443
ocs_io_t * ocs_send_rscn(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, void *port_ids, uint32_t port_ids_count, els_cb_t cb, void *cbarg)
Send an RSCN ELS command.
Definition: ocs_els.c:1295
#define FC_PRLI_ESTABLISH_IMAGE_PAIR
Definition: ocs_fcp.h:431
uint32_t node_name_lo
Definition: ocs_fcp.h:423
#define els_sm_trace(...)
Definition: ocs_els.c:2923
uint32_t port_name_lo
Definition: ocs_fcp.h:325
fcct_fdmi_reg_port_list_t port_list
Definition: ocs_fcp.h:672
uint32_t service_params
Definition: ocs_fcp.h:383
#define FC_ELS_CMD_PLOGI
Definition: ocs_fcp.h:43
uint32_t response_code
Definition: ocs_fcp.h:405
uint32_t fc4_types[8]
Definition: ocs_fcp.h:634
fcct_iu_header_t hdr
Definition: ocs_fcp.h:681
uint32_t port_name_hi
Definition: ocs_fcp.h:324
int ocs_fdmi_hba_attr_vendor_info(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3016
uint32_t resv1
Definition: ocs_fcp.h:338
static void fcct_build_req_header(fcct_iu_header_t *hdr, uint16_t cmd, uint8_t type, uint8_t gs_subtype, uint16_t max_size)
Definition: ocs_fcp.h:597
static ocs_io_t * ocs_send_nvme_prli_acc(ocs_io_t *io)
Definition: ocs_els.c:1592
#define FC_ELS_CMD_FLOGI
Definition: ocs_fcp.h:44
#define FC_REASON_UNABLE_TO_PERFORM
Definition: ocs_fcp.h:252
ocs_io_t * ocs_send_ls_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a generic LS_ACC response without a payload.
Definition: ocs_els.c:1787
ocs_io_t * ocs_ns_send_rffid(ocs_node_t *node, uint8_t fc_type, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a RFFID CT request.
Definition: ocs_els.c:2005
void ocs_sm_transition(ocs_sm_ctx_t *ctx, ocs_sm_function_t state, void *data)
Transition to a new state.
Definition: ocs_sm.c:72
uint32_t class3_service_parameters[4]
Definition: ocs_fcp.h:330
ocs_io_t * ocs_fdmi_send_reg_port(ocs_node_t *node, int req_code, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a RPRT/RPA CT request.
Definition: ocs_els.c:2388
#define FC_ELS_CMD_SCR
Definition: ocs_fcp.h:53
uint32_t port_name_hi
Definition: ocs_fcp.h:420
#define FC_TYPE_GS
Definition: ocs_fcp.h:58
uint32_t payload_length
Definition: ocs_fcp.h:390
uint64_t hba_identifier
Definition: ocs_fcp.h:682
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_sport.h:67
#define OCS_ELS_FDMI_REG_LEN
Definition: ocs_els.c:119
#define FC_PRLI_READ_XRDY_DISABLED
Definition: ocs_fcp.h:442
void ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section end data.
Definition: ocs_ddumplib.c:108
int32_t ocs_send_ct_rsp(ocs_io_t *io, uint32_t ox_id, fcct_iu_header_t *ct_hdr, uint32_t cmd_rsp_code, uint32_t reason_code, uint32_t reason_code_explanation)
Send CT response.
Definition: ocs_els.c:3535
void * __ocs_els_aborted_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for a retry timer to expire having received an abort request.
Definition: ocs_els.c:3230
uint32_t class2_service_parameters[4]
Definition: ocs_fcp.h:329
static int32_t ocs_els_send_rsp(ocs_io_t *els, uint32_t rsplen)
Send the ELS response.
Definition: ocs_els.c:488
uint32_t flags
Definition: ocs_fcp.h:365
static void fcct_loopback_build_req_header(fcct_iu_header_t *hdr, uint16_t cmd, uint16_t max_size)
Definition: ocs_fcp.h:615
#define FC_REASON_LOGICAL_ERROR
Definition: ocs_fcp.h:249
int ocs_fdmi_hba_attr_wwnn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2797
uint32_t command_code
Definition: ocs_fcp.h:347
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:58
ocs_io_t * ocs_send_rrq(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send an RRQ ELS command.
Definition: ocs_els.c:1245
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_node.h:149
uint32_t resv1
Definition: ocs_fcp.h:347
uint64_t hba_identifier
Definition: ocs_fcp.h:671
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
uint64_t hba_identifier
Definition: ocs_fcp.h:719
uint32_t num_entries
Definition: ocs_fcp.h:660
ocs_io_t * ocs_send_flogi_acc(ocs_io_t *io, uint32_t ox_id, uint32_t is_fport, els_cb_t cb, void *cbarg)
Definition: ocs_els.c:1534
int ocs_fdmi_port_attr_host_name(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3478
#define FC_ELS_CMD_ACC
Definition: ocs_fcp.h:42
uint32_t page_length
Definition: ocs_fcp.h:375
uint32_t page_length
Definition: ocs_fcp.h:471
uint32_t port_name_hi
Definition: ocs_fcp.h:342
#define SLI4_FC_WCQE_STATUS_LS_RJT
Definition: sli4_fc.h:1646
#define els_io_printf(els, fmt,...)
Definition: ocs_els.c:57
uint32_t reason_code_exp
Definition: ocs_fcp.h:355
#define FC_GS_TYPE_BIT(type)
Definition: ocs_fcp.h:80
#define FC_GS_FDMI_GRPL
Definition: ocs_fcp.h:108
#define FC_PLOGI_CSP_W1_BBSCN_CLEAR_MASK
Definition: ocs_fcp.h:316
static int32_t ocs_ct_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
Handle CT send response completion.
Definition: ocs_els.c:3511
uint32_t command_code
Definition: ocs_fcp.h:471
static int32_t ocs_els_acc_cb(ocs_hal_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
Handle ELS IO accept/response completions.
Definition: ocs_els.c:629
#define OCS_FC_ELS_DEFAULT_RETRIES
Definition: ocs_fc_config.h:85
uint32_t class4_service_parameters[4]
Definition: ocs_fcp.h:331
ocs_io_t * ocs_ns_send_loopback_frame(ocs_node_t *node, void *buf, uint32_t size, void *rx_buf, uint32_t rx_buf_size, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Definition: ocs_els.c:2118
#define FC_ELS_CMD_PRLO
Definition: ocs_fcp.h:48
uint32_t vendor_version_level[4]
Definition: ocs_fcp.h:332
int ocs_fdmi_port_attr_speed(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3384
void ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
Generate IO context ddump data.
Definition: ocs_io.c:385
int ocs_fdmi_hba_attr_sn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2834
void ocs_scsi_check_pending(ocs_t *ocs)
Check for pending IOs to dispatch.
Definition: ocs_scsi.c:1032
static bool ocs_bbcr_enabled(ocs_t *ocs)
Definition: ocs_drv_fc.h:244
fcct_iu_header_t hdr
Definition: ocs_fcp.h:632
#define FC_GS_FDMI_GPAT
Definition: ocs_fcp.h:109
ocs_io_t * ocs_send_adisc_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send an ADISC accept response.
Definition: ocs_els.c:1883
uint32_t uint32_t ox_id
Definition: ocs_fcp.h:295
ocs_io_t * ocs_bls_send_acc_hdr(ocs_io_t *io, fc_header_t *hdr)
Send a BA_ACC given the request&#39;s FC header.
Definition: ocs_els.c:2573
#define FC4_FEATURE_NVME_DISC
Definition: ocs_fcp.h:639
int ocs_fdmi_hba_attr_description(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2878
ocs_io_t * ocs_send_adisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send an ADISC ELS command.
Definition: ocs_els.c:1081
#define FC_PRLI_REQUEST_EXECUTED
Definition: ocs_fcp.h:433
void * __ocs_els_delay_retry(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Wait for a retry timer to expire.
Definition: ocs_els.c:3267
ocs_io_t * ocs_send_prlo_acc(ocs_io_t *io, uint32_t ox_id, uint8_t fc_type, els_cb_t cb, void *cbarg)
Send a PRLO accept response.
Definition: ocs_els.c:1731
#define FC_GS_SUBTYPE_NAME_SERVER
Definition: ocs_fcp.h:73
uint32_t rx_id
Definition: ocs_fcp.h:168
int ocs_fdmi_port_attr_wwnn(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3497
#define FC_PRLO_REQUEST_EXECUTED
Definition: ocs_fcp.h:450
int ocs_fdmi_hba_attr_os_ver(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2959
static ocs_io_t * ocs_els_abort_io(ocs_io_t *els, int send_abts)
Abort an ELS IO.
Definition: ocs_els.c:2851
fcct_iu_header_t hdr
Definition: ocs_fcp.h:676
ocs_io_t * ocs_send_fdisc(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Format and send a FDISC ELS command.
Definition: ocs_els.c:842
static void _ocs_els_io_free(void *arg)
Free IO structure for an ELS IO context.
Definition: ocs_els.c:348
int ocs_fdmi_hba_attr_vendor_id(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3098
ocs_io_t * ocs_send_flogi(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Format and send a FLOGI ELS command.
Definition: ocs_els.c:773
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
uint32_t service_params
Definition: ocs_fcp.h:370
ocs_io_t * ocs_send_prlo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a PRLO ELS command.
Definition: ocs_els.c:968
int ocs_fdmi_port_attr_fc4type(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3315
#define FC_SCR_REG_FULL
Definition: ocs_fcp.h:461
uint32_t command_code
Definition: ocs_fcp.h:362
static void ocs_io_free(ocs_t *ocs, ocs_io_t *io)
Definition: ocs_drv_fc.h:238
uint32_t uint32_t rx_id
Definition: ocs_fcp.h:295
#define FC_ELS_CMD_PDISC
Definition: ocs_fcp.h:49
#define FC_PRLI_ACC_FCP_PAGE_LENGTH
Definition: ocs_fcp.h:446
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
int ocs_fdmi_port_attr_support_speed(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3334
int ocs_fdmi_port_attr_symbolic_name(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3532
ocs_sm_event_t
Definition: ocs_sm.h:60
ocs_io_t * ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a LOGO ELS command.
Definition: ocs_els.c:1021
uint32_t port_id
Definition: ocs_fcp.h:340
ocs_io_t * ocs_ns_send_ganxt(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg, uint32_t port_id)
Send a GA_NEXT CT request.
Definition: ocs_els.c:2187
#define node_els_trace()
Definition: ocs_els.c:51
#define FC_EXPL_NO_ADDITIONAL
Definition: ocs_fcp.h:258
#define OCS_FC_PLOGI_VENDOR_VERSION_EMLX_ID
Definition: ocs_fcp.h:318
#define FC_ELS_CMD_PRLI
Definition: ocs_fcp.h:47
uint32_t class1_service_parameters[4]
Definition: ocs_fcp.h:328
int32_t(* ocs_hal_srrs_cb_t)(ocs_hal_io_t *io, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
Definition: ocs_hal.h:1334
ocs_io_t * ocs_send_flogi_p2p_acc(ocs_io_t *io, uint32_t ox_id, uint32_t s_id, els_cb_t cb, void *cbarg)
Send an FLOGI accept response for point-to-point negotiation.
Definition: ocs_els.c:1491
static void ocs_els_abort_cleanup(ocs_io_t *els)
cleanup ELS after abort
Definition: ocs_els.c:3356
uint32_t hard_address
Definition: ocs_fcp.h:418
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_node.h:154
ocs_io_t * ocs_send_logo_acc(ocs_io_t *io, uint32_t ox_id, els_cb_t cb, void *cbarg)
Send a LOGO accept response.
Definition: ocs_els.c:1834
uint32_t domain_id_scope
Definition: ocs_fcp.h:774
void ocs_sm_disable(ocs_sm_ctx_t *ctx)
Disable further state machine processing.
Definition: ocs_sm.c:87
uint32_t high_seq_cnt
Definition: ocs_fcp.h:300
#define FC_RCTL_ELS
Definition: ocs_fcp.h:214
static void ocs_sport_unlock(ocs_sport_t *sport)
Definition: ocs_sport.h:74
uint32_t port_name[2]
Definition: ocs_fcp.h:689
#define FC_GS_TYPE_DIRECTORY_SERVICE
Definition: ocs_fcp.h:70
static ocs_io_t * ocs_io_alloc(ocs_t *ocs)
Definition: ocs_drv_fc.h:232
void ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt,...)
Generate driver dump data for a given value.
Definition: ocs_ddumplib.c:126
uint32_t command_code
Definition: ocs_fcp.h:321
uint32_t port_type
Definition: ocs_fcp.h:774
uint32_t type_ext
Definition: ocs_fcp.h:393
#define FC_PRLI_INITIATOR_FUNCTION
Definition: ocs_fcp.h:440
uint32_t function
Definition: ocs_fcp.h:453
int ocs_fdmi_hba_attr_manufacturer(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:2814
int ocs_fdmi_port_attr_port_type(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3549
uint64_t ocs_node_get_wwpn(ocs_node_t *node)
return nodes&#39; WWPN as a uint64_t
Definition: ocs_node.c:1597
uint32_t common_service_parameters[4]
Definition: ocs_fcp.h:323
uint32_t payload_length
Definition: ocs_fcp.h:362
uint32_t reason_explanation
Definition: ocs_fcp.h:305
int ocs_fdmi_port_attr_port_state(ocs_sport_t *sport, ocs_fdmi_attr_def_t *ad)
Definition: ocs_fabric.c:3626