17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*25e8c5aaSvikram  * Common Development and Distribution License (the "License").
6*25e8c5aaSvikram  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  *
21*25e8c5aaSvikram  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
227c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <librcm_impl.h>
267c478bd9Sstevel@tonic-gate #include "rcm_impl.h"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate static int query(char **, int, const char *, int, pid_t, uint_t, timespec_t *,
297c478bd9Sstevel@tonic-gate     int, rcm_info_t **, int *);
307c478bd9Sstevel@tonic-gate static void cancel_query(int, const char *, pid_t, uint_t, int);
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * The following ops are invoked when modules initiate librcm calls which
347c478bd9Sstevel@tonic-gate  * require daemon processing. Cascaded RCM operations must come through
357c478bd9Sstevel@tonic-gate  * this path.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate librcm_ops_t rcm_ops = {
387c478bd9Sstevel@tonic-gate 	add_resource_client,
397c478bd9Sstevel@tonic-gate 	remove_resource_client,
407c478bd9Sstevel@tonic-gate 	get_resource_info,
417c478bd9Sstevel@tonic-gate 	process_resource_suspend,
427c478bd9Sstevel@tonic-gate 	notify_resource_resume,
437c478bd9Sstevel@tonic-gate 	process_resource_offline,
447c478bd9Sstevel@tonic-gate 	notify_resource_online,
457c478bd9Sstevel@tonic-gate 	notify_resource_remove,
467c478bd9Sstevel@tonic-gate 	request_capacity_change,
477c478bd9Sstevel@tonic-gate 	notify_capacity_change,
487c478bd9Sstevel@tonic-gate 	notify_resource_event,
497c478bd9Sstevel@tonic-gate 	get_resource_state
507c478bd9Sstevel@tonic-gate };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Process a request or a notification on a subtree
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
567c478bd9Sstevel@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)577c478bd9Sstevel@tonic-gate common_resource_op(int cmd, char *rsrcname, pid_t pid, uint_t flag, int seq_num,
587c478bd9Sstevel@tonic-gate     timespec_t *interval, nvlist_t *nvl, rcm_info_t **info)
597c478bd9Sstevel@tonic-gate {
607c478bd9Sstevel@tonic-gate 	int error;
617c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
627c478bd9Sstevel@tonic-gate 	tree_walk_arg_t arg;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	/*
657c478bd9Sstevel@tonic-gate 	 * Find the node (root of subtree) in the resource tree, invoke
667c478bd9Sstevel@tonic-gate 	 * appropriate callbacks for all clients hanging off the subtree,
677c478bd9Sstevel@tonic-gate 	 * and mark the subtree with the appropriate state.
687c478bd9Sstevel@tonic-gate 	 *
697c478bd9Sstevel@tonic-gate 	 * NOTE: It's possible the node doesn't exist, which means no RCM
707c478bd9Sstevel@tonic-gate 	 * consumer registered for the resource. In this case we silently
717c478bd9Sstevel@tonic-gate 	 * succeed.
727c478bd9Sstevel@tonic-gate 	 */
737c478bd9Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
747c478bd9Sstevel@tonic-gate 	if ((error == RCM_SUCCESS) && (node != NULL)) {
757c478bd9Sstevel@tonic-gate 		arg.flag = flag;
767c478bd9Sstevel@tonic-gate 		arg.info = info;
777c478bd9Sstevel@tonic-gate 		arg.seq_num = seq_num;
787c478bd9Sstevel@tonic-gate 		arg.interval = interval;
797c478bd9Sstevel@tonic-gate 		arg.nvl = nvl;
807c478bd9Sstevel@tonic-gate 		arg.cmd = cmd;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 		if ((cmd == CMD_NOTIFY_CHANGE) ||
837c478bd9Sstevel@tonic-gate 		    (cmd == CMD_REQUEST_CHANGE) ||
847c478bd9Sstevel@tonic-gate 		    (cmd == CMD_EVENT)) {
857c478bd9Sstevel@tonic-gate 			error = rsrc_client_action_list(node->users, cmd, &arg);
867c478bd9Sstevel@tonic-gate 		} else {
877c478bd9Sstevel@tonic-gate 			error = rsrc_tree_action(node, cmd, &arg);
887c478bd9Sstevel@tonic-gate 		}
89*25e8c5aaSvikram 	} else if ((error == RCM_SUCCESS) && (flag & RCM_RETIRE_REQUEST)) {
90*25e8c5aaSvikram 		/*
91*25e8c5aaSvikram 		 * No matching node, so no client. This means there
92*25e8c5aaSvikram 		 * is no constraint (RCM wise) on this retire. Return
93*25e8c5aaSvikram 		 * RCM_NO_CONSTRAINT to indicate this
94*25e8c5aaSvikram 		 */
95*25e8c5aaSvikram 		rcm_log_message(RCM_TRACE1, "No client. Returning "
96*25e8c5aaSvikram 		    "RCM_NO_CONSTRAINT: %s\n", rsrcname);
97*25e8c5aaSvikram 		error = RCM_NO_CONSTRAINT;
987c478bd9Sstevel@tonic-gate 	}
99*25e8c5aaSvikram 
1007c478bd9Sstevel@tonic-gate 	return (error);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * When a resource is removed, notify all clients who registered for this
1057c478bd9Sstevel@tonic-gate  * particular resource.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate int
notify_resource_remove(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)1087c478bd9Sstevel@tonic-gate notify_resource_remove(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
1097c478bd9Sstevel@tonic-gate     rcm_info_t **info)
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	int i;
1127c478bd9Sstevel@tonic-gate 	int error;
1137c478bd9Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
1187c478bd9Sstevel@tonic-gate 		    "notify_resource_remove(%s, %ld, 0x%x, %d)\n", rsrcnames[i],
1197c478bd9Sstevel@tonic-gate 		    pid, flag, seq_num);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 		/*
1227c478bd9Sstevel@tonic-gate 		 * Mark state as issuing removal notification. Return failure
1237c478bd9Sstevel@tonic-gate 		 * if no DR request for this node exists.
1247c478bd9Sstevel@tonic-gate 		 */
1257c478bd9Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
1267c478bd9Sstevel@tonic-gate 		    RCM_STATE_REMOVING, seq_num, info);
1277c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
1287c478bd9Sstevel@tonic-gate 			retval = error;
1297c478bd9Sstevel@tonic-gate 			continue;
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_REMOVE, rsrcnames[i], pid, flag,
1337c478bd9Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		/*
1367c478bd9Sstevel@tonic-gate 		 * delete the request entry from DR list
1377c478bd9Sstevel@tonic-gate 		 */
1387c478bd9Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
1417c478bd9Sstevel@tonic-gate 			retval = error;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	return (retval);
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * Notify users that a resource has been resumed
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate int
notify_resource_resume(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)1517c478bd9Sstevel@tonic-gate notify_resource_resume(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
1527c478bd9Sstevel@tonic-gate     rcm_info_t **info)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	int i;
1557c478bd9Sstevel@tonic-gate 	int error;
1567c478bd9Sstevel@tonic-gate 	rcm_info_t *state_info;
1577c478bd9Sstevel@tonic-gate 	rcm_info_tuple_t *state_tuple;
1587c478bd9Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		state_info = NULL;
1637c478bd9Sstevel@tonic-gate 		state_tuple = NULL;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		/* Check resource state (was resource actually suspended?) */
1667c478bd9Sstevel@tonic-gate 		if (get_resource_state(rsrcnames[i], pid, &state_info) ||
1677c478bd9Sstevel@tonic-gate 		    ((state_tuple = rcm_info_next(state_info, NULL)) == NULL) ||
1687c478bd9Sstevel@tonic-gate 		    (rcm_info_state(state_tuple) == RCM_STATE_SUSPEND))
1697c478bd9Sstevel@tonic-gate 			flag |= RCM_SUSPENDED;
1707c478bd9Sstevel@tonic-gate 		if (state_info)
1717c478bd9Sstevel@tonic-gate 			rcm_free_info(state_info);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
1747c478bd9Sstevel@tonic-gate 		    "notify_resource_resume(%s, %ld, 0x%x, %d)\n",
1757c478bd9Sstevel@tonic-gate 		    rsrcnames[i], pid, flag, seq_num);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		/*
1787c478bd9Sstevel@tonic-gate 		 * Mark state as sending resumption notifications
1797c478bd9Sstevel@tonic-gate 		 */
1807c478bd9Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
1817c478bd9Sstevel@tonic-gate 		    RCM_STATE_RESUMING, seq_num, info);
1827c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
1837c478bd9Sstevel@tonic-gate 			retval = error;
1847c478bd9Sstevel@tonic-gate 			continue;
1857c478bd9Sstevel@tonic-gate 		}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_RESUME, rsrcnames[i], pid, flag,
1887c478bd9Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
1937c478bd9Sstevel@tonic-gate 			retval = error;
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	return (retval);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * Notify users that an offlined device is again available
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate int
notify_resource_online(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)2037c478bd9Sstevel@tonic-gate notify_resource_online(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
2047c478bd9Sstevel@tonic-gate     rcm_info_t **info)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	int i;
2077c478bd9Sstevel@tonic-gate 	int error;
2087c478bd9Sstevel@tonic-gate 	int retval = RCM_SUCCESS;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
2137c478bd9Sstevel@tonic-gate 		    "notify_resource_online(%s, %ld, 0x%x, %d)\n",
2147c478bd9Sstevel@tonic-gate 		    rsrcnames[i], pid, flag, seq_num);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 		/*
2177c478bd9Sstevel@tonic-gate 		 * Mark state as sending onlining notifications
2187c478bd9Sstevel@tonic-gate 		 */
2197c478bd9Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
2207c478bd9Sstevel@tonic-gate 		    RCM_STATE_ONLINING, seq_num, info);
2217c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
2227c478bd9Sstevel@tonic-gate 			retval = error;
2237c478bd9Sstevel@tonic-gate 			continue;
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_ONLINE, rsrcnames[i], pid, flag,
2277c478bd9Sstevel@tonic-gate 		    seq_num, NULL, NULL, info);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		dr_req_remove(rsrcnames[i], flag);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS)
2327c478bd9Sstevel@tonic-gate 			retval = error;
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	return (retval);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * For offline and suspend, need to get the logic correct here. There are
2407c478bd9Sstevel@tonic-gate  * several cases:
2417c478bd9Sstevel@tonic-gate  *
2427c478bd9Sstevel@tonic-gate  * 1. It is a door call and RCM_QUERY is not set:
2437c478bd9Sstevel@tonic-gate  *	run a QUERY; if that succeeds, run the operation.
2447c478bd9Sstevel@tonic-gate  *
2457c478bd9Sstevel@tonic-gate  * 2. It is a door call and RCM_QUERY is set:
2467c478bd9Sstevel@tonic-gate  *	run the QUERY only.
2477c478bd9Sstevel@tonic-gate  *
2487c478bd9Sstevel@tonic-gate  * 3. It is not a door call:
2497c478bd9Sstevel@tonic-gate  *	run the call, but look at the flag to see if the
2507c478bd9Sstevel@tonic-gate  *	lock should be kept.
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Request permission to suspend a resource
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate int
process_resource_suspend(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,timespec_t * interval,rcm_info_t ** info)2577c478bd9Sstevel@tonic-gate process_resource_suspend(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
2587c478bd9Sstevel@tonic-gate     timespec_t *interval, rcm_info_t **info)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	int i;
2617c478bd9Sstevel@tonic-gate 	int error = RCM_SUCCESS;
2627c478bd9Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * Query the operation first.  The return value of the query indicates
2667c478bd9Sstevel@tonic-gate 	 * if the operation should proceed and be implemented.
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	if (query(rsrcnames, CMD_SUSPEND, "suspend", RCM_STATE_SUSPEND_QUERYING,
2697c478bd9Sstevel@tonic-gate 	    pid, flag, interval, seq_num, info, &error) == 0) {
2707c478bd9Sstevel@tonic-gate 		return (error);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * Implement the operation.
2757c478bd9Sstevel@tonic-gate 	 */
2767c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		/* Update the lock from a query state to the suspending state */
2797c478bd9Sstevel@tonic-gate 		if ((error = dr_req_update(rsrcnames[i], pid, flag,
2807c478bd9Sstevel@tonic-gate 		    RCM_STATE_SUSPENDING, seq_num, info)) != RCM_SUCCESS) {
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
2837c478bd9Sstevel@tonic-gate 			    "suspend %s denied with error %d\n", rsrcnames[i],
2847c478bd9Sstevel@tonic-gate 			    error);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 			/*
2877c478bd9Sstevel@tonic-gate 			 * When called from a module, don't return EAGAIN.
2887c478bd9Sstevel@tonic-gate 			 * This is to avoid recursion if module always retries.
2897c478bd9Sstevel@tonic-gate 			 */
2907c478bd9Sstevel@tonic-gate 			if (!is_doorcall && error == EAGAIN) {
2917c478bd9Sstevel@tonic-gate 				return (RCM_CONFLICT);
2927c478bd9Sstevel@tonic-gate 			}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 			return (error);
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		/* Actually suspend the resource */
2987c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_SUSPEND, rsrcnames[i], pid,
2997c478bd9Sstevel@tonic-gate 		    flag, seq_num, interval, NULL, info);
3007c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3017c478bd9Sstevel@tonic-gate 			(void) dr_req_update(rsrcnames[i], pid, flag,
3027c478bd9Sstevel@tonic-gate 			    RCM_STATE_SUSPEND_FAIL, seq_num, info);
3037c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3047c478bd9Sstevel@tonic-gate 			    "suspend tree failed for %s\n", rsrcnames[i]);
3057c478bd9Sstevel@tonic-gate 			return (error);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "suspend tree succeeded for %s\n",
3097c478bd9Sstevel@tonic-gate 		    rsrcnames[i]);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 		/* Update the lock for the successful suspend */
3127c478bd9Sstevel@tonic-gate 		(void) dr_req_update(rsrcnames[i], pid, flag,
3137c478bd9Sstevel@tonic-gate 		    RCM_STATE_SUSPEND, seq_num, info);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * Process a device removal request, reply is needed
3217c478bd9Sstevel@tonic-gate  */
3227c478bd9Sstevel@tonic-gate int
process_resource_offline(char ** rsrcnames,pid_t pid,uint_t flag,int seq_num,rcm_info_t ** info)3237c478bd9Sstevel@tonic-gate process_resource_offline(char **rsrcnames, pid_t pid, uint_t flag, int seq_num,
3247c478bd9Sstevel@tonic-gate     rcm_info_t **info)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	int i;
3277c478bd9Sstevel@tonic-gate 	int error = RCM_SUCCESS;
3287c478bd9Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * Query the operation first.  The return value of the query indicates
3327c478bd9Sstevel@tonic-gate 	 * if the operation should proceed and be implemented.
3337c478bd9Sstevel@tonic-gate 	 */
3347c478bd9Sstevel@tonic-gate 	if (query(rsrcnames, CMD_OFFLINE, "offline", RCM_STATE_OFFLINE_QUERYING,
3357c478bd9Sstevel@tonic-gate 	    pid, flag, NULL, seq_num, info, &error) == 0) {
3367c478bd9Sstevel@tonic-gate 		return (error);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * Implement the operation.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		error = dr_req_update(rsrcnames[i], pid, flag,
3457c478bd9Sstevel@tonic-gate 		    RCM_STATE_OFFLINING, seq_num, info);
3467c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3477c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3487c478bd9Sstevel@tonic-gate 			    "offline %s denied with error %d\n", rsrcnames[i],
3497c478bd9Sstevel@tonic-gate 			    error);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			/*
3527c478bd9Sstevel@tonic-gate 			 * When called from a module, don't return EAGAIN.
3537c478bd9Sstevel@tonic-gate 			 * This is to avoid recursion if module always retries.
3547c478bd9Sstevel@tonic-gate 			 */
3557c478bd9Sstevel@tonic-gate 			if (!is_doorcall && error == EAGAIN) {
3567c478bd9Sstevel@tonic-gate 				return (RCM_CONFLICT);
3577c478bd9Sstevel@tonic-gate 			}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 			return (error);
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 		/* Actually offline the resource */
3637c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_OFFLINE, rsrcnames[i], pid,
3647c478bd9Sstevel@tonic-gate 		    flag, seq_num, NULL, NULL, info);
3657c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
3667c478bd9Sstevel@tonic-gate 			(void) dr_req_update(rsrcnames[i], pid, flag,
3677c478bd9Sstevel@tonic-gate 			    RCM_STATE_OFFLINE_FAIL, seq_num, info);
3687c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
3697c478bd9Sstevel@tonic-gate 			    "offline tree failed for %s\n", rsrcnames[i]);
3707c478bd9Sstevel@tonic-gate 			return (error);
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "offline tree succeeded for %s\n",
3747c478bd9Sstevel@tonic-gate 		    rsrcnames[i]);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/* Update the lock for the successful offline */
3777c478bd9Sstevel@tonic-gate 		(void) dr_req_update(rsrcnames[i], pid, flag,
3787c478bd9Sstevel@tonic-gate 		    RCM_STATE_OFFLINE, seq_num, info);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * Add a resource client who wishes to interpose on DR, events, or capacity.
3867c478bd9Sstevel@tonic-gate  * Reply needed.
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate int
add_resource_client(char * modname,char * rsrcname,pid_t pid,uint_t flag,rcm_info_t ** infop)3897c478bd9Sstevel@tonic-gate add_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag,
3907c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	int error = RCM_SUCCESS;
3937c478bd9Sstevel@tonic-gate 	client_t *user = NULL;
3947c478bd9Sstevel@tonic-gate 	rsrc_node_t *node = NULL;
3957c478bd9Sstevel@tonic-gate 	rcm_info_t *info = NULL;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
3987c478bd9Sstevel@tonic-gate 	    "add_resource_client(%s, %s, %ld, 0x%x)\n",
3997c478bd9Sstevel@tonic-gate 	    modname, rsrcname, pid, flag);
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (strcmp(rsrcname, "/") == 0) {
4027c478bd9Sstevel@tonic-gate 		/*
4037c478bd9Sstevel@tonic-gate 		 * No need to register for /  because it will never go away.
4047c478bd9Sstevel@tonic-gate 		 */
4057c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO, gettext(
4067c478bd9Sstevel@tonic-gate 		    "registering for / by %s has been turned into a no-op\n"),
4077c478bd9Sstevel@tonic-gate 		    modname);
4087c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/*
4127c478bd9Sstevel@tonic-gate 	 * Hold the rcm_req_lock so no dr request may come in while the
4137c478bd9Sstevel@tonic-gate 	 * registration is in progress.
4147c478bd9Sstevel@tonic-gate 	 */
4157c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&rcm_req_lock);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * Test if the requested registration is a noop, and return EALREADY
4197c478bd9Sstevel@tonic-gate 	 * if it is.
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, RSRC_NODE_CREATE, &node);
4227c478bd9Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || (node == NULL)) {
4237c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rcm_req_lock);
4247c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	user = rsrc_client_find(modname, pid, &node->users);
4287c478bd9Sstevel@tonic-gate 	if ((user != NULL) &&
4297c478bd9Sstevel@tonic-gate 	    ((user->flag & (flag & RCM_REGISTER_MASK)) != 0)) {
4307c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rcm_req_lock);
4317c478bd9Sstevel@tonic-gate 		if ((flag & RCM_REGISTER_DR) &&
4327c478bd9Sstevel@tonic-gate 		    (user->state == RCM_STATE_REMOVE)) {
4337c478bd9Sstevel@tonic-gate 			user->state = RCM_STATE_ONLINE;
4347c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		return (EALREADY);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* If adding a new DR registration, reject if the resource is locked */
4407c478bd9Sstevel@tonic-gate 	if (flag & RCM_REGISTER_DR) {
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		if (rsrc_check_lock_conflicts(rsrcname, flag, LOCK_FOR_USE,
4437c478bd9Sstevel@tonic-gate 		    &info) != RCM_SUCCESS) {
4447c478bd9Sstevel@tonic-gate 			/*
4457c478bd9Sstevel@tonic-gate 			 * The resource is being DR'ed, so return failure
4467c478bd9Sstevel@tonic-gate 			 */
4477c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rcm_req_lock);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 			/*
4507c478bd9Sstevel@tonic-gate 			 * If caller doesn't care about info, free it
4517c478bd9Sstevel@tonic-gate 			 */
4527c478bd9Sstevel@tonic-gate 			if (infop)
4537c478bd9Sstevel@tonic-gate 				*infop = info;
4547c478bd9Sstevel@tonic-gate 			else
4557c478bd9Sstevel@tonic-gate 				rcm_free_info(info);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 			return (RCM_CONFLICT);
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/* The registration is new and allowable, so add it */
4627c478bd9Sstevel@tonic-gate 	error = rsrc_node_add_user(node, rsrcname, modname, pid, flag);
4637c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&rcm_req_lock);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	return (error);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * Remove a resource client, who no longer wishes to interpose on either
4707c478bd9Sstevel@tonic-gate  * DR, events, or capacity.
4717c478bd9Sstevel@tonic-gate  */
4727c478bd9Sstevel@tonic-gate int
remove_resource_client(char * modname,char * rsrcname,pid_t pid,uint_t flag)4737c478bd9Sstevel@tonic-gate remove_resource_client(char *modname, char *rsrcname, pid_t pid, uint_t flag)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	int error;
4767c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
4797c478bd9Sstevel@tonic-gate 	    "remove_resource_client(%s, %s, %ld, 0x%x)\n",
4807c478bd9Sstevel@tonic-gate 	    modname, rsrcname, pid, flag);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/*
4837c478bd9Sstevel@tonic-gate 	 * Allow resource client to leave anytime, assume client knows what
4847c478bd9Sstevel@tonic-gate 	 * it is trying to do.
4857c478bd9Sstevel@tonic-gate 	 */
4867c478bd9Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
4877c478bd9Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || (node == NULL)) {
4887c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
4897c478bd9Sstevel@tonic-gate 		    gettext("resource %s not found\n"), rsrcname);
4907c478bd9Sstevel@tonic-gate 		return (ENOENT);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (rsrc_node_remove_user(node, modname, pid, flag));
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * Reply is needed
4987c478bd9Sstevel@tonic-gate  */
4997c478bd9Sstevel@tonic-gate int
get_resource_info(char ** rsrcnames,uint_t flag,int seq_num,rcm_info_t ** info)5007c478bd9Sstevel@tonic-gate get_resource_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	int rv = RCM_SUCCESS;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if (flag & RCM_DR_OPERATION) {
5057c478bd9Sstevel@tonic-gate 		*info = rsrc_dr_info();
5067c478bd9Sstevel@tonic-gate 	} else if (flag & RCM_MOD_INFO) {
5077c478bd9Sstevel@tonic-gate 		*info = rsrc_mod_info();
5087c478bd9Sstevel@tonic-gate 	} else {
5097c478bd9Sstevel@tonic-gate 		rv = rsrc_usage_info(rsrcnames, flag, seq_num, info);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	return (rv);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@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)5167c478bd9Sstevel@tonic-gate notify_resource_event(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5177c478bd9Sstevel@tonic-gate     nvlist_t *event_data, rcm_info_t **info)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	int error;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	assert(flag == 0);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "notify_resource_event(%s, %ld, 0x%x)\n",
5247c478bd9Sstevel@tonic-gate 	    rsrcname, pid, flag);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	error = common_resource_op(CMD_EVENT, rsrcname, pid, flag, seq_num,
5277c478bd9Sstevel@tonic-gate 	    NULL, event_data, info);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	return (error);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate int
request_capacity_change(char * rsrcname,id_t pid,uint_t flag,int seq_num,nvlist_t * nvl,rcm_info_t ** info)5337c478bd9Sstevel@tonic-gate request_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5347c478bd9Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **info)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	int error;
5377c478bd9Sstevel@tonic-gate 	int is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
5407c478bd9Sstevel@tonic-gate 	    "request_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid,
5417c478bd9Sstevel@tonic-gate 	    flag, seq_num);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (is_doorcall || (flag & RCM_QUERY)) {
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid,
5467c478bd9Sstevel@tonic-gate 		    flag | RCM_QUERY, seq_num, NULL, nvl, info);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
5497c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
5507c478bd9Sstevel@tonic-gate 			    "request state change query denied\n");
5517c478bd9Sstevel@tonic-gate 			return (error);
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	if (flag & RCM_QUERY)
5567c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	error = common_resource_op(CMD_REQUEST_CHANGE, rsrcname, pid, flag,
5597c478bd9Sstevel@tonic-gate 	    seq_num, NULL, nvl, info);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	if (error != RCM_SUCCESS) {
5627c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "request state change failed\n");
5637c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "request state change succeeded\n");
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	return (error);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate int
notify_capacity_change(char * rsrcname,id_t pid,uint_t flag,int seq_num,nvlist_t * nvl,rcm_info_t ** info)5727c478bd9Sstevel@tonic-gate notify_capacity_change(char *rsrcname, id_t pid, uint_t flag, int seq_num,
5737c478bd9Sstevel@tonic-gate     nvlist_t *nvl, rcm_info_t **info)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 	int error;
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
5787c478bd9Sstevel@tonic-gate 	    "notify_capacity_change(%s, %ld, 0x%x, %d)\n", rsrcname, pid,
5797c478bd9Sstevel@tonic-gate 	    flag, seq_num);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	error = common_resource_op(CMD_NOTIFY_CHANGE, rsrcname, pid, flag,
5827c478bd9Sstevel@tonic-gate 	    seq_num, NULL, nvl, info);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (error != RCM_SUCCESS) {
5857c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "notify state change failed\n");
5867c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "notify state change succeeded\n");
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	return (error);
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate int
get_resource_state(char * rsrcname,pid_t pid,rcm_info_t ** info)5957c478bd9Sstevel@tonic-gate get_resource_state(char *rsrcname, pid_t pid, rcm_info_t **info)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	int error;
5987c478bd9Sstevel@tonic-gate 	int state;
5997c478bd9Sstevel@tonic-gate 	char *s;
6007c478bd9Sstevel@tonic-gate 	char *resolved;
6017c478bd9Sstevel@tonic-gate 	rcm_info_t *dr_info = NULL;
6027c478bd9Sstevel@tonic-gate 	rcm_info_tuple_t *dr_info_tuple = NULL;
6037c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
6047c478bd9Sstevel@tonic-gate 	client_t *client;
6057c478bd9Sstevel@tonic-gate 	char *state_info = gettext("State of resource");
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "get_resource_state(%s, %ld)\n",
6087c478bd9Sstevel@tonic-gate 	    rsrcname, pid);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	/*
6117c478bd9Sstevel@tonic-gate 	 * Check for locks, first.
6127c478bd9Sstevel@tonic-gate 	 */
6137c478bd9Sstevel@tonic-gate 	dr_info = rsrc_dr_info();
6147c478bd9Sstevel@tonic-gate 	if (dr_info) {
6157c478bd9Sstevel@tonic-gate 		state = RCM_STATE_UNKNOWN;
6167c478bd9Sstevel@tonic-gate 		if ((resolved = resolve_name(rsrcname)) == NULL)
6177c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
6187c478bd9Sstevel@tonic-gate 		while (dr_info_tuple = rcm_info_next(dr_info, dr_info_tuple)) {
6197c478bd9Sstevel@tonic-gate 			s = (char *)rcm_info_rsrc(dr_info_tuple);
6207c478bd9Sstevel@tonic-gate 			if (s && (strcmp(resolved, s) == 0)) {
6217c478bd9Sstevel@tonic-gate 				state = rcm_info_state(dr_info_tuple);
6227c478bd9Sstevel@tonic-gate 				break;
6237c478bd9Sstevel@tonic-gate 			}
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 		free(resolved);
6267c478bd9Sstevel@tonic-gate 		rcm_free_info(dr_info);
6277c478bd9Sstevel@tonic-gate 		if (state != RCM_STATE_UNKNOWN) {
6287c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
6297c478bd9Sstevel@tonic-gate 			    "get_resource_state(%s)=%d\n", rsrcname, state);
6307c478bd9Sstevel@tonic-gate 			add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL,
6317c478bd9Sstevel@tonic-gate 			    (char *)state_info, NULL, NULL, info);
6327c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
6337c478bd9Sstevel@tonic-gate 		}
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * No locks, so look for client states in the resource tree.
6387c478bd9Sstevel@tonic-gate 	 *
6397c478bd9Sstevel@tonic-gate 	 * NOTE: It's possible the node doesn't exist, which means no RCM
6407c478bd9Sstevel@tonic-gate 	 * consumer registered for the resource. In this case we silently
6417c478bd9Sstevel@tonic-gate 	 * succeed.
6427c478bd9Sstevel@tonic-gate 	 */
6437c478bd9Sstevel@tonic-gate 	error = rsrc_node_find(rsrcname, 0, &node);
6447c478bd9Sstevel@tonic-gate 	state = RCM_STATE_ONLINE;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	if ((error == RCM_SUCCESS) && (node != NULL)) {
6477c478bd9Sstevel@tonic-gate 		for (client = node->users; client; client = client->next) {
6487c478bd9Sstevel@tonic-gate 			if (client->state == RCM_STATE_OFFLINE_FAIL ||
6497c478bd9Sstevel@tonic-gate 			    client->state == RCM_STATE_OFFLINE_QUERY_FAIL ||
6507c478bd9Sstevel@tonic-gate 			    client->state == RCM_STATE_SUSPEND_FAIL ||
6517c478bd9Sstevel@tonic-gate 			    client->state == RCM_STATE_SUSPEND_QUERY_FAIL) {
6527c478bd9Sstevel@tonic-gate 				state = client->state;
6537c478bd9Sstevel@tonic-gate 				break;
6547c478bd9Sstevel@tonic-gate 			}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 			if (client->state != RCM_STATE_ONLINE &&
6577c478bd9Sstevel@tonic-gate 			    client->state != RCM_STATE_REMOVE)
6587c478bd9Sstevel@tonic-gate 				state = client->state;
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (error == RCM_SUCCESS) {
6637c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "get_resource_state(%s)=%d\n",
6647c478bd9Sstevel@tonic-gate 		    rsrcname, state);
6657c478bd9Sstevel@tonic-gate 		add_busy_rsrc_to_list(rsrcname, pid, state, 0, NULL,
6667c478bd9Sstevel@tonic-gate 		    (char *)state_info, NULL, NULL, info);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	return (error);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate  * Perform a query of an offline or suspend.
6747c478bd9Sstevel@tonic-gate  *
6757c478bd9Sstevel@tonic-gate  * The return value of this function indicates whether the operation should
6767c478bd9Sstevel@tonic-gate  * be implemented (0 == No, 1 == Yes).  Note that locks and client state
6777c478bd9Sstevel@tonic-gate  * changes will only persist if the caller is going to implement the operation.
6787c478bd9Sstevel@tonic-gate  */
6797c478bd9Sstevel@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)6807c478bd9Sstevel@tonic-gate query(char **rsrcnames, int cmd, const char *opname, int querystate, pid_t pid,
6817c478bd9Sstevel@tonic-gate     uint_t flag, timespec_t *interval, int seq_num, rcm_info_t **info,
6827c478bd9Sstevel@tonic-gate     int *errorp)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	int	i;
6857c478bd9Sstevel@tonic-gate 	int	error;
6867c478bd9Sstevel@tonic-gate 	int	final_error;
6877c478bd9Sstevel@tonic-gate 	int	is_doorcall = ((seq_num & SEQ_NUM_MASK) == 0);
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	/* Only query for door calls, or when the RCM_QUERY flag is set */
6907c478bd9Sstevel@tonic-gate 	if ((is_doorcall == 0) && ((flag & RCM_QUERY) == 0)) {
6917c478bd9Sstevel@tonic-gate 		return (1);
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	/* Lock all the resources.  Fail the query in the case of a conflict. */
6957c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
6987c478bd9Sstevel@tonic-gate 		    "process_resource_%s(%s, %ld, 0x%x, %d)\n",
6997c478bd9Sstevel@tonic-gate 		    opname, rsrcnames[i], pid, flag, seq_num);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		error = dr_req_add(rsrcnames[i], pid, flag, querystate, seq_num,
7027c478bd9Sstevel@tonic-gate 		    NULL, info);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 		/* The query goes no further if a resource cannot be locked */
7057c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
7087c478bd9Sstevel@tonic-gate 			    "%s query %s defined with error %d\n",
7097c478bd9Sstevel@tonic-gate 			    opname, rsrcnames[i], error);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 			/*
7127c478bd9Sstevel@tonic-gate 			 * Replace EAGAIN with RCM_CONFLICT in the case of
7137c478bd9Sstevel@tonic-gate 			 * module callbacks; to avoid modules from trying
7147c478bd9Sstevel@tonic-gate 			 * again infinitely.
7157c478bd9Sstevel@tonic-gate 			 */
7167c478bd9Sstevel@tonic-gate 			if ((is_doorcall == 0) && (error == EAGAIN)) {
7177c478bd9Sstevel@tonic-gate 				error = RCM_CONFLICT;
7187c478bd9Sstevel@tonic-gate 			}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 			goto finished;
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/*
7257c478bd9Sstevel@tonic-gate 	 * All the resources were locked above, so use common_resource_op()
7267c478bd9Sstevel@tonic-gate 	 * to pass the query on to the clients.  Accumulate the overall error
7277c478bd9Sstevel@tonic-gate 	 * value in 'final_error', before transferring it to 'error' at the end.
7287c478bd9Sstevel@tonic-gate 	 */
7297c478bd9Sstevel@tonic-gate 	for (final_error = RCM_SUCCESS, i = 0; rsrcnames[i] != NULL; i++) {
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		/* Log the query (for tracing purposes). */
7327c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "querying resource %s\n",
7337c478bd9Sstevel@tonic-gate 		    rsrcnames[i]);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 		/* Query the resource's clients through common_resource_op(). */
7367c478bd9Sstevel@tonic-gate 		error = common_resource_op(cmd, rsrcnames[i], pid,
7377c478bd9Sstevel@tonic-gate 		    flag | RCM_QUERY, seq_num, interval, NULL, info);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 		/*
7407c478bd9Sstevel@tonic-gate 		 * If a query fails, don't stop iterating through the loop.
7417c478bd9Sstevel@tonic-gate 		 * Just ensure that 'final_error' is set (if not already),
7427c478bd9Sstevel@tonic-gate 		 * log the error, and continue looping.
7437c478bd9Sstevel@tonic-gate 		 *
7447c478bd9Sstevel@tonic-gate 		 * In the case of a user who manually intervenes and retries
7457c478bd9Sstevel@tonic-gate 		 * the operation, this will maximize the extent of the query
7467c478bd9Sstevel@tonic-gate 		 * so that they experience fewer such iterations overall.
7477c478bd9Sstevel@tonic-gate 		 */
7487c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 			/* Log each query that failed along the way */
7517c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "%s %s query denied\n",
7527c478bd9Sstevel@tonic-gate 			    opname, rsrcnames[i]);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 			if (final_error != RCM_FAILURE) {
7557c478bd9Sstevel@tonic-gate 				final_error = error;
7567c478bd9Sstevel@tonic-gate 			}
7577c478bd9Sstevel@tonic-gate 		}
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 	error = final_error;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/*
7627c478bd9Sstevel@tonic-gate 	 * Tell the calling function not to proceed any further with the
7637c478bd9Sstevel@tonic-gate 	 * implementation phase of the operation if the query failed, or
7647c478bd9Sstevel@tonic-gate 	 * if the user's intent was to only query the operation.
7657c478bd9Sstevel@tonic-gate 	 */
7667c478bd9Sstevel@tonic-gate finished:
7677c478bd9Sstevel@tonic-gate 	if ((error != RCM_SUCCESS) || ((flag & RCM_QUERY) != 0)) {
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		/*
7707c478bd9Sstevel@tonic-gate 		 * Since the operation won't be implemented, cancel the
7717c478bd9Sstevel@tonic-gate 		 * query (unlock resources and reverse client state changes).
7727c478bd9Sstevel@tonic-gate 		 *
7737c478bd9Sstevel@tonic-gate 		 * The cancellation routine cleans up everything for the entire
7747c478bd9Sstevel@tonic-gate 		 * operation, and thus it should only be called from the very
7757c478bd9Sstevel@tonic-gate 		 * root of the operation (e.g. when 'is_doorcall' is TRUE).
7767c478bd9Sstevel@tonic-gate 		 */
7777c478bd9Sstevel@tonic-gate 		if (is_doorcall != 0) {
7787c478bd9Sstevel@tonic-gate 			cancel_query(cmd, opname, pid, flag, seq_num);
7797c478bd9Sstevel@tonic-gate 		}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		*errorp = error;
7827c478bd9Sstevel@tonic-gate 		return (0);
7837c478bd9Sstevel@tonic-gate 	}
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	/* Otherwise, tell the caller to proceed with the implementation. */
7867c478bd9Sstevel@tonic-gate 	*errorp = RCM_SUCCESS;
7877c478bd9Sstevel@tonic-gate 	return (1);
7887c478bd9Sstevel@tonic-gate }
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate /*
7917c478bd9Sstevel@tonic-gate  * Implementation of a query cancellation.
7927c478bd9Sstevel@tonic-gate  *
7937c478bd9Sstevel@tonic-gate  * The full scope of the query is already noted, so the scope of the operation
7947c478bd9Sstevel@tonic-gate  * does not need to be expanded in the same recursive manner that was used for
7957c478bd9Sstevel@tonic-gate  * the query itself.  (Clients don't have to be called to cross namespaces.)
7967c478bd9Sstevel@tonic-gate  * Instead, the locks added to the DR request list during the query are scanned.
7977c478bd9Sstevel@tonic-gate  */
7987c478bd9Sstevel@tonic-gate static void
cancel_query(int cmd,const char * opname,pid_t pid,uint_t flag,int seq_num)7997c478bd9Sstevel@tonic-gate cancel_query(int cmd, const char *opname, pid_t pid, uint_t flag, int seq_num)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	char	rsrc[MAXPATHLEN];
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	/*
8047c478bd9Sstevel@tonic-gate 	 * Find every lock in the DR request list that is a part of this
8057c478bd9Sstevel@tonic-gate 	 * sequence.  Call common_resource_op() with the QUERY_CANCEL flag to
8067c478bd9Sstevel@tonic-gate 	 * cancel each sub-operation, and then remove each lock from the list.
8077c478bd9Sstevel@tonic-gate 	 *
8087c478bd9Sstevel@tonic-gate 	 * The 'rsrc' buffer is required to retrieve the 'device' fields of
8097c478bd9Sstevel@tonic-gate 	 * matching DR request list entries in a way that's multi-thread safe.
8107c478bd9Sstevel@tonic-gate 	 */
8117c478bd9Sstevel@tonic-gate 	while (dr_req_lookup(seq_num, rsrc) == RCM_SUCCESS) {
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "%s query %s cancelled\n",
8147c478bd9Sstevel@tonic-gate 		    opname, rsrc);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 		(void) common_resource_op(cmd, rsrc, pid,
8177c478bd9Sstevel@tonic-gate 		    flag | RCM_QUERY | RCM_QUERY_CANCEL, seq_num, NULL, NULL,
8187c478bd9Sstevel@tonic-gate 		    NULL);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		(void) dr_req_remove(rsrc, flag);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate }
823