xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncp.c (revision 12576:ab8aacaead3f)
111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM  *
411767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM  *
811767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM  * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM  *
1311767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM  *
1911767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM  */
2111767SAnurag.Maskey@Sun.COM 
2211767SAnurag.Maskey@Sun.COM /*
2312371SAnurag.Maskey@Oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM  */
2511767SAnurag.Maskey@Sun.COM 
2611767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
2711767SAnurag.Maskey@Sun.COM #include <assert.h>
2811767SAnurag.Maskey@Sun.COM #include <libdllink.h>
2911767SAnurag.Maskey@Sun.COM #include <libdlstat.h>
3011767SAnurag.Maskey@Sun.COM #include <libnwam.h>
3111767SAnurag.Maskey@Sun.COM #include <libscf.h>
3211767SAnurag.Maskey@Sun.COM #include <netinet/in.h>
3311767SAnurag.Maskey@Sun.COM #include <stdlib.h>
3411767SAnurag.Maskey@Sun.COM #include <sys/socket.h>
3511767SAnurag.Maskey@Sun.COM #include <sys/time.h>
3611767SAnurag.Maskey@Sun.COM #include <sys/types.h>
3711767SAnurag.Maskey@Sun.COM #include <values.h>
3811767SAnurag.Maskey@Sun.COM 
3911767SAnurag.Maskey@Sun.COM #include "conditions.h"
4011767SAnurag.Maskey@Sun.COM #include "events.h"
4111767SAnurag.Maskey@Sun.COM #include "objects.h"
4211767SAnurag.Maskey@Sun.COM #include "ncp.h"
4311767SAnurag.Maskey@Sun.COM #include "ncu.h"
4411767SAnurag.Maskey@Sun.COM #include "util.h"
4511767SAnurag.Maskey@Sun.COM 
4611767SAnurag.Maskey@Sun.COM /*
4711767SAnurag.Maskey@Sun.COM  * ncp.c - handles NCP actions.
4811767SAnurag.Maskey@Sun.COM  */
4911767SAnurag.Maskey@Sun.COM 
5011767SAnurag.Maskey@Sun.COM char active_ncp[NWAM_MAX_NAME_LEN];
5111767SAnurag.Maskey@Sun.COM nwam_ncp_handle_t active_ncph = NULL;
5211767SAnurag.Maskey@Sun.COM int64_t current_ncu_priority_group = INVALID_PRIORITY_GROUP;
5311767SAnurag.Maskey@Sun.COM /*
5411767SAnurag.Maskey@Sun.COM  * active_ncp_mutex protects active_ncp, active_ncph and
5511767SAnurag.Maskey@Sun.COM  * current_ncu_priority_group.
5611767SAnurag.Maskey@Sun.COM  */
5711767SAnurag.Maskey@Sun.COM pthread_mutex_t active_ncp_mutex = PTHREAD_MUTEX_INITIALIZER;
5811767SAnurag.Maskey@Sun.COM 
5911767SAnurag.Maskey@Sun.COM /*
6011767SAnurag.Maskey@Sun.COM  * The variable ncu_wait_time specifies how long to wait to obtain a
6111767SAnurag.Maskey@Sun.COM  * DHCP lease before giving up on that NCU and moving on to the next/lower
6211767SAnurag.Maskey@Sun.COM  * priority-group.
6311767SAnurag.Maskey@Sun.COM  */
6411767SAnurag.Maskey@Sun.COM uint64_t ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
6511767SAnurag.Maskey@Sun.COM 
6611767SAnurag.Maskey@Sun.COM /*
6711767SAnurag.Maskey@Sun.COM  * Specifies if this is the first time the NCP has been enabled. True
6811767SAnurag.Maskey@Sun.COM  * on startup so that we can differentiate between when we start up
6911767SAnurag.Maskey@Sun.COM  * with a given NCP versus when we are asked to reenable it.
7011767SAnurag.Maskey@Sun.COM  */
7111767SAnurag.Maskey@Sun.COM boolean_t initial_ncp_enable = B_TRUE;
7211767SAnurag.Maskey@Sun.COM 
7311767SAnurag.Maskey@Sun.COM /*
7411767SAnurag.Maskey@Sun.COM  * nwamd_ncp_handle_enable_event() should be called in the event handling
7511767SAnurag.Maskey@Sun.COM  * loop in response to an _ENABLE event, triggered as a result of an
7611767SAnurag.Maskey@Sun.COM  * nwam_ncp_enable() call from a libnwam consumer.  To enable the new NCP,
7711767SAnurag.Maskey@Sun.COM  * we first call nwamd_fini_ncus() on the old NCP.  This results in enqueueing
7811767SAnurag.Maskey@Sun.COM  * of a set of _FINI events for each NCU.  These events are handled and in
7911767SAnurag.Maskey@Sun.COM  * order to tear down config, (online*, uninitialized) state change events
8011767SAnurag.Maskey@Sun.COM  * are created and consumed directly by the fini event handler (these events
8111767SAnurag.Maskey@Sun.COM  * are not enqueued as this would result in state events for the old NCP
8211767SAnurag.Maskey@Sun.COM  * appearing after the new NCP has been enabled.  After the _FINI events are
8311767SAnurag.Maskey@Sun.COM  * enqueued, we enqueue an NCP _OBJECT_STATE event for the new NCP.  Since
8411767SAnurag.Maskey@Sun.COM  * it is enqueued after the _FINI events, we are guaranteed no events for the
8511767SAnurag.Maskey@Sun.COM  * old NCP will appear after the new NCP is activated.
8611767SAnurag.Maskey@Sun.COM  */
8711767SAnurag.Maskey@Sun.COM void
nwamd_ncp_handle_enable_event(nwamd_event_t event)8811767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_enable_event(nwamd_event_t event)
8911767SAnurag.Maskey@Sun.COM {
9011767SAnurag.Maskey@Sun.COM 	char *new_ncp = event->event_object;
9111767SAnurag.Maskey@Sun.COM 	nwam_ncp_handle_t new_ncph;
9211767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
9311767SAnurag.Maskey@Sun.COM 
9411767SAnurag.Maskey@Sun.COM 	if (new_ncp[0] == '\0')
9511767SAnurag.Maskey@Sun.COM 		return;
9611767SAnurag.Maskey@Sun.COM 
9711767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
9811767SAnurag.Maskey@Sun.COM 	if (strcmp(active_ncp, new_ncp) == 0 && !initial_ncp_enable) {
9911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: "
10011767SAnurag.Maskey@Sun.COM 		    "%s is already active", new_ncp);
10111767SAnurag.Maskey@Sun.COM 		(void) pthread_mutex_unlock(&active_ncp_mutex);
10211767SAnurag.Maskey@Sun.COM 		return;
10311767SAnurag.Maskey@Sun.COM 	}
10411767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
10511767SAnurag.Maskey@Sun.COM 
10611767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: activating NCP %s",
10711767SAnurag.Maskey@Sun.COM 	    new_ncp);
10811767SAnurag.Maskey@Sun.COM 
10911767SAnurag.Maskey@Sun.COM 	/*
11011767SAnurag.Maskey@Sun.COM 	 * To activate new NCP, run nwamd_fini_ncus(), reset the active
11111767SAnurag.Maskey@Sun.COM 	 * priority-group, set the active_ncp property and refresh the
11211767SAnurag.Maskey@Sun.COM 	 * daemon.  The refresh action will trigger a re-read of the NCUs
11311767SAnurag.Maskey@Sun.COM 	 * for the activated NCP.
11411767SAnurag.Maskey@Sun.COM 	 */
11511767SAnurag.Maskey@Sun.COM 
11611767SAnurag.Maskey@Sun.COM 	nwamd_fini_ncus();
11711767SAnurag.Maskey@Sun.COM 
11812371SAnurag.Maskey@Oracle.COM 	if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph))
11912371SAnurag.Maskey@Oracle.COM 	    == NWAM_ENTITY_NOT_FOUND) {
12011767SAnurag.Maskey@Sun.COM 		err = nwam_ncp_create(new_ncp, 0, &new_ncph);
12111767SAnurag.Maskey@Sun.COM 	}
12211767SAnurag.Maskey@Sun.COM 
12311767SAnurag.Maskey@Sun.COM 	if (err == NWAM_SUCCESS) {
12412371SAnurag.Maskey@Oracle.COM 		nwam_ncp_free(new_ncph);
12511767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCP, new_ncp,
12611767SAnurag.Maskey@Sun.COM 		    NWAM_STATE_ONLINE, NWAM_AUX_STATE_ACTIVE);
12712371SAnurag.Maskey@Oracle.COM 	} else if (initial_ncp_enable) {
12812371SAnurag.Maskey@Oracle.COM 		/*
12912371SAnurag.Maskey@Oracle.COM 		 * We weren't able to enable the NCP when nwamd starts up,
13012371SAnurag.Maskey@Oracle.COM 		 * retry in a few seconds.
13112371SAnurag.Maskey@Oracle.COM 		 */
13212371SAnurag.Maskey@Oracle.COM 		nwamd_event_t retry_event = nwamd_event_init_object_action
13312371SAnurag.Maskey@Oracle.COM 		    (NWAM_OBJECT_TYPE_NCP, new_ncp, NULL, NWAM_ACTION_ENABLE);
13412371SAnurag.Maskey@Oracle.COM 		if (retry_event == NULL) {
13512371SAnurag.Maskey@Oracle.COM 			nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: "
13612371SAnurag.Maskey@Oracle.COM 			    "could not create retry event to enable %s NCP",
13712371SAnurag.Maskey@Oracle.COM 			    new_ncp);
13812371SAnurag.Maskey@Oracle.COM 			return;
13912371SAnurag.Maskey@Oracle.COM 		}
14012371SAnurag.Maskey@Oracle.COM 
14112371SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: "
14212371SAnurag.Maskey@Oracle.COM 		    "failed to enable %s NCP, retrying in %d seconds",
14312371SAnurag.Maskey@Oracle.COM 		    new_ncp, NWAMD_READONLY_RETRY_INTERVAL);
14412371SAnurag.Maskey@Oracle.COM 		nwamd_event_enqueue_timed(retry_event,
14512371SAnurag.Maskey@Oracle.COM 		    NWAMD_READONLY_RETRY_INTERVAL);
14611767SAnurag.Maskey@Sun.COM 	} else {
14711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s",
14811767SAnurag.Maskey@Sun.COM 		    nwam_strerror(err));
14911767SAnurag.Maskey@Sun.COM 		return;
15011767SAnurag.Maskey@Sun.COM 	}
15111767SAnurag.Maskey@Sun.COM }
15211767SAnurag.Maskey@Sun.COM 
15311767SAnurag.Maskey@Sun.COM void
nwamd_ncp_handle_action_event(nwamd_event_t event)15411767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_action_event(nwamd_event_t event)
15511767SAnurag.Maskey@Sun.COM {
15611767SAnurag.Maskey@Sun.COM 	switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
15711767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_ENABLE:
15811767SAnurag.Maskey@Sun.COM 		nwamd_ncp_handle_enable_event(event);
15911767SAnurag.Maskey@Sun.COM 		break;
16011767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_ADD:
16111767SAnurag.Maskey@Sun.COM 	case NWAM_ACTION_DESTROY:
16211767SAnurag.Maskey@Sun.COM 		/* nothing to do */
16311767SAnurag.Maskey@Sun.COM 		break;
16411767SAnurag.Maskey@Sun.COM 	default:
16511767SAnurag.Maskey@Sun.COM 		nlog(LOG_INFO, "nwam_ncp_handle_action_event: "
16611767SAnurag.Maskey@Sun.COM 		    "unexpected action");
16711767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
16811767SAnurag.Maskey@Sun.COM 		break;
16911767SAnurag.Maskey@Sun.COM 	}
17011767SAnurag.Maskey@Sun.COM }
17111767SAnurag.Maskey@Sun.COM 
17211767SAnurag.Maskey@Sun.COM /*
17311767SAnurag.Maskey@Sun.COM  * The only state events we create are (online, active) events which are
17411767SAnurag.Maskey@Sun.COM  * generated as part of an NCP enable action (see above).
17511767SAnurag.Maskey@Sun.COM  */
17611767SAnurag.Maskey@Sun.COM void
nwamd_ncp_handle_state_event(nwamd_event_t event)17711767SAnurag.Maskey@Sun.COM nwamd_ncp_handle_state_event(nwamd_event_t event)
17811767SAnurag.Maskey@Sun.COM {
17911767SAnurag.Maskey@Sun.COM 	char *new_ncp = event->event_object;
18011767SAnurag.Maskey@Sun.COM 	nwam_ncp_handle_t new_ncph, old_ncph;
18111767SAnurag.Maskey@Sun.COM 	nwam_error_t err;
18211767SAnurag.Maskey@Sun.COM 
18311767SAnurag.Maskey@Sun.COM 	/* The NCP to be activated should always exist. */
18411767SAnurag.Maskey@Sun.COM 	if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph)) != NWAM_SUCCESS) {
18511767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_handle_state_event: "
18611767SAnurag.Maskey@Sun.COM 		    "cannot read NCP %s: : %s", new_ncp, nwam_strerror(err));
18711767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
18811767SAnurag.Maskey@Sun.COM 		return;
18911767SAnurag.Maskey@Sun.COM 	}
19011767SAnurag.Maskey@Sun.COM 
19111767SAnurag.Maskey@Sun.COM 	/*
19211767SAnurag.Maskey@Sun.COM 	 * To activate new NCP, reset the active priority-group, set the
19311767SAnurag.Maskey@Sun.COM 	 * active_ncp property and refresh the daemon.  The refresh action will
19411767SAnurag.Maskey@Sun.COM 	 * trigger a re-read of the NCUs for the activated NCP.
19511767SAnurag.Maskey@Sun.COM 	 */
19611767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
19711767SAnurag.Maskey@Sun.COM 	old_ncph = active_ncph;
19811767SAnurag.Maskey@Sun.COM 	active_ncph = new_ncph;
19911767SAnurag.Maskey@Sun.COM 	nwam_ncp_free(old_ncph);
20011767SAnurag.Maskey@Sun.COM 	current_ncu_priority_group = INVALID_PRIORITY_GROUP;
20111767SAnurag.Maskey@Sun.COM 	(void) strlcpy(active_ncp, event->event_object,
20211767SAnurag.Maskey@Sun.COM 	    sizeof (active_ncp));
20311767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
20411767SAnurag.Maskey@Sun.COM 	(void) nwamd_set_string_property(OUR_FMRI, OUR_PG,
20511767SAnurag.Maskey@Sun.COM 	    OUR_ACTIVE_NCP_PROP_NAME, new_ncp);
20611767SAnurag.Maskey@Sun.COM 	(void) smf_refresh_instance(OUR_FMRI);
20711767SAnurag.Maskey@Sun.COM 	initial_ncp_enable = B_FALSE;
20811767SAnurag.Maskey@Sun.COM }
20911767SAnurag.Maskey@Sun.COM 
21011767SAnurag.Maskey@Sun.COM int
nwamd_ncp_action(const char * ncp,nwam_action_t action)21111767SAnurag.Maskey@Sun.COM nwamd_ncp_action(const char *ncp, nwam_action_t action)
21211767SAnurag.Maskey@Sun.COM {
21311767SAnurag.Maskey@Sun.COM 	nwamd_event_t event = nwamd_event_init_object_action
21411767SAnurag.Maskey@Sun.COM 	    (NWAM_OBJECT_TYPE_NCP, ncp, NULL, action);
21511767SAnurag.Maskey@Sun.COM 	if (event == NULL)
21611767SAnurag.Maskey@Sun.COM 		return (1);
21711767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue(event);
21811767SAnurag.Maskey@Sun.COM 	return (0);
21911767SAnurag.Maskey@Sun.COM }
22011767SAnurag.Maskey@Sun.COM 
22111767SAnurag.Maskey@Sun.COM /*
22211767SAnurag.Maskey@Sun.COM  * Below this point are routines handling NCU prioritization
22311767SAnurag.Maskey@Sun.COM  * policy for the active NCP.
22411767SAnurag.Maskey@Sun.COM  */
22511767SAnurag.Maskey@Sun.COM 
22611767SAnurag.Maskey@Sun.COM struct priority_group_cbarg {
22711767SAnurag.Maskey@Sun.COM 	uint64_t minpriority;
22811767SAnurag.Maskey@Sun.COM 	uint64_t currpriority;
22911767SAnurag.Maskey@Sun.COM 	boolean_t found;
23011767SAnurag.Maskey@Sun.COM };
23111767SAnurag.Maskey@Sun.COM 
23211767SAnurag.Maskey@Sun.COM /* Callback used to find next pg in NCP that is >= start_pg */
23311767SAnurag.Maskey@Sun.COM static int
find_next_priority_group_cb(nwamd_object_t object,void * data)23411767SAnurag.Maskey@Sun.COM find_next_priority_group_cb(nwamd_object_t object, void *data)
23511767SAnurag.Maskey@Sun.COM {
23611767SAnurag.Maskey@Sun.COM 	struct priority_group_cbarg *cbarg = data;
23711767SAnurag.Maskey@Sun.COM 	uint64_t priority;
23811767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu = object->nwamd_object_data;
23911767SAnurag.Maskey@Sun.COM 
240*12576SAnurag.Maskey@Oracle.COM 	if (ncu->ncu_link.nwamd_link_activation_mode !=
24111767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_PRIORITIZED)
24211767SAnurag.Maskey@Sun.COM 		return (0);
24311767SAnurag.Maskey@Sun.COM 
244*12576SAnurag.Maskey@Oracle.COM 	priority = ncu->ncu_link.nwamd_link_priority_group;
24511767SAnurag.Maskey@Sun.COM 
24611767SAnurag.Maskey@Sun.COM 	if (priority >= cbarg->minpriority && priority < cbarg->currpriority) {
24711767SAnurag.Maskey@Sun.COM 		cbarg->found = B_TRUE;
24811767SAnurag.Maskey@Sun.COM 		cbarg->currpriority = priority;
24911767SAnurag.Maskey@Sun.COM 	}
25011767SAnurag.Maskey@Sun.COM 	return (0);
25111767SAnurag.Maskey@Sun.COM }
25211767SAnurag.Maskey@Sun.COM 
25311767SAnurag.Maskey@Sun.COM /* Set current_pg to next pg in NCP that is >= start_pg */
25411767SAnurag.Maskey@Sun.COM boolean_t
nwamd_ncp_find_next_priority_group(int64_t minpriority,int64_t * nextpriorityp)25511767SAnurag.Maskey@Sun.COM nwamd_ncp_find_next_priority_group(int64_t minpriority,
25611767SAnurag.Maskey@Sun.COM     int64_t *nextpriorityp)
25711767SAnurag.Maskey@Sun.COM {
25811767SAnurag.Maskey@Sun.COM 	struct priority_group_cbarg cbarg;
25911767SAnurag.Maskey@Sun.COM 
26011767SAnurag.Maskey@Sun.COM 	cbarg.minpriority = minpriority;
26111767SAnurag.Maskey@Sun.COM 	cbarg.currpriority = MAXINT;
26211767SAnurag.Maskey@Sun.COM 	cbarg.found = B_FALSE;
26311767SAnurag.Maskey@Sun.COM 
26411767SAnurag.Maskey@Sun.COM 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
26511767SAnurag.Maskey@Sun.COM 	    find_next_priority_group_cb, &cbarg);
26611767SAnurag.Maskey@Sun.COM 
26711767SAnurag.Maskey@Sun.COM 	if (cbarg.found) {
26811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
26911767SAnurag.Maskey@Sun.COM 		    "next priority group >= %lld is %lld",
27011767SAnurag.Maskey@Sun.COM 		    minpriority, cbarg.currpriority);
27111767SAnurag.Maskey@Sun.COM 		*nextpriorityp = cbarg.currpriority;
27211767SAnurag.Maskey@Sun.COM 		return (B_TRUE);
27311767SAnurag.Maskey@Sun.COM 	} else {
27411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: "
27511767SAnurag.Maskey@Sun.COM 		    "no priority groups >= %lld exist", minpriority);
27611767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
27711767SAnurag.Maskey@Sun.COM 	}
27811767SAnurag.Maskey@Sun.COM }
27911767SAnurag.Maskey@Sun.COM 
28011767SAnurag.Maskey@Sun.COM /*
28111767SAnurag.Maskey@Sun.COM  * Struct for walking NCUs in the selected priority group.  We count
28211767SAnurag.Maskey@Sun.COM  * how many of the exclusive, all and shared NCUs are online, and
28311767SAnurag.Maskey@Sun.COM  * if activate_or_deactivate is true, we either activate or deactivate
28411767SAnurag.Maskey@Sun.COM  * (depending on the value of activate) offline/online NCUs.
28511767SAnurag.Maskey@Sun.COM  */
28611767SAnurag.Maskey@Sun.COM struct nwamd_ncu_check_walk_arg {
28711767SAnurag.Maskey@Sun.COM 	boolean_t manual;	/* enable manual NCUs only */
28811767SAnurag.Maskey@Sun.COM 	int64_t priority_group; /* interested priority-group for this walk */
28911767SAnurag.Maskey@Sun.COM 	uint64_t exclusive_ncus;
29011767SAnurag.Maskey@Sun.COM 	uint64_t exclusive_online_ncus;
29111767SAnurag.Maskey@Sun.COM 	uint64_t shared_ncus;
29211767SAnurag.Maskey@Sun.COM 	uint64_t shared_online_ncus;
29311767SAnurag.Maskey@Sun.COM 	uint64_t all_ncus;
29411767SAnurag.Maskey@Sun.COM 	uint64_t all_online_ncus;
29511767SAnurag.Maskey@Sun.COM 	boolean_t activate_or_deactivate;
29611767SAnurag.Maskey@Sun.COM 	boolean_t activate;
29711767SAnurag.Maskey@Sun.COM };
29811767SAnurag.Maskey@Sun.COM 
29911767SAnurag.Maskey@Sun.COM /*
30011767SAnurag.Maskey@Sun.COM  * This function serves a number of purposes:
30111767SAnurag.Maskey@Sun.COM  * - it supports activation/deactivation of manual NCUs in the current NCP
30211767SAnurag.Maskey@Sun.COM  * (when wa->manual is true, wa->activate determines if we activate or
30311767SAnurag.Maskey@Sun.COM  * deactivate the current NCU)
30411767SAnurag.Maskey@Sun.COM  * - it supports checking/activation of a particular priority group in
30511767SAnurag.Maskey@Sun.COM  * the active NCP. This works as follows:
30611767SAnurag.Maskey@Sun.COM  *
30711767SAnurag.Maskey@Sun.COM  * Count up numbers of exclusive, shared and all NCUs, and how many of each
30811767SAnurag.Maskey@Sun.COM  * are online.  If an NCU is waiting for IP address to be assigned, it is
30911767SAnurag.Maskey@Sun.COM  * also considered online.  If activate_or_deactivate is true, we also
31011767SAnurag.Maskey@Sun.COM  * either activate (if activate is true) or deactivate prioritized NCUs
31111767SAnurag.Maskey@Sun.COM  * that are offline or online.
31211767SAnurag.Maskey@Sun.COM  */
31311767SAnurag.Maskey@Sun.COM static int
nwamd_ncu_check_or_activate(nwamd_object_t object,void * data)31411767SAnurag.Maskey@Sun.COM nwamd_ncu_check_or_activate(nwamd_object_t object, void *data)
31511767SAnurag.Maskey@Sun.COM {
31611767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg *wa = data;
31711767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
31811767SAnurag.Maskey@Sun.COM 	uint64_t priority_group, priority_mode;
31911767SAnurag.Maskey@Sun.COM 	nwamd_object_t if_obj;
32011767SAnurag.Maskey@Sun.COM 	nwam_state_t state, if_state;
32111767SAnurag.Maskey@Sun.COM 	nwam_aux_state_t aux_state, if_aux_state;
32211767SAnurag.Maskey@Sun.COM 	char *name;
32311767SAnurag.Maskey@Sun.COM 
32411767SAnurag.Maskey@Sun.COM 	state = object->nwamd_object_state;
32511767SAnurag.Maskey@Sun.COM 	aux_state = object->nwamd_object_aux_state;
32611767SAnurag.Maskey@Sun.COM 	name = object->nwamd_object_name;
32711767SAnurag.Maskey@Sun.COM 	ncu = object->nwamd_object_data;
32811767SAnurag.Maskey@Sun.COM 
32911767SAnurag.Maskey@Sun.COM 	/* skip NCUs in UNINITIALIZED state */
33011767SAnurag.Maskey@Sun.COM 	if (state == NWAM_STATE_UNINITIALIZED) {
33111767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
33211767SAnurag.Maskey@Sun.COM 		    "skipping uninitialized ncu %s", name);
33311767SAnurag.Maskey@Sun.COM 		return (0);
33411767SAnurag.Maskey@Sun.COM 	}
33511767SAnurag.Maskey@Sun.COM 	if (!wa->manual && wa->priority_group == INVALID_PRIORITY_GROUP)
33611767SAnurag.Maskey@Sun.COM 		return (0);
33711767SAnurag.Maskey@Sun.COM 
33811767SAnurag.Maskey@Sun.COM 	if (ncu->ncu_type != NWAM_NCU_TYPE_LINK) {
33911767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
34011767SAnurag.Maskey@Sun.COM 		    "skipping interface NCU %s", name);
34111767SAnurag.Maskey@Sun.COM 		return (0);
34211767SAnurag.Maskey@Sun.COM 	}
343*12576SAnurag.Maskey@Oracle.COM 	if (!wa->manual && ncu->ncu_link.nwamd_link_activation_mode !=
34411767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_PRIORITIZED) {
34511767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
34611767SAnurag.Maskey@Sun.COM 		    "skipping non-prioritized NCU %s", name);
34711767SAnurag.Maskey@Sun.COM 		return (0);
34811767SAnurag.Maskey@Sun.COM 	}
349*12576SAnurag.Maskey@Oracle.COM 	if (wa->manual && ncu->ncu_link.nwamd_link_activation_mode !=
35011767SAnurag.Maskey@Sun.COM 	    NWAM_ACTIVATION_MODE_MANUAL) {
35111767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
35211767SAnurag.Maskey@Sun.COM 		    "skipping non-manual NCU %s", name);
35311767SAnurag.Maskey@Sun.COM 		return (0);
35411767SAnurag.Maskey@Sun.COM 	}
35511767SAnurag.Maskey@Sun.COM 
356*12576SAnurag.Maskey@Oracle.COM 	priority_group = ncu->ncu_link.nwamd_link_priority_group;
357*12576SAnurag.Maskey@Oracle.COM 	priority_mode = ncu->ncu_link.nwamd_link_priority_mode;
35811767SAnurag.Maskey@Sun.COM 	/* Only work with NCUs in the requested priority-group */
35911767SAnurag.Maskey@Sun.COM 	if (!wa->manual && priority_group != wa->priority_group) {
36011767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
36111767SAnurag.Maskey@Sun.COM 		    "skipping NCU %s in different priority-group", name);
36211767SAnurag.Maskey@Sun.COM 		return (0);
36311767SAnurag.Maskey@Sun.COM 	}
36411767SAnurag.Maskey@Sun.COM 	/* Get the state of the corresponding interface NCU */
36511767SAnurag.Maskey@Sun.COM 	if ((if_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE,
36611767SAnurag.Maskey@Sun.COM 	    ncu->ncu_name)) == NULL) {
36711767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
36811767SAnurag.Maskey@Sun.COM 		    "interface NCU of %s not found, skipping", name);
36911767SAnurag.Maskey@Sun.COM 		return (0);
37011767SAnurag.Maskey@Sun.COM 	}
37111767SAnurag.Maskey@Sun.COM 	if_state = if_obj->nwamd_object_state;
37211767SAnurag.Maskey@Sun.COM 	if_aux_state = if_obj->nwamd_object_aux_state;
37311767SAnurag.Maskey@Sun.COM 	nwamd_object_release(if_obj);
37411767SAnurag.Maskey@Sun.COM 
37511767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: %s ncu %s",
37611767SAnurag.Maskey@Sun.COM 	    wa->activate_or_deactivate ?
37711767SAnurag.Maskey@Sun.COM 	    (wa->activate ? "activating" : "deactivating") :
37811767SAnurag.Maskey@Sun.COM 	    "checking", name);
37911767SAnurag.Maskey@Sun.COM 
38011767SAnurag.Maskey@Sun.COM 	if (wa->manual) {
38111767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
38211767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE && ncu->ncu_enabled) {
38311767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
38411767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to offline* from offline",
38511767SAnurag.Maskey@Sun.COM 				    name);
38611767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
38711767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
38811767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
38911767SAnurag.Maskey@Sun.COM 			}
39011767SAnurag.Maskey@Sun.COM 			if (state != NWAM_STATE_DISABLED &&
39111767SAnurag.Maskey@Sun.COM 			    !ncu->ncu_enabled) {
39211767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
39311767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to online* (disabling)",
39411767SAnurag.Maskey@Sun.COM 				    name);
39511767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
39611767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
39711767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_MANUAL_DISABLE);
39811767SAnurag.Maskey@Sun.COM 			}
39911767SAnurag.Maskey@Sun.COM 		}
40011767SAnurag.Maskey@Sun.COM 		return (0);
40111767SAnurag.Maskey@Sun.COM 	}
40211767SAnurag.Maskey@Sun.COM 	switch (priority_mode) {
40311767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_EXCLUSIVE:
40411767SAnurag.Maskey@Sun.COM 		wa->exclusive_ncus++;
40511767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
40611767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
40711767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
40811767SAnurag.Maskey@Sun.COM 			wa->exclusive_online_ncus++;
40911767SAnurag.Maskey@Sun.COM 
41011767SAnurag.Maskey@Sun.COM 		/*
41111767SAnurag.Maskey@Sun.COM 		 * For exclusive NCUs, we activate offline NCUs as long
41211767SAnurag.Maskey@Sun.COM 		 * as no other exclusive NCUs are active.
41311767SAnurag.Maskey@Sun.COM 		 */
41411767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
41511767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE &&
41611767SAnurag.Maskey@Sun.COM 			    wa->exclusive_online_ncus == 0) {
41711767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
41811767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to offline* from offline",
41911767SAnurag.Maskey@Sun.COM 				    name);
42011767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
42111767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
42211767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
42311767SAnurag.Maskey@Sun.COM 			}
42411767SAnurag.Maskey@Sun.COM 		}
42511767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
42611767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
42711767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
42811767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
42911767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
43011767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
43111767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
43211767SAnurag.Maskey@Sun.COM 			}
43311767SAnurag.Maskey@Sun.COM 		}
43411767SAnurag.Maskey@Sun.COM 		/*
43511767SAnurag.Maskey@Sun.COM 		 * If we are activating or checking the priority group and
43611767SAnurag.Maskey@Sun.COM 		 * too many exclusive NCUs are online, take this NCU down.
43711767SAnurag.Maskey@Sun.COM 		 */
43811767SAnurag.Maskey@Sun.COM 		if ((wa->activate_or_deactivate && wa->activate) ||
43911767SAnurag.Maskey@Sun.COM 		    !wa->activate_or_deactivate) {
44011767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_ONLINE &&
44111767SAnurag.Maskey@Sun.COM 			    if_state == NWAM_STATE_ONLINE &&
44211767SAnurag.Maskey@Sun.COM 			    wa->exclusive_online_ncus > 1) {
44311767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
44411767SAnurag.Maskey@Sun.COM 				    "moving NCU %s to online* since another "
44511767SAnurag.Maskey@Sun.COM 				    "NCU is already active",
44611767SAnurag.Maskey@Sun.COM 				    name);
44711767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
44811767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
44911767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
45011767SAnurag.Maskey@Sun.COM 			}
45111767SAnurag.Maskey@Sun.COM 		}
45211767SAnurag.Maskey@Sun.COM 		break;
45311767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_SHARED:
45411767SAnurag.Maskey@Sun.COM 		wa->shared_ncus++;
45511767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
45611767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
45711767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
45811767SAnurag.Maskey@Sun.COM 			wa->shared_online_ncus++;
45911767SAnurag.Maskey@Sun.COM 
46011767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
46111767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE) {
46211767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
46311767SAnurag.Maskey@Sun.COM 				    "activating NCU %s", name);
46411767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
46511767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
46611767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
46711767SAnurag.Maskey@Sun.COM 			}
46811767SAnurag.Maskey@Sun.COM 		}
46911767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
47011767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
47111767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
47211767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
47311767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
47411767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
47511767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
47611767SAnurag.Maskey@Sun.COM 			}
47711767SAnurag.Maskey@Sun.COM 		}
47811767SAnurag.Maskey@Sun.COM 		break;
47911767SAnurag.Maskey@Sun.COM 	case NWAM_PRIORITY_MODE_ALL:
48011767SAnurag.Maskey@Sun.COM 		wa->all_ncus++;
48111767SAnurag.Maskey@Sun.COM 		if (state == NWAM_STATE_ONLINE &&
48211767SAnurag.Maskey@Sun.COM 		    (if_state == NWAM_STATE_ONLINE ||
48311767SAnurag.Maskey@Sun.COM 		    if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR))
48411767SAnurag.Maskey@Sun.COM 			wa->all_online_ncus++;
48511767SAnurag.Maskey@Sun.COM 
48611767SAnurag.Maskey@Sun.COM 		/*
48711767SAnurag.Maskey@Sun.COM 		 * For "all" NCUs, activate/deactivate all offline/online
48811767SAnurag.Maskey@Sun.COM 		 * NCUs.
48911767SAnurag.Maskey@Sun.COM 		 */
49011767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && wa->activate) {
49111767SAnurag.Maskey@Sun.COM 			if (state == NWAM_STATE_OFFLINE) {
49211767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
49311767SAnurag.Maskey@Sun.COM 				    "activating NCU %s", name);
49411767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
49511767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_OFFLINE_TO_ONLINE,
49611767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_INITIALIZED);
49711767SAnurag.Maskey@Sun.COM 			}
49811767SAnurag.Maskey@Sun.COM 		}
49911767SAnurag.Maskey@Sun.COM 		if (wa->activate_or_deactivate && !wa->activate) {
50011767SAnurag.Maskey@Sun.COM 			if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
50111767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: "
50211767SAnurag.Maskey@Sun.COM 				    "deactivating NCU %s", name);
50311767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
50411767SAnurag.Maskey@Sun.COM 				    name, NWAM_STATE_ONLINE_TO_OFFLINE,
50511767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
50611767SAnurag.Maskey@Sun.COM 			}
50711767SAnurag.Maskey@Sun.COM 		}
50811767SAnurag.Maskey@Sun.COM 
50911767SAnurag.Maskey@Sun.COM 		break;
51011767SAnurag.Maskey@Sun.COM 	default:
51111767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_check_or_activate: "
51211767SAnurag.Maskey@Sun.COM 		    "invalid priority-mode");
51311767SAnurag.Maskey@Sun.COM 		break;
51411767SAnurag.Maskey@Sun.COM 	}
51511767SAnurag.Maskey@Sun.COM 
51611767SAnurag.Maskey@Sun.COM 	return (0);
51711767SAnurag.Maskey@Sun.COM }
51811767SAnurag.Maskey@Sun.COM 
51911767SAnurag.Maskey@Sun.COM void
nwamd_ncp_activate_priority_group(int64_t priority)52011767SAnurag.Maskey@Sun.COM nwamd_ncp_activate_priority_group(int64_t priority)
52111767SAnurag.Maskey@Sun.COM {
52211767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
52311767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event, priority_event;
52411767SAnurag.Maskey@Sun.COM 
52511767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
52611767SAnurag.Maskey@Sun.COM 		return;
52711767SAnurag.Maskey@Sun.COM 
52811767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_lock(&active_ncp_mutex);
52911767SAnurag.Maskey@Sun.COM 	if (priority == current_ncu_priority_group) {
53011767SAnurag.Maskey@Sun.COM 		(void) pthread_mutex_unlock(&active_ncp_mutex);
53111767SAnurag.Maskey@Sun.COM 		return;
53211767SAnurag.Maskey@Sun.COM 	}
53311767SAnurag.Maskey@Sun.COM 	(void) pthread_mutex_unlock(&active_ncp_mutex);
53411767SAnurag.Maskey@Sun.COM 
53511767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_activate_priority_group: "
53611767SAnurag.Maskey@Sun.COM 	    "activating priority group %lld", priority);
53711767SAnurag.Maskey@Sun.COM 
53811767SAnurag.Maskey@Sun.COM 	wa.manual = B_FALSE;
53911767SAnurag.Maskey@Sun.COM 	wa.priority_group = priority;
54011767SAnurag.Maskey@Sun.COM 	wa.exclusive_ncus = 0;
54111767SAnurag.Maskey@Sun.COM 	wa.exclusive_online_ncus = 0;
54211767SAnurag.Maskey@Sun.COM 	wa.shared_ncus = 0;
54311767SAnurag.Maskey@Sun.COM 	wa.shared_online_ncus = 0;
54411767SAnurag.Maskey@Sun.COM 	wa.all_ncus = 0;
54511767SAnurag.Maskey@Sun.COM 	wa.all_online_ncus = 0;
54611767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
54711767SAnurag.Maskey@Sun.COM 	wa.activate = B_TRUE;
54811767SAnurag.Maskey@Sun.COM 
54911767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
55011767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
55111767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_activate_priority_group: "
55211767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
55311767SAnurag.Maskey@Sun.COM 		return;
55411767SAnurag.Maskey@Sun.COM 	}
55511767SAnurag.Maskey@Sun.COM 
55611767SAnurag.Maskey@Sun.COM 	/*
55711767SAnurag.Maskey@Sun.COM 	 * Enqueue event to update current_ncu_priority_group and send to
55811767SAnurag.Maskey@Sun.COM 	 * any event listeners.
55911767SAnurag.Maskey@Sun.COM 	 */
56011767SAnurag.Maskey@Sun.COM 	priority_event = nwamd_event_init_priority_group_change(priority);
56111767SAnurag.Maskey@Sun.COM 	if (priority_event == NULL)
56211767SAnurag.Maskey@Sun.COM 		return;
56311767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue(priority_event);
56411767SAnurag.Maskey@Sun.COM 
56511767SAnurag.Maskey@Sun.COM 	/*
56611767SAnurag.Maskey@Sun.COM 	 * Now we've activated a new priority group, enqueue an event
56711767SAnurag.Maskey@Sun.COM 	 * to check up on the state of this priority group.
56811767SAnurag.Maskey@Sun.COM 	 */
56911767SAnurag.Maskey@Sun.COM 	check_event = nwamd_event_init_ncu_check();
57011767SAnurag.Maskey@Sun.COM 	if (check_event == NULL)
57111767SAnurag.Maskey@Sun.COM 		return;
57211767SAnurag.Maskey@Sun.COM 	nwamd_event_enqueue_timed(check_event, ncu_wait_time);
57311767SAnurag.Maskey@Sun.COM }
57411767SAnurag.Maskey@Sun.COM 
57511767SAnurag.Maskey@Sun.COM void
nwamd_ncp_deactivate_priority_group(int64_t priority)57611767SAnurag.Maskey@Sun.COM nwamd_ncp_deactivate_priority_group(int64_t priority)
57711767SAnurag.Maskey@Sun.COM {
57811767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
57911767SAnurag.Maskey@Sun.COM 
58011767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
58111767SAnurag.Maskey@Sun.COM 		return;
58211767SAnurag.Maskey@Sun.COM 
58311767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group: "
58411767SAnurag.Maskey@Sun.COM 	    "deactivating priority group %lld", priority);
58511767SAnurag.Maskey@Sun.COM 
58611767SAnurag.Maskey@Sun.COM 	wa.manual = B_FALSE;
58711767SAnurag.Maskey@Sun.COM 	wa.priority_group = priority;
58811767SAnurag.Maskey@Sun.COM 	wa.exclusive_ncus = 0;
58911767SAnurag.Maskey@Sun.COM 	wa.exclusive_online_ncus = 0;
59011767SAnurag.Maskey@Sun.COM 	wa.shared_ncus = 0;
59111767SAnurag.Maskey@Sun.COM 	wa.shared_online_ncus = 0;
59211767SAnurag.Maskey@Sun.COM 	wa.all_ncus = 0;
59311767SAnurag.Maskey@Sun.COM 	wa.all_online_ncus = 0;
59411767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
59511767SAnurag.Maskey@Sun.COM 	wa.activate = B_FALSE;
59611767SAnurag.Maskey@Sun.COM 
59711767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
59811767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
59911767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_deactivate_priority_group: "
60011767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
60111767SAnurag.Maskey@Sun.COM 		return;
60211767SAnurag.Maskey@Sun.COM 	}
60311767SAnurag.Maskey@Sun.COM }
60411767SAnurag.Maskey@Sun.COM 
60511767SAnurag.Maskey@Sun.COM /*
60611767SAnurag.Maskey@Sun.COM  * This function deactivates all priority groups at level 'priority' and lower
60711767SAnurag.Maskey@Sun.COM  * (which is, numerically, all priorities >= priority).
60811767SAnurag.Maskey@Sun.COM  */
60911767SAnurag.Maskey@Sun.COM void
nwamd_ncp_deactivate_priority_group_all(int64_t priority)61011767SAnurag.Maskey@Sun.COM nwamd_ncp_deactivate_priority_group_all(int64_t priority)
61111767SAnurag.Maskey@Sun.COM {
61211767SAnurag.Maskey@Sun.COM 	if (priority == INVALID_PRIORITY_GROUP)
61311767SAnurag.Maskey@Sun.COM 		return;
61411767SAnurag.Maskey@Sun.COM 
61511767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group_all: "
61611767SAnurag.Maskey@Sun.COM 	    "deactivating priority group less than or equal to %lld", priority);
61711767SAnurag.Maskey@Sun.COM 
61811767SAnurag.Maskey@Sun.COM 	do {
61911767SAnurag.Maskey@Sun.COM 		nwamd_ncp_deactivate_priority_group(priority);
62011767SAnurag.Maskey@Sun.COM 	} while (nwamd_ncp_find_next_priority_group(priority + 1, &priority));
62111767SAnurag.Maskey@Sun.COM }
62211767SAnurag.Maskey@Sun.COM 
62311767SAnurag.Maskey@Sun.COM /*
62411767SAnurag.Maskey@Sun.COM  * Returns 'true' if it found the highest priority group no higher then what
62511767SAnurag.Maskey@Sun.COM  * is passed that should be activated and sets *priority to that.
62611767SAnurag.Maskey@Sun.COM  */
62711767SAnurag.Maskey@Sun.COM boolean_t
nwamd_ncp_check_priority_group(int64_t * priority)62811767SAnurag.Maskey@Sun.COM nwamd_ncp_check_priority_group(int64_t *priority)
62911767SAnurag.Maskey@Sun.COM {
63011767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
63111767SAnurag.Maskey@Sun.COM 	boolean_t conditions_met = B_FALSE;
63211767SAnurag.Maskey@Sun.COM 
63311767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_check_priority_group: "
63411767SAnurag.Maskey@Sun.COM 	    "checking priority group %lld", *priority);
63511767SAnurag.Maskey@Sun.COM 
63611767SAnurag.Maskey@Sun.COM 	if (*priority == INVALID_PRIORITY_GROUP) {
63711767SAnurag.Maskey@Sun.COM 		if (!nwamd_ncp_find_next_priority_group(0, priority))
63811767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
63911767SAnurag.Maskey@Sun.COM 	}
64011767SAnurag.Maskey@Sun.COM 
64111767SAnurag.Maskey@Sun.COM 	while (!conditions_met) {
64211767SAnurag.Maskey@Sun.COM 		(void) memset(&wa, 0, sizeof (wa));
64311767SAnurag.Maskey@Sun.COM 		wa.manual = B_FALSE;
64411767SAnurag.Maskey@Sun.COM 		wa.priority_group = *priority;
64511767SAnurag.Maskey@Sun.COM 		wa.activate_or_deactivate = B_FALSE;
64611767SAnurag.Maskey@Sun.COM 
64711767SAnurag.Maskey@Sun.COM 		if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
64811767SAnurag.Maskey@Sun.COM 		    nwamd_ncu_check_or_activate, &wa) != 0) {
64911767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_ncp_check_priority_group: "
65011767SAnurag.Maskey@Sun.COM 			    "nwamd_walk_objects() failed");
65111767SAnurag.Maskey@Sun.COM 			return (B_FALSE);
65211767SAnurag.Maskey@Sun.COM 		}
65311767SAnurag.Maskey@Sun.COM 
65411767SAnurag.Maskey@Sun.COM 		/*
65511767SAnurag.Maskey@Sun.COM 		 * Are activation conditons satisifed? In other words:
65611767SAnurag.Maskey@Sun.COM 		 * - exactly one of the exclusive NCUs is online
65711767SAnurag.Maskey@Sun.COM 		 * - 1 or more shared NCUs are online
65811767SAnurag.Maskey@Sun.COM 		 * - all of the all NCUs are online.
65911767SAnurag.Maskey@Sun.COM 		 * If any of these is untrue, conditions are not satisfied.
66011767SAnurag.Maskey@Sun.COM 		 */
66111767SAnurag.Maskey@Sun.COM 		conditions_met = B_TRUE;
66211767SAnurag.Maskey@Sun.COM 		if (wa.exclusive_ncus > 0 && wa.exclusive_online_ncus != 1)
66311767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
66411767SAnurag.Maskey@Sun.COM 		if (wa.shared_ncus > 0 && wa.shared_online_ncus == 0)
66511767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
66611767SAnurag.Maskey@Sun.COM 		if (wa.all_ncus > 0 && wa.all_ncus != wa.all_online_ncus)
66711767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
66811767SAnurag.Maskey@Sun.COM 		if (wa.exclusive_online_ncus == 0 &&
66911767SAnurag.Maskey@Sun.COM 		    wa.shared_online_ncus == 0 && wa.all_online_ncus == 0)
67011767SAnurag.Maskey@Sun.COM 			conditions_met = B_FALSE;
67111767SAnurag.Maskey@Sun.COM 
67211767SAnurag.Maskey@Sun.COM 		if (conditions_met) {
67311767SAnurag.Maskey@Sun.COM 			return (B_TRUE);
67411767SAnurag.Maskey@Sun.COM 		} else {
67511767SAnurag.Maskey@Sun.COM 			/*
67611767SAnurag.Maskey@Sun.COM 			 * If there is a next pg, activate it. If not, do
67711767SAnurag.Maskey@Sun.COM 			 * nothing - we're stuck here unless an event occurs
67811767SAnurag.Maskey@Sun.COM 			 * for our or a higher pg.
67911767SAnurag.Maskey@Sun.COM 			 */
68011767SAnurag.Maskey@Sun.COM 			if (!nwamd_ncp_find_next_priority_group
68111767SAnurag.Maskey@Sun.COM 			    (wa.priority_group + 1, priority)) {
68211767SAnurag.Maskey@Sun.COM 				nlog(LOG_DEBUG, "ran out of prio groups");
68311767SAnurag.Maskey@Sun.COM 				return (B_FALSE);
68411767SAnurag.Maskey@Sun.COM 			}
68511767SAnurag.Maskey@Sun.COM 		}
68611767SAnurag.Maskey@Sun.COM 	}
68711767SAnurag.Maskey@Sun.COM 	return (B_FALSE);
68811767SAnurag.Maskey@Sun.COM }
68911767SAnurag.Maskey@Sun.COM 
69011767SAnurag.Maskey@Sun.COM void
nwamd_ncp_activate_manual_ncus(void)69111767SAnurag.Maskey@Sun.COM nwamd_ncp_activate_manual_ncus(void)
69211767SAnurag.Maskey@Sun.COM {
69311767SAnurag.Maskey@Sun.COM 	struct nwamd_ncu_check_walk_arg wa;
69411767SAnurag.Maskey@Sun.COM 
69511767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncp_activate_manual_ncus: activating NCUs");
69611767SAnurag.Maskey@Sun.COM 
69711767SAnurag.Maskey@Sun.COM 	wa.manual = B_TRUE;
69811767SAnurag.Maskey@Sun.COM 	wa.activate_or_deactivate = B_TRUE;
69911767SAnurag.Maskey@Sun.COM 	wa.activate = B_TRUE;
70011767SAnurag.Maskey@Sun.COM 
70111767SAnurag.Maskey@Sun.COM 	if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
70211767SAnurag.Maskey@Sun.COM 	    nwamd_ncu_check_or_activate, &wa) != 0) {
70311767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncp_activate_manual_ncus: "
70411767SAnurag.Maskey@Sun.COM 		    "nwamd_walk_objects() failed");
70511767SAnurag.Maskey@Sun.COM 		return;
70611767SAnurag.Maskey@Sun.COM 	}
70711767SAnurag.Maskey@Sun.COM }
70811767SAnurag.Maskey@Sun.COM 
70911767SAnurag.Maskey@Sun.COM void
nwamd_create_ncu_check_event(uint64_t when)71011767SAnurag.Maskey@Sun.COM nwamd_create_ncu_check_event(uint64_t when)
71111767SAnurag.Maskey@Sun.COM {
71211767SAnurag.Maskey@Sun.COM 	nwamd_event_t check_event = nwamd_event_init_ncu_check();
71311767SAnurag.Maskey@Sun.COM 	if (check_event != NULL)
71411767SAnurag.Maskey@Sun.COM 		nwamd_event_enqueue_timed(check_event, when);
71511767SAnurag.Maskey@Sun.COM }
716