Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_sport.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  * Details SLI port (sport) functions.
36  */
37 
38 
39 #include "ocs.h"
40 #include "ocs_fabric.h"
41 #include "ocs_els.h"
42 #include "ocs_device.h"
43 
44 static void ocs_vport_update_spec(ocs_sport_t *sport);
45 static void ocs_vport_link_down(ocs_sport_t *sport);
46 static void _ocs_sport_free(void *arg);
47 
48 void ocs_mgmt_sport_list(ocs_textbuf_t *textbuf, void *sport);
49 void ocs_mgmt_sport_get_all(ocs_textbuf_t *textbuf, void *sport);
50 int ocs_mgmt_sport_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *sport);
51 int ocs_mgmt_sport_set(char *parent, char *name, char *value, void *sport);
52 int ocs_mgmt_sport_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
53  void *arg_out, uint32_t arg_out_length, void *object);
54 static int32_t
55 ocs_sport_fdmi_get_cmd(ocs_sport_t *sport, ocs_sport_exec_arg_t *sport_exec_args,
56  uint32_t fdmi_cmd_code);
57 static void
58 ocs_fdmi_get_cmd_cb(ocs_node_t *node, ocs_node_cb_t *node_data,
59  void *cb_data);
62  .get_handler = ocs_mgmt_sport_get,
63  .get_all_handler = ocs_mgmt_sport_get_all,
64  .set_handler = ocs_mgmt_sport_set,
65  .exec_handler = ocs_mgmt_sport_exec,
66 };
67 
68 /*!
69 @defgroup sport_sm SLI Port (sport) State Machine: States
70 */
71 
72 /**
73  * @ingroup sport_sm
74  * @brief SLI port HAL callback.
75  *
76  * @par Description
77  * This function is called in response to a HAL sport event. This code resolves
78  * the reference to the sport object, and posts the corresponding event.
79  *
80  * @param arg Pointer to the OCS context.
81  * @param event HAL sport event.
82  * @param data Application-specific event (pointer to the sport).
83  *
84  * @return Returns 0 on success, or a negative error value on failure.
85  */
86 
87 int32_t
88 ocs_port_cb(void *arg, ocs_hal_port_event_e event, void *data)
89 {
90  ocs_t *ocs = arg;
91  ocs_sli_port_t *sport = data;
92 
93  switch (event) {
95  ocs_log_debug(ocs, "OCS_HAL_PORT_ALLOC_OK\n");
96  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_ALLOC_OK, NULL);
97  break;
99  ocs_log_debug(ocs, "OCS_HAL_PORT_ALLOC_FAIL\n");
100  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_ALLOC_FAIL, NULL);
101  break;
103  ocs_log_debug(ocs, "OCS_HAL_PORT_ATTACH_OK\n");
104  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_ATTACH_OK, NULL);
105  break;
107  ocs_log_debug(ocs, "OCS_HAL_PORT_ATTACH_FAIL\n");
108  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_ATTACH_FAIL, NULL);
109  break;
111  ocs_log_debug(ocs, "OCS_HAL_PORT_FREE_OK\n");
112  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_FREE_OK, NULL);
113  break;
115  ocs_log_debug(ocs, "OCS_HAL_PORT_FREE_FAIL\n");
116  ocs_sm_post_event(&sport->sm, OCS_EVT_SPORT_FREE_FAIL, NULL);
117  break;
118  default:
119  ocs_log_test(ocs, "unknown event %#x\n", event);
120  }
121 
122  return 0;
123 }
124 
125 /**
126  * @ingroup sport_sm
127  * @brief Allocate a SLI port object.
128  *
129  * @par Description
130  * A sport object is allocated and associated with the domain. Various
131  * structure members are initialized.
132  *
133  * @param domain Pointer to the domain structure.
134  * @param wwpn World wide port name in host endian.
135  * @param wwnn World wide node name in host endian.
136  * @param fc_id Port ID of sport may be specified, use UINT32_MAX to fabric choose
137  * @param enable_ini Enables initiator capability on this port using a non-zero value.
138  * @param enable_tgt Enables target capability on this port using a non-zero value.
139  *
140  * @return Pointer to an ocs_sport_t object; or NULL.
141  */
142 
143 ocs_sport_t *
144 ocs_sport_alloc(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id, uint8_t enable_ini, uint8_t enable_tgt)
145 {
146  ocs_sport_t *sport;
147 
148  if (domain->ocs->ctrlmask & OCS_CTRLMASK_INHIBIT_INITIATOR) {
149  enable_ini = 0;
150  }
151 
152  /* Return a failure if this sport has already been allocated */
153  if (wwpn != 0) {
154  sport = ocs_sport_find_wwn(domain, wwnn, wwpn);
155  if (sport != NULL) {
156  ocs_log_test(domain->ocs, "Failed: SPORT %016" PRIx64 " %016" PRIx64 " already allocated\n",
157  wwnn, wwpn);
158  return NULL;
159  }
160  }
161 
162  sport = ocs_malloc(domain->ocs, sizeof(*sport), OCS_M_NOWAIT | OCS_M_ZERO);
163  if (sport) {
164  sport->ocs = domain->ocs;
165  ocs_snprintf(sport->display_name, sizeof(sport->display_name), "------");
166  sport->domain = domain;
167  sport->lookup = spv_new(domain->ocs);
168  sport->instance_index = domain->sport_instance_count++;
169  ocs_sport_lock_init(sport);
170  ocs_list_init(&sport->node_list, ocs_node_t, link);
171  sport->sm.app = sport;
172  sport->enable_ini = enable_ini;
173  sport->enable_tgt = enable_tgt;
174  sport->enable_rscn = (sport->enable_ini || (sport->enable_tgt && enable_target_rscn(sport->ocs)));
175  sport->unreg_rpi_all = FALSE;
176 
177  /* Copy service parameters from domain */
178  ocs_memcpy(sport->service_params, domain->service_params, sizeof(fc_plogi_payload_t));
179 
180  /* Update requested fc_id */
181  sport->fc_id = fc_id;
182 
183  /* Update the sport's service parameters for the new wwn's */
184  sport->wwpn = wwpn;
185  sport->wwnn = wwnn;
186  ocs_snprintf(sport->wwnn_str, sizeof(sport->wwnn_str), "%016" PRIX64, wwnn);
187 
188  /* Initialize node group list */
189  ocs_lock_init(sport->ocs, &sport->node_group_lock, "node_group_lock[%d]", sport->instance_index);
190  ocs_list_init(&sport->node_group_dir_list, ocs_node_group_dir_t, link);
191 
192  /* if this is the "first" sport of the domain, then make it the "phys" sport */
193  ocs_domain_lock(domain);
194  if (ocs_list_empty(&domain->sport_list)) {
195  domain->sport = sport;
196  }
197 
198  ocs_list_add_tail(&domain->sport_list, sport);
199  ocs_domain_unlock(domain);
200 
201  sport->mgmt_functions = &sport_mgmt_functions;
202  ocs_ref_init(&sport->ref, _ocs_sport_free, sport);
203 
204  ocs_log_debug(domain->ocs, "[%s] allocate sport\n", sport->display_name);
205  }
206  return sport;
207 }
208 
209 /**
210  * @ingroup sport_sm
211  * @brief Free a SLI port object.
212  *
213  * @par Description
214  * The sport object is freed.
215  *
216  * @param sport Pointer to the SLI port object.
217  *
218  * @return None.
219  */
220 
221 static void
222 _ocs_sport_free(void *arg)
223 {
224  ocs_sport_t *sport = (ocs_sport_t *)arg;
225  ocs_domain_t *domain;
226  ocs_node_group_dir_t *node_group_dir;
227  ocs_node_group_dir_t *node_group_dir_next;
228  int post_all_free = FALSE;
229 
230  if (sport) {
231  domain = sport->domain;
232  ocs_log_debug(domain->ocs, "[%s] free sport\n", sport->display_name);
233  ocs_domain_lock(domain);
234  ocs_list_remove(&domain->sport_list, sport);
235  ocs_sport_lock(sport);
236  spv_del(sport->lookup);
237  sport->lookup = NULL;
238 
239  ocs_lock(&domain->lookup_lock);
240  /* Remove the sport from the domain's sparse vector lookup table */
241  spv_set(domain->lookup, sport->fc_id, NULL);
242  ocs_unlock(&domain->lookup_lock);
243 
244  /* if this is the physical sport, then clear it out of the domain */
245  if (sport == domain->sport) {
246  domain->sport = NULL;
247  }
248 
249  /*
250  * If the domain's sport_list is empty, then post the ALL_NODES_FREE event to the domain,
251  * after the lock is released. The domain may be free'd as a result of the event.
252  */
253  if (ocs_list_empty(&domain->sport_list)) {
254  post_all_free = TRUE;
255  }
256 
257  /* Free any node group directories */
258  ocs_lock(&sport->node_group_lock);
259  ocs_list_foreach_safe(&sport->node_group_dir_list, node_group_dir, node_group_dir_next) {
260  ocs_unlock(&sport->node_group_lock);
261  ocs_node_group_dir_free(node_group_dir);
262  ocs_lock(&sport->node_group_lock);
263  }
264  ocs_unlock(&sport->node_group_lock);
265  ocs_sport_unlock(sport);
266  ocs_domain_unlock(domain);
267 
268  if (post_all_free) {
270  }
271 
272  ocs_sport_lock_free(sport);
273  ocs_lock_free(&sport->node_group_lock);
274 
275  ocs_free(domain->ocs, sport, sizeof(*sport));
276  }
277 }
278 
279 void
280 ocs_sport_free(ocs_sport_t *sport)
281 {
282  /* Just put the refcount */
283  ocs_assert(ocs_ref_read_count(&sport->ref) > 0);
284  ocs_ref_put(&sport->ref); /* ocs_ref_get(): ocs_sport_alloc() */
285 }
286 
287 /**
288  * @ingroup sport_sm
289  * @brief Free memory resources of a SLI port object.
290  *
291  * @par Description
292  * After the sport object is freed, its child objects are freed.
293  *
294  * @param sport Pointer to the SLI port object.
295  *
296  * @return None.
297  */
298 
299 void ocs_sport_force_free(ocs_sport_t *sport)
300 {
301  ocs_node_t *node;
302  ocs_node_t *next;
303 
304  /* shutdown sm processing */
305  ocs_sm_disable(&sport->sm);
306 
308 
309  ocs_sport_lock(sport);
310  ocs_list_foreach_safe(&sport->node_list, node, next) {
311  ocs_node_force_free(node);
312  }
313  ocs_sport_unlock(sport);
314 
315  if (sport->is_vport) {
316  ocs_vport_link_down(sport);
317  }
318 
319  ocs_sport_free(sport);
320 }
321 
322 /**
323  * @ingroup sport_sm
324  * @brief Return a SLI port object, given an instance index.
325  *
326  * @par Description
327  * A pointer to a sport object is returned, given its instance @c index.
328  *
329  * @param domain Pointer to the domain.
330  * @param index Instance index value to find.
331  *
332  * @return Returns a pointer to the ocs_sport_t object; or NULL.
333  */
334 
335 ocs_sport_t *
336 ocs_sport_get_instance(ocs_domain_t *domain, uint32_t index)
337 {
338  ocs_sport_t *sport;
339 
340  ocs_domain_lock(domain);
341  ocs_list_foreach(&domain->sport_list, sport) {
342  if (sport->instance_index == index) {
343  ocs_domain_unlock(domain);
344  return sport;
345  }
346  }
347  ocs_domain_unlock(domain);
348  return NULL;
349 }
350 
351 /**
352  * @ingroup sport_sm
353  * @brief Find a SLI port object, given an FC_ID.
354  *
355  * @par Description
356  * Returns a pointer to the sport object, given an FC_ID.
357  *
358  * @param domain Pointer to the domain.
359  * @param d_id FC_ID to find.
360  *
361  * @return Returns a pointer to the ocs_sport_t; or NULL.
362  */
363 
364 ocs_sport_t *
365 ocs_sport_find(ocs_domain_t *domain, uint32_t d_id)
366 {
367  ocs_sport_t *sport;
368 
369  ocs_assert(domain, NULL);
370  ocs_lock(&domain->lookup_lock);
371  if (domain->lookup == NULL) {
372  ocs_log_test(domain->ocs, "assertion failed: domain->lookup is not valid\n");
373  ocs_unlock(&domain->lookup_lock);
374  return NULL;
375  }
376 
377  sport = spv_get(domain->lookup, d_id);
378  ocs_unlock(&domain->lookup_lock);
379  return sport;
380 }
381 
382 /**
383  * @ingroup sport_sm
384  * @brief Find a SLI port, given the WWNN and WWPN.
385  *
386  * @par Description
387  * Return a pointer to a sport, given the WWNN and WWPN.
388  *
389  * @param domain Pointer to the domain.
390  * @param wwnn World wide node name.
391  * @param wwpn World wide port name.
392  *
393  * @return Returns a pointer to a SLI port, if found; or NULL.
394  */
395 
396 ocs_sport_t *
397 ocs_sport_find_wwn(ocs_domain_t *domain, uint64_t wwnn, uint64_t wwpn)
398 {
399  ocs_sport_t *sport = NULL;
400 
401  ocs_domain_lock(domain);
402  ocs_list_foreach(&domain->sport_list, sport) {
403  if ((sport->wwnn == wwnn) && (sport->wwpn == wwpn)) {
404  ocs_domain_unlock(domain);
405  return sport;
406  }
407  }
408  ocs_domain_unlock(domain);
409  return NULL;
410 }
411 
412 /**
413  * @ingroup sport_sm
414  * @brief Request a SLI port attach.
415  *
416  * @par Description
417  * External call to request an attach for a sport, given an FC_ID.
418  *
419  * @param sport Pointer to the sport context.
420  * @param fc_id FC_ID of which to attach.
421  *
422  * @return Returns 0 on success, or a negative error value on failure.
423  */
424 
425 int32_t
426 ocs_sport_attach(ocs_sport_t *sport, uint32_t fc_id)
427 {
428  ocs_hal_rtn_e rc;
429  ocs_node_t *node;
430 
431  /* Set our lookup */
432  ocs_lock(&sport->domain->lookup_lock);
433  spv_set(sport->domain->lookup, fc_id, sport);
434  ocs_unlock(&sport->domain->lookup_lock);
435 
436  /* Update our display_name */
437  ocs_node_fcid_display(fc_id, sport->display_name, sizeof(sport->display_name));
438  ocs_sport_lock(sport);
439  ocs_list_foreach(&sport->node_list, node) {
441  }
442  ocs_sport_unlock(sport);
443  ocs_log_debug(sport->ocs, "[%s] attach sport: fc_id x%06x\n", sport->display_name, fc_id);
444 
445  rc = ocs_hal_port_attach(&sport->ocs->hal, sport, fc_id);
446  if (rc != OCS_HAL_RTN_SUCCESS) {
447  ocs_log_err(sport->ocs, "ocs_hal_port_attach failed: %d\n", rc);
448  return -1;
449  }
450  return 0;
451 }
452 
453 /**
454  * @brief Common SLI port state machine declarations and initialization.
455  */
456 #define std_sport_state_decl() \
457  ocs_sport_t *sport = NULL; \
458  ocs_domain_t *domain = NULL; \
459  ocs_t *ocs = NULL; \
460  \
461  ocs_assert(ctx, NULL); \
462  sport = ctx->app; \
463  ocs_assert(sport, NULL); \
464  \
465  domain = sport->domain; \
466  ocs_assert(domain, NULL); \
467  ocs = sport->ocs; \
468  ocs_assert(ocs, NULL);
469 
470 /**
471  * @brief Common SLI port state machine trace logging.
472  */
473 #define sport_sm_trace(sport) \
474  do { \
475  if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(ocs)) \
476  ocs_log_debug(ocs, "[%s] %-20s\n", sport->display_name, ocs_sm_event_name(evt)); \
477  } while (0)
478 
479 
480 /**
481  * @brief SLI port state machine: Common event handler.
482  *
483  * @par Description
484  * Handle common sport events.
485  *
486  * @param funcname Function name to display.
487  * @param ctx Sport state machine context.
488  * @param evt Event to process.
489  * @param arg Per event optional argument.
490  *
491  * @return Returns NULL.
492  */
493 
494 static void *
495 __ocs_sport_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
496 {
498 
499  switch(evt) {
500  case OCS_EVT_ENTER:
501  case OCS_EVT_REENTER:
502  case OCS_EVT_EXIT:
504  break;
507  break;
508  case OCS_EVT_SHUTDOWN: {
509  ocs_node_t *node;
510  ocs_node_t *node_next;
511  int node_list_empty;
512 
513  /* Flag this sport as shutting down */
514  sport->shutting_down = 1;
515 
516  if (sport->is_vport)
517  ocs_vport_link_down(sport);
518 
519  ocs_sport_lock(sport);
520  node_list_empty = ocs_list_empty(&sport->node_list);
521  ocs_sport_unlock(sport);
522 
523  if (node_list_empty) {
524  //sm: node list is empty / ocs_hal_port_free
525  /* Remove the sport from the domain's sparse vector lookup table */
526  ocs_lock(&domain->lookup_lock);
527  spv_set(domain->lookup, sport->fc_id, NULL);
528  ocs_unlock(&domain->lookup_lock);
529 
531  if (ocs_hal_port_free(&ocs->hal, sport))
532  ocs_log_err(ocs, "ocs_hal_port_free failed\n");
533  } else {
534  bool unreg_rpi_all_now = TRUE;
535 
536  //sm: node list is not empty / shutdown nodes
538  ocs_sport_lock(sport);
539  ocs_list_foreach_safe(&sport->node_list, node, node_next) {
540 
541  /* Issue unreg_rpi_all only if at least one node is active on this particular sport */
542  ocs_node_lock(node);
543  if (node->attached && !node->unreg_rpi) {
544  node->unreg_rpi = TRUE;
545  sport->unreg_rpi_all = TRUE;
546  }
547  ocs_node_unlock(node);
548 
549  /*
550  * If this is a vport, logout of the fabric controller so that it deletes
551  * the vport on the switch. Also defer unreg_rpi_all till logo completes.
552  */
553  if (sport->is_vport && node->rnode.fc_id == FC_ADDR_FABRIC) {
554  /* If link is down, don't send logo */
555  if (sport->ocs->hal.link.status == SLI_LINK_STATUS_DOWN) {
557  } else {
558  ocs_log_debug(ocs, "[%s] sport shutdown vport, sending logo to node\n",
559  node->display_name);
560 
562  0, NULL, NULL) == NULL) {
563  /* Failed to send LOGO, go ahead and cleanup node anyways */
564  node_printf(node, "Failed to send LOGO\n");
566  } else {
567  /* Defer unreg_rpi_all till logo of fabric node completes */
568  unreg_rpi_all_now = FALSE;
570  }
571  }
572  } else {
574  }
575  }
576 
577  if (sport->unreg_rpi_all && unreg_rpi_all_now)
578  ocs_hal_unreg_rpi_all(&ocs->hal, sport);
579 
580  ocs_sport_unlock(sport);
581  }
582  break;
583  }
584  default:
585  ocs_log_test(sport->ocs, "[%s] %-20s %-20s not handled\n", sport->display_name, funcname, ocs_sm_event_name(evt));
586  break;
587  }
588 
589  return NULL;
590 }
591 
592 /**
593  * @ingroup sport_sm
594  * @brief SLI port state machine: Physical sport allocated.
595  *
596  * @par Description
597  * This is the initial state for sport objects.
598  *
599  * @param ctx Remote node state machine context.
600  * @param evt Event to process.
601  * @param arg Per event optional argument.
602  *
603  * @return Returns NULL.
604  */
605 
606 void *
607 __ocs_sport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
608 {
610 
611  sport_sm_trace(sport);
612 
613  switch(evt) {
614  /* the physical sport is attached */
616  ocs_assert(sport == domain->sport, NULL);
618  break;
619 
621  /* ignore */
622  break;
623  default:
624  __ocs_sport_common(__func__, ctx, evt, arg);
625  return NULL;
626  }
627  return NULL;
628 }
629 
630 /**
631  * @ingroup sport_sm
632  * @brief SLI port state machine: Handle initial virtual port events.
633  *
634  * @par Description
635  * This state is entered when a virtual port is instantiated,
636  *
637  * @param ctx Remote node state machine context.
638  * @param evt Event to process.
639  * @param arg Per event optional argument.
640  *
641  * @return Returns NULL.
642  */
643 
644 void *
645 __ocs_sport_vport_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
646 {
648 
649  sport_sm_trace(sport);
650 
651  switch(evt) {
652  case OCS_EVT_ENTER: {
653  uint64_t be_wwpn = ocs_htobe64(sport->wwpn);
654 
655  if (sport->wwpn == 0) {
656  ocs_log_debug(ocs, "vport: letting f/w select WWN\n");
657  }
658 
659  if (sport->fc_id != UINT32_MAX) {
660  ocs_log_debug(ocs, "vport: hard coding port id: %x\n", sport->fc_id);
661  }
662 
664  /* If wwpn is zero, then we'll let the f/w */
665  if (ocs_hal_port_alloc(&ocs->hal, sport, sport->domain,
666  (sport->wwpn == 0) ? NULL : (uint8_t *)&be_wwpn)) {
667  ocs_log_err(ocs, "Can't allocate port\n");
668  break;
669  }
670 
671 
672  break;
673  }
674  default:
675  __ocs_sport_common(__func__, ctx, evt, arg);
676  return NULL;
677  }
678  return NULL;
679 }
680 
681 /**
682  * @ingroup sport_sm
683  * @brief SLI port state machine: Wait for the HAL SLI port allocation to complete.
684  *
685  * @par Description
686  * Waits for the HAL sport allocation request to complete.
687  *
688  * @param ctx Remote node state machine context.
689  * @param evt Event to process.
690  * @param arg Per event optional argument.
691  *
692  * @return Returns NULL.
693  */
694 
695 void *
696 __ocs_sport_vport_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
697 {
699 
700  sport_sm_trace(sport);
701 
702  switch(evt) {
703  case OCS_EVT_SPORT_ALLOC_OK: {
704  fc_plogi_payload_t *sp = (fc_plogi_payload_t*) sport->service_params;
705  ocs_node_t *fabric;
706 
707  /* If we let f/w assign wwn's, then sport wwn's with those returned by hal */
708  if (sport->wwnn == 0) {
709  sport->wwnn = ocs_be64toh(sport->sli_wwnn);
710  sport->wwpn = ocs_be64toh(sport->sli_wwpn);
711  ocs_snprintf(sport->wwnn_str, sizeof(sport->wwnn_str), "%016" PRIX64, sport->wwpn);
712  }
713 
714  /* Update the sport's service parameters */
715  sp->port_name_hi = ocs_htobe32((uint32_t) (sport->wwpn >> 32ll));
716  sp->port_name_lo = ocs_htobe32((uint32_t) sport->wwpn);
717  sp->node_name_hi = ocs_htobe32((uint32_t) (sport->wwnn >> 32ll));
718  sp->node_name_lo = ocs_htobe32((uint32_t) sport->wwnn);
719 
720  /* if sport->fc_id is uninitialized, then request that the fabric node use FDISC
721  * to find an fc_id. Otherwise we're restoring vports, or we're in
722  * fabric emulation mode, so attach the fc_id
723  */
724  if (sport->fc_id == UINT32_MAX) {
725  fabric = ocs_node_alloc(sport, FC_ADDR_FABRIC, FALSE, FALSE);
726  if (fabric == NULL) {
727  ocs_log_err(ocs, "ocs_node_alloc() failed\n");
728  return NULL;
729  }
731  } else {
732  ocs_snprintf(sport->wwnn_str, sizeof(sport->wwnn_str), "%016" PRIX64, sport->wwpn);
733  ocs_sport_attach(sport, sport->fc_id);
734  }
736  break;
737  }
738  default:
739  __ocs_sport_common(__func__, ctx, evt, arg);
740  return NULL;
741  }
742  return NULL;
743 }
744 
745 /**
746  * @ingroup sport_sm
747  * @brief SLI port state machine: virtual sport allocated.
748  *
749  * @par Description
750  * This state is entered after the sport is allocated; it then waits for a fabric node
751  * FDISC to complete, which requests a sport attach.
752  * The sport attach complete is handled in this state.
753  *
754  * @param ctx Remote node state machine context.
755  * @param evt Event to process.
756  * @param arg Per event optional argument.
757  *
758  * @return Returns NULL.
759  */
760 
761 void *
762 __ocs_sport_vport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
763 {
765 
766  sport_sm_trace(sport);
767 
768  switch(evt) {
770  ocs_node_t *node;
771 
772  if (!(domain->femul_enable)) {
773  /* Find our fabric node, and forward this event */
774  node = ocs_node_find(sport, FC_ADDR_FABRIC);
775  if (node == NULL) {
776  ocs_log_test(ocs, "can't find node %06x\n", FC_ADDR_FABRIC);
777  break;
778  }
779  //sm: / forward sport attach to fabric node
780  ocs_node_post_event(node, evt, NULL);
781  }
783  break;
784  }
785  default:
786  __ocs_sport_common(__func__, ctx, evt, arg);
787  return NULL;
788  }
789  return NULL;
790 }
791 
792 /**
793  * @ingroup sport_sm
794  * @brief SLI port state machine: Attached.
795  *
796  * @par Description
797  * State entered after the sport attach has completed.
798  *
799  * @param ctx Remote node state machine context.
800  * @param evt Event to process.
801  * @param arg Per event optional argument.
802  *
803  * @return Returns NULL.
804  */
805 
806 void *
807 __ocs_sport_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
808 {
810 
811  sport_sm_trace(sport);
812 
813  switch(evt) {
814  case OCS_EVT_ENTER: {
815  ocs_node_t *node;
816 
817  ocs_log_debug(ocs, "[%s] SPORT attached WWPN %016" PRIx64 " WWNN %016" PRIx64 "\n", sport->display_name,
818  sport->wwpn, sport->wwnn);
819  ocs_sport_lock(sport);
820  ocs_list_foreach(&sport->node_list, node) {
822  }
823  ocs_sport_unlock(sport);
824  sport->tgt_id = sport->fc_id;
825  if (ocs->enable_ini) {
826  ocs_scsi_ini_new_sport(sport);
827  }
828  if (ocs->enable_tgt) {
829  ocs_scsi_tgt_new_sport(sport);
830  }
831  /* Update the vport (if its not the physical sport) parameters */
832  if (sport->is_vport) {
833  ocs_vport_update_spec(sport);
834  }
835 
836 #if defined(ENABLE_FABRIC_EMULATION)
837  /* If Fabric Emulation, then register with driver name server */
838  if (domain->femul_enable) {
839  ocs_femul_sport_attach(sport);
840 
841  /* Decrement outstanding femul_count, if it goes to zero, then notify fabric emulation */
842  if (ocs_atomic_read(&domain->femul_count)) {
843  if (ocs_atomic_sub_return(&domain->femul_count, 1) == 1) {
844  ocs_femul_ports_attached(domain);
845  }
846  }
847  }
848 #endif
849 
850  break;
851  }
852 
853  case OCS_EVT_EXIT:
854  ocs_log_debug(ocs, "[%s] SPORT deattached WWPN %016" PRIx64 " WWNN %016" PRIx64 "\n", sport->display_name,
855  sport->wwpn, sport->wwnn);
856  if (ocs->enable_ini) {
857  ocs_scsi_ini_del_sport(sport);
858  }
859  if (ocs->enable_tgt) {
860  ocs_scsi_tgt_del_sport(sport);
861  }
862  break;
863  default:
864  __ocs_sport_common(__func__, ctx, evt, arg);
865  return NULL;
866  }
867  return NULL;
868 }
869 
870 /**
871  * @ingroup sport_sm
872  * @brief SLI port state machine: Wait for the node shutdowns to complete.
873  *
874  * @par Description
875  * Waits for the ALL_CHILD_NODES_FREE event to be posted from the node
876  * shutdown process.
877  *
878  * @param ctx Remote node state machine context.
879  * @param evt Event to process.
880  * @param arg Per event optional argument.
881  *
882  * @return Returns NULL.
883  */
884 
885 void *
886 __ocs_sport_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
887 {
889 
890  sport_sm_trace(sport);
891 
892  switch(evt) {
897  /* ignore these events - just wait for the all free event */
898  break;
899 
901  /* Remove the sport from the domain's sparse vector lookup table */
902  ocs_lock(&domain->lookup_lock);
903  spv_set(domain->lookup, sport->fc_id, NULL);
904  ocs_unlock(&domain->lookup_lock);
905 
907  if (ocs_hal_port_free(&ocs->hal, sport))
908  ocs_log_err(ocs, "ocs_hal_port_free failed\n");
909 
910  break;
911  }
912  default:
913  __ocs_sport_common(__func__, ctx, evt, arg);
914  return NULL;
915  }
916  return NULL;
917 }
918 
919 /**
920  * @ingroup sport_sm
921  * @brief SLI port state machine: Wait for the HAL's port free to complete.
922  *
923  * @par Description
924  * Waits for the HAL's port free to complete.
925  *
926  * @param ctx Remote node state machine context.
927  * @param evt Event to process.
928  * @param arg Per event optional argument.
929  *
930  * @return Returns NULL.
931  */
932 
933 void *
934 __ocs_sport_wait_port_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
935 {
937 
938  sport_sm_trace(sport);
939 
940  switch(evt) {
942  /* Ignore as we are waiting for the free CB */
943  break;
944  case OCS_EVT_SPORT_FREE_OK: {
945  /* All done, free myself */
946  //sm: / ocs_sport_free
947  ocs_sport_free(sport);
948  break;
949  }
950  default:
951  __ocs_sport_common(__func__, ctx, evt, arg);
952  return NULL;
953  }
954  return NULL;
955 }
956 
957 /**
958  * @ingroup sport_sm
959  * @brief Start the vports on a domain
960  *
961  * @par Description
962  * Use the vport specification to find the associated vports and start them.
963  *
964  * @param domain Pointer to the domain context.
965  *
966  * @return Returns 0 on success, or a negative error value on failure.
967  */
968 int32_t
969 ocs_vport_start(ocs_domain_t *domain)
970 {
971  ocs_t *ocs = domain->ocs;
972  ocs_xport_t *xport = ocs->xport;
973  ocs_vport_spec_t *vport;
974  ocs_vport_spec_t *next;
975  ocs_sport_t *sport;
976  int32_t rc = 0;
977 
978  ocs_device_lock(ocs);
979  ocs_list_foreach_safe(&xport->vport_list, vport, next) {
980  if (vport->domain_instance == domain->instance_index &&
981  vport->sport == NULL) {
982 #if defined(ENABLE_FABRIC_EMULATION)
983  if (domain->femul_enable) {
984  vport->fc_id = ocs_femul_portid_alloc(domain);
985  }
986 #endif
987  /* Allocate a sport */
988  vport->sport = sport = ocs_sport_alloc(domain, vport->wwpn, vport->wwnn, vport->fc_id,
989  vport->enable_ini, vport->enable_tgt);
990  if (sport == NULL) {
991  rc = -1;
992  } else {
993  sport->is_vport = 1;
994  sport->tgt_data = vport->tgt_data;
995  sport->ini_data = vport->ini_data;
996 
997  /* Transition to vport_init */
998  ocs_sm_transition(&sport->sm, __ocs_sport_vport_init, NULL);
999  }
1000  }
1001  }
1002  ocs_device_unlock(ocs);
1003  return rc;
1004 }
1005 
1006 /**
1007  * @ingroup sport_sm
1008  * @brief Clear the sport reference in the vport specification.
1009  *
1010  * @par Description
1011  * Clear the sport pointer on the vport specification when the vport is torn down. This allows it to be
1012  * re-created when the link is re-established.
1013  *
1014  * @param sport Pointer to the sport context.
1015  */
1016 static void
1017 ocs_vport_link_down(ocs_sport_t *sport)
1018 {
1019  ocs_t *ocs = sport->ocs;
1020  ocs_xport_t *xport = ocs->xport;
1021  ocs_vport_spec_t *vport;
1022 
1023  ocs_device_lock(ocs);
1024  ocs_list_foreach(&xport->vport_list, vport) {
1025  if (vport->sport == sport) {
1026  vport->sport = NULL;
1027  break;
1028  }
1029  }
1030  ocs_device_unlock(ocs);
1031 }
1032 
1033 /**
1034  * @ingroup sport_sm
1035  * @brief Allocate a new virtual SLI port.
1036  *
1037  * @par Description
1038  * A new sport is created, in response to an external management request.
1039  *
1040  * @n @b Note: If the WWPN is zero, the firmware will assign the WWNs.
1041  *
1042  * @param domain Pointer to the domain context.
1043  * @param wwpn World wide port name.
1044  * @param wwnn World wide node name
1045  * @param fc_id Requested port ID (used in fabric emulation mode).
1046  * @param ini TRUE, if port is created as an initiator node.
1047  * @param tgt TRUE, if port is created as a target node.
1048  * @param tgt_data Pointer to target specific data
1049  * @param ini_data Pointer to initiator specific data
1050  * @param restore_vport If TRUE, then the vport will be re-created automatically
1051  * on link disruption.
1052  *
1053  * @return Returns 0 on success; or a negative error value on failure.
1054  */
1055 
1056 int32_t
1057 ocs_sport_vport_new(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn,
1058  uint32_t fc_id, uint8_t ini, uint8_t tgt, void *tgt_data,
1059  void *ini_data, uint8_t restore_vport)
1060 {
1061  ocs_sport_t *sport;
1062 
1063  if (ini && (domain->ocs->enable_ini == 0)) {
1064  ocs_log_test(domain->ocs, "driver initiator functionality not enabled\n");
1065  return -1;
1066  }
1067 
1068  if (tgt && (domain->ocs->enable_tgt == 0)) {
1069  ocs_log_test(domain->ocs, "driver target functionality not enabled\n");
1070  return -1;
1071  }
1072 
1073  /* Create a vport spec if we need to recreate this vport after a link up event */
1074  if (restore_vport) {
1075  if (ocs_vport_create_spec(domain->ocs, wwnn, wwpn, fc_id, ini, tgt, tgt_data, ini_data)) {
1076  ocs_log_test(domain->ocs, "failed to create vport object entry\n");
1077  return -1;
1078  }
1079  return ocs_vport_start(domain);
1080  }
1081 
1082  /* Allocate a sport */
1083  sport = ocs_sport_alloc(domain, wwpn, wwnn, fc_id, ini, tgt);
1084 
1085  if (sport == NULL) {
1086  return -1;
1087  }
1088 
1089  sport->is_vport = 1;
1090  sport->tgt_data = tgt_data;
1091  sport->ini_data = ini_data;
1092 
1093  /* Transition to vport_init */
1094  ocs_sm_transition(&sport->sm, __ocs_sport_vport_init, NULL);
1095 
1096  return 0;
1097 }
1098 
1099 /**
1100  * @ingroup sport_sm
1101  * @brief Remove a previously-allocated virtual port.
1102  *
1103  * @par Description
1104  * A previously-allocated virtual port is removed by posting the shutdown event to the
1105  * sport with a matching WWN.
1106  *
1107  * @param ocs Pointer to the device object.
1108  * @param domain Pointer to the domain structure (may be NULL).
1109  * @param wwpn World wide port name of the port to delete (host endian).
1110  * @param wwnn World wide node name of the port to delete (host endian).
1111  *
1112  * @return Returns 0 on success, or a negative error value on failure.
1113  */
1114 
1115 int32_t ocs_sport_vport_del(ocs_t *ocs, ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn)
1116 {
1117  ocs_xport_t *xport = ocs->xport;
1118  ocs_sport_t *sport;
1119  int found = 0;
1120  ocs_vport_spec_t *vport;
1121  ocs_vport_spec_t *next;
1122  uint32_t instance;
1123 
1124  /* If no domain is given, use instance 0, otherwise use domain instance */
1125  if (domain == NULL) {
1126  instance = 0;
1127  } else {
1128  instance = domain->instance_index;
1129  }
1130 
1131  /* walk the ocs_vport_list and remove from there */
1132  ocs_device_lock(ocs);
1133  ocs_list_foreach_safe(&xport->vport_list, vport, next) {
1134  if ((vport->domain_instance == instance) &&
1135  (vport->wwpn == wwpn) && (vport->wwnn == wwnn)) {
1136  ocs_list_remove(&xport->vport_list, vport);
1137  ocs_free(ocs, vport, sizeof(*vport));
1138  break;
1139  }
1140  }
1141  ocs_device_unlock(ocs);
1142 
1143  if (domain == NULL) {
1144  // No domain means no sport to look for
1145  return 0;
1146  }
1147 
1148  ocs_domain_lock(domain);
1149  ocs_list_foreach(&domain->sport_list, sport) {
1150  if ((sport->wwpn == wwpn) && (sport->wwnn == wwnn)) {
1151  found = 1;
1152  break;
1153  }
1154  }
1155  if (found) {
1156  /* Shutdown this SPORT */
1157  ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
1158  }
1159  ocs_domain_unlock(domain);
1160  return 0;
1161 }
1162 
1163 /**
1164  * @brief Force free all saved vports.
1165  *
1166  * @par Description
1167  * Delete all device vports.
1168  *
1169  * @param ocs Pointer to the device object.
1170  *
1171  * @return None.
1172  */
1173 
1174 void
1176 {
1177  ocs_xport_t *xport = ocs->xport;
1178  ocs_vport_spec_t *vport;
1179  ocs_vport_spec_t *next;
1180 
1181  ocs_device_lock(ocs);
1182  ocs_list_foreach_safe(&xport->vport_list, vport, next) {
1183  ocs_list_remove(&xport->vport_list, vport);
1184  ocs_free(ocs, vport, sizeof(*vport));
1185  }
1186  ocs_device_unlock(ocs);
1187 }
1188 
1189 /**
1190  * @ingroup sport_sm
1191  * @brief Generate a SLI port ddump.
1192  *
1193  * @par Description
1194  * Generates the SLI port ddump data.
1195  *
1196  * @param textbuf Pointer to the text buffer.
1197  * @param sport Pointer to the SLI-4 port.
1198  *
1199  * @return Returns 0 on success, or a negative value on failure.
1200  */
1201 
1202 int
1203 ocs_ddump_sport(ocs_textbuf_t *textbuf, ocs_sli_port_t *sport)
1204 {
1205  ocs_node_t *node;
1206  ocs_node_group_dir_t *node_group_dir;
1207  int retval = 0;
1208 
1209  ocs_ddump_section(textbuf, "sport", sport->instance_index);
1210  ocs_ddump_value(textbuf, "display_name", "%s", sport->display_name);
1211 
1212  ocs_ddump_value(textbuf, "is_vport", "%d", sport->is_vport);
1213  ocs_ddump_value(textbuf, "enable_ini", "%d", sport->enable_ini);
1214  ocs_ddump_value(textbuf, "enable_tgt", "%d", sport->enable_tgt);
1215  ocs_ddump_value(textbuf, "shutting_down", "%d", sport->shutting_down);
1216  ocs_ddump_value(textbuf, "topology", "%d", sport->topology);
1217  ocs_ddump_value(textbuf, "p2p_winner", "%d", sport->p2p_winner);
1218  ocs_ddump_value(textbuf, "p2p_port_id", "%06x", sport->p2p_port_id);
1219  ocs_ddump_value(textbuf, "p2p_remote_port_id", "%06x", sport->p2p_remote_port_id);
1220  ocs_ddump_value(textbuf, "wwpn", "%016" PRIx64 "", sport->wwpn);
1221  ocs_ddump_value(textbuf, "wwnn", "%016" PRIx64 "", sport->wwnn);
1222  //TODO: service_params
1223 
1224  ocs_ddump_value(textbuf, "indicator", "x%x", sport->indicator);
1225  ocs_ddump_value(textbuf, "fc_id", "x%06x", sport->fc_id);
1226  ocs_ddump_value(textbuf, "index", "%d", sport->index);
1227 
1228  ocs_display_sparams(NULL, "sport_sparams", 1, textbuf, sport->service_params+4);
1229 
1230  /* HLM dump */
1231  ocs_ddump_section(textbuf, "hlm", sport->instance_index);
1232  ocs_lock(&sport->node_group_lock);
1233  ocs_list_foreach(&sport->node_group_dir_list, node_group_dir) {
1234  ocs_remote_node_group_t *remote_node_group;
1235 
1236  ocs_ddump_section(textbuf, "node_group_dir", node_group_dir->instance_index);
1237 
1238  ocs_ddump_value(textbuf, "node_group_list_count", "%d", node_group_dir->node_group_list_count);
1239  ocs_ddump_value(textbuf, "next_idx", "%d", node_group_dir->next_idx);
1240  ocs_list_foreach(&node_group_dir->node_group_list, remote_node_group) {
1241  ocs_ddump_section(textbuf, "node_group", remote_node_group->instance_index);
1242  ocs_ddump_value(textbuf, "indicator", "x%x", remote_node_group->indicator);
1243  ocs_ddump_value(textbuf, "index", "x%x", remote_node_group->index);
1244  ocs_ddump_value(textbuf, "instance_index", "x%x", remote_node_group->instance_index);
1245  ocs_ddump_endsection(textbuf, "node_group", 0);
1246  }
1247  ocs_ddump_endsection(textbuf, "node_group_dir", 0);
1248  }
1249  ocs_unlock(&sport->node_group_lock);
1250  ocs_ddump_endsection(textbuf, "hlm", sport->instance_index);
1251 
1252  ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_SPORT, sport);
1253  ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_SPORT, sport);
1254 
1255  /* Dump all the nodes */
1256  if (ocs_sport_lock_try(sport) != TRUE) {
1257  /* Didn't get lock */
1258  return -1;
1259  }
1260  /* Here the sport lock is held */
1261  ocs_list_foreach(&sport->node_list, node) {
1262  retval = ocs_ddump_node(textbuf, node);
1263  if (retval != 0) {
1264  break;
1265  }
1266  }
1267  ocs_sport_unlock(sport);
1268 
1269  ocs_ddump_endsection(textbuf, "sport", sport->index);
1270 
1271  return retval;
1272 }
1273 
1274 
1275 void
1276 ocs_mgmt_sport_list(ocs_textbuf_t *textbuf, void *object)
1277 {
1278  ocs_node_t *node;
1279  ocs_sport_t *sport = (ocs_sport_t *)object;
1280 
1281  ocs_mgmt_start_section(textbuf, "sport", sport->instance_index);
1282 
1283  /* Add my status values to textbuf */
1284  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
1285  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fc_id");
1286  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "index");
1287  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
1288  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_vport");
1289  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "enable_ini");
1290  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "enable_tgt");
1291  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "p2p");
1292  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "p2p_winner");
1293  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "p2p_port_id");
1294  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "p2p_remote_port_id");
1295  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwpn");
1296  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwnn");
1297 
1298  if (ocs_sport_lock_try(sport) == TRUE) {
1299 
1300  /* If we get here, then we are holding the sport lock */
1301  ocs_list_foreach(&sport->node_list, node) {
1302  if ((node->mgmt_functions) && (node->mgmt_functions->get_list_handler)) {
1303  node->mgmt_functions->get_list_handler(textbuf, node);
1304  }
1305 
1306  }
1307  ocs_sport_unlock(sport);
1308  }
1309 
1310  ocs_mgmt_end_section(textbuf, "sport", sport->instance_index);
1311 }
1312 
1313 int
1314 ocs_mgmt_sport_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
1315 {
1316  ocs_node_t *node;
1317  ocs_sport_t *sport = (ocs_sport_t *)object;
1318  char qualifier[80];
1319  int retval = -1;
1320 
1321  ocs_mgmt_start_section(textbuf, "sport", sport->instance_index);
1322 
1323  snprintf(qualifier, sizeof(qualifier), "%s/sport[%d]", parent, sport->instance_index);
1324 
1325  /* If it doesn't start with my qualifier I don't know what to do with it */
1326  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1327  char *unqualified_name = name + strlen(qualifier) +1;
1328 
1329  /* See if it's a value I can supply */
1330  if (ocs_strcmp(unqualified_name, "indicator") == 0) {
1331  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", sport->indicator);
1332  retval = 0;
1333  } else if (ocs_strcmp(unqualified_name, "fc_id") == 0) {
1334  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", sport->fc_id);
1335  retval = 0;
1336  } else if (ocs_strcmp(unqualified_name, "index") == 0) {
1337  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "index", "%d", sport->index);
1338  retval = 0;
1339  } else if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1340  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", sport->display_name);
1341  retval = 0;
1342  } else if (ocs_strcmp(unqualified_name, "is_vport") == 0) {
1343  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_vport", sport->is_vport);
1344  retval = 0;
1345  } else if (ocs_strcmp(unqualified_name, "enable_ini") == 0) {
1346  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "enable_ini", sport->enable_ini);
1347  retval = 0;
1348  } else if (ocs_strcmp(unqualified_name, "enable_tgt") == 0) {
1349  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "enable_tgt", sport->enable_tgt);
1350  retval = 0;
1351  } else if (ocs_strcmp(unqualified_name, "p2p_winner") == 0) {
1352  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "p2p_winner", sport->p2p_winner);
1353  retval = 0;
1354  } else if (ocs_strcmp(unqualified_name, "p2p_port_id") == 0) {
1355  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "p2p_port_id", "0x%06x", sport->p2p_port_id);
1356  retval = 0;
1357  } else if (ocs_strcmp(unqualified_name, "p2p_remote_port_id") == 0) {
1358  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "p2p_remote_port_id", "0x%06x", sport->p2p_remote_port_id);
1359  retval = 0;
1360  } else if (ocs_strcmp(unqualified_name, "wwpn") == 0) {
1361  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "0x%016" PRIx64 "", sport->wwpn);
1362  retval = 0;
1363  } else if (ocs_strcmp(unqualified_name, "wwnn") == 0) {
1364  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "0x%016" PRIx64 "", sport->wwnn);
1365  retval = 0;
1366  } else {
1367  /* If I didn't know the value of this status pass the request to each of my children */
1368  ocs_sport_lock(sport);
1369  ocs_list_foreach(&sport->node_list, node) {
1370  if ((node->mgmt_functions) && (node->mgmt_functions->get_handler)) {
1371  retval = node->mgmt_functions->get_handler(textbuf, qualifier, name, node);
1372  }
1373 
1374  if (retval == 0) {
1375  break;
1376  }
1377  }
1378  ocs_sport_unlock(sport);
1379  }
1380  }
1381 
1382  ocs_mgmt_end_section(textbuf, "sport", sport->instance_index);
1383 
1384  return retval;
1385 }
1386 
1387 void
1388 ocs_mgmt_sport_get_all(ocs_textbuf_t *textbuf, void *object)
1389 {
1390  ocs_node_t *node;
1391  ocs_sport_t *sport = (ocs_sport_t *)object;
1392 
1393  ocs_mgmt_start_section(textbuf, "sport", sport->instance_index);
1394 
1395  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", sport->indicator);
1396  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", sport->fc_id);
1397  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "index", "%d", sport->index);
1398  ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", sport->display_name);
1399  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_vport", sport->is_vport);
1400  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "enable_ini", sport->enable_ini);
1401  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "enable_tgt", sport->enable_tgt);
1402  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "p2p_winner", sport->p2p_winner);
1403  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "p2p_port_id", "0x%06x", sport->p2p_port_id);
1404  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "p2p_remote_port_id", "0x%06x", sport->p2p_remote_port_id);
1405  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "0x%016" PRIx64 "", sport->wwpn);
1406  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "0x%016" PRIx64 "", sport->wwnn);
1407 
1408  ocs_sport_lock(sport);
1409  ocs_list_foreach(&sport->node_list, node) {
1410  if ((node->mgmt_functions) && (node->mgmt_functions->get_all_handler)) {
1411  node->mgmt_functions->get_all_handler(textbuf, node);
1412  }
1413  }
1414  ocs_sport_unlock(sport);
1415 
1416  ocs_mgmt_end_section(textbuf, "sport", sport->instance_index);
1417 }
1418 
1419 int
1420 ocs_mgmt_sport_set(char *parent, char *name, char *value, void *object)
1421 {
1422  ocs_node_t *node;
1423  ocs_sport_t *sport = (ocs_sport_t *)object;
1424  char qualifier[80];
1425  int retval = -1;
1426 
1427  snprintf(qualifier, sizeof(qualifier), "%s/sport[%d]", parent, sport->instance_index);
1428 
1429  /* If it doesn't start with my qualifier I don't know what to do with it */
1430  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1431  /* The sport has no settable values. Pass the request to each node. */
1432 
1433  ocs_sport_lock(sport);
1434  ocs_list_foreach(&sport->node_list, node) {
1435  if ((node->mgmt_functions) && (node->mgmt_functions->set_handler)) {
1436  retval = node->mgmt_functions->set_handler(qualifier, name, value, node);
1437  }
1438  if (retval == 0) {
1439  break;
1440  }
1441  }
1442  ocs_sport_unlock(sport);
1443  }
1444 
1445  return retval;
1446 }
1447 
1448 typedef struct ocs_fdmi_get_cmd_results_s {
1449  ocs_lock_t cb_lock;
1450  int32_t status;
1451  ocs_atomic_t refcnt;
1452  uint16_t fdmi_cmd_code;
1457 
1458 static void
1459 ocs_fdmi_get_cmd_cb(ocs_node_t *node, ocs_node_cb_t *node_data,
1460  void *cb_data)
1461 {
1462  ocs_fdmi_get_cmd_results_t *result = cb_data;
1463  ocs_sport_exec_arg_t *sport_exec_args;
1464  ocs_t *ocs = node->ocs;
1465  int rc = 0;
1466 
1467  if (result) {
1468  sport_exec_args = result->sport_exec_args;
1469 
1470  switch (result->fdmi_cmd_code) {
1471  case FC_GS_FDMI_GRHL:
1472  rc = ocs_process_fdmi_grhl_payload(node, node_data->els->els_rsp.virt,
1473  node_data->els->els_rsp.len, result->fdmi_get_cmd_rsp_buf);
1474  break;
1475  case FC_GS_FDMI_GRPL:
1476  rc = ocs_process_fdmi_grpl_payload(node, node_data->els->els_rsp.virt,
1477  node_data->els->els_rsp.len, result->fdmi_get_cmd_rsp_buf);
1478  break;
1479  case FC_GS_FDMI_GHAT:
1480  rc = ocs_process_fdmi_ghat_payload(node, node_data->els->els_rsp.virt,
1481  node_data->els->els_rsp.len, result->fdmi_get_cmd_rsp_buf);
1482  break;
1483  case FC_GS_FDMI_GPAT:
1484  rc = ocs_process_fdmi_gpat_payload(node, node_data->els->els_rsp.virt,
1485  node_data->els->els_rsp.len, result->fdmi_get_cmd_rsp_buf);
1486  break;
1487  default:
1488  ocs_log_err(ocs, "Unsupported FDMI command code(0x%x)\n", result->fdmi_cmd_code);
1489  }
1490  if (rc) {
1491  ocs_log_err(ocs, "failed to process FDMI response payload\n");
1492  }
1493 
1494  if (sport_exec_args) {
1495  if (!ocs_memcpy((uint8_t *)sport_exec_args->arg_out, (uint8_t *)result->fdmi_get_cmd_rsp_buf,
1496  result->fdmi_get_cmd_rsp_buf_len)) {
1497  ocs_log_err(ocs, "Failed to copy resp to user buffer\n");
1498  rc = -EFAULT;
1499 
1500  }
1501  sport_exec_args->exec_cb(node->sport, sport_exec_args);
1502  }
1503  ocs_free(ocs, result->fdmi_get_cmd_rsp_buf, result->fdmi_get_cmd_rsp_buf_len);
1504  ocs_free(ocs, result, sizeof(*result));
1505  }
1506 }
1507 
1508 /**
1509  * @brief send FDMI get command.
1510  *
1511  * @param sport : Pointer to sport
1512  * @param in_buf: input buffer
1513  * @param in_buf_len: input buffer length
1514  * @param buf: User provided buffer to copy HBA lists info
1515  * @param buf_len: user buffer length
1516  * @param fdmi_cmd_code: FDMI command code
1517  * @return Returns 0 on success, or a negative value on failure.
1518  */
1519 static int32_t
1520 ocs_sport_fdmi_get_cmd(ocs_sport_t *sport, ocs_sport_exec_arg_t *sport_exec_args,
1521  uint32_t fdmi_cmd_code)
1522 {
1523  int rc = 0;
1524  ocs_fdmi_get_cmd_results_t *result = NULL;
1525  ocs_fdmi_get_cmd_req_info_t fdmi_cmd_req;
1526  ocs_t *ocs = sport->ocs;
1527  uint64_t identifier = 0;
1528  void *in_buf = sport_exec_args->arg_in;
1529  uint32_t in_buf_len = sport_exec_args->arg_in_length;
1530  void *wwpn = NULL;
1531 
1532  if (in_buf_len) {
1533  wwpn = ocs_malloc(sport->ocs, in_buf_len, OCS_M_ZERO | OCS_M_NOWAIT);
1534  if (wwpn == NULL) {
1535  ocs_log_err(sport->ocs, "failed to allocate memory\n");
1536  return -ENOMEM;
1537  }
1538 
1539  if (ocs_copy_from_user(wwpn, (uint8_t *)in_buf, in_buf_len)) {
1540  ocs_log_err(ocs, "copy from user is failed\n");
1541  ocs_free(ocs, wwpn, in_buf_len);
1542  return -EFAULT;
1543  }
1544  }
1545 
1546  result = ocs_malloc(ocs, sizeof(*result),
1547  OCS_M_ZERO | OCS_M_NOWAIT);
1548  if (result == NULL) {
1549  ocs_log_err(ocs, "failed to allocate memory\n");
1550  ocs_free(ocs, wwpn, in_buf_len);
1551  return -ENOMEM;
1552  }
1553 
1554  result->sport_exec_args = sport_exec_args;
1555  switch (fdmi_cmd_code) {
1556  case FC_GS_FDMI_GRHL:
1558  fdmi_cmd_req.ct_cmd_req_size = sizeof(fcct_fdmi_grhl_req_t);
1559  break;
1560  case FC_GS_FDMI_GRPL:
1561  parse_wwn((char *)wwpn, &identifier);
1563  fdmi_cmd_req.ct_cmd_req_size = sizeof(fcct_fdmi_grpl_req_t);
1564  break;
1565  case FC_GS_FDMI_GHAT:
1566  parse_wwn((char *)wwpn, &identifier);
1568  fdmi_cmd_req.ct_cmd_req_size = sizeof(fcct_fdmi_ghat_req_t);
1569  break;
1570  case FC_GS_FDMI_GPAT:
1571  parse_wwn((char *)wwpn, &identifier);
1573  fdmi_cmd_req.ct_cmd_req_size = sizeof(fcct_fdmi_gpat_req_t);
1574  break;
1575  default:
1576  ocs_log_err(ocs, "Unsupported FDMI cmd code: 0x%x\n", fdmi_cmd_code);
1577  ocs_free(ocs, wwpn, in_buf_len);
1578  ocs_free(ocs, result, sizeof(*result));
1579  return -EFAULT;
1580  }
1581  /* Allocate memory to hold FDMI command response */
1582  result->fdmi_get_cmd_rsp_buf = ocs_malloc(ocs, result->fdmi_get_cmd_rsp_buf_len,
1583  OCS_M_ZERO | OCS_M_NOWAIT);
1584  if (result->fdmi_get_cmd_rsp_buf == NULL) {
1585  ocs_log_err(ocs, "failed to allocate memory for fdmi_get_cmd_rsp_buf\n");
1586  ocs_free(ocs, wwpn, in_buf_len);
1587  ocs_free(ocs, result, sizeof(*result));
1588  return -ENOMEM;
1589  }
1590 
1591  result->fdmi_cmd_code = fdmi_cmd_code;
1592 
1593  fdmi_cmd_req.cmd_code = fdmi_cmd_code;
1594  fdmi_cmd_req.identifier = identifier;
1595 
1596  rc = ocs_fdmi_get_cmd(sport, ocs_fdmi_get_cmd_cb, result, &fdmi_cmd_req);
1597  if (rc) {
1598  ocs_log_err(ocs, "Failed to submit FDMI get cmd(0x%x) ELS IO\n", fdmi_cmd_code);
1599  rc = -EFAULT;
1600  goto done;
1601  }
1602 
1603 done:
1604  ocs_free(ocs, wwpn, in_buf_len);
1605  return rc;
1606 }
1607 
1608 void ocs_mgmt_sport_exec_cb(ocs_sport_t *sport, void *arg_in)
1609 {
1610  ocs_sport_exec_arg_t *sport_exec_args = arg_in;
1611 
1612  if (sport_exec_args) {
1613  ocs_domain_exec_arg_t *domain_exec_args = sport_exec_args->domain_exec_args;
1614  ocs_free(sport->ocs, sport_exec_args, sizeof(*sport_exec_args));
1615  domain_exec_args->exec_cb(sport->domain, domain_exec_args);
1616  }
1617 }
1618 
1619 int
1620 ocs_mgmt_sport_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
1621  void *arg_out, uint32_t arg_out_length, void *object)
1622 {
1623  ocs_node_t *node;
1624  ocs_sport_t *sport = (ocs_sport_t *)object;
1625  ocs_sport_exec_arg_t *sport_exec_args = arg_in;
1626  char qualifier[80];
1627  int retval = -1;
1628 
1629  snprintf(qualifier, sizeof(qualifier), "%s/sport[%d]", parent, sport->instance_index);
1630 
1631  /* If it doesn't start with my qualifier I don't know what to do with it */
1632  if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
1633  char *unqualified_name = action + strlen(qualifier) + 1;
1634 
1635  /* See if it's an action I can perform */
1636  if (ocs_strcmp(unqualified_name, "get_fdmi_hba_list") == 0) {
1637  retval = ocs_sport_fdmi_get_cmd(sport, sport_exec_args, FC_GS_FDMI_GRHL);
1638  } else if (ocs_strcmp(unqualified_name, "get_fdmi_hba_info") == 0) {
1639  retval = ocs_sport_fdmi_get_cmd(sport, sport_exec_args, FC_GS_FDMI_GHAT);
1640  } else if (ocs_strcmp(unqualified_name, "get_fdmi_port_list") == 0) {
1641  retval = ocs_sport_fdmi_get_cmd(sport, sport_exec_args, FC_GS_FDMI_GRPL);
1642  } else if (ocs_strcmp(unqualified_name, "get_fdmi_port_info") == 0) {
1643  retval = ocs_sport_fdmi_get_cmd(sport, sport_exec_args, FC_GS_FDMI_GPAT);
1644  } else {
1645  /* If I didn't know how to do this action pass the request to each of my children */
1646  ocs_sport_lock(sport);
1647  ocs_list_foreach(&sport->node_list, node) {
1648  if ((node->mgmt_functions) && (node->mgmt_functions->exec_handler)) {
1649  retval = node->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
1650  arg_out, arg_out_length, node);
1651  }
1652 
1653  if (retval == 0) {
1654  break;
1655  }
1656 
1657  }
1658  ocs_sport_unlock(sport);
1659  }
1660  }
1661 
1662  return retval;
1663 }
1664 
1665 /**
1666  * @brief Save the virtual port's parameters.
1667  *
1668  * @par Description
1669  * The information required to restore a virtual port is saved.
1670  *
1671  * @param sport Pointer to the sport context.
1672  *
1673  * @return None.
1674  */
1675 
1676 static void
1677 ocs_vport_update_spec(ocs_sport_t *sport)
1678 {
1679  ocs_t *ocs = sport->ocs;
1680  ocs_xport_t *xport = ocs->xport;
1681  ocs_vport_spec_t *vport;
1682 
1683  ocs_device_lock(ocs);
1684  ocs_list_foreach(&xport->vport_list, vport) {
1685  if (vport->sport == sport) {
1686  vport->wwnn = sport->wwnn;
1687  vport->wwpn = sport->wwpn;
1688  vport->tgt_data = sport->tgt_data;
1689  vport->ini_data = sport->ini_data;
1690  break;
1691  }
1692  }
1693  ocs_device_unlock(ocs);
1694 }
1695 
1696 /**
1697  * @brief Create a saved vport entry.
1698  *
1699  * A saved vport entry is added to the vport list, which is restored following
1700  * a link up. This function is used to allow vports to be created the first time
1701  * the link comes up without having to go through the ioctl() API.
1702  *
1703  * @param ocs Pointer to device context.
1704  * @param wwnn World wide node name (may be zero for auto-select).
1705  * @param wwpn World wide port name (may be zero for auto-select).
1706  * @param fc_id Requested port ID (used in fabric emulation mode).
1707  * @param enable_ini TRUE if vport is to be an initiator port.
1708  * @param enable_tgt TRUE if vport is to be a target port.
1709  * @param tgt_data Pointer to target specific data.
1710  * @param ini_data Pointer to initiator specific data.
1711  *
1712  * @return None.
1713  */
1714 
1715 int8_t
1716 ocs_vport_create_spec(ocs_t *ocs, uint64_t wwnn, uint64_t wwpn, uint32_t fc_id, uint32_t enable_ini, uint32_t enable_tgt, void *tgt_data, void *ini_data)
1717 {
1718  ocs_xport_t *xport = ocs->xport;
1719  ocs_vport_spec_t *vport;
1720 
1721  /* walk the ocs_vport_list and return failure if a valid(vport with non zero WWPN and WWNN) vport entry
1722  is already created */
1723  ocs_list_foreach(&xport->vport_list, vport) {
1724  if ((wwpn && (vport->wwpn == wwpn)) && (wwnn && (vport->wwnn == wwnn))) {
1725  ocs_log_test(ocs, "Failed: VPORT %016" PRIx64 " %016" PRIx64 " already allocated\n",
1726  wwnn, wwpn);
1727  return -1;
1728  }
1729  }
1730 
1731  vport = ocs_malloc(ocs, sizeof(*vport), OCS_M_ZERO | OCS_M_NOWAIT);
1732  if (vport == NULL) {
1733  ocs_log_err(ocs, "ocs_malloc failed\n");
1734  return -1;
1735  }
1736 
1737  vport->wwnn = wwnn;
1738  vport->wwpn = wwpn;
1739  vport->fc_id = fc_id;
1740  vport->domain_instance = 0; //TODO: may need to change this
1741  vport->enable_tgt = enable_tgt;
1742  vport->enable_ini = enable_ini;
1743  vport->tgt_data = tgt_data;
1744  vport->ini_data = ini_data;
1745 
1746  ocs_device_lock(ocs);
1747  ocs_list_add_tail(&xport->vport_list, vport);
1748  ocs_device_unlock(ocs);
1749  return 0;
1750 }
1751 
1752 /* node group api */
1753 
1754 /**
1755  * @brief Perform the AND operation on source vectors.
1756  *
1757  * @par Description
1758  * Performs an AND operation on the 8-bit values in source vectors @c b and @c c.
1759  * The resulting value is stored in @c a.
1760  *
1761  * @param a Destination-byte vector.
1762  * @param b Source-byte vector.
1763  * @param c Source-byte vector.
1764  * @param n Byte count.
1765  *
1766  * @return None.
1767  */
1768 
1769 static void
1770 and8(uint8_t *a, uint8_t *b, uint8_t *c, uint32_t n)
1771 {
1772  uint32_t i;
1773 
1774  for (i = 0; i < n; i ++) {
1775  *a = *b & *c;
1776  a++;
1777  b++;
1778  c++;
1779  }
1780 }
1781 
1782 /**
1783  * @brief Service parameters mask data.
1784  */
1786  0, //uint32_t command_code: 8,
1787  0, // resv1: 24;
1788  {~0, ~0, ~0, ~0}, // uint32_t common_service_parameters[4];
1789  0, // uint32_t port_name_hi;
1790  0, // uint32_t port_name_lo;
1791  0, // uint32_t node_name_hi;
1792  0, // uint32_t node_name_lo;
1793  {~0, ~0, ~0, ~0}, // uint32_t class1_service_parameters[4];
1794  {~0, ~0, ~0, ~0}, // uint32_t class2_service_parameters[4];
1795  {~0, ~0, ~0, ~0}, // uint32_t class3_service_parameters[4];
1796  {~0, ~0, ~0, ~0}, // uint32_t class4_service_parameters[4];
1797  {~0, ~0, ~0, ~0}}; // uint32_t vendor_version_level[4];
1798 
1799 /**
1800  * @brief Compare service parameters.
1801  *
1802  * @par Description
1803  * Returns 0 if the two service parameters are the same, excluding the port/node name
1804  * elements.
1805  *
1806  * @param sp1 Pointer to service parameters 1.
1807  * @param sp2 Pointer to service parameters 2.
1808  *
1809  * @return Returns 0 if parameters match; otherwise, returns a positive or negative value,
1810  * depending on the arithmetic magnitude of the first mismatching byte.
1811  */
1812 
1813 int
1814 ocs_sparm_cmp(uint8_t *sp1, uint8_t *sp2)
1815 {
1816  int i;
1817  int v;
1818  uint8_t *sp3 = (uint8_t*) &sparms_cmp_mask;
1819 
1820  for (i = 0; i < OCS_SERVICE_PARMS_LENGTH; i ++) {
1821  v = ((int)(sp1[i] & sp3[i])) - ((int)(sp2[i] & sp3[i]));
1822  if (v) {
1823  break;
1824  }
1825  }
1826  return v;
1827 }
1828 
1829 /**
1830  * @brief Allocate a node group directory entry.
1831  *
1832  * @par Description
1833  * A node group directory entry is allocated, initialized, and added to the sport's
1834  * node group directory list.
1835  *
1836  * @param sport Pointer to the sport object.
1837  * @param sparms Pointer to the service parameters.
1838  *
1839  * @return Returns a pointer to the allocated ocs_node_group_dir_t; or NULL.
1840  */
1841 
1842 ocs_node_group_dir_t *
1843 ocs_node_group_dir_alloc(ocs_sport_t *sport, uint8_t *sparms)
1844 {
1845  ocs_node_group_dir_t *node_group_dir;
1846 
1847  node_group_dir = ocs_malloc(sport->ocs, sizeof(*node_group_dir), OCS_M_ZERO | OCS_M_NOWAIT);
1848  if (node_group_dir != NULL) {
1849  node_group_dir->sport = sport;
1850 
1851  ocs_lock(&sport->node_group_lock);
1852  node_group_dir->instance_index = sport->node_group_dir_next_instance++;
1853  and8(node_group_dir->service_params, sparms, (uint8_t*)&sparms_cmp_mask, OCS_SERVICE_PARMS_LENGTH);
1854  ocs_list_init(&node_group_dir->node_group_list, ocs_remote_node_group_t, link);
1855 
1856  node_group_dir->node_group_list_count = 0;
1857  node_group_dir->next_idx = 0;
1858  ocs_list_add_tail(&sport->node_group_dir_list, node_group_dir);
1859  ocs_unlock(&sport->node_group_lock);
1860 
1861  ocs_log_debug(sport->ocs, "[%s] [%d] allocating node group directory\n", sport->display_name,
1862  node_group_dir->instance_index);
1863  }
1864  return node_group_dir;
1865 }
1866 
1867 /**
1868  * @brief Free a node group directory entry.
1869  *
1870  * @par Description
1871  * The node group directory entry @c node_group_dir is removed
1872  * from the sport's node group directory list and freed.
1873  *
1874  * @param node_group_dir Pointer to the node group directory entry.
1875  *
1876  * @return None.
1877  */
1878 
1879 void
1880 ocs_node_group_dir_free(ocs_node_group_dir_t *node_group_dir)
1881 {
1882  ocs_sport_t *sport;
1883  if (node_group_dir != NULL) {
1884  sport = node_group_dir->sport;
1885  ocs_log_debug(sport->ocs, "[%s] [%d] freeing node group directory\n", sport->display_name,
1886  node_group_dir->instance_index);
1887  ocs_lock(&sport->node_group_lock);
1888  if (!ocs_list_empty(&node_group_dir->node_group_list)) {
1889  ocs_log_test(sport->ocs, "[%s] WARNING: node group list not empty\n", sport->display_name);
1890  }
1891  ocs_list_remove(&sport->node_group_dir_list, node_group_dir);
1892  ocs_unlock(&sport->node_group_lock);
1893  ocs_free(sport->ocs, node_group_dir, sizeof(*node_group_dir));
1894  }
1895 }
1896 
1897 /**
1898  * @brief Find a matching node group directory entry.
1899  *
1900  * @par Description
1901  * The sport's node group directory list is searched for a matching set of
1902  * service parameters. The first matching entry is returned; otherwise
1903  * NULL is returned.
1904  *
1905  * @param sport Pointer to the sport object.
1906  * @param sparms Pointer to the sparams to match.
1907  *
1908  * @return Returns a pointer to the first matching entry found; or NULL.
1909  */
1910 
1911 ocs_node_group_dir_t *
1912 ocs_node_group_dir_find(ocs_sport_t *sport, uint8_t *sparms)
1913 {
1914  ocs_node_group_dir_t *node_dir = NULL;
1915 
1916  ocs_lock(&sport->node_group_lock);
1917  ocs_list_foreach(&sport->node_group_dir_list, node_dir) {
1918  if (ocs_sparm_cmp(sparms, node_dir->service_params) == 0) {
1919  ocs_unlock(&sport->node_group_lock);
1920  return node_dir;
1921  }
1922  }
1923  ocs_unlock(&sport->node_group_lock);
1924  return NULL;
1925 }
1926 
1927 /**
1928  * @brief Allocate a remote node group object.
1929  *
1930  * @par Description
1931  * A remote node group object is allocated, initialized, and placed on the node group
1932  * list of @c node_group_dir. The HAL remote node group @b alloc function is called.
1933  *
1934  * @param node_group_dir Pointer to the node group directory.
1935  *
1936  * @return Returns a pointer to the allocated remote node group object; or NULL.
1937  */
1938 
1939 ocs_remote_node_group_t *
1940 ocs_remote_node_group_alloc(ocs_node_group_dir_t *node_group_dir)
1941 {
1942  ocs_t *ocs;
1943  ocs_sport_t *sport;
1944  ocs_remote_node_group_t *node_group;
1945  ocs_hal_rtn_e hrc;
1946 
1947  ocs_assert(node_group_dir, NULL);
1948  ocs_assert(node_group_dir->sport, NULL);
1949  ocs_assert(node_group_dir->sport->ocs, NULL);
1950 
1951  sport = node_group_dir->sport;
1952  ocs = sport->ocs;
1953 
1954 
1955  node_group = ocs_malloc(ocs, sizeof(*node_group), OCS_M_ZERO | OCS_M_NOWAIT);
1956  if (node_group != NULL) {
1957 
1958  /* set pointer to node group directory */
1959  node_group->node_group_dir = node_group_dir;
1960 
1961  /* invoke HAL node group inialization */
1962  hrc = ocs_hal_node_group_alloc(&ocs->hal, node_group);
1963  if (hrc != OCS_HAL_RTN_SUCCESS) {
1964  ocs_log_err(ocs, "ocs_hal_node_group_alloc() failed: %d\n", hrc);
1965  ocs_free(ocs, node_group, sizeof(*node_group));
1966  return NULL;
1967  }
1968 
1969  /* add to the node group directory entry node group list */
1970  ocs_lock(&node_group_dir->sport->node_group_lock);
1971  node_group->instance_index = sport->node_group_next_instance++;
1972  ocs_list_add_tail(&node_group_dir->node_group_list, node_group);
1973  node_group_dir->node_group_list_count ++;
1974  ocs_unlock(&node_group_dir->sport->node_group_lock);
1975 
1976  ocs_log_debug(ocs, "[%s] [%d] indicator x%03x allocating node group\n", sport->display_name,
1977  node_group->indicator, node_group->instance_index);
1978  }
1979  return node_group;
1980 }
1981 
1982 /**
1983  * @brief Free a remote node group object.
1984  *
1985  * @par Description
1986  * The remote node group object @c node_group is removed from its
1987  * node group directory entry and freed.
1988  *
1989  * @param node_group Pointer to the remote node group object.
1990  *
1991  * @return None.
1992  */
1993 
1994 void
1995 ocs_remote_node_group_free(ocs_remote_node_group_t *node_group)
1996 {
1997  ocs_sport_t *sport;
1998  ocs_t *ocs;
1999  ocs_node_group_dir_t *node_group_dir;
2000 
2001  if (node_group != NULL) {
2002  node_group_dir = node_group->node_group_dir;
2003  ocs_assert(node_group->node_group_dir);
2004 
2005  sport = node_group_dir->sport;
2006  ocs_assert(sport);
2007 
2008  ocs = sport->ocs;
2009  ocs_assert(ocs);
2010 
2011  ocs_log_debug(ocs, "[%s] [%d] indicator x%03x freeing node group\n",
2012  sport->display_name, node_group->indicator, node_group->instance_index);
2013 
2014  /* Remove from node group directory node group list */
2015  ocs_lock(&sport->node_group_lock);
2016  ocs_list_remove(&node_group_dir->node_group_list, node_group);
2017  node_group_dir->node_group_list_count --;
2018 //TODO: note that we're going to have the node_group_dir entry persist forever ... we could delete it if
2019 // the group_list_count goes to zero (or the linked list is empty
2020  ocs_unlock(&sport->node_group_lock);
2021  ocs_free(sport->ocs, node_group, sizeof(*node_group));
2022  }
2023 }
2024 
2025 /**
2026  * @brief Initialize a node for high login mode.
2027  *
2028  * @par Description
2029  * The @c node is initialized for high login mode. The following steps are performed:
2030  * 1. The sports node group directory is searched for a matching set of service parameters.
2031  * 2. If a matching set is not found, a node group directory entry is allocated.
2032  * 3. If less than the @c hlm_group_size number of remote node group objects is present in the
2033  * node group directory, a new remote node group object is allocated and added to the list.
2034  * 4. A remote node group object is selected, and the node is attached to the node group.
2035  *
2036  * @param node Pointer to the node.
2037  *
2038  * @return Returns 0 on success, or a negative error value on failure.
2039  */
2040 
2041 int
2042 ocs_node_group_init(ocs_node_t *node)
2043 {
2044  ocs_t *ocs;
2045  ocs_sport_t *sport;
2046  ocs_node_group_dir_t *node_group_dir;
2047  ocs_remote_node_group_t *node_group;
2048  ocs_hal_rtn_e hrc;
2049 
2050  ocs_assert(node, -1);
2051  ocs_assert(node->sport, -1);
2052  ocs_assert(node->ocs, -1);
2053 
2054  ocs = node->ocs;
2055  sport = node->sport;
2056 
2057  ocs_assert(ocs->enable_hlm, -1);
2058 
2059  /* see if there's a node group directory allocated for this service parameter set */
2060  node_group_dir = ocs_node_group_dir_find(sport, node->service_params);
2061  if (node_group_dir == NULL) {
2062  /* not found, so allocate one */
2063  node_group_dir = ocs_node_group_dir_alloc(sport, node->service_params);
2064  if (node_group_dir == NULL) {
2065  /* node group directory allocation failed ... can't continue, however,
2066  * the node will be allocated with a normal (not shared) RPI
2067  */
2068  ocs_log_err(ocs, "ocs_node_group_dir_alloc() failed\n");
2069  return -1;
2070  }
2071  }
2072 
2073  /* check to see if we've allocated hlm_group_size's worth of node group structures for this
2074  * directory entry, if not, then allocate and use a new one, otherwise pick the next one.
2075  */
2076  ocs_lock(&node->sport->node_group_lock);
2077  if (node_group_dir->node_group_list_count < ocs->hlm_group_size) {
2078  ocs_unlock(&node->sport->node_group_lock);
2079  node_group = ocs_remote_node_group_alloc(node_group_dir);
2080  if (node_group == NULL) {
2081  ocs_log_err(ocs, "ocs_remote_node_group_alloc() failed\n");
2082  return -1;
2083  }
2084  ocs_lock(&node->sport->node_group_lock);
2085  } else {
2086  uint32_t idx = 0;
2087 
2088  ocs_list_foreach(&node_group_dir->node_group_list, node_group) {
2089  if (idx >= ocs->hlm_group_size) {
2090  ocs_log_err(node->ocs, "assertion failed: idx >= ocs->hlm_group_size\n");
2091  ocs_unlock(&node->sport->node_group_lock);
2092  return -1;
2093  }
2094 
2095  if (idx == node_group_dir->next_idx) {
2096  break;
2097  }
2098  idx ++;
2099  }
2100  if (idx == ocs->hlm_group_size) {
2101  node_group = ocs_list_get_head(&node_group_dir->node_group_list);
2102  }
2103  if (++node_group_dir->next_idx >= node_group_dir->node_group_list_count) {
2104  node_group_dir->next_idx = 0;
2105  }
2106  }
2107  ocs_unlock(&node->sport->node_group_lock);
2108 
2109  /* Initialize a pointer in the node back to the node group */
2110  node->node_group = node_group;
2111 
2112  /* Join this node into the group */
2113  hrc = ocs_hal_node_group_attach(&ocs->hal, node_group, &node->rnode);
2114 
2115  return (hrc == OCS_HAL_RTN_SUCCESS) ? 0 : -1;
2116 }
2117 
2118 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
2119 
2120 /**
2121  * @ingroup ocs recovery
2122  * @brief Shutdown all remote nodes of sport
2123  */
2124 void ocs_sport_nodes_shutdown(ocs_t *ocs, ocs_sport_t *sport)
2125 {
2126  ocs_node_t *node;
2127  ocs_node_t *node_next;
2128 
2129  if (sport == NULL)
2130  return;
2131 
2132  /*
2133  * Read number of sessions logged in to sport and
2134  * use this reference to wait for all the sessions to be shutdown.
2135  */
2136  ocs_scsi_tgt_count_sessions(ocs, sport->wwpn);
2137 
2138  /* Shutdown all the sessions */
2139  ocs_sport_lock(sport);
2140  ocs_list_foreach_safe(&sport->node_list, node, node_next) {
2141  if (node->rnode.fc_id != FC_ADDR_FABRIC) {
2143  }
2144  }
2145  ocs_sport_unlock(sport);
2146 
2147  /* Wait for all initiators are shutdown completely */
2149 }
2150 
2151 #endif
ocs_sport_t * ocs_sport_get_instance(ocs_domain_t *domain, uint32_t index)
Return a SLI port object, given an instance index.
Definition: ocs_sport.c:336
static void _ocs_sport_free(void *arg)
Free a SLI port object.
Definition: ocs_sport.c:222
ocs_sport_t * ocs_sport_find(ocs_domain_t *domain, uint32_t d_id)
Find a SLI port object, given an FC_ID.
Definition: ocs_sport.c:365
ocs_sport_exec_arg_t * sport_exec_args
Definition: ocs_sport.c:1455
int32_t ocs_sport_vport_del(ocs_t *ocs, ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn)
Remove a previously-allocated virtual port.
Definition: ocs_sport.c:1115
#define std_sport_state_decl()
Common SLI port state machine declarations and initialization.
Definition: ocs_sport.c:456
void ocs_mgmt_sport_exec_cb(ocs_sport_t *sport, void *)
Definition: ocs_sport.c:1608
#define enable_target_rscn(ocs)
int parse_wwn(char *wwn_in, uint64_t *wwn_out)
parse a WWN from a string into a 64-bit value
Definition: ocs_mgmt.c:3047
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
void ocs_sport_free(ocs_sport_t *sport)
Definition: ocs_sport.c:280
int ocs_mgmt_sport_set(char *parent, char *name, char *value, void *sport)
Definition: ocs_sport.c:1420
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
static void ocs_vport_update_spec(ocs_sport_t *sport)
Save the virtual port&#39;s parameters.
Definition: ocs_sport.c:1677
void ocs_scsi_tgt_count_sessions(ocs_t *ocs, uint64_t wwpn)
void ocs_node_force_free(ocs_node_t *node)
free memory resources of a node object
Definition: ocs_node.c:608
ocs_hal_rtn_e ocs_hal_unreg_rpi_all(ocs_hal_t *hal, ocs_sport_t *sport)
Free all remote node objects.
Definition: ocs_hal.c:3658
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
int32_t ocs_sport_attach(ocs_sport_t *sport, uint32_t fc_id)
Request a SLI port attach.
Definition: ocs_sport.c:426
void ocs_remote_node_group_free(ocs_remote_node_group_t *node_group)
Free a remote node group object.
Definition: ocs_sport.c:1995
ocs_hal_rtn_e ocs_hal_port_attach(ocs_hal_t *hal, ocs_sli_port_t *sport, uint32_t fc_id)
Attach a physical/virtual SLI port to a domain.
Definition: ocs_hal.c:2966
int32_t ocs_scsi_tgt_new_sport(ocs_sport_t *sport)
Accept a new SLI Port notification.
Definition: ocs_ramd.c:924
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
ocs_hal_rtn_e ocs_hal_node_group_attach(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup, ocs_remote_node_t *rnode)
Definition: ocs_hal.c:3714
#define FC_GS_FDMI_GHAT
Definition: ocs_fcp.h:107
#define FC_GS_FDMI_GRHL
Definition: ocs_fcp.h:106
int ocs_fdmi_get_cmd(ocs_sport_t *sport, els_cb_t cb, void *cb_arg, ocs_fdmi_get_cmd_req_info_t *fdmi_cmd_req)
Definition: ocs_fabric.c:3700
ocs_hal_port_event_e
Definition: ocs_hal.h:676
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
void ocs_mgmt_sport_get_all(ocs_textbuf_t *textbuf, void *sport)
Definition: ocs_sport.c:1388
ocs_node_group_dir_t * ocs_node_group_dir_alloc(ocs_sport_t *sport, uint8_t *sparms)
Allocate a node group directory entry.
Definition: ocs_sport.c:1843
int32_t ocs_port_cb(void *arg, ocs_hal_port_event_e event, void *data)
SLI port HAL callback.
Definition: ocs_sport.c:88
static void ocs_device_lock(ocs_t *ocs)
Definition: ocs_drv_fc.h:218
const char * name
Definition: ocs_ddump.h:54
void ocs_sport_force_free(ocs_sport_t *sport)
Free memory resources of a SLI port object.
Definition: ocs_sport.c:299
int ocs_ddump_sport(ocs_textbuf_t *textbuf, ocs_sli_port_t *sport)
Generate a SLI port ddump.
Definition: ocs_sport.c:1203
void ocs_vport_del_all(ocs_t *ocs)
Force free all saved vports.
Definition: ocs_sport.c:1175
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
static ocs_mgmt_functions_t sport_mgmt_functions
Definition: ocs_sport.c:60
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_sport_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Attached.
Definition: ocs_sport.c:807
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
void * __ocs_d_wait_logo_rsp(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Device node state machine: Wait for the LOGO response.
Definition: ocs_device.c:668
void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section start data.
Definition: ocs_ddumplib.c:90
void ocs_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_group_dir_free(ocs_node_group_dir_t *node_group_dir)
Free a node group directory entry.
Definition: ocs_sport.c:1880
static void ocs_domain_unlock(ocs_domain_t *domain)
Definition: ocs_domain.h:70
static void ocs_sport_lock_free(ocs_sport_t *sport)
Definition: ocs_sport.h:55
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
void * __ocs_sport_vport_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Handle initial virtual port events.
Definition: ocs_sport.c:645
int ocs_sparm_cmp(uint8_t *sp1, uint8_t *sp2)
Compare service parameters.
Definition: ocs_sport.c:1814
static int32_t ocs_sport_fdmi_get_cmd(ocs_sport_t *sport, ocs_sport_exec_arg_t *sport_exec_args, uint32_t fdmi_cmd_code)
send FDMI get command.
Definition: ocs_sport.c:1520
ocs_remote_node_group_t * ocs_remote_node_group_alloc(ocs_node_group_dir_t *node_group_dir)
Allocate a remote node group object.
Definition: ocs_sport.c:1940
int ocs_domain_post_event(ocs_domain_t *domain, ocs_sm_event_t event, void *arg)
Definition: ocs_domain.c:1307
int ocs_mgmt_sport_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length, void *object)
Definition: ocs_sport.c:1620
void ocs_scsi_tgt_del_sport(ocs_sport_t *sport)
Accept a SLI Port gone notification.
Definition: ocs_ramd.c:974
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
#define OCS_SERVICE_PARMS_LENGTH
Definition: ocs_common.h:48
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
int32_t ocs_process_fdmi_grpl_payload(ocs_node_t *node, fcct_fdmi_grpl_rsp_t *grpl, uint32_t grpl_len, void *buf)
Process the GRPL acc payload.
Definition: ocs_fabric.c:2372
void ocs_node_update_display_name(ocs_node_t *node)
update the node&#39;s display name
Definition: ocs_node.c:755
void ocs_scsi_ini_del_sport(ocs_sport_t *sport)
Definition: ocs_ini_stub.c:209
uint32_t node_name_lo
Definition: ocs_fcp.h:327
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
static void ocs_device_unlock(ocs_t *ocs)
Definition: ocs_drv_fc.h:223
void * __ocs_vport_fabric_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
Fabric node state machine: Initial state for a virtual port.
Definition: ocs_fabric.c:289
int32_t ocs_process_fdmi_ghat_payload(ocs_node_t *node, fcct_fdmi_ghat_rsp_t *ghat, uint32_t ghat_len, void *buf)
Process the GHAT acc payload.
Definition: ocs_fabric.c:2423
ocs_hal_rtn_e ocs_hal_port_free(ocs_hal_t *hal, ocs_sli_port_t *sport)
Free port resources.
Definition: ocs_hal.c:3172
int32_t ocs_sport_vport_new(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id, uint8_t ini, uint8_t tgt, void *tgt_data, void *ini_data, uint8_t restore_vport)
Allocate a new virtual SLI port.
Definition: ocs_sport.c:1057
uint32_t port_name_lo
Definition: ocs_fcp.h:325
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(* exec_cb)(ocs_domain_t *, void *arg)
Definition: ocs_common.h:260
void * __ocs_sport_vport_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Wait for the HAL SLI port allocation to complete.
Definition: ocs_sport.c:696
int ocs_mgmt_sport_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *sport)
Definition: ocs_sport.c:1314
uint32_t port_name_hi
Definition: ocs_fcp.h:324
ocs_hal_rtn_e ocs_hal_port_alloc(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain, uint8_t *wwpn)
Allocate a port object.
Definition: ocs_hal.c:2882
void ocs_sm_transition(ocs_sm_ctx_t *ctx, ocs_sm_function_t state, void *data)
Transition to a new state.
Definition: ocs_sm.c:72
ocs_sport_t * ocs_sport_alloc(ocs_domain_t *domain, uint64_t wwpn, uint64_t wwnn, uint32_t fc_id, uint8_t enable_ini, uint8_t enable_tgt)
Allocate a SLI port object.
Definition: ocs_sport.c:144
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_sport.h:67
void ocs_mgmt_sport_list(ocs_textbuf_t *textbuf, void *sport)
Definition: ocs_sport.c:1276
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
int32_t ocs_process_fdmi_gpat_payload(ocs_node_t *node, fcct_fdmi_gpat_rsp_t *gpat, uint32_t gpat_len, void *buf)
Process the GPAT acc payload.
Definition: ocs_fabric.c:2599
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
ocs_mgmt_get_list_handler get_list_handler
Definition: ocs_mgmt.h:83
int32_t ocs_scsi_ini_new_sport(ocs_sport_t *sport)
Definition: ocs_ini_stub.c:203
int8_t ocs_vport_create_spec(ocs_t *ocs, uint64_t wwnn, uint64_t wwpn, uint32_t fc_id, uint32_t enable_ini, uint32_t enable_tgt, void *tgt_data, void *ini_data)
Create a saved vport entry.
Definition: ocs_sport.c:1716
static void ocs_scsi_notify_sport_force_free(ocs_sport_t *sport)
Notification from base driver that sport is in force-free path.
#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_sport_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Common event handler.
Definition: ocs_sport.c:495
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
void * __ocs_sport_vport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: virtual sport allocated.
Definition: ocs_sport.c:762
void * __ocs_sport_wait_port_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Wait for the HAL&#39;s port free to complete.
Definition: ocs_sport.c:934
static void ocs_fdmi_get_cmd_cb(ocs_node_t *node, ocs_node_cb_t *node_data, void *cb_data)
Definition: ocs_sport.c:1459
#define FC_GS_FDMI_GRPL
Definition: ocs_fcp.h:108
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
static void ocs_sport_lock_init(ocs_sport_t *sport)
Definition: ocs_sport.h:50
#define OCS_CTRLMASK_INHIBIT_INITIATOR
void * __ocs_sport_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Wait for the node shutdowns to complete.
Definition: ocs_sport.c:886
int32_t ocs_vport_start(ocs_domain_t *domain)
Start the vports on a domain.
Definition: ocs_sport.c:969
int ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node)
Generate node ddump data.
Definition: ocs_node.c:1636
static int32_t ocs_sport_lock_try(ocs_sport_t *sport)
Definition: ocs_sport.h:60
static void ocs_domain_lock(ocs_domain_t *domain)
Definition: ocs_domain.h:63
sparse_vector_t spv_new(ocs_os_handle_t os)
Instantiate a new sparse vector object.
Definition: spv.c:173
#define FC_GS_FDMI_GPAT
Definition: ocs_fcp.h:109
ocs_hal_rtn_e ocs_hal_node_group_alloc(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup)
Definition: ocs_hal.c:3694
ocs_node_group_dir_t * ocs_node_group_dir_find(ocs_sport_t *sport, uint8_t *sparms)
Find a matching node group directory entry.
Definition: ocs_sport.c:1912
void * __ocs_sport_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
SLI port state machine: Physical sport allocated.
Definition: ocs_sport.c:607
static void and8(uint8_t *a, uint8_t *b, uint8_t *c, uint32_t n)
Perform the AND operation on source vectors.
Definition: ocs_sport.c:1770
void ocs_scsi_tgt_sess_del_wait(ocs_sport_t *sport)
#define node_printf(node, fmt,...)
Definition: ocs_node.h:48
void(* exec_cb)(ocs_sport_t *sport, void *arg)
Definition: ocs_common.h:270
void spv_del(sparse_vector_t spv)
Delete a sparse vector.
Definition: spv.c:153
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
ocs_sm_event_t
Definition: ocs_sm.h:60
ocs_io_t * ocs_send_logo(ocs_node_t *node, uint32_t timeout_sec, uint32_t retries, els_cb_t cb, void *cbarg)
Send a LOGO ELS command.
Definition: ocs_els.c:1021
#define sport_sm_trace(sport)
Common SLI port state machine trace logging.
Definition: ocs_sport.c:473
ocs_domain_exec_arg_t * domain_exec_args
Definition: ocs_common.h:269
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.
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
void ocs_sport_nodes_shutdown(ocs_t *ocs, ocs_sport_t *sport)
Shutdown all remote nodes of sport.
Definition: ocs_sport.c:2124
ocs_sport_t * ocs_sport_find_wwn(ocs_domain_t *domain, uint64_t wwnn, uint64_t wwpn)
Find a SLI port, given the WWNN and WWPN.
Definition: ocs_sport.c:397
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
void ocs_sm_disable(ocs_sm_ctx_t *ctx)
Disable further state machine processing.
Definition: ocs_sm.c:87
static fc_sparms_t sparms_cmp_mask
Service parameters mask data.
Definition: ocs_sport.c:1785
uint32_t arg_in_length
Definition: ocs_common.h:265
static void ocs_vport_link_down(ocs_sport_t *sport)
Clear the sport reference in the vport specification.
Definition: ocs_sport.c:1017
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_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
void spv_set(sparse_vector_t sv, uint32_t idx, void *value)
Set the sparse vector cell value.
Definition: spv.c:258
#define OCS_FC_ELS_SEND_DEFAULT_TIMEOUT
Definition: ocs_fc_config.h:77
int32_t ocs_process_fdmi_grhl_payload(ocs_node_t *node, fcct_fdmi_grhl_rsp_t *grhl, uint32_t grhl_len, void *buf)
Process the GRHL acc payload.
Definition: ocs_fabric.c:2322
void ocs_scsi_ini_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
Definition: ocs_ini_stub.c:266
#define FC_ADDR_FABRIC
Definition: ocs_fcp.h:61