xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncp.c (revision 11767)
1*11767SAnurag.Maskey@Sun.COM /*
2*11767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
3*11767SAnurag.Maskey@Sun.COM  *
4*11767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
5*11767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
6*11767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
7*11767SAnurag.Maskey@Sun.COM  *
8*11767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*11767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*11767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
11*11767SAnurag.Maskey@Sun.COM  * and limitations under the License.
12*11767SAnurag.Maskey@Sun.COM  *
13*11767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*11767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*11767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*11767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*11767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*11767SAnurag.Maskey@Sun.COM  *
19*11767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
20*11767SAnurag.Maskey@Sun.COM  */
21*11767SAnurag.Maskey@Sun.COM 
22*11767SAnurag.Maskey@Sun.COM /*
23*11767SAnurag.Maskey@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24*11767SAnurag.Maskey@Sun.COM  * Use is subject to license terms.
25*11767SAnurag.Maskey@Sun.COM  */
26*11767SAnurag.Maskey@Sun.COM 
27*11767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
28*11767SAnurag.Maskey@Sun.COM #include <assert.h>
29*11767SAnurag.Maskey@Sun.COM #include <libdllink.h>
30*11767SAnurag.Maskey@Sun.COM #include <libdlstat.h>
31*11767SAnurag.Maskey@Sun.COM #include <libnwam.h>
32*11767SAnurag.Maskey@Sun.COM #include <libscf.h>
33*11767SAnurag.Maskey@Sun.COM #include <netinet/in.h>
34*11767SAnurag.Maskey@Sun.COM #include <stdlib.h>
35*11767SAnurag.Maskey@Sun.COM #include <sys/socket.h>
36*11767SAnurag.Maskey@Sun.COM #include <sys/time.h>
37*11767SAnurag.Maskey@Sun.COM #include <sys/types.h>
38*11767SAnurag.Maskey@Sun.COM #include <values.h>
39*11767SAnurag.Maskey@Sun.COM 
40*11767SAnurag.Maskey@Sun.COM #include "conditions.h"
41*11767SAnurag.Maskey@Sun.COM #include "events.h"
42*11767SAnurag.Maskey@Sun.COM #include "objects.h"
43*11767SAnurag.Maskey@Sun.COM #include "ncp.h"
44*11767SAnurag.Maskey@Sun.COM #include "ncu.h"
45*11767SAnurag.Maskey@Sun.COM #include "util.h"
46*11767SAnurag.Maskey@Sun.COM 
47*11767SAnurag.Maskey@Sun.COM /*
48*11767SAnurag.Maskey@Sun.COM  * ncp.c - handles NCP actions.
49*11767SAnurag.Maskey@Sun.COM  */
50*11767SAnurag.Maskey@Sun.COM 
51*11767SAnurag.Maskey@Sun.COM char active_ncp[NWAM_MAX_NAME_LEN];
52*11767SAnurag.Maskey@Sun.COM nwam_ncp_handle_t active_ncph = NULL;
53*11767SAnurag.Maskey@Sun.COM int64_t current_ncu_priority_group = INVALID_PRIORITY_GROUP;
54*11767SAnurag.Maskey@Sun.COM /*
55*11767SAnurag.Maskey@Sun.COM  * active_ncp_mutex protects active_ncp, active_ncph and
56*11767SAnurag.Maskey@Sun.COM  * current_ncu_priority_group.
57*11767SAnurag.Maskey@Sun.COM  */
58*11767SAnurag.Maskey@Sun.COM pthread_mutex_t active_ncp_mutex = PTHREAD_MUTEX_INITIALIZER;
59*11767SAnurag.Maskey@Sun.COM 
60*11767SAnurag.Maskey@Sun.COM /*
61*11767SAnurag.Maskey@Sun.COM  * The variable ncu_wait_time specifies how long to wait to obtain a
62*11767SAnurag.Maskey@Sun.COM  * DHCP lease before giving up on that NCU and moving on to the next/lower
63*11767SAnurag.Maskey@Sun.COM  * priority-group.
64*11767SAnurag.Maskey@Sun.COM  */
65*11767SAnurag.Maskey@Sun.COM uint64_t ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
66*11767SAnurag.Maskey@Sun.COM 
67*11767SAnurag.Maskey@Sun.COM /*
68*11767SAnurag.Maskey@Sun.COM  * Specifies if this is the first time the NCP has been enabled. True
69*11767SAnurag.Maskey@Sun.COM  * on startup so that we can differentiate between when we start up
70*11767SAnurag.Maskey@Sun.COM  * with a given NCP versus when we are asked to reenable it.
71*11767SAnurag.Maskey@Sun.COM  */
72*11767SAnurag.Maskey@Sun.COM boolean_t initial_ncp_enable = B_TRUE;
73*11767SAnurag.Maskey@Sun.COM 
74*11767SAnurag.Maskey@Sun.COM /*
75*11767SAnurag.Maskey@Sun.COM  * nwamd_ncp_handle_enable_event() should be called in the event handling
76*11767SAnurag.Maskey@Sun.COM  * loop in response to an _ENABLE event, triggered as a result of an
77*11767SAnurag.Maskey@Sun.COM  * nwam_ncp_enable() call from a libnwam consumer.  To enable the new NCP,
78*11767SAnurag.Maskey@Sun.COM  * we first call nwamd_fini_ncus() on the old NCP.  This results in enqueueing
79*11767SAnurag.Maskey@Sun.COM  * of a set of _FINI events for each NCU.  These events are handled and in
80*11767SAnurag.Maskey@Sun.COM  * order to tear down config, (online*, uninitialized) state change events
81*11767SAnurag.Maskey@Sun.COM  * are created and consumed directly by the fini event handler (these events
82*11767SAnurag.Maskey@Sun.COM  * are not enqueued as this would result in state events for the old NCP
83*11767SAnurag.Maskey@Sun.COM  * appearing after the new NCP has been enabled.  After the _FINI events are
84*11767SAnurag.Maskey@Sun.COM  * enqueued, we enqueue an NCP _OBJECT_STATE event for the new NCP.  Since
85*11767SAnurag.Maskey@Sun.COM  * it is enqueued after the _FINI events, we are guaranteed no events for the
86*11767SAnurag.Maskey@Sun.COM  * old NCP will appear after the new NCP is activated.
87*11767SAnurag.Maskey@Sun.COM  */
88*11767SAnurag.Maskey@Sun.COM void
89*11767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_enable_event(nwamd_event_t event)
90*11767SAnurag.Maskey@Sun.COM {
91*11767SAnurag.Maskey@Sun.COM 	char *new_ncp = event->event_object;
92*11767SAnurag.Maskey@Sun.COM 	nwam_ncp_handle_t new_ncph;
93*11767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
94*11767SAnurag.Maskey@Sun.COM 
95*11767SAnurag.Maskey@Sun.COM 	if (new_ncp[0] == '\0')
96*11767SAnurag.Maskey@Sun.COM 		return;
97*11767SAnurag.Maskey@Sun.COM 
98*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
99*11767SAnurag.Maskey@Sun.COM 	if (strcmp(active_ncp, new_ncp) == 0 && !initial_ncp_enable) {
100*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: "
101*11767SAnurag.Maskey@Sun.COM 		    "%s is already active", new_ncp);
102*11767SAnurag.Maskey@Sun.COM 		(void) pthread_mutex_unlock(&active_ncp_mutex);
103*11767SAnurag.Maskey@Sun.COM 		return;
104*11767SAnurag.Maskey@Sun.COM 	}
105*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
106*11767SAnurag.Maskey@Sun.COM 
107*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: activating NCP %s",
108*11767SAnurag.Maskey@Sun.COM 	    new_ncp);
109*11767SAnurag.Maskey@Sun.COM 
110*11767SAnurag.Maskey@Sun.COM 	/*
111*11767SAnurag.Maskey@Sun.COM 	 * To activate new NCP, run nwamd_fini_ncus(), reset the active
112*11767SAnurag.Maskey@Sun.COM 	 * priority-group, set the active_ncp property and refresh the
113*11767SAnurag.Maskey@Sun.COM 	 * daemon.  The refresh action will trigger a re-read of the NCUs
114*11767SAnurag.Maskey@Sun.COM 	 * for the activated NCP.
115*11767SAnurag.Maskey@Sun.COM 	 */
116*11767SAnurag.Maskey@Sun.COM 
117*11767SAnurag.Maskey@Sun.COM 	nwamd_fini_ncus();
118*11767SAnurag.Maskey@Sun.COM 
119*11767SAnurag.Maskey@Sun.COM 	err = nwam_ncp_read(new_ncp, 0, &new_ncph);
120*11767SAnurag.Maskey@Sun.COM 	switch (err) {
121*11767SAnurag.Maskey@Sun.COM 	case NWAM_ENTITY_NOT_FOUND:
122*11767SAnurag.Maskey@Sun.COM 		err = nwam_ncp_create(new_ncp, 0, &new_ncph);
123*11767SAnurag.Maskey@Sun.COM 		break;
124*11767SAnurag.Maskey@Sun.COM 	case NWAM_SUCCESS:
125*11767SAnurag.Maskey@Sun.COM 		break;
126*11767SAnurag.Maskey@Sun.COM 	default:
127*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s",
128*11767SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
129*11767SAnurag.Maskey@Sun.COM 		return;
130*11767SAnurag.Maskey@Sun.COM 	}
131*11767SAnurag.Maskey@Sun.COM 	nwam_ncp_free(new_ncph);
132*11767SAnurag.Maskey@Sun.COM 
133*11767SAnurag.Maskey@Sun.COM 	if (err == NWAM_SUCCESS) {
134*11767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCP, new_ncp,
135*11767SAnurag.Maskey@Sun.COM 		    NWAM_STATE_ONLINE, NWAM_AUX_STATE_ACTIVE);
136*11767SAnurag.Maskey@Sun.COM 	} else {
137*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s",
138*11767SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
139*11767SAnurag.Maskey@Sun.COM 		return;
140*11767SAnurag.Maskey@Sun.COM 	}
141*11767SAnurag.Maskey@Sun.COM }
142*11767SAnurag.Maskey@Sun.COM 
143*11767SAnurag.Maskey@Sun.COM void
144*11767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_action_event(nwamd_event_t event)
145*11767SAnurag.Maskey@Sun.COM {
146*11767SAnurag.Maskey@Sun.COM 	switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
147*11767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_ENABLE:
148*11767SAnurag.Maskey@Sun.COM 		nwamd_ncp_handle_enable_event(event);
149*11767SAnurag.Maskey@Sun.COM 		break;
150*11767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_ADD:
151*11767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_DESTROY:
152*11767SAnurag.Maskey@Sun.COM 		/* nothing to do */
153*11767SAnurag.Maskey@Sun.COM 		break;
154*11767SAnurag.Maskey@Sun.COM 	default:
155*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_INFO, "nwam_ncp_handle_action_event: "
156*11767SAnurag.Maskey@Sun.COM 		    "unexpected action");
157*11767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
158*11767SAnurag.Maskey@Sun.COM 		break;
159*11767SAnurag.Maskey@Sun.COM 	}
160*11767SAnurag.Maskey@Sun.COM }
161*11767SAnurag.Maskey@Sun.COM 
162*11767SAnurag.Maskey@Sun.COM /*
163*11767SAnurag.Maskey@Sun.COM  * The only state events we create are (online, active) events which are
164*11767SAnurag.Maskey@Sun.COM  * generated as part of an NCP enable action (see above).
165*11767SAnurag.Maskey@Sun.COM  */
166*11767SAnurag.Maskey@Sun.COM void
167*11767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_state_event(nwamd_event_t event)
168*11767SAnurag.Maskey@Sun.COM {
169*11767SAnurag.Maskey@Sun.COM 	char *new_ncp = event->event_object;
170*11767SAnurag.Maskey@Sun.COM 	nwam_ncp_handle_t new_ncph, old_ncph;
171*11767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
172*11767SAnurag.Maskey@Sun.COM 
173*11767SAnurag.Maskey@Sun.COM 	/* The NCP to be activated should always exist. */
174*11767SAnurag.Maskey@Sun.COM 	if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph)) != NWAM_SUCCESS) {
175*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_state_event: "
176*11767SAnurag.Maskey@Sun.COM 		    "cannot read NCP %s: : %s", new_ncp, nwam_strerror(err));
177*11767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
178*11767SAnurag.Maskey@Sun.COM 		return;
179*11767SAnurag.Maskey@Sun.COM 	}
180*11767SAnurag.Maskey@Sun.COM 
181*11767SAnurag.Maskey@Sun.COM 	/*
182*11767SAnurag.Maskey@Sun.COM 	 * To activate new NCP, reset the active priority-group, set the
183*11767SAnurag.Maskey@Sun.COM 	 * active_ncp property and refresh the daemon.  The refresh action will
184*11767SAnurag.Maskey@Sun.COM 	 * trigger a re-read of the NCUs for the activated NCP.
185*11767SAnurag.Maskey@Sun.COM 	 */
186*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
187*11767SAnurag.Maskey@Sun.COM 	old_ncph = active_ncph;
188*11767SAnurag.Maskey@Sun.COM 	active_ncph = new_ncph;
189*11767SAnurag.Maskey@Sun.COM 	nwam_ncp_free(old_ncph);
190*11767SAnurag.Maskey@Sun.COM 	current_ncu_priority_group = INVALID_PRIORITY_GROUP;
191*11767SAnurag.Maskey@Sun.COM 	(void) strlcpy(active_ncp, event->event_object,
192*11767SAnurag.Maskey@Sun.COM 	    sizeof (active_ncp));
193*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
194*11767SAnurag.Maskey@Sun.COM 	(void) nwamd_set_string_property(OUR_FMRI, OUR_PG,
195*11767SAnurag.Maskey@Sun.COM 	    OUR_ACTIVE_NCP_PROP_NAME, new_ncp);
196*11767SAnurag.Maskey@Sun.COM 	(void) smf_refresh_instance(OUR_FMRI);
197*11767SAnurag.Maskey@Sun.COM 	initial_ncp_enable = B_FALSE;
198*11767SAnurag.Maskey@Sun.COM }
199*11767SAnurag.Maskey@Sun.COM 
200*11767SAnurag.Maskey@Sun.COM int
201*11767SAnurag.Maskey@Sun.COM nwamd_ncp_action(const char *ncp, nwam_action_t action)
202*11767SAnurag.Maskey@Sun.COM {
203*11767SAnurag.Maskey@Sun.COM 	nwamd_event_t event = nwamd_event_init_object_action
204*11767SAnurag.Maskey@Sun.COM 	    (NWAM_OBJECT_TYPE_NCP, ncp, NULL, action);
205*11767SAnurag.Maskey@Sun.COM 	if (event == NULL)
206*11767SAnurag.Maskey@Sun.COM 		return (1);
207*11767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue(event);
208*11767SAnurag.Maskey@Sun.COM 	return (0);
209*11767SAnurag.Maskey@Sun.COM }
210*11767SAnurag.Maskey@Sun.COM 
211*11767SAnurag.Maskey@Sun.COM /*
212*11767SAnurag.Maskey@Sun.COM  * Below this point are routines handling NCU prioritization
213*11767SAnurag.Maskey@Sun.COM  * policy for the active NCP.
214*11767SAnurag.Maskey@Sun.COM  */
215*11767SAnurag.Maskey@Sun.COM 
216*11767SAnurag.Maskey@Sun.COM struct priority_group_cbarg {
217*11767SAnurag.Maskey@Sun.COM 	uint64_t minpriority;
218*11767SAnurag.Maskey@Sun.COM 	uint64_t currpriority;
219*11767SAnurag.Maskey@Sun.COM 	boolean_t found;
220*11767SAnurag.Maskey@Sun.COM };
221*11767SAnurag.Maskey@Sun.COM 
222*11767SAnurag.Maskey@Sun.COM /* Callback used to find next pg in NCP that is >= start_pg */
223*11767SAnurag.Maskey@Sun.COM static int
224*11767SAnurag.Maskey@Sun.COM find_next_priority_group_cb(nwamd_object_t object, void *data)
225*11767SAnurag.Maskey@Sun.COM {
226*11767SAnurag.Maskey@Sun.COM 	struct priority_group_cbarg *cbarg = data;
227*11767SAnurag.Maskey@Sun.COM 	uint64_t priority;
228*11767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = object->nwamd_object_data;
229*11767SAnurag.Maskey@Sun.COM 
230*11767SAnurag.Maskey@Sun.COM 	if (ncu->ncu_node.u_link.nwamd_link_activation_mode !=
231*11767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_PRIORITIZED)
232*11767SAnurag.Maskey@Sun.COM 		return (0);
233*11767SAnurag.Maskey@Sun.COM 
234*11767SAnurag.Maskey@Sun.COM 	priority = ncu->ncu_node.u_link.nwamd_link_priority_group;
235*11767SAnurag.Maskey@Sun.COM 
236*11767SAnurag.Maskey@Sun.COM 	if (priority >= cbarg->minpriority && priority < cbarg->currpriority) {
237*11767SAnurag.Maskey@Sun.COM 		cbarg->found = B_TRUE;
238*11767SAnurag.Maskey@Sun.COM 		cbarg->currpriority = priority;
239*11767SAnurag.Maskey@Sun.COM 	}
240*11767SAnurag.Maskey@Sun.COM 	return (0);
241*11767SAnurag.Maskey@Sun.COM }
242*11767SAnurag.Maskey@Sun.COM 
243*11767SAnurag.Maskey@Sun.COM 
244*11767SAnurag.Maskey@Sun.COM /* Set current_pg to next pg in NCP that is >= start_pg */
245*11767SAnurag.Maskey@Sun.COM boolean_t
246*11767SAnurag.Maskey@Sun.COM nwamd_ncp_find_next_priority_group(int64_t minpriority,
247*11767SAnurag.Maskey@Sun.COM     int64_t *nextpriorityp)
248*11767SAnurag.Maskey@Sun.COM {
249*11767SAnurag.Maskey@Sun.COM 	struct priority_group_cbarg cbarg;
250*11767SAnurag.Maskey@Sun.COM 
251*11767SAnurag.Maskey@Sun.COM 	cbarg.minpriority = minpriority;
252*11767SAnurag.Maskey@Sun.COM 	cbarg.currpriority = MAXINT;
253*11767SAnurag.Maskey@Sun.COM 	cbarg.found = B_FALSE;
254*11767SAnurag.Maskey@Sun.COM 
255*11767SAnurag.Maskey@Sun.COM 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
256*11767SAnurag.Maskey@Sun.COM 	    find_next_priority_group_cb, &cbarg);
257*11767SAnurag.Maskey@Sun.COM 
258*11767SAnurag.Maskey@Sun.COM 	if (cbarg.found) {
259*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
260*11767SAnurag.Maskey@Sun.COM 		    "next priority group >= %lld is %lld",
261*11767SAnurag.Maskey@Sun.COM 		    minpriority, cbarg.currpriority);
262*11767SAnurag.Maskey@Sun.COM 		*nextpriorityp = cbarg.currpriority;
263*11767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
264*11767SAnurag.Maskey@Sun.COM 	} else {
265*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
266*11767SAnurag.Maskey@Sun.COM 		    "no priority groups >= %lld exist", minpriority);
267*11767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
268*11767SAnurag.Maskey@Sun.COM 	}
269*11767SAnurag.Maskey@Sun.COM }
270*11767SAnurag.Maskey@Sun.COM 
271*11767SAnurag.Maskey@Sun.COM /*
272*11767SAnurag.Maskey@Sun.COM  * Struct for walking NCUs in the selected priority group.  We count
273*11767SAnurag.Maskey@Sun.COM  * how many of the exclusive, all and shared NCUs are online, and
274*11767SAnurag.Maskey@Sun.COM  * if activate_or_deactivate is true, we either activate or deactivate
275*11767SAnurag.Maskey@Sun.COM  * (depending on the value of activate) offline/online NCUs.
276*11767SAnurag.Maskey@Sun.COM  */
277*11767SAnurag.Maskey@Sun.COM struct nwamd_ncu_check_walk_arg {
278*11767SAnurag.Maskey@Sun.COM 	boolean_t manual;	/* enable manual NCUs only */
279*11767SAnurag.Maskey@Sun.COM 	int64_t priority_group; /* interested priority-group for this walk */
280*11767SAnurag.Maskey@Sun.COM 	uint64_t exclusive_ncus;
281*11767SAnurag.Maskey@Sun.COM 	uint64_t exclusive_online_ncus;
282*11767SAnurag.Maskey@Sun.COM 	uint64_t shared_ncus;
283*11767SAnurag.Maskey@Sun.COM 	uint64_t shared_online_ncus;
284*11767SAnurag.Maskey@Sun.COM 	uint64_t all_ncus;
285*11767SAnurag.Maskey@Sun.COM 	uint64_t all_online_ncus;
286*11767SAnurag.Maskey@Sun.COM 	boolean_t activate_or_deactivate;
287*11767SAnurag.Maskey@Sun.COM 	boolean_t activate;
288*11767SAnurag.Maskey@Sun.COM };
289*11767SAnurag.Maskey@Sun.COM 
290*11767SAnurag.Maskey@Sun.COM /*
291*11767SAnurag.Maskey@Sun.COM  * This function serves a number of purposes:
292*11767SAnurag.Maskey@Sun.COM  * - it supports activation/deactivation of manual NCUs in the current NCP
293*11767SAnurag.Maskey@Sun.COM  * (when wa->manual is true, wa->activate determines if we activate or
294*11767SAnurag.Maskey@Sun.COM  * deactivate the current NCU)
295*11767SAnurag.Maskey@Sun.COM  * - it supports checking/activation of a particular priority group in
296*11767SAnurag.Maskey@Sun.COM  * the active NCP. This works as follows:
297*11767SAnurag.Maskey@Sun.COM  *
298*11767SAnurag.Maskey@Sun.COM  * Count up numbers of exclusive, shared and all NCUs, and how many of each
299*11767SAnurag.Maskey@Sun.COM  * are online.  If an NCU is waiting for IP address to be assigned, it is
300*11767SAnurag.Maskey@Sun.COM  * also considered online.  If activate_or_deactivate is true, we also
301*11767SAnurag.Maskey@Sun.COM  * either activate (if activate is true) or deactivate prioritized NCUs
302*11767SAnurag.Maskey@Sun.COM  * that are offline or online.
303*11767SAnurag.Maskey@Sun.COM  */
304*11767SAnurag.Maskey@Sun.COM static int
305*11767SAnurag.Maskey@Sun.COM nwamd_ncu_check_or_activate(nwamd_object_t object, void *data)
306*11767SAnurag.Maskey@Sun.COM {
307*11767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg *wa = data;
308*11767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
309*11767SAnurag.Maskey@Sun.COM 	uint64_t priority_group, priority_mode;
310*11767SAnurag.Maskey@Sun.COM 	nwamd_object_t if_obj;
311*11767SAnurag.Maskey@Sun.COM 	nwam_state_t state, if_state;
312*11767SAnurag.Maskey@Sun.COM 	nwam_aux_state_t aux_state, if_aux_state;
313*11767SAnurag.Maskey@Sun.COM 	char *name;
314*11767SAnurag.Maskey@Sun.COM 
315*11767SAnurag.Maskey@Sun.COM 	state = object->nwamd_object_state;
316*11767SAnurag.Maskey@Sun.COM 	aux_state = object->nwamd_object_aux_state;
317*11767SAnurag.Maskey@Sun.COM 	name = object->nwamd_object_name;
318*11767SAnurag.Maskey@Sun.COM 	ncu = object->nwamd_object_data;
319*11767SAnurag.Maskey@Sun.COM 
320*11767SAnurag.Maskey@Sun.COM 	/* skip NCUs in UNINITIALIZED state */
321*11767SAnurag.Maskey@Sun.COM 	if (state == NWAM_STATE_UNINITIALIZED) {
322*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
323*11767SAnurag.Maskey@Sun.COM 		    "skipping uninitialized ncu %s", name);
324*11767SAnurag.Maskey@Sun.COM 		return (0);
325*11767SAnurag.Maskey@Sun.COM 	}
326*11767SAnurag.Maskey@Sun.COM 	if (!wa->manual && wa->priority_group == INVALID_PRIORITY_GROUP)
327*11767SAnurag.Maskey@Sun.COM 		return (0);
328*11767SAnurag.Maskey@Sun.COM 
329*11767SAnurag.Maskey@Sun.COM 	if (ncu->ncu_type != NWAM_NCU_TYPE_LINK) {
330*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
331*11767SAnurag.Maskey@Sun.COM 		    "skipping interface NCU %s", name);
332*11767SAnurag.Maskey@Sun.COM 		return (0);
333*11767SAnurag.Maskey@Sun.COM 	}
334*11767SAnurag.Maskey@Sun.COM 	if (!wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode !=
335*11767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_PRIORITIZED) {
336*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
337*11767SAnurag.Maskey@Sun.COM 		    "skipping non-prioritized NCU %s", name);
338*11767SAnurag.Maskey@Sun.COM 		return (0);
339*11767SAnurag.Maskey@Sun.COM 	}
340*11767SAnurag.Maskey@Sun.COM 	if (wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode !=
341*11767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_MANUAL) {
342*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
343*11767SAnurag.Maskey@Sun.COM 		    "skipping non-manual NCU %s", name);
344*11767SAnurag.Maskey@Sun.COM 		return (0);
345*11767SAnurag.Maskey@Sun.COM 	}
346*11767SAnurag.Maskey@Sun.COM 
347*11767SAnurag.Maskey@Sun.COM 	priority_group = ncu->ncu_node.u_link.nwamd_link_priority_group;
348*11767SAnurag.Maskey@Sun.COM 	priority_mode = ncu->ncu_node.u_link.nwamd_link_priority_mode;
349*11767SAnurag.Maskey@Sun.COM 	/* Only work with NCUs in the requested priority-group */
350*11767SAnurag.Maskey@Sun.COM 	if (!wa->manual && priority_group != wa->priority_group) {
351*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
352*11767SAnurag.Maskey@Sun.COM 		    "skipping NCU %s in different priority-group", name);
353*11767SAnurag.Maskey@Sun.COM 		return (0);
354*11767SAnurag.Maskey@Sun.COM 	}
355*11767SAnurag.Maskey@Sun.COM 	/* Get the state of the corresponding interface NCU */
356*11767SAnurag.Maskey@Sun.COM 	if ((if_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE,
357*11767SAnurag.Maskey@Sun.COM 	    ncu->ncu_name)) == NULL) {
358*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
359*11767SAnurag.Maskey@Sun.COM 		    "interface NCU of %s not found, skipping", name);
360*11767SAnurag.Maskey@Sun.COM 		return (0);
361*11767SAnurag.Maskey@Sun.COM 	}
362*11767SAnurag.Maskey@Sun.COM 	if_state = if_obj->nwamd_object_state;
363*11767SAnurag.Maskey@Sun.COM 	if_aux_state = if_obj->nwamd_object_aux_state;
364*11767SAnurag.Maskey@Sun.COM 	nwamd_object_release(if_obj);
365*11767SAnurag.Maskey@Sun.COM 
366*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: %s ncu %s",
367*11767SAnurag.Maskey@Sun.COM 	    wa->activate_or_deactivate ?
368*11767SAnurag.Maskey@Sun.COM 	    (wa->activate ? "activating" : "deactivating") :
369*11767SAnurag.Maskey@Sun.COM 	    "checking", name);
370*11767SAnurag.Maskey@Sun.COM 
371*11767SAnurag.Maskey@Sun.COM 	if (wa->manual) {
372*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
373*11767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE && ncu->ncu_enabled) {
374*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
375*11767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to offline* from offline",
376*11767SAnurag.Maskey@Sun.COM 				    name);
377*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
378*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
379*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
380*11767SAnurag.Maskey@Sun.COM 			}
381*11767SAnurag.Maskey@Sun.COM 			if (state != NWAM_STATE_DISABLED &&
382*11767SAnurag.Maskey@Sun.COM 			    !ncu->ncu_enabled) {
383*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
384*11767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to online* (disabling)",
385*11767SAnurag.Maskey@Sun.COM 				    name);
386*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
387*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
388*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_MANUAL_DISABLE);
389*11767SAnurag.Maskey@Sun.COM 			}
390*11767SAnurag.Maskey@Sun.COM 		}
391*11767SAnurag.Maskey@Sun.COM 		return (0);
392*11767SAnurag.Maskey@Sun.COM 	}
393*11767SAnurag.Maskey@Sun.COM 	switch (priority_mode) {
394*11767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_EXCLUSIVE:
395*11767SAnurag.Maskey@Sun.COM 		wa->exclusive_ncus++;
396*11767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
397*11767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
398*11767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
399*11767SAnurag.Maskey@Sun.COM 			wa->exclusive_online_ncus++;
400*11767SAnurag.Maskey@Sun.COM 
401*11767SAnurag.Maskey@Sun.COM 		/*
402*11767SAnurag.Maskey@Sun.COM 		 * For exclusive NCUs, we activate offline NCUs as long
403*11767SAnurag.Maskey@Sun.COM 		 * as no other exclusive NCUs are active.
404*11767SAnurag.Maskey@Sun.COM 		 */
405*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
406*11767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE &&
407*11767SAnurag.Maskey@Sun.COM 			    wa->exclusive_online_ncus == 0) {
408*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
409*11767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to offline* from offline",
410*11767SAnurag.Maskey@Sun.COM 				    name);
411*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
412*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
413*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
414*11767SAnurag.Maskey@Sun.COM 			}
415*11767SAnurag.Maskey@Sun.COM 		}
416*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
417*11767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
418*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
419*11767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
420*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
421*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
422*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
423*11767SAnurag.Maskey@Sun.COM 			}
424*11767SAnurag.Maskey@Sun.COM 		}
425*11767SAnurag.Maskey@Sun.COM 		/*
426*11767SAnurag.Maskey@Sun.COM 		 * If we are activating or checking the priority group and
427*11767SAnurag.Maskey@Sun.COM 		 * too many exclusive NCUs are online, take this NCU down.
428*11767SAnurag.Maskey@Sun.COM 		 */
429*11767SAnurag.Maskey@Sun.COM 		if ((wa->activate_or_deactivate && wa->activate) ||
430*11767SAnurag.Maskey@Sun.COM 		    !wa->activate_or_deactivate) {
431*11767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_ONLINE &&
432*11767SAnurag.Maskey@Sun.COM 			    if_state == NWAM_STATE_ONLINE &&
433*11767SAnurag.Maskey@Sun.COM 			    wa->exclusive_online_ncus > 1) {
434*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
435*11767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to online* since another "
436*11767SAnurag.Maskey@Sun.COM 				    "NCU is already active",
437*11767SAnurag.Maskey@Sun.COM 				    name);
438*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
439*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
440*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
441*11767SAnurag.Maskey@Sun.COM 			}
442*11767SAnurag.Maskey@Sun.COM 		}
443*11767SAnurag.Maskey@Sun.COM 		break;
444*11767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_SHARED:
445*11767SAnurag.Maskey@Sun.COM 		wa->shared_ncus++;
446*11767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
447*11767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
448*11767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
449*11767SAnurag.Maskey@Sun.COM 			wa->shared_online_ncus++;
450*11767SAnurag.Maskey@Sun.COM 
451*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
452*11767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE) {
453*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
454*11767SAnurag.Maskey@Sun.COM 				    "activating NCU %s", name);
455*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
456*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
457*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
458*11767SAnurag.Maskey@Sun.COM 			}
459*11767SAnurag.Maskey@Sun.COM 		}
460*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
461*11767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
462*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
463*11767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
464*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
465*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
466*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
467*11767SAnurag.Maskey@Sun.COM 			}
468*11767SAnurag.Maskey@Sun.COM 		}
469*11767SAnurag.Maskey@Sun.COM 		break;
470*11767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_ALL:
471*11767SAnurag.Maskey@Sun.COM 		wa->all_ncus++;
472*11767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
473*11767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
474*11767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
475*11767SAnurag.Maskey@Sun.COM 			wa->all_online_ncus++;
476*11767SAnurag.Maskey@Sun.COM 
477*11767SAnurag.Maskey@Sun.COM 		/*
478*11767SAnurag.Maskey@Sun.COM 		 * For "all" NCUs, activate/deactivate all offline/online
479*11767SAnurag.Maskey@Sun.COM 		 * NCUs.
480*11767SAnurag.Maskey@Sun.COM 		 */
481*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
482*11767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE) {
483*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
484*11767SAnurag.Maskey@Sun.COM 				    "activating NCU %s", name);
485*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
486*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
487*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
488*11767SAnurag.Maskey@Sun.COM 			}
489*11767SAnurag.Maskey@Sun.COM 		}
490*11767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
491*11767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
492*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
493*11767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
494*11767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
495*11767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
496*11767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
497*11767SAnurag.Maskey@Sun.COM 			}
498*11767SAnurag.Maskey@Sun.COM 		}
499*11767SAnurag.Maskey@Sun.COM 
500*11767SAnurag.Maskey@Sun.COM 		break;
501*11767SAnurag.Maskey@Sun.COM 	default:
502*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
503*11767SAnurag.Maskey@Sun.COM 		    "invalid priority-mode");
504*11767SAnurag.Maskey@Sun.COM 		break;
505*11767SAnurag.Maskey@Sun.COM 	}
506*11767SAnurag.Maskey@Sun.COM 
507*11767SAnurag.Maskey@Sun.COM 	return (0);
508*11767SAnurag.Maskey@Sun.COM }
509*11767SAnurag.Maskey@Sun.COM 
510*11767SAnurag.Maskey@Sun.COM void
511*11767SAnurag.Maskey@Sun.COM nwamd_ncp_activate_priority_group(int64_t priority)
512*11767SAnurag.Maskey@Sun.COM {
513*11767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
514*11767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event, priority_event;
515*11767SAnurag.Maskey@Sun.COM 
516*11767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
517*11767SAnurag.Maskey@Sun.COM 		return;
518*11767SAnurag.Maskey@Sun.COM 
519*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
520*11767SAnurag.Maskey@Sun.COM 	if (priority == current_ncu_priority_group) {
521*11767SAnurag.Maskey@Sun.COM 		(void) pthread_mutex_unlock(&active_ncp_mutex);
522*11767SAnurag.Maskey@Sun.COM 		return;
523*11767SAnurag.Maskey@Sun.COM 	}
524*11767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
525*11767SAnurag.Maskey@Sun.COM 
526*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_activate_priority_group: "
527*11767SAnurag.Maskey@Sun.COM 	    "activating priority group %lld", priority);
528*11767SAnurag.Maskey@Sun.COM 
529*11767SAnurag.Maskey@Sun.COM 	wa.manual = B_FALSE;
530*11767SAnurag.Maskey@Sun.COM 	wa.priority_group = priority;
531*11767SAnurag.Maskey@Sun.COM 	wa.exclusive_ncus = 0;
532*11767SAnurag.Maskey@Sun.COM 	wa.exclusive_online_ncus = 0;
533*11767SAnurag.Maskey@Sun.COM 	wa.shared_ncus = 0;
534*11767SAnurag.Maskey@Sun.COM 	wa.shared_online_ncus = 0;
535*11767SAnurag.Maskey@Sun.COM 	wa.all_ncus = 0;
536*11767SAnurag.Maskey@Sun.COM 	wa.all_online_ncus = 0;
537*11767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
538*11767SAnurag.Maskey@Sun.COM 	wa.activate = B_TRUE;
539*11767SAnurag.Maskey@Sun.COM 
540*11767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
541*11767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
542*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_activate_priority_group: "
543*11767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
544*11767SAnurag.Maskey@Sun.COM 		return;
545*11767SAnurag.Maskey@Sun.COM 	}
546*11767SAnurag.Maskey@Sun.COM 
547*11767SAnurag.Maskey@Sun.COM 	/*
548*11767SAnurag.Maskey@Sun.COM 	 * Enqueue event to update current_ncu_priority_group and send to
549*11767SAnurag.Maskey@Sun.COM 	 * any event listeners.
550*11767SAnurag.Maskey@Sun.COM 	 */
551*11767SAnurag.Maskey@Sun.COM 	priority_event = nwamd_event_init_priority_group_change(priority);
552*11767SAnurag.Maskey@Sun.COM 	if (priority_event == NULL)
553*11767SAnurag.Maskey@Sun.COM 		return;
554*11767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue(priority_event);
555*11767SAnurag.Maskey@Sun.COM 
556*11767SAnurag.Maskey@Sun.COM 	/*
557*11767SAnurag.Maskey@Sun.COM 	 * Now we've activated a new priority group, enqueue an event
558*11767SAnurag.Maskey@Sun.COM 	 * to check up on the state of this priority group.
559*11767SAnurag.Maskey@Sun.COM 	 */
560*11767SAnurag.Maskey@Sun.COM 	check_event = nwamd_event_init_ncu_check();
561*11767SAnurag.Maskey@Sun.COM 	if (check_event == NULL)
562*11767SAnurag.Maskey@Sun.COM 		return;
563*11767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue_timed(check_event, ncu_wait_time);
564*11767SAnurag.Maskey@Sun.COM }
565*11767SAnurag.Maskey@Sun.COM 
566*11767SAnurag.Maskey@Sun.COM void
567*11767SAnurag.Maskey@Sun.COM nwamd_ncp_deactivate_priority_group(int64_t priority)
568*11767SAnurag.Maskey@Sun.COM {
569*11767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
570*11767SAnurag.Maskey@Sun.COM 
571*11767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
572*11767SAnurag.Maskey@Sun.COM 		return;
573*11767SAnurag.Maskey@Sun.COM 
574*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group: "
575*11767SAnurag.Maskey@Sun.COM 	    "deactivating priority group %lld", priority);
576*11767SAnurag.Maskey@Sun.COM 
577*11767SAnurag.Maskey@Sun.COM 	wa.manual = B_FALSE;
578*11767SAnurag.Maskey@Sun.COM 	wa.priority_group = priority;
579*11767SAnurag.Maskey@Sun.COM 	wa.exclusive_ncus = 0;
580*11767SAnurag.Maskey@Sun.COM 	wa.exclusive_online_ncus = 0;
581*11767SAnurag.Maskey@Sun.COM 	wa.shared_ncus = 0;
582*11767SAnurag.Maskey@Sun.COM 	wa.shared_online_ncus = 0;
583*11767SAnurag.Maskey@Sun.COM 	wa.all_ncus = 0;
584*11767SAnurag.Maskey@Sun.COM 	wa.all_online_ncus = 0;
585*11767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
586*11767SAnurag.Maskey@Sun.COM 	wa.activate = B_FALSE;
587*11767SAnurag.Maskey@Sun.COM 
588*11767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
589*11767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
590*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_deactivate_priority_group: "
591*11767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
592*11767SAnurag.Maskey@Sun.COM 		return;
593*11767SAnurag.Maskey@Sun.COM 	}
594*11767SAnurag.Maskey@Sun.COM }
595*11767SAnurag.Maskey@Sun.COM 
596*11767SAnurag.Maskey@Sun.COM /*
597*11767SAnurag.Maskey@Sun.COM  * This function deactivates all priority groups at level 'priority' and lower
598*11767SAnurag.Maskey@Sun.COM  * (which is, numerically, all priorities >= priority).
599*11767SAnurag.Maskey@Sun.COM  */
600*11767SAnurag.Maskey@Sun.COM void
601*11767SAnurag.Maskey@Sun.COM nwamd_ncp_deactivate_priority_group_all(int64_t priority)
602*11767SAnurag.Maskey@Sun.COM {
603*11767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
604*11767SAnurag.Maskey@Sun.COM 		return;
605*11767SAnurag.Maskey@Sun.COM 
606*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group_all: "
607*11767SAnurag.Maskey@Sun.COM 	    "deactivating priority group less than or equal to %lld", priority);
608*11767SAnurag.Maskey@Sun.COM 
609*11767SAnurag.Maskey@Sun.COM 	do {
610*11767SAnurag.Maskey@Sun.COM 		nwamd_ncp_deactivate_priority_group(priority);
611*11767SAnurag.Maskey@Sun.COM 	} while (nwamd_ncp_find_next_priority_group(priority + 1, &priority));
612*11767SAnurag.Maskey@Sun.COM }
613*11767SAnurag.Maskey@Sun.COM 
614*11767SAnurag.Maskey@Sun.COM /*
615*11767SAnurag.Maskey@Sun.COM  * Returns 'true' if it found the highest priority group no higher then what
616*11767SAnurag.Maskey@Sun.COM  * is passed that should be activated and sets *priority to that.
617*11767SAnurag.Maskey@Sun.COM  */
618*11767SAnurag.Maskey@Sun.COM boolean_t
619*11767SAnurag.Maskey@Sun.COM nwamd_ncp_check_priority_group(int64_t *priority)
620*11767SAnurag.Maskey@Sun.COM {
621*11767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
622*11767SAnurag.Maskey@Sun.COM 	boolean_t conditions_met = B_FALSE;
623*11767SAnurag.Maskey@Sun.COM 
624*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_check_priority_group: "
625*11767SAnurag.Maskey@Sun.COM 	    "checking priority group %lld", *priority);
626*11767SAnurag.Maskey@Sun.COM 
627*11767SAnurag.Maskey@Sun.COM 	if (*priority == INVALID_PRIORITY_GROUP) {
628*11767SAnurag.Maskey@Sun.COM 		if (!nwamd_ncp_find_next_priority_group(0, priority))
629*11767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
630*11767SAnurag.Maskey@Sun.COM 	}
631*11767SAnurag.Maskey@Sun.COM 
632*11767SAnurag.Maskey@Sun.COM 	while (!conditions_met) {
633*11767SAnurag.Maskey@Sun.COM 		(void) memset(&wa, 0, sizeof (wa));
634*11767SAnurag.Maskey@Sun.COM 		wa.manual = B_FALSE;
635*11767SAnurag.Maskey@Sun.COM 		wa.priority_group = *priority;
636*11767SAnurag.Maskey@Sun.COM 		wa.activate_or_deactivate = B_FALSE;
637*11767SAnurag.Maskey@Sun.COM 
638*11767SAnurag.Maskey@Sun.COM 		if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
639*11767SAnurag.Maskey@Sun.COM 		    nwamd_ncu_check_or_activate, &wa) != 0) {
640*11767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_ncp_check_priority_group: "
641*11767SAnurag.Maskey@Sun.COM 			    "nwamd_walk_objects() failed");
642*11767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
643*11767SAnurag.Maskey@Sun.COM 		}
644*11767SAnurag.Maskey@Sun.COM 
645*11767SAnurag.Maskey@Sun.COM 		/*
646*11767SAnurag.Maskey@Sun.COM 		 * Are activation conditons satisifed? In other words:
647*11767SAnurag.Maskey@Sun.COM 		 * - exactly one of the exclusive NCUs is online
648*11767SAnurag.Maskey@Sun.COM 		 * - 1 or more shared NCUs are online
649*11767SAnurag.Maskey@Sun.COM 		 * - all of the all NCUs are online.
650*11767SAnurag.Maskey@Sun.COM 		 * If any of these is untrue, conditions are not satisfied.
651*11767SAnurag.Maskey@Sun.COM 		 */
652*11767SAnurag.Maskey@Sun.COM 		conditions_met = B_TRUE;
653*11767SAnurag.Maskey@Sun.COM 		if (wa.exclusive_ncus > 0 && wa.exclusive_online_ncus != 1)
654*11767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
655*11767SAnurag.Maskey@Sun.COM 		if (wa.shared_ncus > 0 && wa.shared_online_ncus == 0)
656*11767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
657*11767SAnurag.Maskey@Sun.COM 		if (wa.all_ncus > 0 && wa.all_ncus != wa.all_online_ncus)
658*11767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
659*11767SAnurag.Maskey@Sun.COM 		if (wa.exclusive_online_ncus == 0 &&
660*11767SAnurag.Maskey@Sun.COM 		    wa.shared_online_ncus == 0 && wa.all_online_ncus == 0)
661*11767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
662*11767SAnurag.Maskey@Sun.COM 
663*11767SAnurag.Maskey@Sun.COM 		if (conditions_met) {
664*11767SAnurag.Maskey@Sun.COM 			return (B_TRUE);
665*11767SAnurag.Maskey@Sun.COM 		} else {
666*11767SAnurag.Maskey@Sun.COM 			/*
667*11767SAnurag.Maskey@Sun.COM 			 * If there is a next pg, activate it. If not, do
668*11767SAnurag.Maskey@Sun.COM 			 * nothing - we're stuck here unless an event occurs
669*11767SAnurag.Maskey@Sun.COM 			 * for our or a higher pg.
670*11767SAnurag.Maskey@Sun.COM 			 */
671*11767SAnurag.Maskey@Sun.COM 			if (!nwamd_ncp_find_next_priority_group
672*11767SAnurag.Maskey@Sun.COM 			    (wa.priority_group + 1, priority)) {
673*11767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "ran out of prio groups");
674*11767SAnurag.Maskey@Sun.COM 				return (B_FALSE);
675*11767SAnurag.Maskey@Sun.COM 			}
676*11767SAnurag.Maskey@Sun.COM 		}
677*11767SAnurag.Maskey@Sun.COM 	}
678*11767SAnurag.Maskey@Sun.COM 	return (B_FALSE);
679*11767SAnurag.Maskey@Sun.COM }
680*11767SAnurag.Maskey@Sun.COM 
681*11767SAnurag.Maskey@Sun.COM void
682*11767SAnurag.Maskey@Sun.COM nwamd_ncp_activate_manual_ncus(void)
683*11767SAnurag.Maskey@Sun.COM {
684*11767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
685*11767SAnurag.Maskey@Sun.COM 
686*11767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_activate_manual_ncus: activating NCUs");
687*11767SAnurag.Maskey@Sun.COM 
688*11767SAnurag.Maskey@Sun.COM 	wa.manual = B_TRUE;
689*11767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
690*11767SAnurag.Maskey@Sun.COM 	wa.activate = B_TRUE;
691*11767SAnurag.Maskey@Sun.COM 
692*11767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
693*11767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
694*11767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_activate_manual_ncus: "
695*11767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
696*11767SAnurag.Maskey@Sun.COM 		return;
697*11767SAnurag.Maskey@Sun.COM 	}
698*11767SAnurag.Maskey@Sun.COM }
699*11767SAnurag.Maskey@Sun.COM 
700*11767SAnurag.Maskey@Sun.COM void
701*11767SAnurag.Maskey@Sun.COM nwamd_create_ncu_check_event(uint64_t when)
702*11767SAnurag.Maskey@Sun.COM {
703*11767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event = nwamd_event_init_ncu_check();
704*11767SAnurag.Maskey@Sun.COM 	if (check_event != NULL)
705*11767SAnurag.Maskey@Sun.COM 		nwamd_event_enqueue_timed(check_event, when);
706*11767SAnurag.Maskey@Sun.COM }
707