]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ocs_fc/ocs_domain.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / sys / dev / ocs_fc / ocs_domain.c
1 /*-
2  * Copyright (c) 2017 Broadcom. All rights reserved.
3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
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  * $FreeBSD$
32  */
33
34 /**
35  * @file
36  * Handles the domain object callback from the HW.
37  */
38
39 /*!
40 @defgroup domain_sm Domain State Machine: States
41 */
42
43 #include "ocs.h"
44
45 #include "ocs_fabric.h"
46 #include "ocs_device.h"
47
48 #define domain_sm_trace(domain)  \
49         do { \
50                 if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain->ocs)) \
51                         ocs_log_info(domain->ocs, "[domain] %-20s %-20s\n", __func__, ocs_sm_event_name(evt)); \
52         } while (0)
53
54 #define domain_trace(domain, fmt, ...) \
55         do { \
56                 if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain ? domain->ocs : NULL)) \
57                         ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
58         } while (0)
59
60 #define domain_printf(domain, fmt, ...) \
61         do { \
62                 ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
63         } while (0)
64
65 void ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *domain);
66 void ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *domain);
67 int ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *domain);
68 int ocs_mgmt_domain_set(char *parent, char *name, char *value, void *domain);
69 int ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
70                 void *arg_out, uint32_t arg_out_length, void *domain);
71
72 static ocs_mgmt_functions_t domain_mgmt_functions = {
73         .get_list_handler = ocs_mgmt_domain_list,
74         .get_handler = ocs_mgmt_domain_get,
75         .get_all_handler = ocs_mgmt_domain_get_all,
76         .set_handler = ocs_mgmt_domain_set,
77         .exec_handler = ocs_mgmt_domain_exec,
78 };
79
80
81
82 /**
83  * @brief Accept domain callback events from the HW.
84  *
85  * <h3 class="desc">Description</h3>
86  * HW calls this function with various domain-related events.
87  *
88  * @param arg Application-specified argument.
89  * @param event Domain event.
90  * @param data Event specific data.
91  *
92  * @return Returns 0 on success; or a negative error value on failure.
93  */
94
95 int32_t
96 ocs_domain_cb(void *arg, ocs_hw_domain_event_e event, void *data)
97 {
98         ocs_t *ocs = arg;
99         ocs_domain_t *domain = NULL;
100         int32_t rc = 0;
101
102         ocs_assert(data, -1);
103
104         if (event != OCS_HW_DOMAIN_FOUND) {
105                 domain = data;
106         }
107
108         switch (event) {
109         case OCS_HW_DOMAIN_FOUND: {
110                 uint64_t fcf_wwn = 0;
111                 ocs_domain_record_t *drec = data;
112                 ocs_assert(drec, -1);
113
114                 /* extract the fcf_wwn */
115                 fcf_wwn = ocs_be64toh(*((uint64_t*)drec->wwn));
116
117                 /* lookup domain, or allocate a new one if one doesn't exist already */
118                 domain = ocs_domain_find(ocs, fcf_wwn);
119                 if (domain == NULL) {
120                         domain = ocs_domain_alloc(ocs, fcf_wwn);
121                         if (domain == NULL) {
122                                 ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
123                                 rc = -1;
124                                 break;
125                         }
126                         ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
127                 }
128                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FOUND, drec);
129                 break;
130         }
131
132         case OCS_HW_DOMAIN_LOST:
133                 domain_trace(domain, "OCS_HW_DOMAIN_LOST:\n");
134                 ocs_domain_hold_frames(domain);
135                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_LOST, NULL);
136                 break;
137
138         case OCS_HW_DOMAIN_ALLOC_OK: {
139                 domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_OK:\n");
140                 domain->instance_index = 0;
141                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_OK, NULL);
142                 break;
143         }
144
145         case OCS_HW_DOMAIN_ALLOC_FAIL:
146                 domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_FAIL:\n");
147                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_FAIL, NULL);
148                 break;
149
150         case OCS_HW_DOMAIN_ATTACH_OK:
151                 domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_OK:\n");
152                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
153                 break;
154
155         case OCS_HW_DOMAIN_ATTACH_FAIL:
156                 domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_FAIL:\n");
157                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_FAIL, NULL);
158                 break;
159
160         case OCS_HW_DOMAIN_FREE_OK:
161                 domain_trace(domain, "OCS_HW_DOMAIN_FREE_OK:\n");
162                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_OK, NULL);
163                 break;
164
165         case OCS_HW_DOMAIN_FREE_FAIL:
166                 domain_trace(domain, "OCS_HW_DOMAIN_FREE_FAIL:\n");
167                 ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_FAIL, NULL);
168                 break;
169
170         default:
171                 ocs_log_warn(ocs, "unsupported event %#x\n", event);
172         }
173
174         return rc;
175 }
176
177
178 /**
179  * @brief Find the domain, given its FCF_WWN.
180  *
181  * <h3 class="desc">Description</h3>
182  * Search the domain_list to find a matching domain object.
183  *
184  * @param ocs Pointer to the OCS device.
185  * @param fcf_wwn FCF WWN to find.
186  *
187  * @return Returns the pointer to the domain if found; or NULL otherwise.
188  */
189
190 ocs_domain_t *
191 ocs_domain_find(ocs_t *ocs, uint64_t fcf_wwn)
192 {
193         ocs_domain_t *domain = NULL;
194
195         /* Check to see if this domain is already allocated */
196         ocs_device_lock(ocs);
197                 ocs_list_foreach(&ocs->domain_list, domain) {
198                         if (fcf_wwn == domain->fcf_wwn) {
199                                 break;
200                         }
201                 }
202         ocs_device_unlock(ocs);
203         return domain;
204 }
205
206 /**
207  * @brief Allocate a domain object.
208  *
209  * <h3 class="desc">Description</h3>
210  * A domain object is allocated and initialized. It is associated with the
211  * \c ocs argument.
212  *
213  * @param ocs Pointer to the OCS device.
214  * @param fcf_wwn FCF WWN of the domain.
215  *
216  * @return Returns a pointer to the ocs_domain_t object; or NULL.
217  */
218
219 ocs_domain_t *
220 ocs_domain_alloc(ocs_t *ocs, uint64_t fcf_wwn)
221 {
222         ocs_domain_t *domain;
223
224         ocs_assert(ocs, NULL);
225
226         domain = ocs_malloc(ocs, sizeof(*domain), OCS_M_NOWAIT | OCS_M_ZERO);
227         if (domain) {
228
229                 domain->ocs = ocs;
230                 domain->instance_index = ocs->domain_instance_count++;
231                 domain->drvsm.app = domain;
232                 ocs_domain_lock_init(domain);
233                 ocs_lock_init(ocs, &domain->lookup_lock, "Domain lookup[%d]", domain->instance_index);
234
235                 /* Allocate a sparse vector for sport FC_ID's */
236                 domain->lookup = spv_new(ocs);
237                 if (domain->lookup == NULL) {
238                         ocs_log_err(ocs, "spv_new() failed\n");
239                         ocs_free(ocs, domain, sizeof(*domain));
240                         return NULL;
241                 }
242
243                 ocs_list_init(&domain->sport_list, ocs_sport_t, link);
244                 domain->fcf_wwn = fcf_wwn;
245                 ocs_log_debug(ocs, "Domain allocated: wwn %016" PRIX64 "\n", domain->fcf_wwn);
246                 domain->femul_enable = (ocs->ctrlmask & OCS_CTRLMASK_ENABLE_FABRIC_EMULATION) != 0;
247
248                 ocs_device_lock(ocs);
249                         /* if this is the first domain, then assign it as the "root" domain */
250                         if (ocs_list_empty(&ocs->domain_list)) {
251                                 ocs->domain = domain;
252                         }
253                         ocs_list_add_tail(&ocs->domain_list, domain);
254                 ocs_device_unlock(ocs);
255
256                 domain->mgmt_functions = &domain_mgmt_functions;
257         } else {
258                 ocs_log_err(ocs, "domain allocation failed\n");
259         }
260
261
262         return domain;
263 }
264
265 /**
266  * @brief Free a domain object.
267  *
268  * <h3 class="desc">Description</h3>
269  * The domain object is freed.
270  *
271  * @param domain Domain object to free.
272  *
273  * @return None.
274  */
275
276 void
277 ocs_domain_free(ocs_domain_t *domain)
278 {
279         ocs_t *ocs;
280
281         ocs_assert(domain);
282         ocs_assert(domain->ocs);
283
284         /* Hold frames to clear the domain pointer from the xport lookup */
285         ocs_domain_hold_frames(domain);
286
287         ocs = domain->ocs;
288
289         ocs_log_debug(ocs, "Domain free: wwn %016" PRIX64 "\n", domain->fcf_wwn);
290
291         spv_del(domain->lookup);
292         domain->lookup = NULL;
293
294         ocs_device_lock(ocs);
295                 ocs_list_remove(&ocs->domain_list, domain);
296                 if (domain == ocs->domain) {
297                         /* set global domain to the new head */
298                         ocs->domain = ocs_list_get_head(&ocs->domain_list);
299                         if (ocs->domain) {
300                                 ocs_log_debug(ocs, "setting new domain, old=%p new=%p\n",
301                                                 domain, ocs->domain);
302                         }
303                 }
304
305                 if (ocs_list_empty(&ocs->domain_list) && ocs->domain_list_empty_cb ) {
306                         (*ocs->domain_list_empty_cb)(ocs, ocs->domain_list_empty_cb_arg);
307                 }
308         ocs_device_unlock(ocs);
309
310         ocs_lock_free(&domain->lookup_lock);
311
312         ocs_free(ocs, domain, sizeof(*domain));
313 }
314
315 /**
316  * @brief Free memory resources of a domain object.
317  *
318  * <h3 class="desc">Description</h3>
319  * After the domain object is freed, its child objects are also freed.
320  *
321  * @param domain Pointer to a domain object.
322  *
323  * @return None.
324  */
325
326 void
327 ocs_domain_force_free(ocs_domain_t *domain)
328 {
329         ocs_sport_t *sport;
330         ocs_sport_t *next;
331
332         /* Shutdown domain sm */
333         ocs_sm_disable(&domain->drvsm);
334
335         ocs_scsi_notify_domain_force_free(domain);
336
337         ocs_domain_lock(domain);
338                 ocs_list_foreach_safe(&domain->sport_list, sport, next) {
339                         ocs_sport_force_free(sport);
340                 }
341         ocs_domain_unlock(domain);
342         ocs_hw_domain_force_free(&domain->ocs->hw, domain);
343         ocs_domain_free(domain);
344 }
345
346 /**
347  * @brief Register a callback when the domain_list goes empty.
348  *
349  * <h3 class="desc">Description</h3>
350  * A function callback may be registered when the domain_list goes empty.
351  *
352  * @param ocs Pointer to a device object.
353  * @param callback Callback function.
354  * @param arg Callback argument.
355  *
356  * @return None.
357  */
358
359 void
360 ocs_register_domain_list_empty_cb(ocs_t *ocs, void (*callback)(ocs_t *ocs, void *arg), void *arg)
361 {
362         ocs_device_lock(ocs);
363                 ocs->domain_list_empty_cb = callback;
364                 ocs->domain_list_empty_cb_arg = arg;
365                 if (ocs_list_empty(&ocs->domain_list) && callback) {
366                         (*callback)(ocs, arg);
367                 }
368         ocs_device_unlock(ocs);
369 }
370
371 /**
372  * @brief Return a pointer to the domain, given the instance index.
373  *
374  * <h3 class="desc">Description</h3>
375  * A pointer to the domain context, given by the index, is returned.
376  *
377  * @param ocs Pointer to the driver instance context.
378  * @param index Instance index.
379  *
380  * @return Returns a pointer to the domain; or NULL.
381  */
382
383 ocs_domain_t *
384 ocs_domain_get_instance(ocs_t *ocs, uint32_t index)
385 {
386         ocs_domain_t *domain = NULL;
387
388         if (index >= OCS_MAX_DOMAINS) {
389                 ocs_log_err(ocs, "invalid index: %d\n", index);
390                 return NULL;
391         }
392         ocs_device_lock(ocs);
393                 ocs_list_foreach(&ocs->domain_list, domain) {
394                         if (domain->instance_index == index) {
395                                 break;
396                         }
397                 }
398         ocs_device_unlock(ocs);
399         return domain;
400 }
401
402 /**
403  * @ingroup domain_sm
404  * @brief Domain state machine: Common event handler.
405  *
406  * <h3 class="desc">Description</h3>
407  * Common/shared events are handled here for the domain state machine.
408  *
409  * @param funcname Function name text.
410  * @param ctx Domain state machine context.
411  * @param evt Event to process.
412  * @param arg Per event optional argument.
413  *
414  * @return Returns NULL.
415  */
416
417 static void *
418 __ocs_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
419 {
420         ocs_domain_t *domain = ctx->app;
421
422         switch(evt) {
423         case OCS_EVT_ENTER:
424         case OCS_EVT_REENTER:
425         case OCS_EVT_EXIT:
426         case OCS_EVT_ALL_CHILD_NODES_FREE:
427                 /* this can arise if an FLOGI fails on the SPORT, and the SPORT is shutdown */
428                 break;
429         default:
430                 ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
431                 break;
432         }
433
434         return NULL;
435 }
436
437 /**
438  * @ingroup domain_sm
439  * @brief Domain state machine: Common shutdown.
440  *
441  * <h3 class="desc">Description</h3>
442  * Handles common shutdown events.
443  *
444  * @param funcname Function name text.
445  * @param ctx Remote node state machine context.
446  * @param evt Event to process.
447  * @param arg Per event optional argument.
448  *
449  * @return Returns NULL.
450  */
451
452 static void *
453 __ocs_domain_common_shutdown(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
454 {
455         ocs_domain_t *domain = ctx->app;
456
457         switch(evt) {
458         case OCS_EVT_ENTER:
459         case OCS_EVT_REENTER:
460         case OCS_EVT_EXIT:
461                 break;
462         case OCS_EVT_DOMAIN_FOUND:
463                 ocs_assert(arg, NULL);
464                 /* sm: / save drec, mark domain_found_pending */
465                 ocs_memcpy(&domain->pending_drec, arg, sizeof(domain->pending_drec));
466                 domain->domain_found_pending = TRUE;
467                 break;
468         case OCS_EVT_DOMAIN_LOST: 
469                 /* clear drec available
470                  * sm: unmark domain_found_pending */
471                 domain->domain_found_pending = FALSE;
472                 break;
473
474         default:
475                 ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
476                 break;
477         }
478
479         return NULL;
480 }
481
482 #define std_domain_state_decl(...) \
483         ocs_domain_t *domain = NULL; \
484         ocs_t *ocs = NULL; \
485         \
486         ocs_assert(ctx, NULL); \
487         ocs_assert(ctx->app, NULL); \
488         domain = ctx->app; \
489         ocs_assert(domain->ocs, NULL); \
490         ocs = domain->ocs; \
491         ocs_assert(ocs->xport, NULL);
492
493 /**
494  * @ingroup domain_sm
495  * @brief Domain state machine: Initial state.
496  *
497  * <h3 class="desc">Description</h3>
498  * The initial state for a domain. Each domain is initialized to
499  * this state at start of day (SOD).
500  *
501  * @param ctx Domain state machine context.
502  * @param evt Event to process.
503  * @param arg Per event optional argument.
504  *
505  * @return Returns NULL.
506  */
507
508 void *
509 __ocs_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
510 {
511         std_domain_state_decl();
512
513         domain_sm_trace(domain);
514
515         switch(evt) {
516         case OCS_EVT_ENTER:
517                 domain->attached = 0;
518                 break;
519
520         case OCS_EVT_DOMAIN_FOUND: {
521                 int32_t         vlan = 0;
522                 uint32_t        i;
523                 ocs_domain_record_t *drec = arg;
524                 ocs_sport_t *sport;
525
526                 uint64_t        my_wwnn = ocs->xport->req_wwnn;
527                 uint64_t        my_wwpn = ocs->xport->req_wwpn;
528                 uint64_t        be_wwpn;
529
530                 /* For now, user must specify both port name and node name, or we let firmware
531                  * pick both (same as for vports).
532                  * TODO: do we want to allow setting only port name or only node name?
533                  */
534                 if ((my_wwpn == 0) || (my_wwnn == 0)) {
535                         ocs_log_debug(ocs, "using default hardware WWN configuration \n");
536                         my_wwpn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_PORT);
537                         my_wwnn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_NODE);
538                 }
539
540                 ocs_log_debug(ocs, "Creating base sport using WWPN %016" PRIx64 " WWNN %016" PRIx64 "\n",
541                         my_wwpn, my_wwnn);
542
543                 /* Allocate a sport and transition to __ocs_sport_allocated */
544                 sport = ocs_sport_alloc(domain, my_wwpn, my_wwnn, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt);
545
546                 if (sport == NULL) {
547                         ocs_log_err(ocs, "ocs_sport_alloc() failed\n");
548                         break;
549                 }
550                 ocs_sm_transition(&sport->sm, __ocs_sport_allocated, NULL);
551
552                 /* If domain is ethernet, then fetch the vlan id value */
553                 if (drec->is_ethernet) {
554                         vlan = ocs_bitmap_search((void *)drec->map.vlan, TRUE, 512 * 8);
555                         if (vlan < 0) {
556                                 ocs_log_err(ocs, "no VLAN id available (FCF=%d)\n",
557                                                 drec->index);
558                                 break;
559                         }
560                 }
561
562                 be_wwpn = ocs_htobe64(sport->wwpn);
563
564                 /* allocate ocs_sli_port_t object for local port
565                  * Note: drec->fc_id is ALPA from read_topology only if loop
566                  */
567                 if (ocs_hw_port_alloc(&ocs->hw, sport, NULL, (uint8_t *)&be_wwpn)) {
568                         ocs_log_err(ocs, "Can't allocate port\n");
569                         ocs_sport_free(sport);
570                         break;
571                 }
572
573                 /* initialize domain object */
574                 domain->is_loop = drec->is_loop;
575                 domain->is_fc = drec->is_fc;
576
577                 /*
578                  * If the loop position map includes ALPA == 0, then we are in a public loop (NL_PORT)
579                  * Note that the first element of the loopmap[] contains the count of elements, and if
580                  * ALPA == 0 is present, it will occupy the first location after the count.
581                  */
582                 domain->is_nlport = drec->map.loop[1] == 0x00;
583
584                 if (domain->is_loop) {
585                         ocs_log_debug(ocs, "%s fc_id=%#x speed=%d\n",
586                                         drec->is_loop ? (domain->is_nlport ? "public-loop" : "loop") : "other",
587                                         drec->fc_id, drec->speed);
588
589                         sport->fc_id = drec->fc_id;
590                         sport->topology = OCS_SPORT_TOPOLOGY_LOOP;
591                         ocs_snprintf(sport->display_name, sizeof(sport->display_name), "s%06x", drec->fc_id);
592
593                         if (ocs->enable_ini) {
594                                 uint32_t count = drec->map.loop[0];
595                                 ocs_log_debug(ocs, "%d position map entries\n", count);
596                                 for (i = 1; i <= count; i++) {
597                                         if (drec->map.loop[i] != drec->fc_id) {
598                                                 ocs_node_t *node;
599
600                                                 ocs_log_debug(ocs, "%#x -> %#x\n",
601                                                                 drec->fc_id, drec->map.loop[i]);
602                                                 node = ocs_node_alloc(sport, drec->map.loop[i], FALSE, TRUE);
603                                                 if (node == NULL) {
604                                                         ocs_log_err(ocs, "ocs_node_alloc() failed\n");
605                                                         break;
606                                                 }
607                                                 ocs_node_transition(node, __ocs_d_wait_loop, NULL);
608                                         }
609                                 }
610                         }
611                 }
612
613                 /* Initiate HW domain alloc */
614                 if (ocs_hw_domain_alloc(&ocs->hw, domain, drec->index, vlan)) {
615                         ocs_log_err(ocs, "Failed to initiate HW domain allocation\n");
616                         break;
617                 }
618                 ocs_sm_transition(ctx, __ocs_domain_wait_alloc, arg);
619                 break;
620         }
621         default:
622                 __ocs_domain_common(__func__, ctx, evt, arg);
623                 return NULL;
624         }
625
626         return NULL;
627 }
628
629 /**
630  * @ingroup domain_sm
631  * @brief Domain state machine: Wait for the domain allocation to complete.
632  *
633  * <h3 class="desc">Description</h3>
634  * Waits for the domain state to be allocated. After the HW domain
635  * allocation process has been initiated, this state waits for
636  * that process to complete (i.e. a domain-alloc-ok event).
637  *
638  * @param ctx Domain state machine context.
639  * @param evt Event to process.
640  * @param arg Per event optional argument.
641  *
642  * @return Returns NULL.
643  */
644
645 void *
646 __ocs_domain_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
647 {
648         ocs_sport_t *sport;
649         std_domain_state_decl();
650
651         domain_sm_trace(domain);
652
653         switch(evt) {
654         case OCS_EVT_DOMAIN_ALLOC_OK: {
655                 char prop_buf[32];
656                 uint64_t wwn_bump = 0;
657                 fc_plogi_payload_t *sp;
658
659                 if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) {
660                         wwn_bump = ocs_strtoull(prop_buf, 0, 0);
661                 }
662
663                 sport = domain->sport;
664                 ocs_assert(sport, NULL);
665                 sp = (fc_plogi_payload_t*) sport->service_params;
666
667                 /* Save the domain service parameters */
668                 ocs_memcpy(domain->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
669                 ocs_memcpy(sport->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
670
671                 /* If we're in fabric emulation mode, the flogi service parameters have not been setup yet,
672                  * so we need some reasonable BB credit value
673                  */
674                 if (domain->femul_enable) {
675                         ocs_memcpy(domain->flogi_service_params + 4, domain->service_params + 4, sizeof(fc_plogi_payload_t) - 4);
676                 }
677
678                 /* Update the sport's service parameters, user might have specified non-default names */
679                 sp->port_name_hi = ocs_htobe32((uint32_t) (sport->wwpn >> 32ll));
680                 sp->port_name_lo = ocs_htobe32((uint32_t) sport->wwpn);
681                 sp->node_name_hi = ocs_htobe32((uint32_t) (sport->wwnn >> 32ll));
682                 sp->node_name_lo = ocs_htobe32((uint32_t) sport->wwnn);
683
684                 if (wwn_bump) {
685                         sp->port_name_lo = ocs_htobe32(ocs_be32toh(sp->port_name_lo) ^ ((uint32_t)(wwn_bump)));
686                         sp->port_name_hi = ocs_htobe32(ocs_be32toh(sp->port_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
687                         sp->node_name_lo = ocs_htobe32(ocs_be32toh(sp->node_name_lo) ^ ((uint32_t)(wwn_bump)));
688                         sp->node_name_hi = ocs_htobe32(ocs_be32toh(sp->node_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
689                         ocs_log_info(ocs, "Overriding WWN\n");
690                 }
691
692                 /* Take the loop topology path, unless we are an NL_PORT (public loop) */
693                 if (domain->is_loop && !domain->is_nlport) {
694                         /*
695                          * For loop, we already have our FC ID and don't need fabric login.
696                          * Transition to the allocated state and post an event to attach to
697                          * the domain. Note that this breaks the normal action/transition
698                          * pattern here to avoid a race with the domain attach callback.
699                          */
700                         /* sm: is_loop / domain_attach */
701                         ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
702                         __ocs_domain_attach_internal(domain, sport->fc_id);
703                         break;
704                 } else {
705                         ocs_node_t *node;
706
707                         /* alloc fabric node, send FLOGI */
708                         node = ocs_node_find(sport, FC_ADDR_FABRIC);
709                         if (node) {
710                                 ocs_log_err(ocs, "Hmmmm ... Fabric Controller node already exists\n");
711                                 break;
712                         }
713                         node = ocs_node_alloc(sport, FC_ADDR_FABRIC, FALSE, FALSE);
714                         if (!node) {
715                                 ocs_log_err(ocs, "Error: ocs_node_alloc() failed\n");
716                         } else {
717                                 if (ocs->nodedb_mask & OCS_NODEDB_PAUSE_FABRIC_LOGIN) {
718                                         ocs_node_pause(node, __ocs_fabric_init);
719                                 } else {
720                                         ocs_node_transition(node, __ocs_fabric_init, NULL);
721                                 }
722                         }
723                         /* Accept frames */
724                         domain->req_accept_frames = 1;
725                 }
726                 /* sm: start fabric logins */
727                 ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
728                 break;
729         }
730
731         case OCS_EVT_DOMAIN_ALLOC_FAIL:
732                 /* TODO: hw/device reset */
733                 ocs_log_err(ocs, "%s recv'd waiting for DOMAIN_ALLOC_OK; shutting down domain\n",
734                         ocs_sm_event_name(evt));
735                 domain->req_domain_free = 1;
736                 break;
737
738         case OCS_EVT_DOMAIN_FOUND:
739                 /* Should not happen */
740                 ocs_assert(evt, NULL);
741                 break;
742
743         case OCS_EVT_DOMAIN_LOST:
744                 ocs_log_debug(ocs, "%s received while waiting for ocs_hw_domain_alloc() to complete\n", ocs_sm_event_name(evt));
745                 ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
746                 break;
747
748         default:
749                 __ocs_domain_common(__func__, ctx, evt, arg);
750                 return NULL;
751         }
752
753         return NULL;
754 }
755
756 /**
757  * @ingroup domain_sm
758  * @brief Domain state machine: Wait for the domain attach request.
759  *
760  * <h3 class="desc">Description</h3>
761  * In this state, the domain has been allocated and is waiting for a domain attach request.
762  * The attach request comes from a node instance completing the fabric login,
763  * or from a point-to-point negotiation and login.
764  *
765  * @param ctx Remote node state machine context.
766  * @param evt Event to process.
767  * @param arg Per event optional argument.
768  *
769  * @return Returns NULL.
770  */
771
772 void *
773 __ocs_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
774 {
775         int32_t rc = 0;
776         std_domain_state_decl();
777
778         domain_sm_trace(domain);
779
780         switch(evt) {
781         case OCS_EVT_DOMAIN_REQ_ATTACH: {
782                 uint32_t fc_id;
783
784                 ocs_assert(arg, NULL);
785
786                 fc_id = *((uint32_t*)arg);
787                 ocs_log_debug(ocs, "Requesting hw domain attach fc_id x%x\n", fc_id);
788                 /* Update sport lookup */
789                 ocs_lock(&domain->lookup_lock);
790                         spv_set(domain->lookup, fc_id, domain->sport);
791                 ocs_unlock(&domain->lookup_lock);
792
793                 /* Update display name for the sport */
794                 ocs_node_fcid_display(fc_id, domain->sport->display_name, sizeof(domain->sport->display_name));
795
796                 /* Issue domain attach call */
797                 rc = ocs_hw_domain_attach(&ocs->hw, domain, fc_id);
798                 if (rc) {
799                         ocs_log_err(ocs, "ocs_hw_domain_attach failed: %d\n", rc);
800                         return NULL;
801                 }
802                 /* sm: / domain_attach */
803                 ocs_sm_transition(ctx, __ocs_domain_wait_attach, NULL);
804                 break;
805         }
806
807         case OCS_EVT_DOMAIN_FOUND:
808                 /* Should not happen */
809                 ocs_assert(evt, NULL);
810                 break;
811
812         case OCS_EVT_DOMAIN_LOST: {
813                 int32_t rc;
814                 ocs_log_debug(ocs, "%s received while waiting for OCS_EVT_DOMAIN_REQ_ATTACH\n",
815                         ocs_sm_event_name(evt));
816                 ocs_domain_lock(domain);
817                 if (!ocs_list_empty(&domain->sport_list)) {
818                         /* if there are sports, transition to wait state and
819                          * send shutdown to each sport */
820                         ocs_sport_t     *sport = NULL;
821                         ocs_sport_t     *sport_next = NULL;
822                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
823                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
824                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
825                         }
826                         ocs_domain_unlock(domain);
827                 } else {
828                         ocs_domain_unlock(domain);
829                         /* no sports exist, free domain */
830                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
831                         rc = ocs_hw_domain_free(&ocs->hw, domain);
832                         if (rc) {
833                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
834                                 /* TODO: hw/device reset needed */
835                         }
836                 }
837
838                 break;
839         }
840
841         default:
842                 __ocs_domain_common(__func__, ctx, evt, arg);
843                 return NULL;
844         }
845
846         return NULL;
847 }
848
849 /**
850  * @ingroup domain_sm
851  * @brief Domain state machine: Wait for the HW domain attach to complete.
852  *
853  * <h3 class="desc">Description</h3>
854  * Waits for the HW domain attach to complete. Forwards attach ok event to the
855  * fabric node state machine.
856  *
857  * @param ctx Remote node state machine context.
858  * @param evt Event to process.
859  * @param arg Per event optional argument.
860  *
861  * @return Returns NULL.
862  */
863
864 void *
865 __ocs_domain_wait_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
866 {
867         std_domain_state_decl();
868
869         domain_sm_trace(domain);
870
871         switch(evt) {
872         case OCS_EVT_DOMAIN_ATTACH_OK: {
873                 ocs_node_t *node = NULL;
874                 ocs_node_t *next_node = NULL;
875                 ocs_sport_t *sport;
876                 ocs_sport_t *next_sport;
877
878                 /* Mark as attached */
879                 domain->attached = 1;
880
881                 /* Register with SCSI API */
882                 if (ocs->enable_tgt)
883                         ocs_scsi_tgt_new_domain(domain);
884                 if (ocs->enable_ini)
885                         ocs_scsi_ini_new_domain(domain);
886
887                 /* Transition to ready */
888                 /* sm: / forward event to all sports and nodes */
889                 ocs_sm_transition(ctx, __ocs_domain_ready, NULL);
890
891                 /* We have an FCFI, so we can accept frames */
892                 domain->req_accept_frames = 1;
893                 /* Set domain notify pending state to avoid duplicate domain event post */
894                 domain->domain_notify_pend = 1;
895
896                 /* Notify all nodes that the domain attach request has completed
897                  * Note: sport will have already received notification of sport attached
898                  * as a result of the HW's port attach.
899                  */
900                 ocs_domain_lock(domain);
901                         ocs_list_foreach_safe(&domain->sport_list, sport, next_sport) {
902                                 ocs_sport_lock(sport);
903                                         ocs_list_foreach_safe(&sport->node_list, node, next_node) {
904                                                 ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
905                                         }
906                                 ocs_sport_unlock(sport);
907                         }
908                 ocs_domain_unlock(domain);
909                 domain->domain_notify_pend = 0;
910                 break;
911         }
912
913         case OCS_EVT_DOMAIN_ATTACH_FAIL:
914                 ocs_log_debug(ocs, "%s received while waiting for hw attach to complete\n", ocs_sm_event_name(evt));
915                 /* TODO: hw/device reset */
916                 break;
917
918         case OCS_EVT_DOMAIN_FOUND:
919                 /* Should not happen */
920                 ocs_assert(evt, NULL);
921                 break;
922
923         case OCS_EVT_DOMAIN_LOST:
924                 /* Domain lost while waiting for an attach to complete, go to a state that waits for
925                  * the domain attach to complete, then handle domain lost
926                  */
927                 ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
928                 break;
929
930         case OCS_EVT_DOMAIN_REQ_ATTACH:
931                 /* In P2P we can get an attach request from the other FLOGI path, so drop this one */
932                 break;
933
934         default:
935                 __ocs_domain_common(__func__, ctx, evt, arg);
936                 return NULL;
937         }
938
939         return NULL;
940 }
941
942 /**
943  * @ingroup domain_sm
944  * @brief Domain state machine: Ready state.
945  *
946  * <h3 class="desc">Description</h3>
947  * This is a domain ready state. It waits for a domain-lost event, and initiates shutdown.
948  *
949  * @param ctx Remote node state machine context.
950  * @param evt Event to process.
951  * @param arg Per event optional argument.
952  *
953  * @return Returns NULL.
954  */
955
956 void *
957 __ocs_domain_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
958 {
959         std_domain_state_decl();
960
961         domain_sm_trace(domain);
962
963         switch(evt) {
964         case OCS_EVT_ENTER: {
965
966                 /* start any pending vports */
967                 if (ocs_vport_start(domain)) {
968                         ocs_log_debug(domain->ocs, "ocs_vport_start() did not start all vports\n");
969                 }
970                 break;
971         }
972         case OCS_EVT_DOMAIN_LOST: {
973                 int32_t rc;
974                 ocs_domain_lock(domain);
975                 if (!ocs_list_empty(&domain->sport_list)) {
976                         /* if there are sports, transition to wait state and send
977                         * shutdown to each sport */
978                         ocs_sport_t     *sport = NULL;
979                         ocs_sport_t     *sport_next = NULL;
980                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
981                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
982                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
983                         }
984                         ocs_domain_unlock(domain);
985                 } else {
986                         ocs_domain_unlock(domain);
987                         /* no sports exist, free domain */
988                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
989                         rc = ocs_hw_domain_free(&ocs->hw, domain);
990                         if (rc) {
991                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
992                                 /* TODO: hw/device reset needed */
993                         }
994                 }
995                 break;
996         }
997
998         case OCS_EVT_DOMAIN_FOUND:
999                 /* Should not happen */
1000                 ocs_assert(evt, NULL);
1001                 break;
1002
1003         case OCS_EVT_DOMAIN_REQ_ATTACH: {
1004                 /* can happen during p2p */
1005                 uint32_t fc_id;
1006
1007                 ocs_assert(arg, NULL);
1008                 fc_id = *((uint32_t*)arg);
1009
1010                 /* Assume that the domain is attached */
1011                 ocs_assert(domain->attached, NULL);
1012
1013                 /* Verify that the requested FC_ID is the same as the one we're working with */
1014                 ocs_assert(domain->sport->fc_id == fc_id, NULL);
1015                 break;
1016         }
1017
1018         default:
1019                 __ocs_domain_common(__func__, ctx, evt, arg);
1020                 return NULL;
1021         }
1022
1023         return NULL;
1024 }
1025
1026 /**
1027  * @ingroup domain_sm
1028  * @brief Domain state machine: Wait for nodes to free prior to the domain shutdown.
1029  *
1030  * <h3 class="desc">Description</h3>
1031  * All nodes are freed, and ready for a domain shutdown.
1032  *
1033  * @param ctx Remote node sm context.
1034  * @param evt Event to process.
1035  * @param arg Per event optional argument.
1036  *
1037  * @return Returns NULL.
1038  */
1039
1040 void *
1041 __ocs_domain_wait_sports_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1042 {
1043         std_domain_state_decl();
1044
1045         domain_sm_trace(domain);
1046
1047         switch(evt) {
1048         case OCS_EVT_ALL_CHILD_NODES_FREE: {
1049                 int32_t rc;
1050
1051                 /* sm: ocs_hw_domain_free */
1052                 ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
1053
1054                 /* Request ocs_hw_domain_free and wait for completion */
1055                 rc = ocs_hw_domain_free(&ocs->hw, domain);
1056                 if (rc) {
1057                         ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
1058                 }
1059                 break;
1060         }
1061         default:
1062                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
1063                 return NULL;
1064         }
1065
1066         return NULL;
1067 }
1068
1069 /**
1070  * @ingroup domain_sm
1071  * @brief Domain state machine: Complete the domain shutdown.
1072  *
1073  * <h3 class="desc">Description</h3>
1074  * Waits for a HW domain free to complete.
1075  *
1076  * @param ctx Remote node state machine context.
1077  * @param evt Event to process.
1078  * @param arg Per event optional argument.
1079  *
1080  * @return Returns NULL.
1081  */
1082
1083 void *
1084 __ocs_domain_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1085 {
1086         std_domain_state_decl();
1087
1088         domain_sm_trace(domain);
1089
1090         switch(evt) {
1091         case OCS_EVT_DOMAIN_FREE_OK: {
1092                 if (ocs->enable_ini)
1093                         ocs_scsi_ini_del_domain(domain);
1094                 if (ocs->enable_tgt)
1095                         ocs_scsi_tgt_del_domain(domain);
1096
1097                 /* sm: domain_free */
1098                 if (domain->domain_found_pending) {
1099                         /* save fcf_wwn and drec from this domain, free current domain and allocate
1100                          * a new one with the same fcf_wwn
1101                          * TODO: could use a SLI-4 "re-register VPI" operation here
1102                          */
1103                         uint64_t fcf_wwn = domain->fcf_wwn;
1104                         ocs_domain_record_t drec = domain->pending_drec;
1105
1106                         ocs_log_debug(ocs, "Reallocating domain\n");
1107                         domain->req_domain_free = 1;
1108                         domain = ocs_domain_alloc(ocs, fcf_wwn);
1109
1110                         if (domain == NULL) {
1111                                 ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
1112                                 /* TODO: hw/device reset needed */
1113                                 return NULL;
1114                         }
1115                         /*
1116                          * got a new domain; at this point, there are at least two domains
1117                          * once the req_domain_free flag is processed, the associated domain
1118                          * will be removed.
1119                          */
1120                         ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
1121                         ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_FOUND, &drec);
1122                 } else {
1123                         domain->req_domain_free = 1;
1124                 }
1125                 break;
1126         }
1127
1128         default:
1129                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
1130                 return NULL;
1131         }
1132
1133         return NULL;
1134 }
1135
1136 /**
1137  * @ingroup domain_sm
1138  * @brief Domain state machine: Wait for the domain alloc/attach completion
1139  * after receiving a domain lost.
1140  *
1141  * <h3 class="desc">Description</h3>
1142  * This state is entered when receiving a domain lost while waiting for a domain alloc
1143  * or a domain attach to complete.
1144  *
1145  * @param ctx Remote node state machine context.
1146  * @param evt Event to process.
1147  * @param arg Per event optional argument.
1148  *
1149  * @return Returns NULL.
1150  */
1151
1152 void *
1153 __ocs_domain_wait_domain_lost(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
1154 {
1155         std_domain_state_decl();
1156
1157         domain_sm_trace(domain);
1158
1159         switch(evt) {
1160         case OCS_EVT_DOMAIN_ALLOC_OK:
1161         case OCS_EVT_DOMAIN_ATTACH_OK: {
1162                 int32_t rc;
1163                 ocs_domain_lock(domain);
1164                 if (!ocs_list_empty(&domain->sport_list)) {
1165                         /* if there are sports, transition to wait state and send
1166                         * shutdown to each sport */
1167                         ocs_sport_t     *sport = NULL;
1168                         ocs_sport_t     *sport_next = NULL;
1169                         ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
1170                         ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
1171                                 ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
1172                         }
1173                         ocs_domain_unlock(domain);
1174                 } else {
1175                         ocs_domain_unlock(domain);
1176                         /* no sports exist, free domain */
1177                         ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
1178                         rc = ocs_hw_domain_free(&ocs->hw, domain);
1179                         if (rc) {
1180                                 ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
1181                                 /* TODO: hw/device reset needed */
1182                         }
1183                 }
1184                 break;
1185         }
1186         case OCS_EVT_DOMAIN_ALLOC_FAIL:
1187         case OCS_EVT_DOMAIN_ATTACH_FAIL:
1188                 ocs_log_err(ocs, "[domain] %-20s: failed\n", ocs_sm_event_name(evt));
1189                 /* TODO: hw/device reset needed */
1190                 break;
1191
1192         default:
1193                 __ocs_domain_common_shutdown(__func__, ctx, evt, arg);
1194                 return NULL;
1195         }
1196
1197         return NULL;
1198 }
1199
1200
1201
1202 /**
1203  * @brief Save the port's service parameters.
1204  *
1205  * <h3 class="desc">Description</h3>
1206  * Service parameters from the fabric FLOGI are saved in the domain's
1207  * flogi_service_params array.
1208  *
1209  * @param domain Pointer to the domain.
1210  * @param payload Service parameters to save.
1211  *
1212  * @return None.
1213  */
1214
1215 void
1216 ocs_domain_save_sparms(ocs_domain_t *domain, void *payload)
1217 {
1218         ocs_memcpy(domain->flogi_service_params, payload, sizeof (fc_plogi_payload_t));
1219 }
1220 /**
1221  * @brief Initiator domain attach. (internal call only)
1222  *
1223  * Assumes that the domain SM lock is already locked
1224  *
1225  * <h3 class="desc">Description</h3>
1226  * The HW domain attach function is started.
1227  *
1228  * @param domain Pointer to the domain object.
1229  * @param s_id FC_ID of which to register this domain.
1230  *
1231  * @return None.
1232  */
1233
1234 void
1235 __ocs_domain_attach_internal(ocs_domain_t *domain, uint32_t s_id)
1236 {
1237         ocs_memcpy(domain->dma.virt, ((uint8_t*)domain->flogi_service_params)+4, sizeof (fc_plogi_payload_t) - 4);
1238         (void)ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_REQ_ATTACH, &s_id);
1239 }
1240
1241 /**
1242  * @brief Initiator domain attach.
1243  *
1244  * <h3 class="desc">Description</h3>
1245  * The HW domain attach function is started.
1246  *
1247  * @param domain Pointer to the domain object.
1248  * @param s_id FC_ID of which to register this domain.
1249  *
1250  * @return None.
1251  */
1252
1253 void
1254 ocs_domain_attach(ocs_domain_t *domain, uint32_t s_id)
1255 {
1256         __ocs_domain_attach_internal(domain, s_id);
1257 }
1258
1259 int
1260 ocs_domain_post_event(ocs_domain_t *domain, ocs_sm_event_t event, void *arg)
1261 {
1262         int rc;
1263         int accept_frames;
1264         int req_domain_free;
1265
1266         rc = ocs_sm_post_event(&domain->drvsm, event, arg);
1267
1268         req_domain_free = domain->req_domain_free;
1269         domain->req_domain_free = 0;
1270
1271         accept_frames = domain->req_accept_frames;
1272         domain->req_accept_frames = 0;
1273
1274         if (accept_frames) {
1275                 ocs_domain_accept_frames(domain);
1276         }
1277
1278         if (req_domain_free) {
1279                 ocs_domain_free(domain);
1280         }
1281
1282         return rc;
1283 }
1284
1285
1286 /**
1287  * @brief Return the WWN as a uint64_t.
1288  *
1289  * <h3 class="desc">Description</h3>
1290  * Calls the HW property function for the WWNN or WWPN, and returns the value
1291  * as a uint64_t.
1292  *
1293  * @param hw Pointer to the HW object.
1294  * @param prop HW property.
1295  *
1296  * @return Returns uint64_t request value.
1297  */
1298
1299 uint64_t
1300 ocs_get_wwn(ocs_hw_t *hw, ocs_hw_property_e prop)
1301 {
1302         uint8_t *p = ocs_hw_get_ptr(hw, prop);
1303         uint64_t value = 0;
1304
1305         if (p) {
1306                 uint32_t i;
1307                 for (i = 0; i < sizeof(value); i++) {
1308                         value = (value << 8) | p[i];
1309                 }
1310         }
1311         return value;
1312 }
1313
1314 /**
1315  * @brief Generate a domain ddump.
1316  *
1317  * <h3 class="desc">Description</h3>
1318  * Generates a domain ddump.
1319  *
1320  * @param textbuf Pointer to the text buffer.
1321  * @param domain Pointer to the domain context.
1322  *
1323  * @return Returns 0 on success, or a negative value on failure.
1324  */
1325
1326 int
1327 ocs_ddump_domain(ocs_textbuf_t *textbuf, ocs_domain_t *domain)
1328 {
1329         ocs_sport_t *sport;
1330         int retval = 0;
1331
1332         ocs_ddump_section(textbuf, "domain", domain->instance_index);
1333         ocs_ddump_value(textbuf, "display_name", "%s", domain->display_name);
1334
1335         ocs_ddump_value(textbuf, "fcf", "%#x", domain->fcf);
1336         ocs_ddump_value(textbuf, "fcf_indicator", "%#x", domain->fcf_indicator);
1337         ocs_ddump_value(textbuf, "vlan_id", "%#x", domain->vlan_id);
1338         ocs_ddump_value(textbuf, "indicator", "%#x", domain->indicator);
1339         ocs_ddump_value(textbuf, "attached", "%d", domain->attached);
1340         ocs_ddump_value(textbuf, "is_loop", "%d", domain->is_loop);
1341         ocs_ddump_value(textbuf, "is_nlport", "%d", domain->is_nlport);
1342
1343         ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
1344         ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
1345
1346         ocs_display_sparams(NULL, "domain_sparms", 1, textbuf, domain->dma.virt);
1347
1348         if (ocs_domain_lock_try(domain) != TRUE) {
1349                 /* Didn't get the lock */
1350                 return -1;
1351         }
1352                 ocs_list_foreach(&domain->sport_list, sport) {
1353                         retval = ocs_ddump_sport(textbuf, sport);
1354                         if (retval != 0) {
1355                                 break;
1356                         }
1357                 }
1358
1359 #if defined(ENABLE_FABRIC_EMULATION)
1360                 ocs_ddump_ns(textbuf, domain->ocs_ns);
1361 #endif
1362
1363         ocs_domain_unlock(domain);
1364
1365         ocs_ddump_endsection(textbuf, "domain", domain->instance_index);
1366
1367         return retval;
1368 }
1369
1370
1371 void
1372 ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *object)
1373 {
1374         ocs_sport_t *sport;
1375         ocs_domain_t *domain = (ocs_domain_t *)object;
1376
1377         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
1378
1379         /* Add my status values to textbuf */
1380         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf");
1381         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf_indicator");
1382         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "vlan_id");
1383         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
1384         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached");
1385         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_loop");
1386         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
1387         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "num_sports");
1388 #if defined(ENABLE_FABRIC_EMULATION)
1389         ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RW, "femul_enable");
1390 #endif
1391
1392         if (ocs_domain_lock_try(domain) == TRUE) {
1393
1394
1395                 /* If we get here, then we are holding the domain lock */
1396                 ocs_list_foreach(&domain->sport_list, sport) {
1397                         if ((sport->mgmt_functions) && (sport->mgmt_functions->get_list_handler)) {
1398                                 sport->mgmt_functions->get_list_handler(textbuf, sport);
1399                         }
1400                 }
1401                 ocs_domain_unlock(domain);
1402         }
1403
1404         ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
1405 }
1406
1407 int
1408 ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
1409 {
1410         ocs_sport_t *sport;
1411         ocs_domain_t *domain = (ocs_domain_t *)object;
1412         char qualifier[80];
1413         int retval = -1;
1414
1415         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
1416
1417         snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
1418
1419         /* If it doesn't start with my qualifier I don't know what to do with it */
1420         if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1421                 char *unqualified_name = name + strlen(qualifier) +1;
1422
1423                 /* See if it's a value I can supply */
1424                 if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1425                         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
1426                         retval = 0;
1427                 } else if (ocs_strcmp(unqualified_name, "fcf") == 0) {
1428                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
1429                         retval = 0;
1430                 } else if (ocs_strcmp(unqualified_name, "fcf_indicator") == 0) {
1431                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
1432                         retval = 0;
1433                 } else if (ocs_strcmp(unqualified_name, "vlan_id") == 0) {
1434                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
1435                         retval = 0;
1436                 } else if (ocs_strcmp(unqualified_name, "indicator") == 0) {
1437                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
1438                         retval = 0;
1439                 } else if (ocs_strcmp(unqualified_name, "attached") == 0) {
1440                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
1441                         retval = 0;
1442                 } else if (ocs_strcmp(unqualified_name, "is_loop") == 0) {
1443                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop",  domain->is_loop);
1444                         retval = 0;
1445                 } else if (ocs_strcmp(unqualified_name, "is_nlport") == 0) {
1446                         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport",  domain->is_nlport);
1447                         retval = 0;
1448                 } else if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1449                         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
1450                         retval = 0;
1451 #if defined(ENABLE_FABRIC_EMULATION)
1452                 } else if (ocs_strcmp(unqualified_name, "femul_enable") == 0) {
1453                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
1454                         retval = 0;
1455 #endif
1456                 } else if (ocs_strcmp(unqualified_name, "num_sports") == 0) {
1457                         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports", "%d", domain->sport_instance_count);
1458                         retval = 0;
1459                 } else {
1460                         /* If I didn't know the value of this status pass the request to each of my children */
1461
1462                         ocs_domain_lock(domain);
1463                         ocs_list_foreach(&domain->sport_list, sport) {
1464                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->get_handler)) {
1465                                         retval = sport->mgmt_functions->get_handler(textbuf, qualifier, name, sport);
1466                                 }
1467
1468                                 if (retval == 0) {
1469                                         break;
1470                                 }
1471
1472                         }
1473                         ocs_domain_unlock(domain);
1474                 }
1475         }
1476
1477         ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
1478         return retval;
1479 }
1480
1481 void
1482 ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *object)
1483 {
1484         ocs_sport_t *sport;
1485         ocs_domain_t *domain = (ocs_domain_t *)object;
1486
1487         ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
1488
1489         ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
1490         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
1491         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
1492         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
1493         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
1494         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
1495         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop",  domain->is_loop);
1496         ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport",  domain->is_nlport);
1497 #if defined(ENABLE_FABRIC_EMULATION)
1498         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
1499 #endif
1500         ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports",  "%d", domain->sport_instance_count);
1501
1502         ocs_domain_lock(domain);
1503         ocs_list_foreach(&domain->sport_list, sport) {
1504                 if ((sport->mgmt_functions) && (sport->mgmt_functions->get_all_handler)) {
1505                         sport->mgmt_functions->get_all_handler(textbuf, sport);
1506                 }
1507         }
1508         ocs_domain_unlock(domain);
1509
1510
1511         ocs_mgmt_end_unnumbered_section(textbuf, "domain");
1512
1513 }
1514
1515 int
1516 ocs_mgmt_domain_set(char *parent, char *name, char *value, void *object)
1517 {
1518         ocs_sport_t *sport;
1519         ocs_domain_t *domain = (ocs_domain_t *)object;
1520         char qualifier[80];
1521         int retval = -1;
1522
1523         snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
1524
1525         /* If it doesn't start with my qualifier I don't know what to do with it */
1526         if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
1527
1528                 /* See if it's a value I can supply */
1529
1530                 /* if (ocs_strcmp(unqualified_name, "display_name") == 0) {
1531
1532                 } else */
1533                 {
1534                         /* If I didn't know the value of this status pass the request to each of my children */
1535                         ocs_domain_lock(domain);
1536                         ocs_list_foreach(&domain->sport_list, sport) {
1537                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->set_handler)) {
1538                                         retval = sport->mgmt_functions->set_handler(qualifier, name, value, sport);
1539                                 }
1540
1541                                 if (retval == 0) {
1542                                         break;
1543                                 }
1544
1545                         }
1546                         ocs_domain_unlock(domain);
1547                 }
1548         }
1549
1550         return retval;
1551 }
1552
1553 int
1554 ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
1555                         void *arg_out, uint32_t arg_out_length, void *object)
1556 {
1557         ocs_sport_t *sport;
1558         ocs_domain_t *domain = (ocs_domain_t *)object;
1559         char qualifier[80];
1560         int retval = -1;
1561
1562         snprintf(qualifier, sizeof(qualifier), "%s.domain%d", parent, domain->instance_index);
1563
1564         /* If it doesn't start with my qualifier I don't know what to do with it */
1565         if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
1566
1567                 {
1568                         /* If I didn't know how to do this action pass the request to each of my children */
1569                         ocs_domain_lock(domain);
1570                         ocs_list_foreach(&domain->sport_list, sport) {
1571                                 if ((sport->mgmt_functions) && (sport->mgmt_functions->exec_handler)) {
1572                                         retval = sport->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, arg_out, arg_out_length, sport);
1573                                 }
1574
1575                                 if (retval == 0) {
1576                                         break;
1577                                 }
1578
1579                         }
1580                         ocs_domain_unlock(domain);
1581                 }
1582         }
1583
1584         return retval;
1585 }