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