xref: /onnv-gate/usr/src/cmd/rcm_daemon/common/rcm_impl.c (revision 4845:357e8e7542af)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*4845Svikram  * Common Development and Distribution License (the "License").
6*4845Svikram  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
21*4845Svikram  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <librcm_impl.h>
280Sstevel@tonic-gate #include "rcm_impl.h"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate static int query(char **, int, const char *, int, pid_t, uint_t, timespec_t *,
310Sstevel@tonic-gate     int, rcm_info_t **, int *);
320Sstevel@tonic-gate static void cancel_query(int, const char *, pid_t, uint_t, int);
330Sstevel@tonic-gate 
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate  * The following ops are invoked when modules initiate librcm calls which
360Sstevel@tonic-gate  * require daemon processing. Cascaded RCM operations must come through
370Sstevel@tonic-gate  * this path.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate librcm_ops_t rcm_ops = {
400Sstevel@tonic-gate 	add_resource_client,
410Sstevel@tonic-gate 	remove_resource_client,
420Sstevel@tonic-gate 	get_resource_info,
430Sstevel@tonic-gate 	process_resource_suspend,
440Sstevel@tonic-gate 	notify_resource_resume,
450Sstevel@tonic-gate 	process_resource_offline,
460Sstevel@tonic-gate 	notify_resource_online,
470Sstevel@tonic-gate 	notify_resource_remove,
480Sstevel@tonic-gate 	request_capacity_change,
490Sstevel@tonic-gate 	notify_capacity_change,
500Sstevel@tonic-gate 	notify_resource_event,
510Sstevel@tonic-gate 	get_resource_state
520Sstevel@tonic-gate };
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * Process a request or a notification on a subtree
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate /*ARGSUSED2*/
580Sstevel@tonic-gate static int
common_resource_op(int cmd,char * rsrcname,pid_t pid,uint_t flag,int seq_num,timespec_t * interval,nvlist_t * nvl,rcm_info_t ** info)590Sstevel@tonic-gate common_resource_op(int cmd, char *rsrcname, pid_t pid, uint_t flag, int seq_num,
600Sstevel@tonic-gate     timespec_t *interval, nvlist_t *nvl, rcm_info_t **info)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	int error;
630Sstevel@tonic-gate 	rsrc_node_t *node;
640Sstevel@tonic-gate 	tree_walk_arg_t arg;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	/*
670Sstevel@tonic-gate 	 * Find the node (root of subtree) in the resource tree, invoke
680Sstevel@tonic-gate 	 * appropriate callbacks for all clients hanging off the subtree,
690Sstevel@tonic-gate 	 * and mark the subtree with the appropriate state.
700Sstevel@tonic-gate 	 *
710Sstevel@tonic-gate 	 * NOTE: It's possible the node doesn't exist, which means no RCM
720Sstevel@tonic-gate 	 * consumer registered for the resource. In this case we silently
730Sstevel@tonic-gate 	 * succeed.
740Sstevel@tonic-gate 	 */
750Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
760Sstevel@tonic-gate 	if ((error == RCM_SUCCESS) && (node != NULL)) {
770Sstevel@tonic-gate 		arg.flag = flag;
780Sstevel@tonic-gate 		arg.info = info;
790Sstevel@tonic-gate 		arg.seq_num = seq_num;
800Sstevel@tonic-gate 		arg.interval = interval;
810Sstevel@tonic-gate 		arg.nvl = nvl;
820Sstevel@tonic-gate 		arg.cmd = cmd;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 		if ((cmd == CMD_NOTIFY_CHANGE) ||
850Sstevel@tonic-gate 		    (cmd == CMD_REQUEST_CHANGE) ||
860Sstevel@tonic-gate 		    (cmd == CMD_EVENT)) {
870Sstevel@tonic-gate 			error = rsrc_client_action_list(node->users, cmd, &arg);
880Sstevel@tonic-gate 		} else {
890Sstevel@tonic-gate 			error = rsrc_tree_action(node, cmd, &arg);
900Sstevel@tonic-gate 		}
91*4845Svikram 	} else if ((error == RCM_SUCCESS) && (flag & RCM_RETIRE_REQUEST)) {
92*4845Svikram 		/*
93*4845Svikram 		 * No matching node, so no client. This means there
94*4845Svikram 		 * is no constraint (RCM wise) on this retire. Return
95*4845Svikram 		 * RCM_NO_CONSTRAINT to indicate this
96*4845Svikram 		 */
97*4845Svikram 		rcm_log_message(RCM_TRACE1, "No client. Returning "
98*4845Svikram 		    "RCM_NO_CONSTRAINT: %s\n", rsrcname);
99*4845Svikram 		error = RCM_NO_CONSTRAINT;
1000Sstevel@tonic-gate 	}
101*4845Svikram 
1020Sstevel@tonic-gate 	return (error);
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * When a resource is removed, notify all clients who registered for this
1070Sstevel@tonic-gate  * particular resource.
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate int
notify_resource_remove(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)1100Sstevel@tonic-gate notify_resource_remove(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
1110Sstevel@tonic-gate     rcm_info_t **info)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	int i;
1140Sstevel@tonic-gate 	int error;
1150Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
1200Sstevel@tonic-gate 		    "notify_resource_remove(%s, %ld, 0x%x, %d)\n", rsrcnames[i],
1210Sstevel@tonic-gate 		    pid, flag, seq_num);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 		/*
1240Sstevel@tonic-gate 		 * Mark state as issuing removal notification. Return failure
1250Sstevel@tonic-gate 		 * if no DR request for this node exists.
1260Sstevel@tonic-gate 		 */
1270Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
1280Sstevel@tonic-gate 		    RCM_STATE_REMOVING, seq_num, info);
1290Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
1300Sstevel@tonic-gate 			retval = error;
1310Sstevel@tonic-gate 			continue;
1320Sstevel@tonic-gate 		}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 		error = common_resource_op(CMD_REMOVE, rsrcnames[i], pid, flag,
1350Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 		/*
1380Sstevel@tonic-gate 		 * delete the request entry from DR list
1390Sstevel@tonic-gate 		 */
1400Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
1430Sstevel@tonic-gate 			retval = error;
1440Sstevel@tonic-gate 	}
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	return (retval);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /*
1500Sstevel@tonic-gate  * Notify users that a resource has been resumed
1510Sstevel@tonic-gate  */
1520Sstevel@tonic-gate int
notify_resource_resume(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)1530Sstevel@tonic-gate notify_resource_resume(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
1540Sstevel@tonic-gate     rcm_info_t **info)
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate 	int i;
1570Sstevel@tonic-gate 	int error;
1580Sstevel@tonic-gate 	rcm_info_t *state_info;
1590Sstevel@tonic-gate 	rcm_info_tuple_t *state_tuple;
1600Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		state_info = NULL;
1650Sstevel@tonic-gate 		state_tuple = NULL;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 		/* Check resource state (was resource actually suspended?) */
1680Sstevel@tonic-gate 		if (get_resource_state(rsrcnames[i], pid, &state_info) ||
1690Sstevel@tonic-gate 		    ((state_tuple = rcm_info_next(state_info, NULL)) == NULL) ||
1700Sstevel@tonic-gate 		    (rcm_info_state(state_tuple) == RCM_STATE_SUSPEND))
1710Sstevel@tonic-gate 			flag |= RCM_SUSPENDED;
1720Sstevel@tonic-gate 		if (state_info)
1730Sstevel@tonic-gate 			rcm_free_info(state_info);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
1760Sstevel@tonic-gate 		    "notify_resource_resume(%s, %ld, 0x%x, %d)\n",
1770Sstevel@tonic-gate 		    rsrcnames[i], pid, flag, seq_num);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 		/*
1800Sstevel@tonic-gate 		 * Mark state as sending resumption notifications
1810Sstevel@tonic-gate 		 */
1820Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
1830Sstevel@tonic-gate 		    RCM_STATE_RESUMING, seq_num, info);
1840Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
1850Sstevel@tonic-gate 			retval = error;
1860Sstevel@tonic-gate 			continue;
1870Sstevel@tonic-gate 		}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 		error = common_resource_op(CMD_RESUME, rsrcnames[i], pid, flag,
1900Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
1950Sstevel@tonic-gate 			retval = error;
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	return (retval);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * Notify users that an offlined device is again available
2030Sstevel@tonic-gate  */
2040Sstevel@tonic-gate int
notify_resource_online(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)2050Sstevel@tonic-gate notify_resource_online(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
2060Sstevel@tonic-gate     rcm_info_t **info)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	int i;
2090Sstevel@tonic-gate 	int error;
2100Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
2150Sstevel@tonic-gate 		    "notify_resource_online(%s, %ld, 0x%x, %d)\n",
2160Sstevel@tonic-gate 		    rsrcnames[i], pid, flag, seq_num);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 		/*
2190Sstevel@tonic-gate 		 * Mark state as sending onlining notifications
2200Sstevel@tonic-gate 		 */
2210Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
2220Sstevel@tonic-gate 		    RCM_STATE_ONLINING, seq_num, info);
2230Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
2240Sstevel@tonic-gate 			retval = error;
2250Sstevel@tonic-gate 			continue;
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		error = common_resource_op(CMD_ONLINE, rsrcnames[i], pid, flag,
2290Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
2340Sstevel@tonic-gate 			retval = error;
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	return (retval);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  * For offline and suspend, need to get the logic correct here. There are
2420Sstevel@tonic-gate  * several cases:
2430Sstevel@tonic-gate  *
2440Sstevel@tonic-gate  * 1. It is a door call and RCM_QUERY is not set:
2450Sstevel@tonic-gate  *	run a QUERY; if that succeeds, run the operation.
2460Sstevel@tonic-gate  *
2470Sstevel@tonic-gate  * 2. It is a door call and RCM_QUERY is set:
2480Sstevel@tonic-gate  *	run the QUERY only.
2490Sstevel@tonic-gate  *
2500Sstevel@tonic-gate  * 3. It is not a door call:
2510Sstevel@tonic-gate  *	run the call, but look at the flag to see if the
2520Sstevel@tonic-gate  *	lock should be kept.
2530Sstevel@tonic-gate  */
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * Request permission to suspend a resource
2570Sstevel@tonic-gate  */
2580Sstevel@tonic-gate int
process_resource_suspend(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,timespec_t * interval,rcm_info_t ** info)2590Sstevel@tonic-gate process_resource_suspend(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
2600Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **info)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	int i;
2630Sstevel@tonic-gate 	int error = RCM_SUCCESS;
2640Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/*
2670Sstevel@tonic-gate 	 * Query the operation first.  The return value of the query indicates
2680Sstevel@tonic-gate 	 * if the operation should proceed and be implemented.
2690Sstevel@tonic-gate 	 */
2700Sstevel@tonic-gate 	if (query(rsrcnames, CMD_SUSPEND, "suspend", RCM_STATE_SUSPEND_QUERYING,
2710Sstevel@tonic-gate 	    pid, flag, interval, seq_num, info, &error) == 0) {
2720Sstevel@tonic-gate 		return (error);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/*
2760Sstevel@tonic-gate 	 * Implement the operation.
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/* Update the lock from a query state to the suspending state */
2810Sstevel@tonic-gate 		if ((error = dr_req_update(rsrcnames[i], pid, flag,
2820Sstevel@tonic-gate 		    RCM_STATE_SUSPENDING, seq_num, info)) != RCM_SUCCESS) {
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
2850Sstevel@tonic-gate 			    "suspend %s denied with error %d\n", rsrcnames[i],
2860Sstevel@tonic-gate 			    error);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 			/*
2890Sstevel@tonic-gate 			 * When called from a module, don't return EAGAIN.
2900Sstevel@tonic-gate 			 * This is to avoid recursion if module always retries.
2910Sstevel@tonic-gate 			 */
2920Sstevel@tonic-gate 			if (!is_doorcall && error == EAGAIN) {
2930Sstevel@tonic-gate 				return (RCM_CONFLICT);
2940Sstevel@tonic-gate 			}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 			return (error);
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 		/* Actually suspend the resource */
3000Sstevel@tonic-gate 		error = common_resource_op(CMD_SUSPEND, rsrcnames[i], pid,
3010Sstevel@tonic-gate 		    flag, seq_num, interval, NULL, info);
3020Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3030Sstevel@tonic-gate 			(void) dr_req_update(rsrcnames[i], pid, flag,
3040Sstevel@tonic-gate 			    RCM_STATE_SUSPEND_FAIL, seq_num, info);
3050Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3060Sstevel@tonic-gate 			    "suspend tree failed for %s\n", rsrcnames[i]);
3070Sstevel@tonic-gate 			return (error);
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "suspend tree succeeded for %s\n",
3110Sstevel@tonic-gate 		    rsrcnames[i]);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		/* Update the lock for the successful suspend */
3140Sstevel@tonic-gate 		(void) dr_req_update(rsrcnames[i], pid, flag,
3150Sstevel@tonic-gate 		    RCM_STATE_SUSPEND, seq_num, info);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	return (RCM_SUCCESS);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate /*
3220Sstevel@tonic-gate  * Process a device removal request, reply is needed
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate int
process_resource_offline(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)3250Sstevel@tonic-gate process_resource_offline(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
3260Sstevel@tonic-gate     rcm_info_t **info)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	int i;
3290Sstevel@tonic-gate 	int error = RCM_SUCCESS;
3300Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	/*
3330Sstevel@tonic-gate 	 * Query the operation first.  The return value of the query indicates
3340Sstevel@tonic-gate 	 * if the operation should proceed and be implemented.
3350Sstevel@tonic-gate 	 */
3360Sstevel@tonic-gate 	if (query(rsrcnames, CMD_OFFLINE, "offline", RCM_STATE_OFFLINE_QUERYING,
3370Sstevel@tonic-gate 	    pid, flag, NULL, seq_num, info, &error) == 0) {
3380Sstevel@tonic-gate 		return (error);
3390Sstevel@tonic-gate 	}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	/*
3420Sstevel@tonic-gate 	 * Implement the operation.
3430Sstevel@tonic-gate 	 */
3440Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
3470Sstevel@tonic-gate 		    RCM_STATE_OFFLINING, seq_num, info);
3480Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3490Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3500Sstevel@tonic-gate 			    "offline %s denied with error %d\n", rsrcnames[i],
3510Sstevel@tonic-gate 			    error);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 			/*
3540Sstevel@tonic-gate 			 * When called from a module, don't return EAGAIN.
3550Sstevel@tonic-gate 			 * This is to avoid recursion if module always retries.
3560Sstevel@tonic-gate 			 */
3570Sstevel@tonic-gate 			if (!is_doorcall && error == EAGAIN) {
3580Sstevel@tonic-gate 				return (RCM_CONFLICT);
3590Sstevel@tonic-gate 			}
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 			return (error);
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		/* Actually offline the resource */
3650Sstevel@tonic-gate 		error = common_resource_op(CMD_OFFLINE, rsrcnames[i], pid,
3660Sstevel@tonic-gate 		    flag, seq_num, NULL, NULL, info);
3670Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3680Sstevel@tonic-gate 			(void) dr_req_update(rsrcnames[i], pid, flag,
3690Sstevel@tonic-gate 			    RCM_STATE_OFFLINE_FAIL, seq_num, info);
3700Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3710Sstevel@tonic-gate 			    "offline tree failed for %s\n", rsrcnames[i]);
3720Sstevel@tonic-gate 			return (error);
3730Sstevel@tonic-gate 		}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "offline tree succeeded for %s\n",
3760Sstevel@tonic-gate 		    rsrcnames[i]);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 		/* Update the lock for the successful offline */
3790Sstevel@tonic-gate 		(void) dr_req_update(rsrcnames[i], pid, flag,
3800Sstevel@tonic-gate 		    RCM_STATE_OFFLINE, seq_num, info);
3810Sstevel@tonic-gate 	}
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	return (RCM_SUCCESS);
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate /*
3870Sstevel@tonic-gate  * Add a resource client who wishes to interpose on DR, events, or capacity.
3880Sstevel@tonic-gate  * Reply needed.
3890Sstevel@tonic-gate  */
3900Sstevel@tonic-gate int
add_resource_client(char * modname,char * rsrcname,pid_t pid,uint_t flag,rcm_info_t ** infop)3910Sstevel@tonic-gate add_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag,
3920Sstevel@tonic-gate     rcm_info_t **infop)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	int error = RCM_SUCCESS;
3950Sstevel@tonic-gate 	client_t *user = NULL;
3960Sstevel@tonic-gate 	rsrc_node_t *node = NULL;
3970Sstevel@tonic-gate 	rcm_info_t *info = NULL;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
4000Sstevel@tonic-gate 	    "add_resource_client(%s, %s, %ld, 0x%x)\n",
4010Sstevel@tonic-gate 	    modname, rsrcname, pid, flag);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (strcmp(rsrcname, "/") == 0) {
4040Sstevel@tonic-gate 		/*
4050Sstevel@tonic-gate 		 * No need to register for /  because it will never go away.
4060Sstevel@tonic-gate 		 */
4070Sstevel@tonic-gate 		rcm_log_message(RCM_INFO, gettext(
4080Sstevel@tonic-gate 		    "registering for / by %s has been turned into a no-op\n"),
4090Sstevel@tonic-gate 		    modname);
4100Sstevel@tonic-gate 		return (RCM_SUCCESS);
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * Hold the rcm_req_lock so no dr request may come in while the
4150Sstevel@tonic-gate 	 * registration is in progress.
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	(void) mutex_lock(&rcm_req_lock);
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	/*
4200Sstevel@tonic-gate 	 * Test if the requested registration is a noop, and return EALREADY
4210Sstevel@tonic-gate 	 * if it is.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, RSRC_NODE_CREATE, &node);
4240Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || (node == NULL)) {
4250Sstevel@tonic-gate 		(void) mutex_unlock(&rcm_req_lock);
4260Sstevel@tonic-gate 		return (RCM_FAILURE);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	user = rsrc_client_find(modname, pid, &node->users);
4300Sstevel@tonic-gate 	if ((user != NULL) &&
4310Sstevel@tonic-gate 	    ((user->flag & (flag & RCM_REGISTER_MASK)) != 0)) {
4320Sstevel@tonic-gate 		(void) mutex_unlock(&rcm_req_lock);
4330Sstevel@tonic-gate 		if ((flag & RCM_REGISTER_DR) &&
4340Sstevel@tonic-gate 		    (user->state == RCM_STATE_REMOVE)) {
4350Sstevel@tonic-gate 			user->state = RCM_STATE_ONLINE;
4360Sstevel@tonic-gate 			return (RCM_SUCCESS);
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 		return (EALREADY);
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* If adding a new DR registration, reject if the resource is locked */
4420Sstevel@tonic-gate 	if (flag & RCM_REGISTER_DR) {
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		if (rsrc_check_lock_conflicts(rsrcname, flag, LOCK_FOR_USE,
4450Sstevel@tonic-gate 		    &info) != RCM_SUCCESS) {
4460Sstevel@tonic-gate 			/*
4470Sstevel@tonic-gate 			 * The resource is being DR'ed, so return failure
4480Sstevel@tonic-gate 			 */
4490Sstevel@tonic-gate 			(void) mutex_unlock(&rcm_req_lock);
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 			/*
4520Sstevel@tonic-gate 			 * If caller doesn't care about info, free it
4530Sstevel@tonic-gate 			 */
4540Sstevel@tonic-gate 			if (infop)
4550Sstevel@tonic-gate 				*infop = info;
4560Sstevel@tonic-gate 			else
4570Sstevel@tonic-gate 				rcm_free_info(info);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 			return (RCM_CONFLICT);
4600Sstevel@tonic-gate 		}
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/* The registration is new and allowable, so add it */
4640Sstevel@tonic-gate 	error = rsrc_node_add_user(node, rsrcname, modname, pid, flag);
4650Sstevel@tonic-gate 	(void) mutex_unlock(&rcm_req_lock);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	return (error);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * Remove a resource client, who no longer wishes to interpose on either
4720Sstevel@tonic-gate  * DR, events, or capacity.
4730Sstevel@tonic-gate  */
4740Sstevel@tonic-gate int
remove_resource_client(char * modname,char * rsrcname,pid_t pid,uint_t flag)4750Sstevel@tonic-gate remove_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	int error;
4780Sstevel@tonic-gate 	rsrc_node_t *node;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
4810Sstevel@tonic-gate 	    "remove_resource_client(%s, %s, %ld, 0x%x)\n",
4820Sstevel@tonic-gate 	    modname, rsrcname, pid, flag);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Allow resource client to leave anytime, assume client knows what
4860Sstevel@tonic-gate 	 * it is trying to do.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
4890Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || (node == NULL)) {
4900Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
4910Sstevel@tonic-gate 		    gettext("resource %s not found\n"), rsrcname);
4920Sstevel@tonic-gate 		return (ENOENT);
4930Sstevel@tonic-gate 	}
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	return (rsrc_node_remove_user(node, modname, pid, flag));
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * Reply is needed
5000Sstevel@tonic-gate  */
5010Sstevel@tonic-gate int
get_resource_info(char ** rsrcnames,uint_t flag,int seq_num,rcm_info_t ** info)5020Sstevel@tonic-gate get_resource_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	int rv = RCM_SUCCESS;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	if (flag & RCM_DR_OPERATION) {
5070Sstevel@tonic-gate 		*info = rsrc_dr_info();
5080Sstevel@tonic-gate 	} else if (flag & RCM_MOD_INFO) {
5090Sstevel@tonic-gate 		*info = rsrc_mod_info();
5100Sstevel@tonic-gate 	} else {
5110Sstevel@tonic-gate 		rv = rsrc_usage_info(rsrcnames, flag, seq_num, info);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	return (rv);
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate int
notify_resource_event(char * rsrcname,id_t pid,uint_t flag,int seq_num,nvlist_t * event_data,rcm_info_t ** info)5180Sstevel@tonic-gate notify_resource_event(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5190Sstevel@tonic-gate     nvlist_t *event_data, rcm_info_t **info)
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 	int error;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	assert(flag == 0);
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "notify_resource_event(%s, %ld, 0x%x)\n",
5260Sstevel@tonic-gate 	    rsrcname, pid, flag);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	error = common_resource_op(CMD_EVENT, rsrcname, pid, flag, seq_num,
5290Sstevel@tonic-gate 	    NULL, event_data, info);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	return (error);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate int
request_capacity_change(char * rsrcname,id_t pid,uint_t flag,int seq_num,nvlist_t * nvl,rcm_info_t ** info)5350Sstevel@tonic-gate request_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5360Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **info)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	int error;
5390Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
5420Sstevel@tonic-gate 	    "request_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid,
5430Sstevel@tonic-gate 	    flag, seq_num);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (is_doorcall || (flag & RCM_QUERY)) {
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 		error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid,
5480Sstevel@tonic-gate 		    flag | RCM_QUERY, seq_num, NULL, nvl, info);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
5510Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
5520Sstevel@tonic-gate 			    "request state change query denied\n");
5530Sstevel@tonic-gate 			return (error);
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (flag & RCM_QUERY)
5580Sstevel@tonic-gate 		return (RCM_SUCCESS);
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid, flag,
5610Sstevel@tonic-gate 	    seq_num, NULL, nvl, info);
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (error != RCM_SUCCESS) {
5640Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "request state change failed\n");
5650Sstevel@tonic-gate 		return (RCM_FAILURE);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "request state change succeeded\n");
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	return (error);
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate int
notify_capacity_change(char * rsrcname,id_t pid,uint_t flag,int seq_num,nvlist_t * nvl,rcm_info_t ** info)5740Sstevel@tonic-gate notify_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5750Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **info)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate 	int error;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
5800Sstevel@tonic-gate 	    "notify_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid,
5810Sstevel@tonic-gate 	    flag, seq_num);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	error = common_resource_op(CMD_NOTIFY_CHANGE, rsrcname, pid, flag,
5840Sstevel@tonic-gate 	    seq_num, NULL, nvl, info);
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if (error != RCM_SUCCESS) {
5870Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "notify state change failed\n");
5880Sstevel@tonic-gate 		return (RCM_FAILURE);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "notify state change succeeded\n");
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	return (error);
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate int
get_resource_state(char * rsrcname,pid_t pid,rcm_info_t ** info)5970Sstevel@tonic-gate get_resource_state(char *rsrcname, pid_t pid, rcm_info_t **info)
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate 	int error;
6000Sstevel@tonic-gate 	int state;
6010Sstevel@tonic-gate 	char *s;
6020Sstevel@tonic-gate 	char *resolved;
6030Sstevel@tonic-gate 	rcm_info_t *dr_info = NULL;
6040Sstevel@tonic-gate 	rcm_info_tuple_t *dr_info_tuple = NULL;
6050Sstevel@tonic-gate 	rsrc_node_t *node;
6060Sstevel@tonic-gate 	client_t *client;
6070Sstevel@tonic-gate 	char *state_info = gettext("State of resource");
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "get_resource_state(%s, %ld)\n",
6100Sstevel@tonic-gate 	    rsrcname, pid);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	/*
6130Sstevel@tonic-gate 	 * Check for locks, first.
6140Sstevel@tonic-gate 	 */
6150Sstevel@tonic-gate 	dr_info = rsrc_dr_info();
6160Sstevel@tonic-gate 	if (dr_info) {
6170Sstevel@tonic-gate 		state = RCM_STATE_UNKNOWN;
6180Sstevel@tonic-gate 		if ((resolved = resolve_name(rsrcname)) == NULL)
6190Sstevel@tonic-gate 			return (RCM_FAILURE);
6200Sstevel@tonic-gate 		while (dr_info_tuple = rcm_info_next(dr_info, dr_info_tuple)) {
6210Sstevel@tonic-gate 			s = (char *)rcm_info_rsrc(dr_info_tuple);
6220Sstevel@tonic-gate 			if (s && (strcmp(resolved, s) == 0)) {
6230Sstevel@tonic-gate 				state = rcm_info_state(dr_info_tuple);
6240Sstevel@tonic-gate 				break;
6250Sstevel@tonic-gate 			}
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 		free(resolved);
6280Sstevel@tonic-gate 		rcm_free_info(dr_info);
6290Sstevel@tonic-gate 		if (state != RCM_STATE_UNKNOWN) {
6300Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
6310Sstevel@tonic-gate 			    "get_resource_state(%s)=%d\n", rsrcname, state);
6320Sstevel@tonic-gate 			add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL,
6330Sstevel@tonic-gate 			    (char *)state_info, NULL, NULL, info);
6340Sstevel@tonic-gate 			return (RCM_SUCCESS);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * No locks, so look for client states in the resource tree.
6400Sstevel@tonic-gate 	 *
6410Sstevel@tonic-gate 	 * NOTE: It's possible the node doesn't exist, which means no RCM
6420Sstevel@tonic-gate 	 * consumer registered for the resource. In this case we silently
6430Sstevel@tonic-gate 	 * succeed.
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
6460Sstevel@tonic-gate 	state = RCM_STATE_ONLINE;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	if ((error == RCM_SUCCESS) && (node != NULL)) {
6490Sstevel@tonic-gate 		for (client = node->users; client; client = client->next) {
6500Sstevel@tonic-gate 			if (client->state == RCM_STATE_OFFLINE_FAIL ||
6510Sstevel@tonic-gate 			    client->state == RCM_STATE_OFFLINE_QUERY_FAIL ||
6520Sstevel@tonic-gate 			    client->state == RCM_STATE_SUSPEND_FAIL ||
6530Sstevel@tonic-gate 			    client->state == RCM_STATE_SUSPEND_QUERY_FAIL) {
6540Sstevel@tonic-gate 				state = client->state;
6550Sstevel@tonic-gate 				break;
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 			if (client->state != RCM_STATE_ONLINE &&
6590Sstevel@tonic-gate 			    client->state != RCM_STATE_REMOVE)
6600Sstevel@tonic-gate 				state = client->state;
6610Sstevel@tonic-gate 		}
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	if (error == RCM_SUCCESS) {
6650Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "get_resource_state(%s)=%d\n",
6660Sstevel@tonic-gate 		    rsrcname, state);
6670Sstevel@tonic-gate 		add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL,
6680Sstevel@tonic-gate 		    (char *)state_info, NULL, NULL, info);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	return (error);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate  * Perform a query of an offline or suspend.
6760Sstevel@tonic-gate  *
6770Sstevel@tonic-gate  * The return value of this function indicates whether the operation should
6780Sstevel@tonic-gate  * be implemented (0 == No, 1 == Yes).  Note that locks and client state
6790Sstevel@tonic-gate  * changes will only persist if the caller is going to implement the operation.
6800Sstevel@tonic-gate  */
6810Sstevel@tonic-gate static int
query(char ** rsrcnames,int cmd,const char * opname,int querystate,pid_t pid,uint_t flag,timespec_t * interval,int seq_num,rcm_info_t ** info,int * errorp)6820Sstevel@tonic-gate query(char **rsrcnames, int cmd, const char *opname, int querystate, pid_t pid,
6830Sstevel@tonic-gate     uint_t flag, timespec_t *interval, int seq_num, rcm_info_t **info,
6840Sstevel@tonic-gate     int *errorp)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	int	i;
6870Sstevel@tonic-gate 	int	error;
6880Sstevel@tonic-gate 	int	final_error;
6890Sstevel@tonic-gate 	int	is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	/* Only query for door calls, or when the RCM_QUERY flag is set */
6920Sstevel@tonic-gate 	if ((is_doorcall == 0) && ((flag & RCM_QUERY) == 0)) {
6930Sstevel@tonic-gate 		return (1);
6940Sstevel@tonic-gate 	}
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/* Lock all the resources.  Fail the query in the case of a conflict. */
6970Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
7000Sstevel@tonic-gate 		    "process_resource_%s(%s, %ld, 0x%x, %d)\n",
7010Sstevel@tonic-gate 		    opname, rsrcnames[i], pid, flag, seq_num);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		error = dr_req_add(rsrcnames[i], pid, flag, querystate, seq_num,
7040Sstevel@tonic-gate 		    NULL, info);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		/* The query goes no further if a resource cannot be locked */
7070Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
7100Sstevel@tonic-gate 			    "%s query %s defined with error %d\n",
7110Sstevel@tonic-gate 			    opname, rsrcnames[i], error);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 			/*
7140Sstevel@tonic-gate 			 * Replace EAGAIN with RCM_CONFLICT in the case of
7150Sstevel@tonic-gate 			 * module callbacks; to avoid modules from trying
7160Sstevel@tonic-gate 			 * again infinitely.
7170Sstevel@tonic-gate 			 */
7180Sstevel@tonic-gate 			if ((is_doorcall == 0) && (error == EAGAIN)) {
7190Sstevel@tonic-gate 				error = RCM_CONFLICT;
7200Sstevel@tonic-gate 			}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 			goto finished;
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 	}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * All the resources were locked above, so use common_resource_op()
7280Sstevel@tonic-gate 	 * to pass the query on to the clients.  Accumulate the overall error
7290Sstevel@tonic-gate 	 * value in 'final_error', before transferring it to 'error' at the end.
7300Sstevel@tonic-gate 	 */
7310Sstevel@tonic-gate 	for (final_error = RCM_SUCCESS, i = 0; rsrcnames[i] != NULL; i++) {
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 		/* Log the query (for tracing purposes). */
7340Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "querying resource %s\n",
7350Sstevel@tonic-gate 		    rsrcnames[i]);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		/* Query the resource's clients through common_resource_op(). */
7380Sstevel@tonic-gate 		error = common_resource_op(cmd, rsrcnames[i], pid,
7390Sstevel@tonic-gate 		    flag | RCM_QUERY, seq_num, interval, NULL, info);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 		/*
7420Sstevel@tonic-gate 		 * If a query fails, don't stop iterating through the loop.
7430Sstevel@tonic-gate 		 * Just ensure that 'final_error' is set (if not already),
7440Sstevel@tonic-gate 		 * log the error, and continue looping.
7450Sstevel@tonic-gate 		 *
7460Sstevel@tonic-gate 		 * In the case of a user who manually intervenes and retries
7470Sstevel@tonic-gate 		 * the operation, this will maximize the extent of the query
7480Sstevel@tonic-gate 		 * so that they experience fewer such iterations overall.
7490Sstevel@tonic-gate 		 */
7500Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 			/* Log each query that failed along the way */
7530Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "%s %s query denied\n",
7540Sstevel@tonic-gate 			    opname, rsrcnames[i]);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 			if (final_error != RCM_FAILURE) {
7570Sstevel@tonic-gate 				final_error = error;
7580Sstevel@tonic-gate 			}
7590Sstevel@tonic-gate 		}
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 	error = final_error;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	/*
7640Sstevel@tonic-gate 	 * Tell the calling function not to proceed any further with the
7650Sstevel@tonic-gate 	 * implementation phase of the operation if the query failed, or
7660Sstevel@tonic-gate 	 * if the user's intent was to only query the operation.
7670Sstevel@tonic-gate 	 */
7680Sstevel@tonic-gate finished:
7690Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || ((flag & RCM_QUERY) != 0)) {
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 		/*
7720Sstevel@tonic-gate 		 * Since the operation won't be implemented, cancel the
7730Sstevel@tonic-gate 		 * query (unlock resources and reverse client state changes).
7740Sstevel@tonic-gate 		 *
7750Sstevel@tonic-gate 		 * The cancellation routine cleans up everything for the entire
7760Sstevel@tonic-gate 		 * operation, and thus it should only be called from the very
7770Sstevel@tonic-gate 		 * root of the operation (e.g. when 'is_doorcall' is TRUE).
7780Sstevel@tonic-gate 		 */
7790Sstevel@tonic-gate 		if (is_doorcall != 0) {
7800Sstevel@tonic-gate 			cancel_query(cmd, opname, pid, flag, seq_num);
7810Sstevel@tonic-gate 		}
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 		*errorp = error;
7840Sstevel@tonic-gate 		return (0);
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	/* Otherwise, tell the caller to proceed with the implementation. */
7880Sstevel@tonic-gate 	*errorp = RCM_SUCCESS;
7890Sstevel@tonic-gate 	return (1);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate /*
7930Sstevel@tonic-gate  * Implementation of a query cancellation.
7940Sstevel@tonic-gate  *
7950Sstevel@tonic-gate  * The full scope of the query is already noted, so the scope of the operation
7960Sstevel@tonic-gate  * does not need to be expanded in the same recursive manner that was used for
7970Sstevel@tonic-gate  * the query itself.  (Clients don't have to be called to cross namespaces.)
7980Sstevel@tonic-gate  * Instead, the locks added to the DR request list during the query are scanned.
7990Sstevel@tonic-gate  */
8000Sstevel@tonic-gate static void
cancel_query(int cmd,const char * opname,pid_t pid,uint_t flag,int seq_num)8010Sstevel@tonic-gate cancel_query(int cmd, const char *opname, pid_t pid, uint_t flag, int seq_num)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate 	char	rsrc[MAXPATHLEN];
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	/*
8060Sstevel@tonic-gate 	 * Find every lock in the DR request list that is a part of this
8070Sstevel@tonic-gate 	 * sequence.  Call common_resource_op() with the QUERY_CANCEL flag to
8080Sstevel@tonic-gate 	 * cancel each sub-operation, and then remove each lock from the list.
8090Sstevel@tonic-gate 	 *
8100Sstevel@tonic-gate 	 * The 'rsrc' buffer is required to retrieve the 'device' fields of
8110Sstevel@tonic-gate 	 * matching DR request list entries in a way that's multi-thread safe.
8120Sstevel@tonic-gate 	 */
8130Sstevel@tonic-gate 	while (dr_req_lookup(seq_num, rsrc) == RCM_SUCCESS) {
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "%s query %s cancelled\n",
8160Sstevel@tonic-gate 		    opname, rsrc);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		(void) common_resource_op(cmd, rsrc, pid,
8190Sstevel@tonic-gate 		    flag | RCM_QUERY | RCM_QUERY_CANCEL, seq_num, NULL, NULL,
8200Sstevel@tonic-gate 		    NULL);
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 		(void) dr_req_remove(rsrc, flag);
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate }
825