Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  * OCS driver remote node handler. This file contains code that is shared
36  * between fabric (ocs_fabric.c) and device (ocs_device.c) nodes.
37  */
38 
39 /*!
40  * @defgroup node_common Node common support
41  * @defgroup node_alloc Node allocation
42  */
43 
44 #include "ocs.h"
45 #include "spv.h"
46 #include "ocs_els.h"
47 #include "ocs_device.h"
48 
49 #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]"
50 #define SCSI_ITT_SIZE(ocs) ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8)
51 
52 #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag
53 
54 #define scsi_io_printf(io, fmt, ...) ocs_log_debug(io->ocs, "[%s]" SCSI_IOFMT fmt, \
55  io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__)
56 
57 void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node);
58 void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node);
59 int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node);
60 int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node);
61 int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
62  void *arg_out, uint32_t arg_out_length, void *node);
65  .get_handler = ocs_mgmt_node_get,
66  .get_all_handler = ocs_mgmt_node_get_all,
67  .set_handler = ocs_mgmt_node_set,
68  .exec_handler = ocs_mgmt_node_exec,
69 };
70 
71 
72 /**
73  * @ingroup node_common
74  * @brief Device node state machine wait for all ELS's to
75  * complete
76  *
77  * Abort all ELS's for given node.
78  *
79  * @param node node for which ELS's will be aborted
80  */
81 
82 void
83 ocs_node_abort_all_els(ocs_node_t *node)
84 {
85  ocs_io_t *els;
86  ocs_io_t *els_next;
87  ocs_node_cb_t cbdata = {0};
88 
90  ocs_lock(&node->active_ios_lock);
91  ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) {
92  ocs_log_debug(node->ocs, "[%s] initiate ELS abort %s\n", node->display_name, els->display_name);
93  ocs_unlock(&node->active_ios_lock);
94  cbdata.els = els;
96  ocs_lock(&node->active_ios_lock);
97  }
98  ocs_unlock(&node->active_ios_lock);
99 }
100 
101 /**
102  * @ingroup node_common
103  * @brief Handle remote node events from HAL
104  *
105  * Handle remote node events from HAL. Essentially the HAL event is translated into
106  * a node state machine event that is posted to the affected node.
107  *
108  * @param arg pointer to ocs
109  * @param event HAL event to proceoss
110  * @param data application specific data (pointer to the affected node)
111  *
112  * @return returns 0 for success, a negative error code value for failure.
113  */
114 int32_t
115 ocs_remote_node_cb(void *arg, ocs_hal_remote_node_event_e event, void *data)
116 {
117  ocs_t *ocs = arg;
118  ocs_sm_event_t sm_event = OCS_EVT_LAST;
119  ocs_remote_node_t *rnode = data;
120  ocs_node_t *node = rnode->node;
121 
122  switch (event) {
124  sm_event = OCS_EVT_NODE_ATTACH_OK;
125  break;
126 
128  sm_event = OCS_EVT_NODE_ATTACH_FAIL;
129  break;
130 
132  sm_event = OCS_EVT_NODE_FREE_OK;
133  break;
134 
136  sm_event = OCS_EVT_NODE_FREE_FAIL;
137  break;
138 
139  default:
140  ocs_log_test(ocs, "unhandled event %#x\n", event);
141  return -1;
142  }
143 
144  /* If we're using HLM, forward the NODE_ATTACH_OK/FAIL event to all nodes in the node group */
145  if ((node->node_group != NULL) &&
146  ((sm_event == OCS_EVT_NODE_ATTACH_OK) || (sm_event == OCS_EVT_NODE_ATTACH_FAIL))) {
147  ocs_node_t *n = NULL;
148  uint8_t attach_ok = sm_event == OCS_EVT_NODE_ATTACH_OK;
149 
150  ocs_sport_lock(node->sport);
151  {
152  ocs_list_foreach(&node->sport->node_list, n) {
153  if (node == n) {
154  continue;
155  }
156  ocs_node_lock(n);
157  if ((!n->rnode.attached) && (node->node_group == n->node_group)) {
158  n->rnode.attached = attach_ok;
159  node_printf(n, "rpi[%d] deferred HLM node attach %s posted\n",
160  n->rnode.index, attach_ok ? "ok" : "fail");
161 
162  if (!n->rnode.attached) {
163  ocs_atomic_sub_return(&ocs->hal.rpi_ref[n->rnode.index].rpi_count, 1);
164 
165  if (0 == ocs_atomic_read(&ocs->hal.rpi_ref[n->rnode.index].rpi_count)) {
166  ocs_atomic_set(&ocs->hal.rpi_ref[n->rnode.index].rpi_attached, 0);
167  }
168  }
169 
170  ocs_node_post_event(n, sm_event, NULL);
171  }
172  ocs_node_unlock(n);
173  }
174  }
175 
176  ocs_sport_unlock(node->sport);
177  }
178 
179  if (sm_event == OCS_EVT_NODE_ATTACH_FAIL) {
180  ocs_atomic_sub_return(&ocs->hal.rpi_ref[node->rnode.index].rpi_count, 1);
181 
182  if (0 == ocs_atomic_read(&ocs->hal.rpi_ref[node->rnode.index].rpi_count)) {
183  ocs_atomic_set(&ocs->hal.rpi_ref[node->rnode.index].rpi_attached, 0);
184  }
185  }
186 
187  ocs_node_post_event(node, sm_event, NULL);
188 
189  return 0;
190 }
191 
192 /**
193  * @ingroup node_alloc
194  * @brief Find an FC node structure given the FC port ID
195  *
196  * @param sport the SPORT to search
197  * @param port_id FC port ID
198  *
199  * @return pointer to the object or NULL if not found
200  */
201 ocs_node_t *
202 ocs_node_find(ocs_sport_t *sport, uint32_t port_id)
203 {
204  ocs_node_t *node;
205 
206  ocs_assert(sport->lookup, NULL);
207  ocs_sport_lock(sport);
208  node = spv_get(sport->lookup, port_id);
209  ocs_sport_unlock(sport);
210  return node;
211 }
212 
213 /**
214  * @ingroup node_alloc
215  * @brief Find an FC node structure given the WWPN
216  *
217  * @param sport the SPORT to search
218  * @param wwpn the WWPN to search for (host endian)
219  *
220  * @return pointer to the object or NULL if not found
221  */
222 ocs_node_t *
223 ocs_node_find_wwpn(ocs_sport_t *sport, uint64_t wwpn)
224 {
225  ocs_node_t *node = NULL;;
226 
227  ocs_assert(sport, NULL);
228 
229  ocs_sport_lock(sport);
230  ocs_list_foreach(&sport->node_list, node) {
231  if (ocs_node_get_wwpn(node) == wwpn) {
232  ocs_sport_unlock(sport);
233  return node;
234  }
235  }
236  ocs_sport_unlock(sport);
237  return NULL;
238 }
239 
240 /**
241  * @ingroup node_alloc
242  * @brief Find an FC node structure given the WWNN
243  *
244  * @param sport the SPORT to search
245  * @param wwnn the WWNN to search for (host endian)
246  *
247  * @return pointer to the object or NULL if not found
248  */
249 ocs_node_t *
250 ocs_node_find_wwnn(ocs_sport_t *sport, uint64_t wwnn)
251 {
252  ocs_node_t *node = NULL;;
253 
254  ocs_assert(sport, NULL);
255 
256  ocs_sport_lock(sport);
257  ocs_list_foreach(&sport->node_list, node) {
258  if (ocs_node_get_wwnn(node) == wwnn) {
259  ocs_sport_unlock(sport);
260  return node;
261  }
262  }
263  ocs_sport_unlock(sport);
264  return NULL;
265 }
266 
267 
268 /**
269  * @ingroup node_alloc
270  * @brief allocate node object pool
271  *
272  * A pool of ocs_node_t objects is allocated.
273  *
274  * @param ocs pointer to driver instance context
275  * @param node_count count of nodes to allocate
276  *
277  * @return returns 0 for success, a negative error code value for failure.
278  */
279 
280 int32_t
281 ocs_node_create_pool(ocs_t *ocs, uint32_t node_count)
282 {
283  ocs_xport_t *xport = ocs->xport;
284  uint32_t i;
285  ocs_node_t *node;
286  uint32_t max_sge;
287  uint32_t num_sgl;
288  uint64_t max_xfer_size;
289  int32_t rc;
290 
291  xport->nodes_count = node_count;
292 
293  xport->nodes = ocs_malloc(ocs, node_count * sizeof(ocs_node_t *), OCS_M_ZERO | OCS_M_NOWAIT);
294  if (xport->nodes == NULL) {
295  ocs_log_err(ocs, "node ptrs allocation failed");
296  return -1;
297  }
298 
299  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_MAX_SGE, &max_sge) &&
300  0 == ocs_hal_get(&ocs->hal, OCS_HAL_N_SGL, &num_sgl)) {
301  max_xfer_size = (max_sge * (uint64_t)num_sgl);
302  } else {
303  max_xfer_size = 65536;
304  }
305 
306  ocs_list_init(&xport->nodes_free_list, ocs_node_t, link);
307 
308 
309  for (i = 0; i < node_count; i ++) {
310  node = ocs_malloc(ocs, sizeof(ocs_node_t), OCS_M_ZERO | OCS_M_NOWAIT);
311  if (node == NULL) {
312  ocs_log_err(ocs, "node allocation failed");
313  goto error;
314  }
315 
316  /* Assign any persistent field values */
317  node->instance_index = i;
318  node->max_wr_xfer_size = max_xfer_size;
319  node->rnode.indicator = UINT32_MAX;
320 
321  rc = ocs_dma_alloc(ocs, &node->sparm_dma_buf, 256, 16);
322  if (rc) {
323  ocs_free(ocs, node, sizeof(ocs_node_t));
324  ocs_log_err(ocs, "ocs_dma_alloc failed: %d\n", rc);
325  goto error;
326  }
327 
328  xport->nodes[i] = node;
329  ocs_list_add_tail(&xport->nodes_free_list, node);
330  }
331  return 0;
332 
333 error:
334  ocs_node_free_pool(ocs);
335  return -1;
336 }
337 
338 /**
339  * @ingroup node_alloc
340  * @brief free node object pool
341  *
342  * The pool of previously allocated node objects is freed
343  *
344  * @param ocs pointer to driver instance context
345  *
346  * @return none
347  */
348 
349 void
351 {
352  ocs_xport_t *xport = ocs->xport;
353  ocs_node_t *node;
354  uint32_t i;
355 
356  if (!xport->nodes)
357  return;
358 
359  ocs_device_lock(ocs);
360 
361  for (i = 0; i < xport->nodes_count; i ++) {
362  node = xport->nodes[i];
363  if (node) {
364  /* free sparam_dma_buf */
365  ocs_dma_free(ocs, &node->sparm_dma_buf);
366  ocs_free(ocs, node, sizeof(ocs_node_t));
367  }
368  xport->nodes[i] = NULL;
369  }
370 
371  ocs_free(ocs, xport->nodes, (xport->nodes_count * sizeof(ocs_node_t *)));
372 
373  ocs_device_unlock(ocs);
374 }
375 
376 /**
377  * @ingroup node_alloc
378  * @brief return pointer to node object given instance index
379  *
380  * A pointer to the node object given by an instance index is returned.
381  *
382  * @param ocs pointer to driver instance context
383  * @param index instance index
384  *
385  * @return returns pointer to node object, or NULL
386  */
387 
388 ocs_node_t *
389 ocs_node_get_instance(ocs_t *ocs, uint32_t index)
390 {
391  ocs_xport_t *xport = ocs->xport;
392  ocs_node_t *node = NULL;
393 
394  if (index >= (xport->nodes_count)) {
395  ocs_log_test(ocs, "invalid index: %d\n", index);
396  return NULL;
397  }
398  node = xport->nodes[index];
399  return node->attached ? node : NULL;
400 }
401 
402 /**
403  * @ingroup node_alloc
404  * @brief Allocate an fc node structure and add to node list
405  *
406  * @param sport pointer to the SPORT from which this node is allocated
407  * @param port_id FC port ID of new node
408  * @param init Port is an inititiator (sent a plogi)
409  * @param targ Port is potentially a target
410  *
411  * @return pointer to the object or NULL if none available
412  */
413 
414 ocs_node_t *
415 ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
416 {
417  int32_t rc;
418  ocs_node_t *node = NULL;
419  uint32_t instance_index;
420  uint64_t max_wr_xfer_size;
421  ocs_t *ocs = sport->ocs;
422  ocs_xport_t *xport = ocs->xport;
423  ocs_dma_t sparm_dma_buf;
424 
425  ocs_assert(sport, NULL);
426 
427  if (sport->shutting_down) {
428  ocs_log_debug(ocs, "node allocation when shutting down %06x", port_id);
429  return NULL;
430  }
431 
432  ocs_device_lock(ocs);
433  node = ocs_list_remove_head(&xport->nodes_free_list);
434  ocs_device_unlock(ocs);
435  if (node == NULL) {
436  ocs_log_err(ocs, "node allocation failed %06x", port_id);
437  return NULL;
438  }
439 
440  /* Save persistent values across memset zero */
441  instance_index = node->instance_index;
442  max_wr_xfer_size = node->max_wr_xfer_size;
443  sparm_dma_buf = node->sparm_dma_buf;
444 
445  ocs_memset(node, 0, sizeof(*node));
446  node->instance_index = instance_index;
447  node->max_wr_xfer_size = max_wr_xfer_size;
448  node->sparm_dma_buf = sparm_dma_buf;
449  node->rnode.indicator = UINT32_MAX;
450 
451  node->sport = sport;
452  ocs_sport_lock(sport);
453 
454  node->ocs = ocs;
455  node->init = init;
456  node->targ = targ;
457 
458  rc = ocs_hal_node_alloc(&ocs->hal, &node->rnode, port_id, sport);
459  if (rc) {
460  ocs_log_err(ocs, "ocs_hal_node_alloc failed: %d\n", rc);
461  ocs_sport_unlock(sport);
462 
463  /* Return back to pool. */
464  ocs_device_lock(ocs);
465  ocs_list_add_tail(&xport->nodes_free_list, node);
466  ocs_device_unlock(ocs);
467 
468  return NULL;
469  }
470  ocs_list_add_tail(&sport->node_list, node);
471 
472  ocs_node_lock_init(node);
473  ocs_lock_init(ocs, &node->pend_frames_lock, "pend_frames_lock[%d]", node->instance_index);
474  ocs_list_init(&node->pend_frames, ocs_hal_sequence_t, link);
475  ocs_lock_init(ocs, &node->active_ios_lock, "active_ios[%d]", node->instance_index);
476  ocs_list_init(&node->active_ios, ocs_io_t, link);
477  ocs_list_init(&node->els_io_pend_list, ocs_io_t, link);
478  ocs_list_init(&node->els_io_active_list, ocs_io_t, link);
480 
481  /* zero the service parameters */
482  ocs_memset(node->sparm_dma_buf.virt, 0, node->sparm_dma_buf.size);
483 
484  node->rnode.node = node;
485  node->sm.app = node;
486  node->evtdepth = 0;
487  node->unreg_rpi = FALSE;
488 
490 
491  spv_set(sport->lookup, port_id, node);
492  ocs_sport_unlock(sport);
493  node->mgmt_functions = &node_mgmt_functions;
494 
495  return node;
496 }
497 
498 /**
499  * @ingroup node_alloc
500  * @brief free a node structure
501  *
502  * The node structure given by 'node' is free'd
503  *
504  * @param node the node to free
505  *
506  * @return returns 0 for success, a negative error code value for failure.
507  */
508 
509 int32_t
510 ocs_node_free(ocs_node_t *node)
511 {
512  ocs_sport_t *sport;
513  ocs_t *ocs;
514  ocs_xport_t *xport;
515  ocs_hal_rtn_e rc = 0;
516  ocs_node_t *ns = NULL;
517  int post_all_free = FALSE;
518 
519  ocs_assert(node, -1);
520  ocs_assert(node->sport, -1);
521  ocs_assert(node->ocs, -1);
522  sport = node->sport;
523  ocs_assert(sport, -1);
524  ocs = node->ocs;
525  ocs_assert(ocs->xport, -1);
526  xport = ocs->xport;
527 
528  node_printf(node, "Free'd\n");
529 
530  if(node->refound) {
531  /*
532  * Save the name server node. We will send fake RSCN event at
533  * the end to handle ignored RSCN event during node deletion
534  */
535  ns = ocs_node_find(node->sport, FC_ADDR_NAMESERVER);
536  }
537 
538  /* Remove from node list */
539  ocs_sport_lock(sport);
540  ocs_list_remove(&sport->node_list, node);
541 
542  /* Free HAL resources */
543  if (OCS_HAL_RTN_IS_ERROR((rc = ocs_hal_node_free_resources(&ocs->hal, &node->rnode)))) {
544  ocs_log_test(ocs, "ocs_hal_node_free failed: %d\n", rc);
545  rc = -1;
546  }
547 
548  /* if the gidpt_delay_timer is still running, then delete it */
549  if (ocs_timer_pending(&node->gidpt_delay_timer)) {
550  ocs_del_timer(&node->gidpt_delay_timer);
551  }
552 
553  /* remove entry from sparse vector list */
554  if (sport->lookup == NULL) {
555  ocs_log_test(node->ocs, "assertion failed: sport lookup is NULL\n");
556  ocs_sport_unlock(sport);
557  return -1;
558  }
559 
560  spv_set(sport->lookup, node->rnode.fc_id, NULL);
561 
562  /*
563  * If the node_list is empty, then post a ALL_CHILD_NODES_FREE event to the sport,
564  * after the lock is released. The sport may be free'd as a result of the event.
565  */
566  if (ocs_list_empty(&sport->node_list)) {
567  post_all_free = TRUE;
568  }
569 
570  ocs_sport_unlock(sport);
571 
572  if (post_all_free) {
574  }
575 
576  node->sport = NULL;
577  node->sm.current_state = NULL;
578 
579  ocs_node_lock_free(node);
580  ocs_lock_free(&node->pend_frames_lock);
581  ocs_lock_free(&node->active_ios_lock);
582 
583  /* return to free list */
584  ocs_device_lock(ocs);
585  ocs_list_add_tail(&xport->nodes_free_list, node);
586  ocs_device_unlock(ocs);
587 
588  if(ns != NULL) {
589  /* sending fake RSCN event to name server node */
591  }
592 
593  return rc;
594 }
595 
596 /**
597  * @brief free memory resources of a node object
598  *
599  * The node object's child objects are freed after which the
600  * node object is freed.
601  *
602  * @param node pointer to a node object
603  *
604  * @return none
605  */
606 
607 void
608 ocs_node_force_free(ocs_node_t *node)
609 {
610  ocs_io_t *io;
611  ocs_io_t *next;
612  ocs_io_t *els;
613  ocs_io_t *els_next;
614 
615  /* shutdown sm processing */
616  ocs_sm_disable(&node->sm);
617  ocs_strncpy(node->prev_state_name, node->current_state_name, sizeof(node->prev_state_name));
618  ocs_strncpy(node->current_state_name, "disabled", sizeof(node->current_state_name));
619 
620  /* Let the backend cleanup if needed */
622 
623  ocs_lock(&node->active_ios_lock);
624  ocs_list_foreach_safe(&node->active_ios, io, next) {
625  ocs_list_remove(&io->node->active_ios, io);
626  ocs_io_free(node->ocs, io);
627  }
628  ocs_unlock(&node->active_ios_lock);
629 
630  /* free all pending ELS IOs */
631  ocs_lock(&node->active_ios_lock);
632  ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) {
633  /* can't call ocs_els_io_free() because lock is held; cleanup manually */
634  ocs_list_remove(&node->els_io_pend_list, els);
635 
636  ocs_dma_free(els->ocs, &els->els_rsp);
637  ocs_dma_free(els->ocs, &els->els_req);
638 
639  ocs_io_free(node->ocs, els);
640  }
641  ocs_unlock(&node->active_ios_lock);
642 
643  /* free all active ELS IOs */
644  ocs_lock(&node->active_ios_lock);
645  ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) {
646  /* can't call ocs_els_io_free() because lock is held; cleanup manually */
647  ocs_list_remove(&node->els_io_active_list, els);
648 
649  ocs_dma_free(els->ocs, &els->els_rsp);
650  ocs_dma_free(els->ocs, &els->els_req);
651 
652  ocs_io_free(node->ocs, els);
653  }
654  ocs_unlock(&node->active_ios_lock);
655 
656  /* manually purge pending frames (if any) */
658 
659  ocs_node_free(node);
660 }
661 
662 /**
663  * @ingroup node_common
664  * @brief Perform HAL call to attach a remote node
665  *
666  * @param node pointer to node object
667  *
668  * @return 0 on success, non-zero otherwise
669  */
670 int32_t
671 ocs_node_attach(ocs_node_t *node)
672 {
673  int32_t rc = 0;
674  ocs_sport_t *sport = node->sport;
675  ocs_domain_t *domain = sport->domain;
676  ocs_t *ocs = node->ocs;
677 
678  if (!domain->attached) {
679  ocs_log_test(ocs, "Warning: ocs_node_attach with unattached domain\n");
680  return -1;
681  }
682  /* Update node->wwpn/wwnn */
683 
684  ocs_node_build_eui_name(node->wwpn, sizeof(node->wwpn), ocs_node_get_wwpn(node));
685  ocs_node_build_eui_name(node->wwnn, sizeof(node->wwnn), ocs_node_get_wwnn(node));
686 
687  if (ocs->enable_hlm) {
688  ocs_node_group_init(node);
689  }
690 
691  ocs_dma_copy_in(&node->sparm_dma_buf, node->service_params+4, sizeof(node->service_params)-4);
692 
693  /* take lock to protect node->rnode.attached */
694  ocs_node_lock(node);
695  rc = ocs_hal_node_attach(&ocs->hal, &node->rnode, &node->sparm_dma_buf);
696  if (OCS_HAL_RTN_IS_ERROR(rc)) {
697  ocs_log_test(ocs, "ocs_hal_node_attach failed: %d\n", rc);
698  }
699  ocs_node_unlock(node);
700 
701  return rc;
702 }
703 
704 /**
705  * @ingroup node_common
706  * @brief Generate text for a node's fc_id
707  *
708  * The text for a nodes fc_id is generated, either as a well known name, or a 6 digit
709  * hex value.
710  *
711  * @param fc_id fc_id
712  * @param buffer text buffer
713  * @param buffer_length text buffer length in bytes
714  *
715  * @return none
716  */
717 
718 void
719 ocs_node_fcid_display(uint32_t fc_id, char *buffer, uint32_t buffer_length)
720 {
721  switch (fc_id) {
722  case FC_ADDR_FABRIC:
723  ocs_snprintf(buffer, buffer_length, "fabric");
724  break;
725  case FC_ADDR_CONTROLLER:
726  ocs_snprintf(buffer, buffer_length, "fabctl");
727  break;
728  case FC_ADDR_NAMESERVER:
729  ocs_snprintf(buffer, buffer_length, "nserve");
730  break;
731  default:
732  if (FC_ADDR_IS_DOMAIN_CTRL(fc_id)) {
733  ocs_snprintf(buffer, buffer_length, "dctl%02x",
734  FC_ADDR_GET_DOMAIN_CTRL(fc_id));
735  } else {
736  ocs_snprintf(buffer, buffer_length, "%06x", fc_id);
737  }
738  break;
739  }
740 
741 }
742 
743 /**
744  * @brief update the node's display name
745  *
746  * The node's display name is updated, sometimes needed because the sport part
747  * is updated after the node is allocated.
748  *
749  * @param node pointer to the node object
750  *
751  * @return none
752  */
753 
754 void
756 {
757  uint32_t port_id = node->rnode.fc_id;
758  ocs_sport_t *sport = node->sport;
759  char portid_display[16];
760 
761  ocs_assert(sport);
762 
763  ocs_node_fcid_display(port_id, portid_display, sizeof(portid_display));
764 
765  ocs_snprintf(node->display_name, sizeof(node->display_name), "%s.%s", sport->display_name, portid_display);
766 }
767 
768 /**
769  * @brief cleans up an XRI for the pending link services accept by aborting the
770  * XRI if required.
771  *
772  * <h3 class="desc">Description</h3>
773  * This function is called when the LS accept is not sent.
774  *
775  * @param node Node for which should be cleaned up
776  */
777 
778 void
780 {
781  ocs_t *ocs = node->ocs;
782 
783  if (node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) {
784  ocs_assert(node->ls_acc_io);
785  ocs_log_debug(ocs, "[%s] cleaning up LS_ACC oxid=0x%x\n",
786  node->display_name, node->ls_acc_oxid);
787 
788  node->ls_acc_io->hio = NULL;
789  ocs_els_io_free(node->ls_acc_io);
790  node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE;
791  node->ls_acc_io = NULL;
792  }
793 }
794 
795 static int
797 {
798  ocs_hal_sequence_t *frame = NULL;
799  fc_header_t *hdr = NULL;
800  uint8_t *buf = NULL;
801  ocs_io_t *io = NULL;
802  for (;;) {
803  frame = ocs_frame_next(&node->pend_frames, &node->pend_frames_lock);
804  if (frame == NULL) {
805  break;
806  }
807  hdr = frame->header->dma.virt;
808  if((fc_be24toh(hdr->f_ctl) & FC_FCTL_END_SEQUENCE) && (hdr->r_ctl == FC_RCTL_ELS)) {
809  buf = frame->payload->dma.virt;
810  if (buf[0] == FC_ELS_CMD_PLOGI) {
811  /* Save plogi parameters */
812  ocs_node_save_sparms(node, frame->payload->dma.virt);
816  ocs_hal_sequence_free(&node->ocs->hal, frame);
817  return 1;
818  }
819  }
820  ocs_hal_sequence_free(&node->ocs->hal, frame);
821  }
822  return 0;
823 }
824 
825 /**
826  * @ingroup node_common
827  * @brief state: shutdown a node
828  *
829  * A node is shutdown,
830  *
831  * @param ctx remote node sm context
832  * @param evt event to process
833  * @param arg per event optional argument
834  *
835  * @return returns NULL
836  *
837  * @note
838  */
839 
840 void *
841 __ocs_node_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
842 {
843  int32_t rc;
845 
846  node_sm_trace();
847 
848  switch(evt) {
849  case OCS_EVT_ENTER: {
850  ocs_node_hold_frames(node);
852  ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL);
853 
854  /* by default, we will be freeing node after we unwind */
855  node->req_free = 1;
856 
857  switch (node->shutdown_reason) {
859 restart_node_attach:
860  //sm: if shutdown reason is implicit logout / ocs_node_attach
861  /* Node shutdown b/c of PLOGI received when node already
862  * logged in. We have PLOGI service parameters, so submit
863  * node attach; we won't be freeing this node
864  */
865 
866  /* currently, only case for implicit logo is PLOGI recvd. Thus,
867  * node's ELS IO pending list won't be empty (PLOGI will be on it)
868  */
869  ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL);
870  node_printf(node, "Shutdown reason: implicit logout, re-authenticate\n");
871 
872  /* Check and allocate an RPI before re-attaching the node */
873  if (node->rnode.indicator == UINT32_MAX) {
874  if (sli_resource_alloc(&ocs->hal.sli, SLI_RSRC_FCOE_RPI,
875  &node->rnode.indicator, &node->rnode.index)) {
876  ocs_log_err(node->ocs, "FCOE_RPI allocation failure addr=%#x\n", node->rnode.fc_id);
877  }
878  }
879 
881 
882  /* Re-attach node with the same HAL node resources */
883  node->req_free = 0;
884  node->unreg_rpi = FALSE;
885 
886  rc = ocs_node_attach(node);
888  if (rc == OCS_HAL_RTN_SUCCESS_SYNC) {
890  }
891  break;
893  int8_t pend_frames_empty;
894 
895  /* cleanup any pending LS_ACC ELSs */
897  ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL);
898 
899  ocs_lock(&node->pend_frames_lock);
900  pend_frames_empty = ocs_list_empty(&node->pend_frames);
901  ocs_unlock(&node->pend_frames_lock);
902 
903  /* there are two scenarios where we want to keep this node alive:
904  * 1. there are pending frames that need to be processed or
905  * 2. we're an initiator and the remote node is a target and we
906  * need to re-authenticate
907  */
908  node_printf(node, "Shutdown: explicit logo pend=%d sport.ini=%d node.tgt=%d\n",
909  !pend_frames_empty, node->sport->enable_ini, node->targ);
910 
911  if((!pend_frames_empty) || (node->sport->enable_ini && node->targ)) {
912  uint8_t send_plogi = FALSE;
913  if (node->sport->enable_ini && node->targ) {
914  /* we're an initiator and node shutting down is a target; we'll
915  * need to re-authenticate in initial state
916  */
917  send_plogi = TRUE;
918  }
919 
920  /* Check and allocate an RPI before moving the node to initial state */
921  if (node->rnode.indicator == UINT32_MAX) {
922  if (sli_resource_alloc(&ocs->hal.sli, SLI_RSRC_FCOE_RPI,
923  &node->rnode.indicator, &node->rnode.index)) {
924  ocs_log_err(node->ocs, "FCOE_RPI allocation failure addr=%#x\n", node->rnode.fc_id);
925  }
926  }
927 
928  /* transition to __ocs_d_init (will retain HAL node resources) */
930  node->req_free = 0;
931  node->unreg_rpi = FALSE;
932 
933  /* either pending frames exist, or we're re-authenticating with PLOGI
934  * (or both); in either case, return to initial state
935  */
936  ocs_node_init_device(node, send_plogi);
937 
938  }
939  /* else: let node shutdown occur */
940  break;
941  }
943  default:
944  /* If there is a PLOGI in the pending frames restart node attach
945  * with new service paramters, and send ACC
946  */
947  if( ocs_node_process_plogi_frame(node) ) {
948  goto restart_node_attach;
949  }
950 
951  /* shutdown due to link down, node going away (xport event) or
952  * sport shutdown, purge pending and proceed to cleanup node
953  */
954 
955  /* cleanup any pending LS_ACC ELSs */
957  ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL);
958 
959  node_printf(node, "Shutdown reason: default, purge pending\n");
961  break;
962  }
963 
964  break;
965  }
966  case OCS_EVT_EXIT:
968  break;
969 
970  default:
971  __ocs_node_common(__func__, ctx, evt, arg);
972  return NULL;
973  }
974 
975  return NULL;
976 }
977 
978 /**
979  * @ingroup common_node
980  * @brief Checks to see if ELS's have been quiesced
981  *
982  * Check if ELS's have been quiesced. If so, transition to the
983  * next state in the shutdown process.
984  *
985  * @param node Node for which ELS's are checked
986  *
987  * @return Returns 1 if ELS's have been quiesced, 0 otherwise.
988  */
989 static int
991 {
992  ocs_assert(node, -1);
993 
994  /* check to see if ELS requests, completions are quiesced */
995  if ((node->els_req_cnt == 0) && (node->els_cmpl_cnt == 0) &&
996  ocs_els_io_list_empty(node, &node->els_io_active_list)) {
997  if (!node->attached) {
998  /* hal node detach already completed, proceed */
999  node_printf(node, "HAL node not attached\n");
1001  } else {
1002  /* hal node detach hasn't completed, transition and wait */
1003  node_printf(node, "HAL node still attached\n");
1005  }
1006  return 1;
1007  }
1008  return 0;
1009 }
1010 
1011 /**
1012  * @ingroup common_node
1013  * @brief Initiate node IO cleanup.
1014  *
1015  * Note: this function must be called with a non-attached node
1016  * or a node for which the node detach (ocs_hal_node_detach())
1017  * has already been initiated.
1018  *
1019  * @param node Node for which shutdown is initiated
1020  *
1021  * @return Returns None.
1022  */
1023 
1024 void
1025 ocs_node_initiate_cleanup(ocs_node_t *node)
1026 {
1027  ocs_io_t *els;
1028  ocs_io_t *els_next;
1029  ocs_t *ocs;
1030  ocs_assert(node);
1031  ocs = node->ocs;
1032 
1033  /* first cleanup ELS's that are pending (not yet active) */
1034  ocs_lock(&node->active_ios_lock);
1035  ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) {
1036 
1037  /* skip the ELS IO for which a response will be sent after shutdown */
1038  if ((node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) &&
1039  (els == node->ls_acc_io)) {
1040  continue;
1041  }
1042  /* can't call ocs_els_io_free() because lock is held; cleanup manually */
1043  node_printf(node, "Freeing pending els %s\n", els->display_name);
1044  ocs_list_remove(&node->els_io_pend_list, els);
1045 
1046  ocs_dma_free(els->ocs, &els->els_rsp);
1047  ocs_dma_free(els->ocs, &els->els_req);
1048 
1049  ocs_io_free(node->ocs, els);
1050  }
1051  ocs_unlock(&node->active_ios_lock);
1052 
1053  if (node->ls_acc_io && node->ls_acc_io->hio != NULL) {
1054  /*
1055  * if there's an IO that will result in an LS_ACC after
1056  * shutdown and its HAL IO is non-NULL, it better be an
1057  * implicit logout in vanilla sequence coalescing. In this
1058  * case, force the LS_ACC to go out on another XRI (hio)
1059  * since the previous will have been aborted by the UNREG_RPI
1060  */
1061  ocs_assert(node->shutdown_reason == OCS_NODE_SHUTDOWN_IMPLICIT_LOGO);
1062  ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI);
1063  node_printf(node, "invalidating ls_acc_io due to implicit logo\n");
1064 
1065  /* No need to abort because the unreg_rpi takes care of it, just free */
1066  ocs_hal_io_free(&ocs->hal, node->ls_acc_io->hio);
1067 
1068  /* NULL out hio to force the LS_ACC to grab a new XRI */
1069  node->ls_acc_io->hio = NULL;
1070  }
1071 
1072  /*
1073  * if ELS's have already been quiesced, will move to next state
1074  * if ELS's have not been quiesced, abort them
1075  */
1076  if (ocs_node_check_els_quiesced(node) == 0) {
1077  /*
1078  * Abort all ELS's since ELS's won't be aborted by HAL
1079  * node free.
1080  */
1081  ocs_node_abort_all_els(node);
1083  }
1084 }
1085 
1086 /**
1087  * @ingroup node_common
1088  * @brief Node state machine: Wait for all ELSs to complete.
1089  *
1090  * <h3 class="desc">Description</h3>
1091  * State waits for all ELSs to complete after aborting all
1092  * outstanding .
1093  *
1094  * @param ctx Remote node state machine context.
1095  * @param evt Event to process.
1096  * @param arg Per event optional argument.
1097  *
1098  * @return Returns NULL.
1099  */
1100 
1101 void *
1102 __ocs_node_wait_els_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1103 {
1104  uint8_t check_quiesce = FALSE;
1106 
1107  node_sm_trace();
1108 
1109  switch(evt) {
1110 
1111  case OCS_EVT_ENTER: {
1112  ocs_node_hold_frames(node);
1113  if (ocs_els_io_list_empty(node, &node->els_io_active_list)) {
1114  node_printf(node, "All ELS IOs complete\n");
1115  check_quiesce = TRUE;
1116  }
1117  break;
1118  }
1119  case OCS_EVT_EXIT:
1120  ocs_node_accept_frames(node);
1121  break;
1122 
1127  ocs_assert(node->els_req_cnt, NULL);
1128  node->els_req_cnt--;
1129  check_quiesce = TRUE;
1130  break;
1131 
1134  ocs_assert(node->els_cmpl_cnt, NULL);
1135  node->els_cmpl_cnt--;
1136  check_quiesce = TRUE;
1137  break;
1138 
1140  /* all ELS IO's complete */
1141  node_printf(node, "All ELS IOs complete\n");
1142  ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL);
1143  check_quiesce = TRUE;
1144  break;
1145 
1147  break;
1148 
1150  /* don't care about domain_attach_ok */
1151  break;
1152 
1153  /* ignore shutdown events as we're already in shutdown path */
1154  case OCS_EVT_SHUTDOWN:
1155  /* have default shutdown event take precedence */
1156  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1157  /* fall through */
1160  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1161  break;
1162  default:
1163  __ocs_node_common(__func__, ctx, evt, arg);
1164  return NULL;
1165  }
1166 
1167  if (check_quiesce) {
1169  }
1170  return NULL;
1171 }
1172 
1173 /**
1174  * @ingroup node_command
1175  * @brief Node state machine: Wait for a HAL node free event to
1176  * complete.
1177  *
1178  * <h3 class="desc">Description</h3>
1179  * State waits for the node free event to be received from the HAL.
1180  *
1181  * @param ctx Remote node state machine context.
1182  * @param evt Event to process.
1183  * @param arg Per event optional argument.
1184  *
1185  * @return Returns NULL.
1186  */
1187 
1188 void *
1189 __ocs_node_wait_node_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1190 {
1192 
1193  node_sm_trace();
1194 
1195  switch(evt) {
1196 
1197  case OCS_EVT_ENTER:
1198  ocs_node_hold_frames(node);
1199  break;
1200 
1201  case OCS_EVT_EXIT:
1202  ocs_node_accept_frames(node);
1203  break;
1204 
1205  case OCS_EVT_NODE_FREE_OK:
1206  /* node is officially no longer attached */
1207  node->attached = FALSE;
1209  break;
1210 
1213  /* As IOs and ELS IO's complete we expect to get these events */
1214  break;
1215 
1217  /* don't care about domain_attach_ok */
1218  break;
1219 
1220  /* ignore shutdown events as we're already in shutdown path */
1221  case OCS_EVT_SHUTDOWN:
1222  /* have default shutdown event take precedence */
1223  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1224  /* Fall through */
1227  node_printf(node, "%s received\n", ocs_sm_event_name(evt));
1228  break;
1229  default:
1230  __ocs_node_common(__func__, ctx, evt, arg);
1231  return NULL;
1232  }
1233 
1234  return NULL;
1235 }
1236 
1237 /**
1238  * @ingroup node_common
1239  * @brief state: initiate node shutdown
1240  *
1241  * State is entered when a node receives a shutdown event, and it's waiting
1242  * for all the active IOs and ELS IOs associated with the node to complete.
1243  *
1244  * @param ctx remote node sm context
1245  * @param evt event to process
1246  * @param arg per event optional argument
1247  *
1248  * @return returns NULL
1249  */
1250 
1251 void *
1252 __ocs_node_wait_ios_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1253 {
1255 
1256  node_sm_trace();
1257 
1258  switch(evt) {
1259  case OCS_EVT_ENTER:
1260  ocs_node_hold_frames(node);
1261  /* Fall Through */
1262 
1265  if (ocs_node_active_ios_empty(node) &&
1266  ocs_els_io_list_empty(node, &node->els_io_active_list)) {
1268  }
1269  break;
1270  }
1271 
1272  case OCS_EVT_EXIT:
1273  ocs_node_accept_frames(node);
1274  break;
1275 
1277  /* Can happen as ELS IO IO's complete */
1278  ocs_assert(node->els_req_cnt, NULL);
1279  node->els_req_cnt--;
1280  break;
1281 
1282  /* ignore shutdown events as we're already in shutdown path */
1283  case OCS_EVT_SHUTDOWN:
1284  /* have default shutdown event take precedence */
1285  node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT;
1286  /* fall through */
1289  ocs_log_debug(ocs, "[%s] %-20s\n", node->display_name, ocs_sm_event_name(evt));
1290  break;
1292  /* don't care about domain_attach_ok */
1293  break;
1294  default:
1295  __ocs_node_common(__func__, ctx, evt, arg);
1296  return NULL;
1297  }
1298 
1299  return NULL;
1300 }
1301 
1302 /**
1303  * @ingroup node_common
1304  * @brief state: common node event handler
1305  *
1306  * Handle common/shared node events
1307  *
1308  * @param funcname calling function's name
1309  * @param ctx remote node sm context
1310  * @param evt event to process
1311  * @param arg per event optional argument
1312  *
1313  * @return returns NULL
1314  */
1315 
1316 void *
1317 __ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1318 {
1319  ocs_node_t *node = NULL;
1320  ocs_t *ocs = NULL;
1321  ocs_node_cb_t *cbdata = arg;
1322  ocs_assert(ctx, NULL);
1323  ocs_assert(ctx->app, NULL);
1324  node = ctx->app;
1325  ocs_assert(node->ocs, NULL);
1326  ocs = node->ocs;
1327 
1328  switch(evt) {
1329  case OCS_EVT_ENTER:
1330  case OCS_EVT_REENTER:
1331  case OCS_EVT_EXIT:
1333  case OCS_EVT_NODE_MISSING:
1334  case OCS_EVT_FCP_CMD_RCVD:
1335  case OCS_EVT_RSCN_RCVD:
1336  break;
1337 
1338  case OCS_EVT_NODE_REFOUND:
1339  node->refound = 1;
1340  break;
1341 
1342  /* node->attached must be set appropriately for all node attach/detach events */
1344  node->attached = TRUE;
1345  break;
1346 
1347  case OCS_EVT_NODE_FREE_OK:
1349  node->attached = FALSE;
1350  break;
1351 
1352  /* handle any ELS completions that other states either didn't care about
1353  * or forgot about
1354  */
1357  ocs_assert(node->els_cmpl_cnt, NULL);
1358  node->els_cmpl_cnt--;
1359  break;
1360 
1361  /* handle any ELS request completions that other states either didn't care about
1362  * or forgot about
1363  */
1368  ocs_assert(node->els_req_cnt, NULL);
1369  node->els_req_cnt--;
1370  break;
1371 
1372  case OCS_EVT_ELS_RCVD: {
1373  fc_header_t *hdr = cbdata->header->dma.virt;
1374 
1375  /* Unsupported ELS was received, send LS_RJT, command not supported */
1376  ocs_log_debug(ocs, "[%s] (%s) ELS x%02x, LS_RJT not supported\n",
1377  node->display_name, funcname, ((uint8_t*)cbdata->payload->dma.virt)[0]);
1378  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1380  NULL, NULL);
1381  break;
1382  }
1383 
1384  case OCS_EVT_PLOGI_RCVD:
1385  case OCS_EVT_FLOGI_RCVD:
1386  case OCS_EVT_LOGO_RCVD:
1387  case OCS_EVT_PRLI_RCVD:
1388  case OCS_EVT_PRLO_RCVD:
1389  case OCS_EVT_PDISC_RCVD:
1390  case OCS_EVT_FDISC_RCVD:
1391  case OCS_EVT_ADISC_RCVD:
1392  case OCS_EVT_SCR_RCVD: {
1393  fc_header_t *hdr = cbdata->header->dma.virt;
1394  //sm: / send ELS_RJT
1395  ocs_log_debug(ocs, "[%s] (%s) %s sending ELS_RJT\n",
1396  node->display_name, funcname, ocs_sm_event_name(evt));
1397  /* if we didn't catch this in a state, send generic LS_RJT */
1398  ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id),
1400  NULL, NULL);
1401 
1402  break;
1403  }
1404  case OCS_EVT_GID_FT_RCVD:
1405  case OCS_EVT_GID_PT_RCVD:
1406  case OCS_EVT_RFT_ID_RCVD:
1407  case OCS_EVT_RFF_ID_RCVD:
1409  fc_header_t *hdr = cbdata->header->dma.virt;
1410  ocs_log_debug(ocs, "[%s] (%s) %s sending CT_REJECT\n",
1411  node->display_name, funcname, ocs_sm_event_name(evt));
1412  ocs_send_ct_rsp(cbdata->io, hdr->ox_id, cbdata->payload->dma.virt, FCCT_HDR_CMDRSP_REJECT, FCCT_COMMAND_NOT_SUPPORTED, 0);
1413  break;
1414  }
1415  case OCS_EVT_CT_LOOPBACK_RCVD: {
1416  fc_header_t *hdr = cbdata->header->dma.virt;
1417  ocs_log_debug(ocs, "[%s] (%s) %s sending CT_ACCEPT\n",
1418  node->display_name, funcname, ocs_sm_event_name(evt));
1419  ocs_send_ct_rsp(cbdata->io, hdr->ox_id, cbdata->payload->dma.virt, FCCT_HDR_CMDRSP_ACCEPT, 0, 0);
1420  break;
1421  }
1422 
1423  case OCS_EVT_ABTS_RCVD: {
1424  fc_header_t *hdr = cbdata->header->dma.virt;
1425  ocs_log_debug(ocs, "[%s] (%s) %s sending BA_ACC\n",
1426  node->display_name, funcname, ocs_sm_event_name(evt));
1427 
1428  //sm: / send BA_ACC
1429  ocs_bls_send_acc_hdr(cbdata->io, hdr);
1430  break;
1431  }
1433  int send_empty_event;
1434 
1435  ocs_lock(&node->active_ios_lock);
1436  ocs_list_remove(&node->active_ios, cbdata->io);
1437  send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->active_ios);
1438  ocs_unlock(&node->active_ios_lock);
1439  if (send_empty_event) {
1441  }
1442  break;
1443  }
1444 
1445  default:
1446  ocs_log_test(node->ocs, "[%s] %-20s %-20s not handled\n", node->display_name, funcname,
1447  ocs_sm_event_name(evt));
1448  break;
1449  }
1450  return NULL;
1451 }
1452 
1453 
1454 /**
1455  * @ingroup node_common
1456  * @brief save node service parameters
1457  *
1458  * Service parameters are copyed into the node structure
1459  *
1460  * @param node pointer to node structure
1461  * @param payload pointer to service paramters to save
1462  *
1463  * @return none
1464  */
1465 
1466 void
1467 ocs_node_save_sparms(ocs_node_t *node, void *payload)
1468 {
1469  fc_plogi_payload_t *plogi;
1470 
1471  ocs_memcpy(node->service_params, payload, sizeof(node->service_params));
1472 
1473  /* Check for vendor specific info. for Suppress response feature */
1474  plogi = (fc_plogi_payload_t *)payload;
1475  node->suppress_rsp = 0;
1476  if (((ocs_be32toh(plogi->common_service_parameters[1]) & FC_PLOGI_CSP_W1_VALID_VENDOR_VER_LEVEL)) &&
1477  (ocs_be32toh(plogi->vendor_version_level[0]) == OCS_FC_PLOGI_VENDOR_VERSION_EMLX_ID)) {
1478  node->suppress_rsp = ocs_be32toh(plogi->vendor_version_level[1]);
1479  }
1480 }
1481 
1482 /**
1483  * @ingroup node_common
1484  * @brief Post event to node state machine context
1485  *
1486  * This is used by the node state machine code to post events to the nodes. Upon
1487  * completion of the event posting, if the nesting depth is zero and we're not holding
1488  * inbound frames, then the pending frames are processed.
1489  *
1490  * @param node pointer to node
1491  * @param evt event to post
1492  * @param arg event posting argument
1493  *
1494  * @return none
1495  */
1496 
1497 void
1498 ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg)
1499 {
1500  int free_node = FALSE;
1501  ocs_assert(node);
1502 
1503  ocs_node_lock(node);
1504  node->evtdepth ++;
1505 
1506  ocs_sm_post_event(&node->sm, evt, arg);
1507 
1508  /* If our event call depth is one and we're not holding frames
1509  * then we can dispatch any pending frames. We don't want to allow
1510  * the ocs_process_node_pending() call to recurse.
1511  */
1512  if (!node->hold_frames && (node->evtdepth == 1)) {
1514  }
1515  node->evtdepth --;
1516 
1517  /* Free the node object if so requested, and we're at an event
1518  * call depth of zero
1519  */
1520  if ((node->evtdepth == 0) && node->req_free) {
1521  free_node = TRUE;
1522  }
1523  ocs_node_unlock(node);
1524 
1525  if (free_node) {
1526  ocs_node_free(node);
1527  }
1528 
1529  return;
1530 }
1531 
1532 /**
1533  * @ingroup node_common
1534  * @brief transition state of a node
1535  *
1536  * The node's state is transitioned to the requested state. Entry/Exit
1537  * events are posted as needed.
1538  *
1539  * @param node pointer to node
1540  * @param state state to transition to
1541  * @param data transition data
1542  *
1543  * @return none
1544  */
1545 
1546 void
1547 ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data)
1548 {
1549  ocs_sm_ctx_t *ctx = &node->sm;
1550 
1551  ocs_node_lock(node);
1552  if (ctx->current_state == state) {
1553  ocs_node_post_event(node, OCS_EVT_REENTER, data);
1554  } else {
1555  ocs_node_post_event(node, OCS_EVT_EXIT, data);
1556  ctx->current_state = state;
1557  ocs_node_post_event(node, OCS_EVT_ENTER, data);
1558  }
1559  ocs_node_unlock(node);
1560 }
1561 
1562 /**
1563  * @ingroup node_common
1564  * @brief build EUI formatted WWN
1565  *
1566  * Build a WWN given the somewhat transport agnostic iScsi naming specification, for FC
1567  * use the eui. format, an ascii string such as: "eui.10000000C9A19501"
1568  *
1569  * @param buffer buffer to place formatted name into
1570  * @param buffer_len length in bytes of the buffer
1571  * @param eui_name cpu endian 64 bit WWN value
1572  *
1573  * @return none
1574  */
1575 
1576 void
1577 ocs_node_build_eui_name(char *buffer, uint32_t buffer_len, uint64_t eui_name)
1578 {
1579  ocs_memset(buffer, 0, buffer_len);
1580 
1581  ocs_snprintf(buffer, buffer_len, "eui.%016" PRIX64, eui_name);
1582 }
1583 
1584 /**
1585  * @ingroup node_common
1586  * @brief return nodes' WWPN as a uint64_t
1587  *
1588  * The WWPN is computed from service parameters and returned as a uint64_t
1589  *
1590  * @param node pointer to node structure
1591  *
1592  * @return WWPN
1593  *
1594  */
1595 
1596 uint64_t
1597 ocs_node_get_wwpn(ocs_node_t *node)
1598 {
1599  fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params;
1600 
1601  return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo)));
1602 }
1603 
1604 /**
1605  * @ingroup node_common
1606  * @brief return nodes' WWNN as a uint64_t
1607  *
1608  * The WWNN is computed from service parameters and returned as a uint64_t
1609  *
1610  * @param node pointer to node structure
1611  *
1612  * @return WWNN
1613  *
1614  */
1615 
1616 uint64_t
1617 ocs_node_get_wwnn(ocs_node_t *node)
1618 {
1619  fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params;
1620 
1621  return (((uint64_t)ocs_be32toh(sp->node_name_hi) << 32ll) | (ocs_be32toh(sp->node_name_lo)));
1622 }
1623 
1624 /**
1625  * @brief Generate node ddump data
1626  *
1627  * Generates the node ddumpdata
1628  *
1629  * @param textbuf pointer to text buffer
1630  * @param node pointer to node context
1631  *
1632  * @return Returns 0 on success, or a negative value on failure.
1633  */
1634 
1635 int
1636 ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
1637 {
1638  ocs_io_t *io;
1639  ocs_io_t *els;
1640  int retval = 0;
1641 
1642  ocs_ddump_section(textbuf, "node", node->instance_index);
1643  ocs_ddump_value(textbuf, "display_name", "%s", node->display_name);
1644  ocs_ddump_value(textbuf, "current_state", "%s", node->current_state_name);
1645  ocs_ddump_value(textbuf, "prev_state", "%s", node->prev_state_name);
1646  ocs_ddump_value(textbuf, "current_evt", "%s", ocs_sm_event_name(node->current_evt));
1647  ocs_ddump_value(textbuf, "prev_evt", "%s", ocs_sm_event_name(node->prev_evt));
1648 
1649  ocs_ddump_value(textbuf, "indicator", "%#x", node->rnode.indicator);
1650  ocs_ddump_value(textbuf, "fc_id", "%#06x", node->rnode.fc_id);
1651  ocs_ddump_value(textbuf, "attached", "%d", node->rnode.attached);
1652 
1653  ocs_ddump_value(textbuf, "hold_frames", "%d", node->hold_frames);
1654  ocs_ddump_value(textbuf, "io_alloc_enabled", "%d", node->io_alloc_enabled);
1655  ocs_ddump_value(textbuf, "shutdown_reason", "%d", node->shutdown_reason);
1656  ocs_ddump_value(textbuf, "send_ls_acc", "%d", node->send_ls_acc);
1657  ocs_ddump_value(textbuf, "ls_acc_did", "%d", node->ls_acc_did);
1658  ocs_ddump_value(textbuf, "ls_acc_oxid", "%#04x", node->ls_acc_oxid);
1659  ocs_ddump_value(textbuf, "req_free", "%d", node->req_free);
1660  ocs_ddump_value(textbuf, "els_req_cnt", "%d", node->els_req_cnt);
1661  ocs_ddump_value(textbuf, "els_cmpl_cnt", "%d", node->els_cmpl_cnt);
1662 
1663  ocs_ddump_value(textbuf, "targ", "%d", node->targ);
1664  ocs_ddump_value(textbuf, "init", "%d", node->init);
1665  ocs_ddump_value(textbuf, "wwnn", "%s", node->wwnn);
1666  ocs_ddump_value(textbuf, "wwpn", "%s", node->wwpn);
1667  ocs_ddump_value(textbuf, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
1668  ocs_ddump_value(textbuf, "chained_io_count", "%d", node->chained_io_count);
1669  ocs_ddump_value(textbuf, "abort_cnt", "%d", node->abort_cnt);
1670 
1671  ocs_display_sparams(NULL, "node_sparams", 1, textbuf, node->service_params+4);
1672 
1673  ocs_lock(&node->pend_frames_lock);
1674  if (!ocs_list_empty(&node->pend_frames)) {
1675  ocs_hal_sequence_t *frame;
1676  ocs_ddump_section(textbuf, "pending_frames", 0);
1677  ocs_list_foreach(&node->pend_frames, frame) {
1678  fc_header_t *hdr;
1679  char buf[256];
1680 
1681  hdr = frame->header->dma.virt;
1682  ocs_snprintf(buf, sizeof(buf), "%02x/%06x/%02x/%02x/%04x/%04x len %ld",
1683  hdr->type, fc_be24toh(hdr->f_ctl), hdr->r_ctl, hdr->info,
1684  ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
1685  frame->payload->dma.len);
1686  ocs_ddump_value(textbuf, "frame", "%s", buf);
1687  }
1688  ocs_ddump_endsection(textbuf, "pending_frames", 0);
1689  }
1690  ocs_unlock(&node->pend_frames_lock);
1691 
1692  ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1693  ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node);
1694 
1695  ocs_lock(&node->active_ios_lock);
1696  ocs_ddump_section(textbuf, "active_ios", 0);
1697  ocs_list_foreach(&node->active_ios, io) {
1698  ocs_ddump_io(textbuf, io);
1699  }
1700  ocs_ddump_endsection(textbuf, "active_ios", 0);
1701 
1702  ocs_ddump_section(textbuf, "els_io_pend_list", 0);
1703  ocs_list_foreach(&node->els_io_pend_list, els) {
1704  ocs_ddump_els(textbuf, els);
1705  }
1706  ocs_ddump_endsection(textbuf, "els_io_pend_list", 0);
1707 
1708  ocs_ddump_section(textbuf, "els_io_active_list", 0);
1709  ocs_list_foreach(&node->els_io_active_list, els) {
1710  ocs_ddump_els(textbuf, els);
1711  }
1712  ocs_ddump_endsection(textbuf, "els_io_active_list", 0);
1713  ocs_unlock(&node->active_ios_lock);
1714 
1715  ocs_ddump_endsection(textbuf, "node", node->instance_index);
1716 
1717  return retval;
1718 }
1719 
1720 /**
1721  * @brief check ELS request completion
1722  *
1723  * Check ELS request completion event to make sure it's for the
1724  * ELS request we expect. If not, invoke given common event
1725  * handler and return an error.
1726  *
1727  * @param ctx state machine context
1728  * @param evt ELS request event
1729  * @param arg event argument
1730  * @param cmd ELS command expected
1731  * @param node_common_func common event handler to call if ELS
1732  * doesn't match
1733  * @param funcname function name that called this
1734  *
1735  * @return zero if ELS command matches, -1 otherwise
1736  */
1737 int32_t
1738 node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
1739 {
1740  ocs_node_t *node = NULL;
1741  ocs_t *ocs = NULL;
1742  ocs_node_cb_t *cbdata = arg;
1743  fc_els_gen_t *els_gen = NULL;
1744  ocs_assert(ctx, -1);
1745  node = ctx->app;
1746  ocs_assert(node, -1);
1747  ocs = node->ocs;
1748  ocs_assert(ocs, -1);
1749  cbdata = arg;
1750  ocs_assert(cbdata, -1);
1751  ocs_assert(cbdata->els, -1);
1752  els_gen = (fc_els_gen_t *)cbdata->els->els_req.virt;
1753  ocs_assert(els_gen, -1);
1754 
1755  if ((cbdata->els->hio_type != OCS_HAL_ELS_REQ) || (els_gen->command_code != cmd)) {
1756  if (cbdata->els->hio_type != OCS_HAL_ELS_REQ) {
1757  ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received type=%d\n",
1758  node->display_name, funcname, cmd, cbdata->els->hio_type);
1759  } else {
1760  ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received cmd=x%x\n",
1761  node->display_name, funcname, cmd, els_gen->command_code);
1762  }
1763  /* send event to common handler */
1764  node_common_func(funcname, ctx, evt, arg);
1765  return -1;
1766  }
1767  return 0;
1768 }
1769 
1770 /**
1771  * @brief check CT request completion
1772  *
1773  * Check ELS CY request completion event to make sure it's for the
1774  * nameserver request we expect. If not, invoke given common
1775  * event handler and return an error.
1776  *
1777  * @param ctx state machine context
1778  * @param evt ELS request event
1779  * @param arg event argument
1780  * @param cmd nameserver command expected
1781  * @param node_common_func common event handler to call if
1782  * nameserver cmd doesn't match
1783  * @param funcname function name that called this
1784  *
1785  * @return zero if CT command matches, -1 otherwise
1786  */
1787 int32_t
1788 node_check_ct_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint32_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
1789 {
1790  ocs_node_t *node = NULL;
1791  ocs_t *ocs = NULL;
1792  ocs_node_cb_t *cbdata = arg;
1793  fcct_iu_header_t *fcct = NULL;
1794  ocs_assert(ctx, -1);
1795  node = ctx->app;
1796  ocs_assert(node, -1);
1797  ocs = node->ocs;
1798  ocs_assert(ocs, -1);
1799  cbdata = arg;
1800  ocs_assert(cbdata, -1);
1801  ocs_assert(cbdata->els, -1);
1802  fcct = (fcct_iu_header_t *)cbdata->els->els_req.virt;
1803  ocs_assert(fcct, -1);
1804 
1805  if ((cbdata->els->hio_type != OCS_HAL_FC_CT) || fcct->cmd_rsp_code != ocs_htobe16(cmd)) {
1806  if (cbdata->els->hio_type != OCS_HAL_FC_CT) {
1807  ocs_log_debug(node->ocs, "[%s] %-20s expecting CT cmd=x%x received type=%d\n",
1808  node->display_name, funcname, cmd, cbdata->els->hio_type);
1809  } else {
1810  ocs_log_debug(node->ocs, "[%s] %-20s expecting CT cmd=x%x received cmd=x%x\n",
1811  node->display_name, funcname, cmd, fcct->cmd_rsp_code);
1812  }
1813  /* send event to common handler */
1814  node_common_func(funcname, ctx, evt, arg);
1815  return -1;
1816  }
1817  return 0;
1818 }
1819 
1820 int32_t
1821 node_check_ct_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1822 {
1823  ocs_node_cb_t *cbdata = arg;
1824  fcct_iu_header_t *ct_resp = (fcct_iu_header_t *)cbdata->els->els_rsp.virt;
1825  int32_t rc;
1826  ocs_assert(ct_resp, -1);
1827 
1828  if (cbdata->els->hio_type != OCS_HAL_FC_CT) {
1829  rc = -1;
1830  } else {
1831  rc = ocs_be16toh(ct_resp->cmd_rsp_code);
1832  }
1833 
1834  return rc;
1835 }
1836 void
1837 ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *object)
1838 {
1839  ocs_io_t *io;
1840  ocs_node_t *node = (ocs_node_t *)object;
1841 
1842  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1843 
1844  /* Readonly values */
1845  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
1846  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
1847  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fc_id");
1848  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached");
1849  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "hold_frames");
1850  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "shutting_down");
1851  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "req_free");
1852  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id");
1853  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id_in_use");
1854  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "abort_cnt");
1855  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "targ");
1856  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init");
1857  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwpn");
1858  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwnn");
1859  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "pend_frames");
1860  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "chained_io_count");
1861 
1862  /* Actions */
1863  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume");
1864 
1865  ocs_lock(&node->active_ios_lock);
1866  ocs_list_foreach(&node->active_ios, io) {
1867  if ((io->mgmt_functions) && (io->mgmt_functions->get_list_handler)) {
1868  io->mgmt_functions->get_list_handler(textbuf, io);
1869  }
1870  }
1871  ocs_unlock(&node->active_ios_lock);
1872 
1873  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1874 }
1875 
1876 int
1877 ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
1878 {
1879  ocs_io_t *io;
1880  ocs_node_t *node = (ocs_node_t *)object;
1881  char qualifier[80];
1882  int retval = -1;
1883 
1884  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1885 
1886  ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index);
1887 
1888  /* If it doesn't start with my qualifier I don't know what to do with it */
1889  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1890  char *unqualified_name = name + strlen(qualifier) +1;
1891 
1892  /* See if it's a value I can supply */
1893  if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1894  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1895  retval = 0;
1896  } else if (ocs_strcmp(unqualified_name, "indicator") == 0) {
1897  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator);
1898  retval = 0;
1899  } else if (ocs_strcmp(unqualified_name, "fc_id") == 0) {
1900  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id);
1901  retval = 0;
1902  } else if (ocs_strcmp(unqualified_name, "attached") == 0) {
1903  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached);
1904  retval = 0;
1905  } else if (ocs_strcmp(unqualified_name, "hold_frames") == 0) {
1906  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames);
1907  retval = 0;
1908  } else if (ocs_strcmp(unqualified_name, "io_alloc_enabled") == 0) {
1909  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled);
1910  retval = 0;
1911  } else if (ocs_strcmp(unqualified_name, "req_free") == 0) {
1912  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free);
1913  retval = 0;
1914  } else if (ocs_strcmp(unqualified_name, "ls_acc_oxid") == 0) {
1915  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid);
1916  retval = 0;
1917  } else if (ocs_strcmp(unqualified_name, "ls_acc_did") == 0) {
1918  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did);
1919  retval = 0;
1920  } else if (ocs_strcmp(unqualified_name, "abort_cnt") == 0) {
1921  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt);
1922  retval = 0;
1923  } else if (ocs_strcmp(unqualified_name, "targ") == 0) {
1924  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ", node->targ);
1925  retval = 0;
1926  } else if (ocs_strcmp(unqualified_name, "init") == 0) {
1927  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init", node->init);
1928  retval = 0;
1929  } else if (ocs_strcmp(unqualified_name, "wwpn") == 0) {
1930  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn);
1931  retval = 0;
1932  } else if (ocs_strcmp(unqualified_name, "wwnn") == 0) {
1933  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn);
1934  retval = 0;
1935  } else if (ocs_strcmp(unqualified_name, "current_state") == 0) {
1936  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name);
1937  retval = 0;
1938  } else if (ocs_strcmp(unqualified_name, "login_state") == 0) {
1939  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
1940  retval = 0;
1941  } else if (ocs_strcmp(unqualified_name, "pend_frames") == 0) {
1942  ocs_hal_sequence_t *frame;
1943  ocs_lock(&node->pend_frames_lock);
1944  ocs_list_foreach(&node->pend_frames, frame) {
1945  fc_header_t *hdr;
1946  char buf[128];
1947 
1948  hdr = frame->header->dma.virt;
1949  ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %ld", hdr->r_ctl,
1950  ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
1951  frame->payload->dma.len);
1952  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf);
1953  }
1954  ocs_unlock(&node->pend_frames_lock);
1955  retval = 0;
1956  } else if (ocs_strcmp(unqualified_name, "chained_io_count") == 0) {
1957  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count);
1958  retval = 0;
1959  } else {
1960  /* If I didn't know the value of this status pass the request to each of my children */
1961  ocs_lock(&node->active_ios_lock);
1962  ocs_list_foreach(&node->active_ios, io) {
1963  if ((io->mgmt_functions) && (io->mgmt_functions->get_handler)) {
1964  retval = io->mgmt_functions->get_handler(textbuf, qualifier, name, io);
1965  }
1966 
1967  if (retval == 0) {
1968  break;
1969  }
1970  }
1971  ocs_unlock(&node->active_ios_lock);
1972  }
1973  }
1974 
1975  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
1976 
1977  return retval;
1978 }
1979 
1980 void
1981 ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *object)
1982 {
1983  ocs_io_t *io;
1984  ocs_node_t *node = (ocs_node_t *)object;
1985  ocs_hal_sequence_t *frame;
1986 
1987  ocs_mgmt_start_section(textbuf, "node", node->instance_index);
1988 
1989  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name);
1990  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator);
1991  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id);
1992  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached);
1993  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames);
1994  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled);
1995  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free);
1996  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid);
1997  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did);
1998  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt);
1999  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ", node->targ);
2000  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init", node->init);
2001  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn);
2002  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn);
2003 
2004  ocs_lock(&node->pend_frames_lock);
2005  ocs_list_foreach(&node->pend_frames, frame) {
2006  fc_header_t *hdr;
2007  char buf[128];
2008 
2009  hdr = frame->header->dma.virt;
2010  ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %ld", hdr->r_ctl,
2011  ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id),
2012  frame->payload->dma.len);
2013  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf);
2014  }
2015  ocs_unlock(&node->pend_frames_lock);
2016 
2017  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count);
2018  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume");
2019  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name);
2020  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0);
2021 
2022  ocs_lock(&node->active_ios_lock);
2023  ocs_list_foreach(&node->active_ios, io) {
2024  if ((io->mgmt_functions) && (io->mgmt_functions->get_all_handler)) {
2025  io->mgmt_functions->get_all_handler(textbuf,io);
2026  }
2027  }
2028  ocs_unlock(&node->active_ios_lock);
2029 
2030  ocs_mgmt_end_section(textbuf, "node", node->instance_index);
2031 }
2032 
2033 int
2034 ocs_mgmt_node_set(char *parent, char *name, char *value, void *object)
2035 {
2036  ocs_io_t *io;
2037  ocs_node_t *node = (ocs_node_t *)object;
2038  char qualifier[80];
2039  int retval = -1;
2040 
2041  ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index);
2042 
2043  /* If it doesn't start with my qualifier I don't know what to do with it */
2044  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
2045 
2046  ocs_lock(&node->active_ios_lock);
2047  ocs_list_foreach(&node->active_ios, io) {
2048  if ((io->mgmt_functions) && (io->mgmt_functions->set_handler)) {
2049  retval = io->mgmt_functions->set_handler(qualifier, name, value, io);
2050  }
2051 
2052  if (retval == 0) {
2053  break;
2054  }
2055 
2056  }
2057  ocs_unlock(&node->active_ios_lock);
2058 
2059  }
2060 
2061  return retval;
2062 }
2063 
2064 int
2065 ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
2066  void *arg_out, uint32_t arg_out_length, void *object)
2067 {
2068  ocs_io_t *io;
2069  ocs_node_t *node = (ocs_node_t *)object;
2070  char qualifier[80];
2071  int retval = -1;
2072 
2073  ocs_snprintf(qualifier, sizeof(qualifier), "%s.node%d", parent, node->instance_index);
2074 
2075  /* If it doesn't start with my qualifier I don't know what to do with it */
2076  if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
2077  char *unqualified_name = action + strlen(qualifier) +1;
2078 
2079  if (ocs_strcmp(unqualified_name, "resume") == 0) {
2080  ocs_node_post_event(node, OCS_EVT_RESUME, NULL);
2081  }
2082 
2083  {
2084  /* If I didn't know how to do this action pass the request to each of my children */
2085  ocs_lock(&node->active_ios_lock);
2086  ocs_list_foreach(&node->active_ios, io) {
2087  if ((io->mgmt_functions) && (io->mgmt_functions->exec_handler)) {
2088  retval = io->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
2089  arg_out, arg_out_length, io);
2090  }
2091 
2092  if (retval == 0) {
2093  break;
2094  }
2095 
2096  }
2097  ocs_unlock(&node->active_ios_lock);
2098  }
2099  }
2100 
2101  return retval;
2102 }
2103 
2104 
2105 
2106 /**
2107  * @brief Return TRUE if active ios list is empty
2108  *
2109  * Test if node->active_ios list is empty while holding the node->active_ios_lock.
2110  *
2111  * @param node pointer to node object
2112  *
2113  * @return TRUE if node active ios list is empty
2114  */
2115 
2116 int
2117 ocs_node_active_ios_empty(ocs_node_t *node)
2118 {
2119  int empty;
2120 
2121  ocs_lock(&node->active_ios_lock);
2122  empty = ocs_list_empty(&node->active_ios);
2123  ocs_unlock(&node->active_ios_lock);
2124  return empty;
2125 }
2126 
2127 /**
2128  * @brief Pause a node
2129  *
2130  * The node is placed in the __ocs_node_paused state after saving the state
2131  * to return to
2132  *
2133  * @param node Pointer to node object
2134  * @param state State to resume to
2135  *
2136  * @return none
2137  */
2138 
2139 void
2140 ocs_node_pause(ocs_node_t *node, ocs_sm_function_t state)
2141 {
2142  node->nodedb_state = state;
2144 }
2145 
2146 /**
2147  * @brief Paused node state
2148  *
2149  * This state is entered when a state is "paused". When resumed, the node
2150  * is transitioned to a previously saved state (node->ndoedb_state)
2151  *
2152  * @param ctx Remote node state machine context.
2153  * @param evt Event to process.
2154  * @param arg Per event optional argument.
2155  *
2156  * @return returns NULL
2157  */
2158 
2159 void *
2160 __ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
2161 {
2163 
2164  node_sm_trace();
2165 
2166  switch(evt) {
2167  case OCS_EVT_ENTER:
2168  node_printf(node, "Paused\n");
2169  break;
2170 
2171  case OCS_EVT_RESUME: {
2172  ocs_sm_function_t pf = node->nodedb_state;
2173 
2174  node->nodedb_state = NULL;
2175  ocs_node_transition(node, pf, NULL);
2176  break;
2177  }
2178 
2180  break;
2181 
2182  case OCS_EVT_SHUTDOWN:
2183  node->req_free = 1;
2184  break;
2185 
2186  default:
2187  __ocs_node_common(__func__, ctx, evt, arg);
2188  break;
2189  }
2190  return NULL;
2191 }
2192 
2193 /**
2194  * @brief Resume a paused state
2195  *
2196  * Posts a resume event to the paused node.
2197  *
2198  * @param node Pointer to node object
2199  *
2200  * @return returns 0 for success, a negative error code value for failure.
2201  */
2202 
2203 int32_t
2204 ocs_node_resume(ocs_node_t *node)
2205 {
2206  ocs_assert(node != NULL, -1);
2207 
2208  ocs_node_post_event(node, OCS_EVT_RESUME, NULL);
2209 
2210  return 0;
2211 }
2212 
2213 /**
2214  * @ingroup node_common
2215  * @brief Dispatch a ELS frame.
2216  *
2217  * <h3 class="desc">Description</h3>
2218  * An ELS frame is dispatched to the \c node state machine.
2219  * RQ Pair mode: this function is always called with a NULL hal
2220  * io.
2221  *
2222  * @param node Node that originated the frame.
2223  * @param seq header/payload sequence buffers
2224  *
2225  * @return Returns 0 if frame processed and RX buffers cleaned
2226  * up appropriately, -1 if frame not handled and RX buffers need
2227  * to be returned.
2228  */
2229 
2230 int32_t
2232 {
2233  struct {
2234  uint32_t cmd;
2235  ocs_sm_event_t evt;
2236  uint32_t payload_size;
2237  } els_cmd_list[] = {
2249  };
2250  ocs_t *ocs = node->ocs;
2251  ocs_node_cb_t cbdata;
2252  fc_header_t *hdr = seq->header->dma.virt;
2253  uint8_t *buf = seq->payload->dma.virt;
2255  uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD;
2256  uint32_t i;
2257 
2258  ocs_memset(&cbdata, 0, sizeof(cbdata));
2259  cbdata.header = seq->header;
2260  cbdata.payload = seq->payload;
2261 
2262  /* find a matching event for the ELS command */
2263  for (i = 0; i < ARRAY_SIZE(els_cmd_list); i ++) {
2264  if (els_cmd_list[i].cmd == buf[0]) {
2265  evt = els_cmd_list[i].evt;
2266  payload_size = els_cmd_list[i].payload_size;
2267  if (els_cmd_list[i].cmd == FC_ELS_CMD_PRLI) {
2268  fc_prli_payload_t *prli = seq->payload->dma.virt;
2269  /*
2270  * FC-NVME spec Section 6.3.3 defines different
2271  * format for PRLI ACC
2272  */
2273  if (prli->type == FC_TYPE_NVME)
2274  payload_size = sizeof(fc_nvme_prli_payload_t);
2275  }
2276  break;
2277  }
2278  }
2279 
2280  switch(evt) {
2281  case OCS_EVT_FLOGI_RCVD:
2282  ocs_display_sparams(node->display_name, "flogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2283  break;
2284  case OCS_EVT_FDISC_RCVD:
2285  ocs_display_sparams(node->display_name, "fdisc rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2286  break;
2287  case OCS_EVT_PLOGI_RCVD: {
2289 
2290  ocs_log_info(ocs, "ELS PLOGI (0x%x) REQ rcvd; OX_ID: %04x, S_ID: %06x, WWPN: %016" PRIX64"\n",
2291  FC_ELS_CMD_PLOGI, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->s_id),
2292  (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo))));
2293  ocs_display_sparams(node->display_name, "plogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4);
2294  break;
2295  }
2296  case OCS_EVT_PRLI_RCVD:
2297  ocs_log_info(ocs, "ELS PRLI (0x%x) REQ rcvd; OX_ID: %04x, S_ID: %06x, WWPN: %016" PRIX64"\n",
2298  FC_ELS_CMD_PRLI, ocs_be16toh(hdr->ox_id), fc_be24toh(hdr->s_id), ocs_node_get_wwpn(node));
2299  break;
2300  default:
2301  break;
2302  }
2303 
2304  /* Update FCP control requests */
2305  if (ocs->xport) {
2306  ocs->xport->fc_stats.stats.fcp_stats.control_requests++;
2307  }
2308 
2309  cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER);
2310 
2311  if (cbdata.io != NULL) {
2312  cbdata.io->hal_priv = seq->hal_priv;
2313  /* if we're here, sequence initiative has been transferred */
2314  cbdata.io->seq_init = 1;
2315 
2316  ocs_node_post_event(node, evt, &cbdata);
2317  } else {
2318  node_printf(node, "failure to allocate SCSI IO for ELS s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2319  fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2320  }
2321  ocs_hal_sequence_free(&ocs->hal, seq);
2322  return 0;
2323 }
2324 
2325 /**
2326  * @ingroup node_common
2327  * @brief Dispatch a ABTS frame (RQ Pair/sequence coalescing).
2328  *
2329  * <h3 class="desc">Description</h3>
2330  * An ABTS frame is dispatched to the node state machine. This
2331  * function is used for both RQ Pair and sequence coalescing.
2332  *
2333  * @param node Node that originated the frame.
2334  * @param seq Header/payload sequence buffers
2335  *
2336  * @return Returns 0 if frame processed and RX buffers cleaned
2337  * up appropriately, -1 if frame not handled and RX buffers need
2338  * to be returned.
2339  */
2340 
2341 int32_t
2343 {
2344  ocs_t *ocs = node->ocs;
2345  ocs_xport_t *xport = ocs->xport;
2346  fc_header_t *hdr = seq->header->dma.virt;
2347  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
2348  uint16_t rx_id = ocs_be16toh(hdr->rx_id);
2349  ocs_node_cb_t cbdata;
2350  int32_t rc = 0;
2351 
2352  node->abort_cnt++;
2353 
2354  /*
2355  * Check to see if the IO we want to abort is active, if it not active,
2356  * then we can send the BA_ACC using the send frame option
2357  */
2358  if (ocs_io_find_tgt_io(ocs, node, ox_id, rx_id) == NULL) {
2359  uint32_t send_frame_capable;
2360 
2361  ocs_log_debug(ocs, "IO not found (ox_id %04x)\n", ox_id);
2362 
2363  /* If we have SEND_FRAME capability, then use it to send BA_ACC */
2364  rc = ocs_hal_get(&ocs->hal, OCS_HAL_SEND_FRAME_CAPABLE, &send_frame_capable);
2365  if ((rc == 0) && send_frame_capable) {
2366  rc = ocs_sframe_send_bls_acc(node, seq);
2367  if (rc) {
2368  ocs_log_test(ocs, "ocs_bls_acc_send_frame failed\n");
2369  }
2370  return rc;
2371  }
2372  /* continuing */
2373  }
2374 
2375  ocs_memset(&cbdata, 0, sizeof(cbdata));
2376  cbdata.header = seq->header;
2377  cbdata.payload = seq->payload;
2378 
2379  cbdata.io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_RESPONDER);
2380  if (cbdata.io != NULL) {
2381  cbdata.io->hal_priv = seq->hal_priv;
2382  /* If we got this far, SIT=1 */
2383  cbdata.io->seq_init = 1;
2384 
2385  /* fill out generic fields */
2386  cbdata.io->ocs = ocs;
2387  cbdata.io->node = node;
2388  cbdata.io->cmd_tgt = TRUE;
2389 
2390  ocs_node_post_event(node, OCS_EVT_ABTS_RCVD, &cbdata);
2391  } else {
2392  ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
2393  node_printf(node, "SCSI IO allocation failed for ABTS received s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2394  fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2395  }
2396 
2397  /* ABTS processed, return RX buffer to the chip */
2398  ocs_hal_sequence_free(&ocs->hal, seq);
2399  return 0;
2400 }
2401 
2402 /**
2403  * @ingroup node_common
2404  * @brief Dispatch a CT frame.
2405  *
2406  * <h3 class="desc">Description</h3>
2407  * A CT frame is dispatched to the \c node state machine.
2408  * RQ Pair mode: this function is always called with a NULL hal
2409  * io.
2410  *
2411  * @param node Node that originated the frame.
2412  * @param seq header/payload sequence buffers
2413  *
2414  * @return Returns 0 if frame processed and RX buffers cleaned
2415  * up appropriately, -1 if frame not handled and RX buffers need
2416  * to be returned.
2417  */
2418 
2419 int32_t
2421 {
2422  ocs_t *ocs = node->ocs;
2423  fc_header_t *hdr = seq->header->dma.virt;
2424  fcct_iu_header_t *iu = seq->payload->dma.virt;
2426  uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD;
2427  uint16_t gscmd = ocs_be16toh(iu->cmd_rsp_code);
2428  uint16_t gstype = iu->gs_type;
2429  ocs_node_cb_t cbdata;
2430  uint32_t i;
2431  struct {
2432  uint32_t cmd;
2433  ocs_sm_event_t evt;
2434  uint32_t payload_size;
2435  } ct_cmd_list[] = {
2452  };
2453 
2454  ocs_memset(&cbdata, 0, sizeof(cbdata));
2455  cbdata.header = seq->header;
2456  cbdata.payload = seq->payload;
2457 
2458  if (gstype == FC_GS_TYPE_LOOPBACK) {
2459  ocs_io_t *els_loopback_io = NULL;
2460  uint16_t ox_id = ocs_be16toh(hdr->ox_id);
2461 
2462  els_loopback_io = ocs_io_find_init_els_io(ocs, node, ox_id);
2463  if (els_loopback_io && els_loopback_io->loopback_evt_data.is_loopback_frame) {
2464  cbdata.els = els_loopback_io;
2465 
2466  if (els_loopback_io->loopback_evt_data.loopback_rx_data) {
2467  ocs_memcpy(els_loopback_io->loopback_evt_data.loopback_rx_data,
2468  ((uint8_t *)seq->payload->dma.virt + sizeof(fcct_iu_header_t)),
2469  els_loopback_io->loopback_evt_data.loopback_rx_data_len);
2470  }
2471  ocs_sem_v(&els_loopback_io->loopback_evt_data.wait_io_sem);
2473  } else {
2474  ocs_log_err(node->ocs, "Unable to find loopback frame\n");
2476  }
2477  } else {
2478  /* find a matching event for the ELS/GS command */
2479  for (i = 0; i < ARRAY_SIZE(ct_cmd_list); i ++) {
2480  if (ct_cmd_list[i].cmd == gscmd) {
2481  evt = ct_cmd_list[i].evt;
2482  payload_size = ct_cmd_list[i].payload_size;
2483  break;
2484  }
2485  }
2486  }
2487 
2488  /* Update FCP control requests */
2489  if (ocs->xport) {
2490  ocs->xport->fc_stats.stats.fcp_stats.control_requests++;
2491  }
2492  /* Allocate an IO and send a reject */
2493  cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER);
2494  if (cbdata.io == NULL) {
2495  node_printf(node, "GS IO failed for s_id %06x d_id %06x ox_id %04x rx_id %04x\n",
2496  fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id),
2497  ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id));
2498  return -1;
2499  }
2500  cbdata.io->hal_priv = seq->hal_priv;
2501  ocs_node_post_event(node, evt, &cbdata);
2502 
2503  ocs_hal_sequence_free(&ocs->hal, seq);
2504  return 0;
2505 }
2506 
2507 /**
2508  * @ingroup node_common
2509  * @brief Dispatch a FCP command frame when the node is not ready.
2510  *
2511  * <h3 class="desc">Description</h3>
2512  * A frame is dispatched to the \c node state machine.
2513  *
2514  * @param node Node that originated the frame.
2515  * @param seq header/payload sequence buffers
2516  *
2517  * @return Returns 0 if frame processed and RX buffers cleaned
2518  * up appropriately, -1 if frame not handled.
2519  */
2520 
2521 int32_t
2523 {
2524  ocs_node_cb_t cbdata;
2525  ocs_t *ocs = node->ocs;
2526 
2527  ocs_memset(&cbdata, 0, sizeof(cbdata));
2528  cbdata.header = seq->header;
2529  cbdata.payload = seq->payload;
2530  ocs_node_post_event(node, OCS_EVT_FCP_CMD_RCVD, &cbdata);
2531  ocs_hal_sequence_free(&ocs->hal, seq);
2532  return 0;
2533 }
2534 
2535 /**
2536  * @ingroup node_common
2537  * @brief Stub handler for non-ABTS BLS frames
2538  *
2539  * <h3 class="desc">Description</h3>
2540  * Log message and drop. Customer can plumb it to their back-end as needed
2541  *
2542  * @param node Node that originated the frame.
2543  * @param seq header/payload sequence buffers
2544  *
2545  * @return Returns 0
2546  */
2547 
2548 int32_t
2550 {
2551  fc_header_t *hdr = seq->header->dma.virt;
2552 
2553  node_printf(node, "Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n",
2554  ocs_htobe32(((uint32_t *)hdr)[0]),
2555  ocs_htobe32(((uint32_t *)hdr)[1]),
2556  ocs_htobe32(((uint32_t *)hdr)[2]),
2557  ocs_htobe32(((uint32_t *)hdr)[3]),
2558  ocs_htobe32(((uint32_t *)hdr)[4]),
2559  ocs_htobe32(((uint32_t *)hdr)[5]));
2560 
2561  return -1;
2562 }
2563 
2564 int32_t ocs_node_is_remote_node(ocs_remote_node_t *rnode)
2565 {
2566  if (rnode) {
2567  if (rnode->fc_id != FC_ADDR_FABRIC &&
2568  rnode->fc_id != FC_ADDR_NAMESERVER &&
2569  rnode->fc_id != FC_ADDR_CONTROLLER &&
2570  !FC_ADDR_IS_DOMAIN_CTRL(rnode->fc_id)) {
2571  return TRUE;
2572  }
2573  }
2574 
2575  return FALSE;
2576 }
2577 
2578 /**
2579  * @ingroup node_common
2580  * @brief Return node suppress_rsp state
2581  *
2582  * @return true if suppress response is enabled for the node, otherwise false
2583  */
2584 inline int32_t ocs_node_suppress_resp(ocs_remote_node_t *rnode)
2585 {
2586  ocs_node_t *node = (ocs_node_t *)rnode->node;
2587  ocs_assert(node!=NULL, false);
2588 
2589  return node->suppress_rsp;
2590 }
int32_t ocs_node_suppress_resp(ocs_remote_node_t *rnode)
Return node suppress_rsp state.
Definition: ocs_node.c:2584
#define FC_GS_NAMESERVER_GA_NXT
Definition: ocs_fcp.h:91
uint32_t r_ctl
Definition: ocs_fcp.h:158
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
#define FC_GS_NAMESERVER_GFF_ID
Definition: ocs_fcp.h:88
#define FC_ELS_CMD_RRQ
Definition: ocs_fcp.h:46
ocs_hal_rtn_e ocs_hal_node_alloc(ocs_hal_t *hal, ocs_remote_node_t *rnode, uint32_t fc_addr, ocs_sli_port_t *sport)
Allocate a remote node object.
Definition: ocs_hal.c:3389
int32_t ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hal_sequence_t *seq)
Stub handler for non-ABTS BLS frames.
Definition: ocs_node.c:2549
#define FC_GS_NAMESERVER_RCS_ID
Definition: ocs_fcp.h:96
#define FC_GS_NAMESERVER_RFT_ID
Definition: ocs_fcp.h:97
int32_t ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ABTS frame (RQ Pair/sequence coalescing).
Definition: ocs_node.c:2342
void * __ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Paused node state.
Definition: ocs_node.c:2160
uint32_t command_code
Definition: ocs_fcp.h:312
#define FC_GS_NAMESERVER_RPA
Definition: ocs_fcp.h:93
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
ocs_hal_rq_buffer_t * header
Definition: ocs_hal.h:790
#define FC_ADDR_CONTROLLER
Definition: ocs_fcp.h:62
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static void ocs_node_lock_free(ocs_node_t *node)
Definition: ocs_node.h:137
int32_t ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a CT frame.
Definition: ocs_node.c:2420
void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt,...)
Generate a property with an integer value in a management XML document.
uint32_t node_name_hi
Definition: ocs_fcp.h:326
void ocs_ddump_els(ocs_textbuf_t *textbuf, ocs_io_t *els)
Generate ELS context ddump data.
Definition: ocs_els.c:3463
#define FC_ELS_CMD_RSCN
Definition: ocs_fcp.h:52
#define FCCT_HDR_CMDRSP_ACCEPT
Definition: ocs_fcp.h:594
int32_t node_check_ct_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint32_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
check CT request completion
Definition: ocs_node.c:1788
uint32_t cmd_rsp_code
Definition: ocs_fcp.h:485
int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node)
Definition: ocs_node.c:2034
void ocs_node_force_free(ocs_node_t *node)
free memory resources of a node object
Definition: ocs_node.c:608
#define FCCT_COMMAND_NOT_SUPPORTED
Definition: ocs_fcp.h:503
#define FC_GS_NAMESERVER_GID_PT
Definition: ocs_fcp.h:90
void * __ocs_node_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: shutdown a node
Definition: ocs_node.c:841
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
int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node)
Definition: ocs_node.c:1877
#define FC_TYPE_NVME
Definition: ocs_fcp.h:57
void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node)
Definition: ocs_node.c:1837
static void ocs_node_accept_frames(ocs_node_t *node)
accept frames
Definition: ocs_node.h:120
uint32_t ox_id
Definition: ocs_fcp.h:168
ocs_hal_rtn_e
Definition: ocs_hal.h:159
void ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data)
transition state of a node
Definition: ocs_node.c:1547
#define FC_ELS_CMD_FDISC
Definition: ocs_fcp.h:50
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
int32_t sli_resource_alloc(sli4_t *sli4, sli4_resource_e rtype, uint32_t *rid, uint32_t *index)
Allocate SLI Port resources.
Definition: sli4.c:5851
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
#define MGMT_MODE_EX
Definition: ocs_mgmt.h:49
#define FC_GS_NAMESERVER_RPN_ID
Definition: ocs_fcp.h:94
static void ocs_device_lock(ocs_t *ocs)
Definition: ocs_drv_fc.h:218
const char * name
Definition: ocs_ddump.h:54
int32_t ocs_node_attach(ocs_node_t *node)
Perform HAL call to attach a remote node.
Definition: ocs_node.c:671
int32_t ocs_node_purge_pending(ocs_node_t *node)
Purge node&#39;s pending (queued) frames.
Definition: ocs_unsol.c:431
ocs_hal_sequence_t * ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock)
Return next FC frame on node-&gt;pend_frames list.
Definition: ocs_unsol.c:1248
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
ocs_io_t * ocs_io_find_init_els_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id)
Find an els I/O given it&#39;s node and ox_id.
Definition: ocs_io.c:339
ocs_node_t * ocs_node_find(ocs_sport_t *sport, uint32_t port_id)
Find an FC node structure given the FC port ID.
Definition: ocs_node.c:202
void ocs_node_fcid_display(uint32_t fc_id, char *buffer, uint32_t buffer_length)
Generate text for a node&#39;s fc_id.
Definition: ocs_node.c:719
#define FC_GS_NAMESERVER_RHBA
Definition: ocs_fcp.h:92
ocs_node_t * ocs_node_get_instance(ocs_t *ocs, uint32_t index)
return pointer to node object given instance index
Definition: ocs_node.c:389
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
int ocs_node_active_ios_empty(ocs_node_t *node)
Return TRUE if active ios list is empty.
Definition: ocs_node.c:2117
void *(* ocs_node_common_func_t)(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Definition: ocs_node.h:197
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
void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the beginning of a numbered section in a management XML document.
int const char const char void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int access, const char *name, const int value)
Generate a property with a boolean value in a management XML document.
void ocs_node_init_device(ocs_node_t *node, int send_plogi)
Initialize device node.
Definition: ocs_device.c:781
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
#define FC_ELS_CMD_LOGO
Definition: ocs_fcp.h:45
#define FC_FCTL_END_SEQUENCE
Definition: ocs_fcp.h:230
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
#define FC_GS_NAMESERVER_GID_FT
Definition: ocs_fcp.h:89
static ocs_hal_rtn_e ocs_hal_sequence_free(ocs_hal_t *hal, ocs_hal_sequence_t *seq)
Definition: ocs_hal.h:1512
#define FC_REASON_COMMAND_NOT_SUPPORTED
Definition: ocs_fcp.h:253
void ocs_node_send_ls_io_cleanup(ocs_node_t *node)
cleans up an XRI for the pending link services accept by aborting the XRI if required.
Definition: ocs_node.c:779
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
uint32_t gs_type
Definition: ocs_fcp.h:481
#define FC_GS_NAMESERVER_RSNN_NN
Definition: ocs_fcp.h:99
uint32_t type
Definition: ocs_fcp.h:365
#define FC_PLOGI_CSP_W1_VALID_VENDOR_VER_LEVEL
Definition: ocs_fcp.h:317
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
static void ocs_node_lock_init(ocs_node_t *node)
Definition: ocs_node.h:131
uint32_t d_id
Definition: ocs_fcp.h:158
#define FC_ELS_CMD_ADISC
Definition: ocs_fcp.h:51
FC header in big-endian order.
Definition: ocs_fcp.h:157
#define FC_GS_NAMESERVER_GFPN_ID
Definition: ocs_fcp.h:87
void ocs_node_update_display_name(ocs_node_t *node)
update the node&#39;s display name
Definition: ocs_node.c:755
static ocs_mgmt_functions_t node_mgmt_functions
Definition: ocs_node.c:63
#define FC_ADDR_IS_DOMAIN_CTRL(x)
Definition: ocs_fcp.h:63
int32_t ocs_node_free(ocs_node_t *node)
free a node structure
Definition: ocs_node.c:510
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 ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
int32_t ocs_node_create_pool(ocs_t *ocs, uint32_t node_count)
allocate node object pool
Definition: ocs_node.c:281
static void ocs_device_unlock(ocs_t *ocs)
Definition: ocs_drv_fc.h:223
int32_t ocs_remote_node_cb(void *arg, ocs_hal_remote_node_event_e event, void *data)
Handle remote node events from HAL.
Definition: ocs_node.c:115
#define FC_GS_NAMESERVER_RNN_ID
Definition: ocs_fcp.h:95
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:1840
ocs_node_t * ocs_node_find_wwnn(ocs_sport_t *sport, uint64_t wwnn)
Find an FC node structure given the WWNN.
Definition: ocs_node.c:250
uint32_t port_name_lo
Definition: ocs_fcp.h:325
ocs_hal_rtn_e ocs_hal_node_attach(ocs_hal_t *hal, ocs_remote_node_t *rnode, ocs_dma_t *sparms)
Update a remote node object with the remote port&#39;s service parameters.
Definition: ocs_hal.c:3433
#define FC_ELS_CMD_PLOGI
Definition: ocs_fcp.h:43
void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the indexed end of a section in a management XML document.
void ocs_node_initiate_cleanup(ocs_node_t *node)
Initiate node IO cleanup.
Definition: ocs_node.c:1025
int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length, void *node)
Definition: ocs_node.c:2065
uint32_t port_name_hi
Definition: ocs_fcp.h:324
#define FC_ELS_CMD_FLOGI
Definition: ocs_fcp.h:44
#define FC_REASON_UNABLE_TO_PERFORM
Definition: ocs_fcp.h:252
ocs_node_t * ocs_node_find_wwpn(ocs_sport_t *sport, uint64_t wwpn)
Find an FC node structure given the WWPN.
Definition: ocs_node.c:223
#define FC_ELS_CMD_SCR
Definition: ocs_fcp.h:53
uint64_t ocs_node_get_wwnn(ocs_node_t *node)
return nodes&#39; WWNN as a uint64_t
Definition: ocs_node.c:1617
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_sport.h:67
ocs_node_t * ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ)
Allocate an fc node structure and add to node list.
Definition: ocs_node.c:415
void ocs_node_pause(ocs_node_t *node, ocs_sm_function_t state)
Pause a node.
Definition: ocs_node.c:2140
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
ocs_mgmt_get_list_handler get_list_handler
Definition: ocs_mgmt.h:83
void ocs_node_build_eui_name(char *buffer, uint32_t buffer_len, uint64_t eui_name)
build EUI formatted WWN
Definition: ocs_node.c:1577
int32_t ocs_node_recv_els_frame(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a ELS frame.
Definition: ocs_node.c:2231
#define MAX_ACC_REJECT_PAYLOAD
Definition: ocs_fcp.h:922
void * __ocs_node_wait_ios_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: initiate node shutdown
Definition: ocs_node.c:1252
uint32_t f_ctl
Definition: ocs_fcp.h:163
ocs_hal_rtn_e ocs_hal_node_free_resources(ocs_hal_t *hal, ocs_remote_node_t *rnode)
Free a remote node resource.
Definition: ocs_hal.c:3516
void ocs_scsi_io_alloc_enable(ocs_node_t *node)
Enable IO allocation.
Definition: ocs_scsi.c:122
#define MGMT_MODE_RD
Definition: ocs_mgmt.h:47
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
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_node.h:149
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
int32_t node_check_ct_resp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Definition: ocs_node.c:1821
#define OCS_HAL_RTN_IS_ERROR(e)
Definition: ocs_hal.h:171
int32_t ocs_node_resume(ocs_node_t *node)
Resume a paused state.
Definition: ocs_node.c:2204
#define FC_ADDR_GET_DOMAIN_CTRL(x)
Definition: ocs_fcp.h:64
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
int32_t ocs_sframe_send_bls_acc(ocs_node_t *node, ocs_hal_sequence_t *seq)
Send BA_ACC using sent frame.
Definition: ocs_unsol.c:1450
void ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
Definition: ocs_ramd.c:6580
void * spv_get(sparse_vector_t sv, uint32_t idx)
Return the sparse vector cell value.
Definition: spv.c:279
#define FCCT_HDR_CMDRSP_REJECT
Definition: ocs_fcp.h:595
#define FC_ELS_CMD_PRLO
Definition: ocs_fcp.h:48
#define FC_ADDR_NAMESERVER
Definition: ocs_fcp.h:65
uint32_t vendor_version_level[4]
Definition: ocs_fcp.h:332
int32_t ocs_node_is_remote_node(ocs_remote_node_t *rnode)
Definition: ocs_node.c:2564
int ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
Generate node ddump data.
Definition: ocs_node.c:1636
void ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
Generate IO context ddump data.
Definition: ocs_io.c:385
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
Definition: ocs_hal.h:784
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
void * __ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
state: common node event handler
Definition: ocs_node.c:1317
#define std_node_state_decl(...)
Definition: ocs_node.h:62
static void ocs_node_hold_frames(ocs_node_t *node)
hold frames in pending frame list
Definition: ocs_node.h:102
uint32_t rx_id
Definition: ocs_fcp.h:168
#define node_sm_trace()
Definition: ocs_node.h:42
ocs_dma_t dma
Definition: ocs_hal.h:328
static int ocs_node_check_els_quiesced(ocs_node_t *node)
Checks to see if ELS&#39;s have been quiesced.
Definition: ocs_node.c:990
uint32_t info
Definition: ocs_fcp.h:158
void * __ocs_d_device_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Device is ready.
Definition: ocs_device.c:1728
uint32_t type
Definition: ocs_fcp.h:163
int32_t ocs_process_node_pending(ocs_node_t *node)
Process pending frames queued to the given node.
Definition: ocs_unsol.c:278
#define node_printf(node, fmt,...)
Definition: ocs_node.h:48
void * __ocs_d_wait_node_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for a node attach when found by a remote node.
Definition: ocs_device.c:1364
void ocs_node_free_pool(ocs_t *ocs)
free node object pool
Definition: ocs_node.c:350
ocs_hal_remote_node_event_e
Definition: ocs_hal.h:685
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
static int ocs_node_process_plogi_frame(ocs_node_t *node)
Definition: ocs_node.c:796
#define FC_GS_TYPE_LOOPBACK
Definition: ocs_fcp.h:71
static void ocs_io_free(ocs_t *ocs, ocs_io_t *io)
Definition: ocs_drv_fc.h:238
void * __ocs_node_wait_node_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Node state machine: Wait for a HAL node free event to complete.
Definition: ocs_node.c:1189
#define FC_ELS_CMD_PDISC
Definition: ocs_fcp.h:49
void * __ocs_node_wait_els_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Node state machine: Wait for all ELSs to complete.
Definition: ocs_node.c:1102
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
static void ocs_scsi_notify_node_force_free(ocs_node_t *node)
Notification from base driver that node is in force-free path.
ocs_sm_event_t
Definition: ocs_sm.h:60
#define FC_GS_NAMESERVER_RSPN_ID
Definition: ocs_fcp.h:100
void ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int access, const char *name, const char *value)
Generate a property with a string value in a management XML document.
ocs_io_t * ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id)
Find an I/O given it&#39;s node and ox_id.
Definition: ocs_io.c:316
ocs_io_t * ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
Allocate a SCSI IO context.
Definition: ocs_scsi.c:192
uint32_t s_id
Definition: ocs_fcp.h:161
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
void ocs_node_abort_all_els(ocs_node_t *node)
Device node state machine wait for all ELS&#39;s to complete.
Definition: ocs_node.c:83
int32_t node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname)
check ELS request completion
Definition: ocs_node.c:1738
#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
#define FC_GS_NAMESERVER_GPN_ID
Definition: ocs_fcp.h:85
int32_t ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hal_sequence_t *seq)
Dispatch a FCP command frame when the node is not ready.
Definition: ocs_node.c:2522
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_node.h:154
int ocs_node_group_init(ocs_node_t *node)
Initialize a node for high login mode.
Definition: ocs_sport.c:2042
#define FC_GS_NAMESERVER_GNN_ID
Definition: ocs_fcp.h:86
void ocs_sm_disable(ocs_sm_ctx_t *ctx)
Disable further state machine processing.
Definition: ocs_sm.c:87
#define FC_RCTL_ELS
Definition: ocs_fcp.h:214
static void ocs_sport_unlock(ocs_sport_t *sport)
Definition: ocs_sport.h:74
void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int access, const char *name)
Generate a property, with no value, in a management XML document.
void ocs_node_save_sparms(ocs_node_t *node, void *payload)
save node service parameters
Definition: ocs_node.c:1467
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
ocs_hal_rq_buffer_t * payload
Definition: ocs_hal.h:791
uint64_t ocs_node_get_wwpn(ocs_node_t *node)
return nodes&#39; WWPN as a uint64_t
Definition: ocs_node.c:1597
void spv_set(sparse_vector_t sv, uint32_t idx, void *value)
Set the sparse vector cell value.
Definition: spv.c:258
uint32_t common_service_parameters[4]
Definition: ocs_fcp.h:323
Sparse Vector API.
void ocs_scsi_ini_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
Definition: ocs_ini_stub.c:266
void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node)
Definition: ocs_node.c:1981
#define FC_ADDR_FABRIC
Definition: ocs_fcp.h:61
void ocs_send_ls_acc_after_attach(ocs_io_t *io, fc_header_t *hdr, ocs_node_send_ls_acc_e ls)
Save the OX_ID for sending LS_ACC sometime later.
Definition: ocs_device.c:475