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
ocs_domain_cb(void * arg,ocs_hw_domain_event_e event,void * data)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 *
ocs_domain_find(ocs_t * ocs,uint64_t fcf_wwn)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 *
ocs_domain_alloc(ocs_t * ocs,uint64_t fcf_wwn)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
ocs_domain_free(ocs_domain_t * domain)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
ocs_domain_force_free(ocs_domain_t * domain)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
ocs_register_domain_list_empty_cb(ocs_t * ocs,void (* callback)(ocs_t * ocs,void * arg),void * arg)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 *
ocs_domain_get_instance(ocs_t * ocs,uint32_t index)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 *
__ocs_domain_common(const char * funcname,ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_common_shutdown(const char * funcname,ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_init(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_wait_alloc(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_allocated(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_wait_attach(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_ready(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_wait_sports_free(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_wait_shutdown(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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 *
__ocs_domain_wait_domain_lost(ocs_sm_ctx_t * ctx,ocs_sm_event_t evt,void * arg)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
ocs_domain_save_sparms(ocs_domain_t * domain,void * payload)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
__ocs_domain_attach_internal(ocs_domain_t * domain,uint32_t s_id)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
ocs_domain_attach(ocs_domain_t * domain,uint32_t s_id)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
ocs_domain_post_event(ocs_domain_t * domain,ocs_sm_event_t event,void * arg)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
ocs_get_wwn(ocs_hw_t * hw,ocs_hw_property_e prop)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
ocs_ddump_domain(ocs_textbuf_t * textbuf,ocs_domain_t * domain)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
ocs_mgmt_domain_list(ocs_textbuf_t * textbuf,void * object)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
ocs_mgmt_domain_get(ocs_textbuf_t * textbuf,char * parent,char * name,void * object)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
ocs_mgmt_domain_get_all(ocs_textbuf_t * textbuf,void * object)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
ocs_mgmt_domain_set(char * parent,char * name,char * value,void * object)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
ocs_mgmt_domain_exec(char * parent,char * action,void * arg_in,uint32_t arg_in_length,void * arg_out,uint32_t arg_out_length,void * object)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 }
1586