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