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
525e8c5aaSvikram  * Common Development and Distribution License (the "License").
625e8c5aaSvikram  * 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  *
2125e8c5aaSvikram  * 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 "rcm_impl.h"
267c478bd9Sstevel@tonic-gate #include "rcm_module.h"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Short-circuits unloading of modules with no registrations, so that
307c478bd9Sstevel@tonic-gate  * they are present during the next db_sync cycle.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate #define	MOD_REFCNT_INIT		2
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate int need_cleanup;	/* flag indicating if clean up is needed */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static mutex_t mod_lock;	/* protects module list */
377c478bd9Sstevel@tonic-gate static module_t *module_head;	/* linked list of modules */
387c478bd9Sstevel@tonic-gate static rsrc_node_t *rsrc_root;	/* root of all resources */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Misc help routines
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate static void rcmd_db_print();
447c478bd9Sstevel@tonic-gate static void rcm_handle_free(rcm_handle_t *);
457c478bd9Sstevel@tonic-gate static rcm_handle_t *rcm_handle_alloc(module_t *);
467c478bd9Sstevel@tonic-gate static void rsrc_clients_free(client_t *);
477c478bd9Sstevel@tonic-gate static struct rcm_mod_ops *modops_from_v1(void *);
487c478bd9Sstevel@tonic-gate static int call_getinfo(struct rcm_mod_ops *, rcm_handle_t *, char *, id_t,
497c478bd9Sstevel@tonic-gate     uint_t, char **, char **, nvlist_t *, rcm_info_t **);
507c478bd9Sstevel@tonic-gate static int node_action(rsrc_node_t *, void *);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate extern void start_polling_thread();
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * translate /dev name to a /devices path
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * N.B. This routine can be enhanced to understand network names
587c478bd9Sstevel@tonic-gate  *	and friendly names in the future.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate char *
resolve_name(char * alias)617c478bd9Sstevel@tonic-gate resolve_name(char *alias)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	char *tmp;
647c478bd9Sstevel@tonic-gate 	const char *dev = "/dev/";
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	if (strlen(alias) == 0)
677c478bd9Sstevel@tonic-gate 		return (NULL);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (strncmp(alias, dev, strlen(dev)) == 0) {
707c478bd9Sstevel@tonic-gate 		/*
717c478bd9Sstevel@tonic-gate 		 * Treat /dev/... as a symbolic link
727c478bd9Sstevel@tonic-gate 		 */
737c478bd9Sstevel@tonic-gate 		tmp = s_malloc(PATH_MAX);
747c478bd9Sstevel@tonic-gate 		if (realpath(alias, tmp) != NULL) {
757c478bd9Sstevel@tonic-gate 			return (tmp);
767c478bd9Sstevel@tonic-gate 		} else {
777c478bd9Sstevel@tonic-gate 			free(tmp);
787c478bd9Sstevel@tonic-gate 		}
797c478bd9Sstevel@tonic-gate 		/* Fail to resolve /dev/ name, use the name as is */
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	return (s_strdup(alias));
837c478bd9Sstevel@tonic-gate }
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Figure out resource type based on "resolved" name
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * N.B. This routine does not figure out file system mount points.
897c478bd9Sstevel@tonic-gate  *	This is determined at runtime when filesys module register
907c478bd9Sstevel@tonic-gate  *	with RCM_FILESYS flag.
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate int
rsrc_get_type(const char * resolved_name)937c478bd9Sstevel@tonic-gate rsrc_get_type(const char *resolved_name)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate 	if (resolved_name[0] != '/')
967c478bd9Sstevel@tonic-gate 		return (RSRC_TYPE_ABSTRACT);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (strncmp("/devices/", resolved_name, 9) == 0)
997c478bd9Sstevel@tonic-gate 		return (RSRC_TYPE_DEVICE);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	return (RSRC_TYPE_NORMAL);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Module operations:
1067c478bd9Sstevel@tonic-gate  *	module_load, module_unload, module_info, module_attach, module_detach,
1077c478bd9Sstevel@tonic-gate  *	cli_module_hold, cli_module_rele
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #ifdef	ENABLE_MODULE_DETACH
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * call unregister() entry point to allow module to unregister for
1137c478bd9Sstevel@tonic-gate  * resources without getting confused.
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate static void
module_detach(module_t * module)1167c478bd9Sstevel@tonic-gate module_detach(module_t *module)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	struct rcm_mod_ops *ops = module->modops;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "module_detach(name=%s)\n", module->name);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	ops->rcmop_unregister(module->rcmhandle);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate #endif	/* ENABLE_MODULE_DETACH */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * call register() entry point to allow module to register for resources
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static void
module_attach(module_t * module)1307c478bd9Sstevel@tonic-gate module_attach(module_t *module)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	struct rcm_mod_ops *ops = module->modops;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "module_attach(name=%s)\n", module->name);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (ops->rcmop_register(module->rcmhandle) != RCM_SUCCESS) {
1377c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
1387c478bd9Sstevel@tonic-gate 		    gettext("module %s register() failed\n"), module->name);
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
module_init(module_t * module)1437c478bd9Sstevel@tonic-gate module_init(module_t *module)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	if (module->dlhandle)
1467c478bd9Sstevel@tonic-gate 		/* rcm module */
1477c478bd9Sstevel@tonic-gate 		return (module->init());
1487c478bd9Sstevel@tonic-gate 	else
1497c478bd9Sstevel@tonic-gate 		/* rcm script */
1507c478bd9Sstevel@tonic-gate 		return (script_init(module));
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * call rmc_mod_info() entry of module
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate static const char *
module_info(module_t * module)1577c478bd9Sstevel@tonic-gate module_info(module_t *module)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	if (module->dlhandle)
1607c478bd9Sstevel@tonic-gate 		/* rcm module */
1617c478bd9Sstevel@tonic-gate 		return (module->info());
1627c478bd9Sstevel@tonic-gate 	else
1637c478bd9Sstevel@tonic-gate 		/* rcm script */
1647c478bd9Sstevel@tonic-gate 		return (script_info(module));
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate int
module_fini(module_t * module)1687c478bd9Sstevel@tonic-gate module_fini(module_t *module)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	if (module->dlhandle)
1717c478bd9Sstevel@tonic-gate 		/* rcm module */
1727c478bd9Sstevel@tonic-gate 		return (module->fini());
1737c478bd9Sstevel@tonic-gate 	else
1747c478bd9Sstevel@tonic-gate 		/* rcm script */
1757c478bd9Sstevel@tonic-gate 		return (script_fini(module));
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate  * call rmc_mod_fini() entry of module, dlclose module, and free memory
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate static void
module_unload(module_t * module)1827c478bd9Sstevel@tonic-gate module_unload(module_t *module)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	int version = module->modops->version;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "module_unload(name=%s)\n", module->name);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	(void) module_fini(module);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	rcm_handle_free(module->rcmhandle);
1917c478bd9Sstevel@tonic-gate 	free(module->name);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	switch (version) {
1947c478bd9Sstevel@tonic-gate 	case RCM_MOD_OPS_V1:
1957c478bd9Sstevel@tonic-gate 		/*
1967c478bd9Sstevel@tonic-gate 		 * Free memory associated with converted ops vector
1977c478bd9Sstevel@tonic-gate 		 */
1987c478bd9Sstevel@tonic-gate 		free(module->modops);
1997c478bd9Sstevel@tonic-gate 		break;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	case RCM_MOD_OPS_VERSION:
2027c478bd9Sstevel@tonic-gate 	default:
2037c478bd9Sstevel@tonic-gate 		break;
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (module->dlhandle)
2077c478bd9Sstevel@tonic-gate 		rcm_module_close(module->dlhandle);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	free(module);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * Locate the module, execute rcm_mod_init() and check ops vector version
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate static module_t *
module_load(char * modname)2167c478bd9Sstevel@tonic-gate module_load(char *modname)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	module_t *module;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "module_load(name=%s)\n", modname);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	 * dlopen the module
2247c478bd9Sstevel@tonic-gate 	 */
2257c478bd9Sstevel@tonic-gate 	module = s_calloc(1, sizeof (*module));
2267c478bd9Sstevel@tonic-gate 	module->name = s_strdup(modname);
2277c478bd9Sstevel@tonic-gate 	module->modops = NULL;
2287c478bd9Sstevel@tonic-gate 	rcm_init_queue(&module->client_q);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if (rcm_is_script(modname) == 0) {
2317c478bd9Sstevel@tonic-gate 		/* rcm module */
2327c478bd9Sstevel@tonic-gate 		module->dlhandle = rcm_module_open(modname);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		if (module->dlhandle == NULL) {
2357c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_NOTICE,
23646fbc806SToomas Soome 			    gettext("cannot open module %s\n"), modname);
2377c478bd9Sstevel@tonic-gate 			goto fail;
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		/*
2417c478bd9Sstevel@tonic-gate 		 * dlsym rcm_mod_init/fini/info() entry points
2427c478bd9Sstevel@tonic-gate 		 */
2437c478bd9Sstevel@tonic-gate 		module->init = (struct rcm_mod_ops *(*)())dlsym(
24446fbc806SToomas Soome 		    module->dlhandle, "rcm_mod_init");
2457c478bd9Sstevel@tonic-gate 		module->fini = (int (*)())dlsym(
24646fbc806SToomas Soome 		    module->dlhandle, "rcm_mod_fini");
2477c478bd9Sstevel@tonic-gate 		module->info = (const char *(*)())dlsym(module->dlhandle,
2487c478bd9Sstevel@tonic-gate 		    "rcm_mod_info");
2497c478bd9Sstevel@tonic-gate 		if (module->init == NULL || module->fini == NULL ||
2507c478bd9Sstevel@tonic-gate 		    module->info == NULL) {
2517c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
2527c478bd9Sstevel@tonic-gate 			    gettext("missing entries in module %s\n"), modname);
2537c478bd9Sstevel@tonic-gate 			goto fail;
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	} else {
2577c478bd9Sstevel@tonic-gate 		/* rcm script */
2587c478bd9Sstevel@tonic-gate 		module->dlhandle = NULL;
2597c478bd9Sstevel@tonic-gate 		module->init = (struct rcm_mod_ops *(*)()) NULL;
2607c478bd9Sstevel@tonic-gate 		module->fini = (int (*)()) NULL;
2617c478bd9Sstevel@tonic-gate 		module->info = (const char *(*)()) NULL;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	if ((module->modops = module_init(module)) == NULL) {
2657c478bd9Sstevel@tonic-gate 		if (module->dlhandle)
2667c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
26746fbc806SToomas Soome 			    gettext("cannot init module %s\n"), modname);
2687c478bd9Sstevel@tonic-gate 		goto fail;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/*
2727c478bd9Sstevel@tonic-gate 	 * Check ops vector version
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 	switch (module->modops->version) {
2757c478bd9Sstevel@tonic-gate 	case RCM_MOD_OPS_V1:
2767c478bd9Sstevel@tonic-gate 		module->modops = modops_from_v1((void *)module->modops);
2777c478bd9Sstevel@tonic-gate 		break;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	case RCM_MOD_OPS_VERSION:
2807c478bd9Sstevel@tonic-gate 		break;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	default:
2837c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2847c478bd9Sstevel@tonic-gate 		    gettext("module %s rejected: version %d not supported\n"),
2857c478bd9Sstevel@tonic-gate 		    modname, module->modops->version);
2867c478bd9Sstevel@tonic-gate 		(void) module_fini(module);
2877c478bd9Sstevel@tonic-gate 		goto fail;
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	/*
2917c478bd9Sstevel@tonic-gate 	 * Make sure all fields are set
2927c478bd9Sstevel@tonic-gate 	 */
2937c478bd9Sstevel@tonic-gate 	if ((module->modops->rcmop_register == NULL) ||
2947c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_unregister == NULL) ||
2957c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_get_info == NULL) ||
2967c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_request_suspend == NULL) ||
2977c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_notify_resume == NULL) ||
2987c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_request_offline == NULL) ||
2997c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_notify_online == NULL) ||
3007c478bd9Sstevel@tonic-gate 	    (module->modops->rcmop_notify_remove == NULL)) {
3017c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
3027c478bd9Sstevel@tonic-gate 		    gettext("module %s rejected: has NULL ops fields\n"),
3037c478bd9Sstevel@tonic-gate 		    modname);
3047c478bd9Sstevel@tonic-gate 		(void) module_fini(module);
3057c478bd9Sstevel@tonic-gate 		goto fail;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	module->rcmhandle = rcm_handle_alloc(module);
3097c478bd9Sstevel@tonic-gate 	return (module);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate fail:
3127c478bd9Sstevel@tonic-gate 	if (module->modops && module->modops->version == RCM_MOD_OPS_V1)
3137c478bd9Sstevel@tonic-gate 		free(module->modops);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (module->dlhandle)
3167c478bd9Sstevel@tonic-gate 		rcm_module_close(module->dlhandle);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	free(module->name);
3197c478bd9Sstevel@tonic-gate 	free(module);
3207c478bd9Sstevel@tonic-gate 	return (NULL);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate  * add one to module hold count. load the module if not loaded
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate static module_t *
cli_module_hold(char * modname)3277c478bd9Sstevel@tonic-gate cli_module_hold(char *modname)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	module_t *module;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "cli_module_hold(%s)\n", modname);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mod_lock);
3347c478bd9Sstevel@tonic-gate 	module = module_head;
3357c478bd9Sstevel@tonic-gate 	while (module) {
3367c478bd9Sstevel@tonic-gate 		if (strcmp(module->name, modname) == 0) {
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 		module = module->next;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (module) {
3437c478bd9Sstevel@tonic-gate 		module->ref_count++;
3447c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mod_lock);
3457c478bd9Sstevel@tonic-gate 		return (module);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	/*
3497c478bd9Sstevel@tonic-gate 	 * Module not found, attempt to load it
3507c478bd9Sstevel@tonic-gate 	 */
3517c478bd9Sstevel@tonic-gate 	if ((module = module_load(modname)) == NULL) {
3527c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mod_lock);
3537c478bd9Sstevel@tonic-gate 		return (NULL);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	/*
3577c478bd9Sstevel@tonic-gate 	 * Hold module and link module into module list
3587c478bd9Sstevel@tonic-gate 	 */
3597c478bd9Sstevel@tonic-gate 	module->ref_count = MOD_REFCNT_INIT;
3607c478bd9Sstevel@tonic-gate 	module->next = module_head;
3617c478bd9Sstevel@tonic-gate 	module_head = module;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mod_lock);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	return (module);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate  * decrement module hold count. Unload it if no reference
3707c478bd9Sstevel@tonic-gate  */
3717c478bd9Sstevel@tonic-gate static void
cli_module_rele(module_t * module)3727c478bd9Sstevel@tonic-gate cli_module_rele(module_t *module)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	module_t *curr = module_head, *prev = NULL;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "cli_module_rele(name=%s)\n", module->name);
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mod_lock);
3797c478bd9Sstevel@tonic-gate 	if (--(module->ref_count) != 0) {
3807c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mod_lock);
3817c478bd9Sstevel@tonic-gate 		return;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "unloading module %s\n", module->name);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	/*
3877c478bd9Sstevel@tonic-gate 	 * Unlink the module from list
3887c478bd9Sstevel@tonic-gate 	 */
3897c478bd9Sstevel@tonic-gate 	while (curr && (curr != module)) {
3907c478bd9Sstevel@tonic-gate 		prev = curr;
3917c478bd9Sstevel@tonic-gate 		curr = curr->next;
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 	if (curr == NULL) {
3947c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
3957c478bd9Sstevel@tonic-gate 		    gettext("Unexpected error: module %s not found.\n"),
3967c478bd9Sstevel@tonic-gate 		    module->name);
3977c478bd9Sstevel@tonic-gate 	} else if (prev == NULL) {
3987c478bd9Sstevel@tonic-gate 		module_head = curr->next;
3997c478bd9Sstevel@tonic-gate 	} else {
4007c478bd9Sstevel@tonic-gate 		prev->next = curr->next;
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mod_lock);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	module_unload(module);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * Gather usage info be passed back to requester. Discard info if user does
4097c478bd9Sstevel@tonic-gate  * not care (list == NULL).
4107c478bd9Sstevel@tonic-gate  */
4117c478bd9Sstevel@tonic-gate void
add_busy_rsrc_to_list(char * alias,pid_t pid,int state,int seq_num,char * modname,const char * infostr,const char * errstr,nvlist_t * client_props,rcm_info_t ** list)4127c478bd9Sstevel@tonic-gate add_busy_rsrc_to_list(char *alias, pid_t pid, int state, int seq_num,
4137c478bd9Sstevel@tonic-gate     char *modname, const char *infostr, const char *errstr,
4147c478bd9Sstevel@tonic-gate     nvlist_t *client_props, rcm_info_t **list)
4157c478bd9Sstevel@tonic-gate {
4167c478bd9Sstevel@tonic-gate 	rcm_info_t *info;
4177c478bd9Sstevel@tonic-gate 	rcm_info_t *tmp;
4187c478bd9Sstevel@tonic-gate 	char *buf = NULL;
4197c478bd9Sstevel@tonic-gate 	size_t buflen = 0;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if (list == NULL) {
4227c478bd9Sstevel@tonic-gate 		return;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	info = s_calloc(1, sizeof (*info));
4267c478bd9Sstevel@tonic-gate 	if (errno = nvlist_alloc(&(info->info), NV_UNIQUE_NAME, 0)) {
4277c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, "failed (nvlist_alloc=%s).\n",
4287c478bd9Sstevel@tonic-gate 		    strerror(errno));
4297c478bd9Sstevel@tonic-gate 		rcmd_exit(errno);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	/*LINTED*/
4337c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(info->info, RCM_RSRCNAME, alias)) ||
4347c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_int32(info->info, RCM_SEQ_NUM, seq_num)) ||
4357c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_int64(info->info, RCM_CLIENT_ID, pid)) ||
4367c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_int32(info->info, RCM_RSRCSTATE, state))) {
4377c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4387c478bd9Sstevel@tonic-gate 		    strerror(errno));
4397c478bd9Sstevel@tonic-gate 		rcmd_exit(errno);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * Daemon calls to add_busy_rsrc_to_list may pass in
4447c478bd9Sstevel@tonic-gate 	 * error/info. Add these through librcm interfaces.
4457c478bd9Sstevel@tonic-gate 	 */
4467c478bd9Sstevel@tonic-gate 	if (errstr) {
4477c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE3, "adding error string: %s\n",
4487c478bd9Sstevel@tonic-gate 		    errstr);
4497c478bd9Sstevel@tonic-gate 		if (errno = nvlist_add_string(info->info, RCM_CLIENT_ERROR,
4507c478bd9Sstevel@tonic-gate 		    (char *)errstr)) {
4517c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4527c478bd9Sstevel@tonic-gate 			    strerror(errno));
4537c478bd9Sstevel@tonic-gate 			rcmd_exit(errno);
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (infostr) {
4587c478bd9Sstevel@tonic-gate 		if (errno = nvlist_add_string(info->info, RCM_CLIENT_INFO,
4597c478bd9Sstevel@tonic-gate 		    (char *)infostr)) {
4607c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4617c478bd9Sstevel@tonic-gate 			    strerror(errno));
4627c478bd9Sstevel@tonic-gate 			rcmd_exit(errno);
4637c478bd9Sstevel@tonic-gate 		}
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	if (modname) {
4677c478bd9Sstevel@tonic-gate 		if (errno = nvlist_add_string(info->info, RCM_CLIENT_MODNAME,
4687c478bd9Sstevel@tonic-gate 		    modname)) {
4697c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4707c478bd9Sstevel@tonic-gate 			    strerror(errno));
4717c478bd9Sstevel@tonic-gate 			rcmd_exit(errno);
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (client_props) {
4767c478bd9Sstevel@tonic-gate 		if (errno = nvlist_pack(client_props, &buf, &buflen,
4777c478bd9Sstevel@tonic-gate 		    NV_ENCODE_NATIVE, 0)) {
4787c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, "failed (nvlist_pack=%s).\n",
4797c478bd9Sstevel@tonic-gate 			    strerror(errno));
4807c478bd9Sstevel@tonic-gate 			rcmd_exit(errno);
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 		if (errno = nvlist_add_byte_array(info->info,
4837c478bd9Sstevel@tonic-gate 		    RCM_CLIENT_PROPERTIES, (uchar_t *)buf, buflen)) {
4847c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, "failed (nvlist_add=%s).\n",
4857c478bd9Sstevel@tonic-gate 			    strerror(errno));
4867c478bd9Sstevel@tonic-gate 			rcmd_exit(errno);
4877c478bd9Sstevel@tonic-gate 		}
4887c478bd9Sstevel@tonic-gate 		(void) free(buf);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	/* link info at end of list */
4937c478bd9Sstevel@tonic-gate 	if (*list) {
4947c478bd9Sstevel@tonic-gate 		tmp = *list;
4957c478bd9Sstevel@tonic-gate 		while (tmp->next)
4967c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
4977c478bd9Sstevel@tonic-gate 		tmp->next = info;
4987c478bd9Sstevel@tonic-gate 	} else {
4997c478bd9Sstevel@tonic-gate 		*list = info;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /*
5047c478bd9Sstevel@tonic-gate  * Resource client realted operations:
5057c478bd9Sstevel@tonic-gate  *	rsrc_client_alloc, rsrc_client_find, rsrc_client_add,
5067c478bd9Sstevel@tonic-gate  *	rsrc_client_remove, rsrc_client_action,	rsrc_client_action_list
5077c478bd9Sstevel@tonic-gate  */
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /* Allocate rsrc_client_t structure. Load module if necessary. */
5107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5117c478bd9Sstevel@tonic-gate static client_t *
rsrc_client_alloc(char * alias,char * modname,pid_t pid,uint_t flag)5127c478bd9Sstevel@tonic-gate rsrc_client_alloc(char *alias, char *modname, pid_t pid, uint_t flag)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	client_t *client;
5157c478bd9Sstevel@tonic-gate 	module_t *mod;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	assert((alias != NULL) && (modname != NULL));
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rsrc_client_alloc(%s, %s, %ld)\n",
5207c478bd9Sstevel@tonic-gate 	    alias, modname, pid);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if ((mod = cli_module_hold(modname)) == NULL) {
5237c478bd9Sstevel@tonic-gate 		return (NULL);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	client = s_calloc(1, sizeof (client_t));
5277c478bd9Sstevel@tonic-gate 	client->module = mod;
5287c478bd9Sstevel@tonic-gate 	client->pid = pid;
5297c478bd9Sstevel@tonic-gate 	client->alias = s_strdup(alias);
5307c478bd9Sstevel@tonic-gate 	client->prv_flags = 0;
5317c478bd9Sstevel@tonic-gate 	client->state = RCM_STATE_ONLINE;
5327c478bd9Sstevel@tonic-gate 	client->flag = flag;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/* This queue is protected by rcm_req_lock */
5357c478bd9Sstevel@tonic-gate 	rcm_enqueue_tail(&mod->client_q, &client->queue);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	return (client);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /* Find client in list matching modname and pid */
5417c478bd9Sstevel@tonic-gate client_t *
rsrc_client_find(char * modname,pid_t pid,client_t ** list)5427c478bd9Sstevel@tonic-gate rsrc_client_find(char *modname, pid_t pid, client_t **list)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	client_t *client = *list;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rsrc_client_find(%s, %ld, %p)\n",
5477c478bd9Sstevel@tonic-gate 	    modname, pid, (void *)list);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	while (client) {
5507c478bd9Sstevel@tonic-gate 		if ((client->pid == pid) &&
5517c478bd9Sstevel@tonic-gate 		    strcmp(modname, client->module->name) == 0) {
5527c478bd9Sstevel@tonic-gate 			break;
5537c478bd9Sstevel@tonic-gate 		}
5547c478bd9Sstevel@tonic-gate 		client = client->next;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 	return (client);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /* Add a client to client list */
5607c478bd9Sstevel@tonic-gate static void
rsrc_client_add(client_t * client,client_t ** list)5617c478bd9Sstevel@tonic-gate rsrc_client_add(client_t *client, client_t **list)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rsrc_client_add: %s, %s, %ld\n",
5647c478bd9Sstevel@tonic-gate 	    client->alias, client->module->name, client->pid);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	client->next = *list;
5677c478bd9Sstevel@tonic-gate 	*list = client;
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /* Remove client from list and destroy it */
5717c478bd9Sstevel@tonic-gate static void
rsrc_client_remove(client_t * client,client_t ** list)5727c478bd9Sstevel@tonic-gate rsrc_client_remove(client_t *client, client_t **list)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	client_t *tmp, *prev = NULL;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rsrc_client_remove: %s, %s, %ld\n",
5777c478bd9Sstevel@tonic-gate 	    client->alias, client->module->name, client->pid);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	tmp = *list;
5807c478bd9Sstevel@tonic-gate 	while (tmp) {
5817c478bd9Sstevel@tonic-gate 		if (client != tmp) {
5827c478bd9Sstevel@tonic-gate 			prev = tmp;
5837c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
5847c478bd9Sstevel@tonic-gate 			continue;
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 		if (prev) {
5877c478bd9Sstevel@tonic-gate 			prev->next = tmp->next;
5887c478bd9Sstevel@tonic-gate 		} else {
5897c478bd9Sstevel@tonic-gate 			*list = tmp->next;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 		tmp->next = NULL;
5927c478bd9Sstevel@tonic-gate 		rsrc_clients_free(tmp);
5937c478bd9Sstevel@tonic-gate 		return;
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate /* Free a list of clients. Called from cleanup thread only */
5987c478bd9Sstevel@tonic-gate static void
rsrc_clients_free(client_t * list)5997c478bd9Sstevel@tonic-gate rsrc_clients_free(client_t *list)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	client_t *client = list;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	while (client) {
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 		/*
6067c478bd9Sstevel@tonic-gate 		 * Note that the rcm daemon is single threaded while
6077c478bd9Sstevel@tonic-gate 		 * executing this routine. So there is no need to acquire
6087c478bd9Sstevel@tonic-gate 		 * rcm_req_lock here while dequeuing.
6097c478bd9Sstevel@tonic-gate 		 */
6107c478bd9Sstevel@tonic-gate 		rcm_dequeue(&client->queue);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		if (client->module) {
6137c478bd9Sstevel@tonic-gate 			cli_module_rele(client->module);
6147c478bd9Sstevel@tonic-gate 		}
6157c478bd9Sstevel@tonic-gate 		list = client->next;
6167c478bd9Sstevel@tonic-gate 		if (client->alias) {
6177c478bd9Sstevel@tonic-gate 			free(client->alias);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		free(client);
6207c478bd9Sstevel@tonic-gate 		client = list;
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate  * Invoke a callback into a single client
6267c478bd9Sstevel@tonic-gate  * This is the core of rcm_mod_ops interface
6277c478bd9Sstevel@tonic-gate  */
6287c478bd9Sstevel@tonic-gate static int
rsrc_client_action(client_t * client,int cmd,void * arg)6297c478bd9Sstevel@tonic-gate rsrc_client_action(client_t *client, int cmd, void *arg)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	int			rval = RCM_SUCCESS;
6327c478bd9Sstevel@tonic-gate 	char			*dummy_error = NULL;
6337c478bd9Sstevel@tonic-gate 	char			*error = NULL;
6347c478bd9Sstevel@tonic-gate 	char			*info = NULL;
6357c478bd9Sstevel@tonic-gate 	rcm_handle_t		*hdl;
6367c478bd9Sstevel@tonic-gate 	nvlist_t		*client_props = NULL;
6377c478bd9Sstevel@tonic-gate 	rcm_info_t		*depend_info = NULL;
6387c478bd9Sstevel@tonic-gate 	struct rcm_mod_ops	*ops = client->module->modops;
6397c478bd9Sstevel@tonic-gate 	tree_walk_arg_t		*targ = (tree_walk_arg_t *)arg;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4,
6427c478bd9Sstevel@tonic-gate 	    "rsrc_client_action: %s, %s, cmd=%d, flag=0x%x\n", client->alias,
6437c478bd9Sstevel@tonic-gate 	    client->module->name, cmd, targ->flag);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	/*
6467c478bd9Sstevel@tonic-gate 	 * Create a per-operation handle, increment seq_num by 1 so we will
6477c478bd9Sstevel@tonic-gate 	 * know if a module uses this handle to callback into rcm_daemon.
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	hdl = rcm_handle_alloc(client->module);
6507c478bd9Sstevel@tonic-gate 	hdl->seq_num = targ->seq_num + 1;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	/*
6537c478bd9Sstevel@tonic-gate 	 * Filter out operations for which the client didn't register.
6547c478bd9Sstevel@tonic-gate 	 */
6557c478bd9Sstevel@tonic-gate 	switch (cmd) {
6567c478bd9Sstevel@tonic-gate 	case CMD_SUSPEND:
6577c478bd9Sstevel@tonic-gate 	case CMD_RESUME:
6587c478bd9Sstevel@tonic-gate 	case CMD_OFFLINE:
6597c478bd9Sstevel@tonic-gate 	case CMD_ONLINE:
6607c478bd9Sstevel@tonic-gate 	case CMD_REMOVE:
6617c478bd9Sstevel@tonic-gate 		if ((client->flag & RCM_REGISTER_DR) == 0) {
6627c478bd9Sstevel@tonic-gate 			rcm_handle_free(hdl);
6637c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
6647c478bd9Sstevel@tonic-gate 		}
6657c478bd9Sstevel@tonic-gate 		break;
6667c478bd9Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
6677c478bd9Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
6687c478bd9Sstevel@tonic-gate 		if ((client->flag & RCM_REGISTER_CAPACITY) == 0) {
6697c478bd9Sstevel@tonic-gate 			rcm_handle_free(hdl);
6707c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 		break;
6737c478bd9Sstevel@tonic-gate 	case CMD_EVENT:
6747c478bd9Sstevel@tonic-gate 		if ((client->flag & RCM_REGISTER_EVENT) == 0) {
6757c478bd9Sstevel@tonic-gate 			rcm_handle_free(hdl);
6767c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 		break;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/*
6827c478bd9Sstevel@tonic-gate 	 * Create nvlist_t for any client-specific properties.
6837c478bd9Sstevel@tonic-gate 	 */
6847c478bd9Sstevel@tonic-gate 	if (errno = nvlist_alloc(&client_props, NV_UNIQUE_NAME, 0)) {
6857c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
6867c478bd9Sstevel@tonic-gate 		    "client action failed (nvlist_alloc=%s)\n",
6877c478bd9Sstevel@tonic-gate 		    strerror(errno));
6887c478bd9Sstevel@tonic-gate 		rcmd_exit(errno);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/*
6927c478bd9Sstevel@tonic-gate 	 * Process the operation via a callback to the client module.
6937c478bd9Sstevel@tonic-gate 	 */
6947c478bd9Sstevel@tonic-gate 	switch (cmd) {
6957c478bd9Sstevel@tonic-gate 	case CMD_GETINFO:
6967c478bd9Sstevel@tonic-gate 		rval = call_getinfo(ops, hdl, client->alias, client->pid,
6977c478bd9Sstevel@tonic-gate 		    targ->flag, &info, &error, client_props, &depend_info);
6987c478bd9Sstevel@tonic-gate 		break;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	case CMD_SUSPEND:
7017c478bd9Sstevel@tonic-gate 		if (((targ->flag & RCM_QUERY_CANCEL) == 0) &&
7027c478bd9Sstevel@tonic-gate 		    (client->state == RCM_STATE_SUSPEND)) {
7037c478bd9Sstevel@tonic-gate 			break;
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
7077c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "suspending %s\n",
7087c478bd9Sstevel@tonic-gate 			    client->alias);
7097c478bd9Sstevel@tonic-gate 		} else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7107c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "suspend query %s\n",
7117c478bd9Sstevel@tonic-gate 			    client->alias);
7127c478bd9Sstevel@tonic-gate 		} else {
7137c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
7147c478bd9Sstevel@tonic-gate 			    "suspend query %s cancelled\n", client->alias);
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 		/*
7187c478bd9Sstevel@tonic-gate 		 * Update the client's state before the operation.
7197c478bd9Sstevel@tonic-gate 		 * If this is a cancelled query, then updating the state is
7207c478bd9Sstevel@tonic-gate 		 * the only thing that needs to be done, so break afterwards.
7217c478bd9Sstevel@tonic-gate 		 */
7227c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
7237c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_SUSPENDING;
7247c478bd9Sstevel@tonic-gate 		} else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7257c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_SUSPEND_QUERYING;
7267c478bd9Sstevel@tonic-gate 		} else {
7277c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_ONLINE;
7287c478bd9Sstevel@tonic-gate 			break;
7297c478bd9Sstevel@tonic-gate 		}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		rval = ops->rcmop_request_suspend(hdl, client->alias,
7327c478bd9Sstevel@tonic-gate 		    client->pid, targ->interval, targ->flag, &error,
7337c478bd9Sstevel@tonic-gate 		    &depend_info);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 		/* Update the client's state after the operation. */
7367c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
7377c478bd9Sstevel@tonic-gate 			if (rval == RCM_SUCCESS) {
7387c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_SUSPEND;
7397c478bd9Sstevel@tonic-gate 			} else {
7407c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_SUSPEND_FAIL;
7417c478bd9Sstevel@tonic-gate 			}
7427c478bd9Sstevel@tonic-gate 		} else {
7437c478bd9Sstevel@tonic-gate 			if (rval == RCM_SUCCESS) {
7447c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_SUSPEND_QUERY;
7457c478bd9Sstevel@tonic-gate 			} else {
7467c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_SUSPEND_QUERY_FAIL;
7477c478bd9Sstevel@tonic-gate 			}
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	case CMD_RESUME:
7527c478bd9Sstevel@tonic-gate 		if (client->state == RCM_STATE_ONLINE) {
7537c478bd9Sstevel@tonic-gate 			break;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_RESUMING;
7567c478bd9Sstevel@tonic-gate 		rval = ops->rcmop_notify_resume(hdl, client->alias, client->pid,
7577c478bd9Sstevel@tonic-gate 		    targ->flag, &error, &depend_info);
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		/* online state is unconditional */
7607c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_ONLINE;
7617c478bd9Sstevel@tonic-gate 		break;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	case CMD_OFFLINE:
7647c478bd9Sstevel@tonic-gate 		if (((targ->flag & RCM_QUERY_CANCEL) == 0) &&
7657c478bd9Sstevel@tonic-gate 		    (client->state == RCM_STATE_OFFLINE)) {
7667c478bd9Sstevel@tonic-gate 			break;
7677c478bd9Sstevel@tonic-gate 		}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
7707c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "offlining %s\n",
7717c478bd9Sstevel@tonic-gate 			    client->alias);
7727c478bd9Sstevel@tonic-gate 		} else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7737c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "offline query %s\n",
7747c478bd9Sstevel@tonic-gate 			    client->alias);
7757c478bd9Sstevel@tonic-gate 		} else {
7767c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
7777c478bd9Sstevel@tonic-gate 			    "offline query %s cancelled\n", client->alias);
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 		/*
7817c478bd9Sstevel@tonic-gate 		 * Update the client's state before the operation.
7827c478bd9Sstevel@tonic-gate 		 * If this is a cancelled query, then updating the state is
7837c478bd9Sstevel@tonic-gate 		 * the only thing that needs to be done, so break afterwards.
7847c478bd9Sstevel@tonic-gate 		 */
7857c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
7867c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_OFFLINING;
7877c478bd9Sstevel@tonic-gate 		} else if ((targ->flag & RCM_QUERY_CANCEL) == 0) {
7887c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_OFFLINE_QUERYING;
7897c478bd9Sstevel@tonic-gate 		} else {
7907c478bd9Sstevel@tonic-gate 			client->state = RCM_STATE_ONLINE;
7917c478bd9Sstevel@tonic-gate 			break;
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		rval = ops->rcmop_request_offline(hdl, client->alias,
7957c478bd9Sstevel@tonic-gate 		    client->pid, targ->flag, &error, &depend_info);
7967c478bd9Sstevel@tonic-gate 
79725e8c5aaSvikram 		/*
79825e8c5aaSvikram 		 * If this is a retire operation and we managed to call
79925e8c5aaSvikram 		 * into at least one client, set retcode to RCM_SUCCESS to
80025e8c5aaSvikram 		 * indicate that retire has been subject to constraints
80125e8c5aaSvikram 		 * This retcode will be further modified by actual return
80225e8c5aaSvikram 		 * code.
80325e8c5aaSvikram 		 */
80425e8c5aaSvikram 		if ((targ->flag & RCM_RETIRE_REQUEST) &&
80525e8c5aaSvikram 		    (targ->retcode == RCM_NO_CONSTRAINT)) {
80625e8c5aaSvikram 			rcm_log_message(RCM_DEBUG,
80725e8c5aaSvikram 			    "at least 1 client, constraint applied: %s\n",
80825e8c5aaSvikram 			    client->alias);
80925e8c5aaSvikram 			targ->retcode = RCM_SUCCESS;
81025e8c5aaSvikram 		}
81125e8c5aaSvikram 
8127c478bd9Sstevel@tonic-gate 		/* Update the client's state after the operation. */
8137c478bd9Sstevel@tonic-gate 		if ((targ->flag & RCM_QUERY) == 0) {
8147c478bd9Sstevel@tonic-gate 			if (rval == RCM_SUCCESS) {
8157c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_OFFLINE;
8167c478bd9Sstevel@tonic-gate 			} else {
8177c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_OFFLINE_FAIL;
8187c478bd9Sstevel@tonic-gate 			}
8197c478bd9Sstevel@tonic-gate 		} else {
8207c478bd9Sstevel@tonic-gate 			if (rval == RCM_SUCCESS) {
8217c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_OFFLINE_QUERY;
8227c478bd9Sstevel@tonic-gate 			} else {
8237c478bd9Sstevel@tonic-gate 				client->state = RCM_STATE_OFFLINE_QUERY_FAIL;
8247c478bd9Sstevel@tonic-gate 			}
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 		break;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	case CMD_ONLINE:
8297c478bd9Sstevel@tonic-gate 		if (client->state == RCM_STATE_ONLINE) {
8307c478bd9Sstevel@tonic-gate 			break;
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "onlining %s\n", client->alias);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_ONLINING;
8367c478bd9Sstevel@tonic-gate 		rval = ops->rcmop_notify_online(hdl, client->alias, client->pid,
8377c478bd9Sstevel@tonic-gate 		    targ->flag, &error, &depend_info);
8387c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_ONLINE;
8397c478bd9Sstevel@tonic-gate 		break;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	case CMD_REMOVE:
8427c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "removing %s\n", client->alias);
8437c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_REMOVING;
8447c478bd9Sstevel@tonic-gate 		rval = ops->rcmop_notify_remove(hdl, client->alias, client->pid,
8457c478bd9Sstevel@tonic-gate 		    targ->flag, &error, &depend_info);
8467c478bd9Sstevel@tonic-gate 		client->state = RCM_STATE_REMOVE;
8477c478bd9Sstevel@tonic-gate 		break;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	case CMD_REQUEST_CHANGE:
8507c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "requesting state change of %s\n",
8517c478bd9Sstevel@tonic-gate 		    client->alias);
8527c478bd9Sstevel@tonic-gate 		if (ops->rcmop_request_capacity_change)
8537c478bd9Sstevel@tonic-gate 			rval = ops->rcmop_request_capacity_change(hdl,
8547c478bd9Sstevel@tonic-gate 			    client->alias, client->pid, targ->flag, targ->nvl,
8557c478bd9Sstevel@tonic-gate 			    &error, &depend_info);
8567c478bd9Sstevel@tonic-gate 		break;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	case CMD_NOTIFY_CHANGE:
8597c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "requesting state change of %s\n",
8607c478bd9Sstevel@tonic-gate 		    client->alias);
8617c478bd9Sstevel@tonic-gate 		if (ops->rcmop_notify_capacity_change)
8627c478bd9Sstevel@tonic-gate 			rval = ops->rcmop_notify_capacity_change(hdl,
8637c478bd9Sstevel@tonic-gate 			    client->alias, client->pid, targ->flag, targ->nvl,
8647c478bd9Sstevel@tonic-gate 			    &error, &depend_info);
8657c478bd9Sstevel@tonic-gate 		break;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	case CMD_EVENT:
8687c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "delivering event to %s\n",
8697c478bd9Sstevel@tonic-gate 		    client->alias);
8707c478bd9Sstevel@tonic-gate 		if (ops->rcmop_notify_event)
8717c478bd9Sstevel@tonic-gate 			rval = ops->rcmop_notify_event(hdl, client->alias,
8727c478bd9Sstevel@tonic-gate 			    client->pid, targ->flag, &error, targ->nvl,
8737c478bd9Sstevel@tonic-gate 			    &depend_info);
8747c478bd9Sstevel@tonic-gate 		break;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	default:
8777c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, gettext("unknown command %d\n"),
8787c478bd9Sstevel@tonic-gate 		    cmd);
8797c478bd9Sstevel@tonic-gate 		rval = RCM_FAILURE;
8807c478bd9Sstevel@tonic-gate 		break;
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/* reset error code to the most significant error */
8847c478bd9Sstevel@tonic-gate 	if (rval != RCM_SUCCESS)
8857c478bd9Sstevel@tonic-gate 		targ->retcode = rval;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	/*
8887c478bd9Sstevel@tonic-gate 	 * XXX - The code below may produce duplicate rcm_info_t's on error?
8897c478bd9Sstevel@tonic-gate 	 */
8907c478bd9Sstevel@tonic-gate 	if ((cmd != CMD_GETINFO) &&
8917c478bd9Sstevel@tonic-gate 	    ((rval != RCM_SUCCESS) ||
8927c478bd9Sstevel@tonic-gate 	    (error != NULL) ||
8937c478bd9Sstevel@tonic-gate 	    (targ->flag & RCM_SCOPE))) {
8947c478bd9Sstevel@tonic-gate 		(void) call_getinfo(ops, hdl, client->alias, client->pid,
8957c478bd9Sstevel@tonic-gate 		    targ->flag & (~(RCM_INCLUDE_DEPENDENT|RCM_INCLUDE_SUBTREE)),
8967c478bd9Sstevel@tonic-gate 		    &info, &dummy_error, client_props, &depend_info);
8977c478bd9Sstevel@tonic-gate 		if (dummy_error)
8987c478bd9Sstevel@tonic-gate 			(void) free(dummy_error);
8997c478bd9Sstevel@tonic-gate 	} else if (cmd != CMD_GETINFO) {
9007c478bd9Sstevel@tonic-gate 		nvlist_free(client_props);
9017c478bd9Sstevel@tonic-gate 		client_props = NULL;
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if (client_props) {
9057c478bd9Sstevel@tonic-gate 		add_busy_rsrc_to_list(client->alias, client->pid, client->state,
9067c478bd9Sstevel@tonic-gate 		    targ->seq_num, client->module->name, info, error,
9077c478bd9Sstevel@tonic-gate 		    client_props, targ->info);
9087c478bd9Sstevel@tonic-gate 		nvlist_free(client_props);
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	if (info)
9127c478bd9Sstevel@tonic-gate 		(void) free(info);
9137c478bd9Sstevel@tonic-gate 	if (error)
9147c478bd9Sstevel@tonic-gate 		(void) free(error);
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	if (depend_info) {
9177c478bd9Sstevel@tonic-gate 		if (targ->info) {
9187c478bd9Sstevel@tonic-gate 			(void) rcm_append_info(targ->info, depend_info);
9197c478bd9Sstevel@tonic-gate 		} else {
9207c478bd9Sstevel@tonic-gate 			rcm_free_info(depend_info);
9217c478bd9Sstevel@tonic-gate 		}
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	rcm_handle_free(hdl);
9257c478bd9Sstevel@tonic-gate 	return (rval);
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate  * invoke a callback into a list of clients, return 0 if all success
9307c478bd9Sstevel@tonic-gate  */
9317c478bd9Sstevel@tonic-gate int
rsrc_client_action_list(client_t * list,int cmd,void * arg)9327c478bd9Sstevel@tonic-gate rsrc_client_action_list(client_t *list, int cmd, void *arg)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate 	int error, rval = RCM_SUCCESS;
93525e8c5aaSvikram 	tree_walk_arg_t		*targ = (tree_walk_arg_t *)arg;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	while (list) {
9387c478bd9Sstevel@tonic-gate 		client_t *client = list;
9397c478bd9Sstevel@tonic-gate 		list = client->next;
9407c478bd9Sstevel@tonic-gate 
94125e8c5aaSvikram 		/*
94225e8c5aaSvikram 		 * Make offline idempotent in the retire
94325e8c5aaSvikram 		 * case
94425e8c5aaSvikram 		 */
94525e8c5aaSvikram 		if ((targ->flag & RCM_RETIRE_REQUEST) &&
94625e8c5aaSvikram 		    client->state == RCM_STATE_REMOVE) {
94725e8c5aaSvikram 			client->state = RCM_STATE_ONLINE;
94825e8c5aaSvikram 			rcm_log_message(RCM_DEBUG, "RETIRE: idempotent client "
94925e8c5aaSvikram 			    "state: REMOVE -> ONLINE: %s\n", client->alias);
95025e8c5aaSvikram 		}
95125e8c5aaSvikram 
9527c478bd9Sstevel@tonic-gate 		if (client->state == RCM_STATE_REMOVE)
9537c478bd9Sstevel@tonic-gate 			continue;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 		error = rsrc_client_action(client, cmd, arg);
9567c478bd9Sstevel@tonic-gate 		if (error != RCM_SUCCESS) {
9577c478bd9Sstevel@tonic-gate 			rval = error;
9587c478bd9Sstevel@tonic-gate 		}
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	return (rval);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate  * Node realted operations:
9667c478bd9Sstevel@tonic-gate  *
9677c478bd9Sstevel@tonic-gate  *	rn_alloc, rn_free, rn_find_child,
9687c478bd9Sstevel@tonic-gate  *	rn_get_child, rn_get_sibling,
9697c478bd9Sstevel@tonic-gate  *	rsrc_node_find, rsrc_node_add_user, rsrc_node_remove_user,
9707c478bd9Sstevel@tonic-gate  */
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate /* Allocate node based on a logical or physical name */
9737c478bd9Sstevel@tonic-gate static rsrc_node_t *
rn_alloc(char * name,int type)9747c478bd9Sstevel@tonic-gate rn_alloc(char *name, int type)
9757c478bd9Sstevel@tonic-gate {
9767c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rn_alloc(%s, %d)\n", name, type);
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	node = s_calloc(1, sizeof (*node));
9817c478bd9Sstevel@tonic-gate 	node->name = s_strdup(name);
9827c478bd9Sstevel@tonic-gate 	node->type = type;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (node);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate /*
9887c478bd9Sstevel@tonic-gate  * Free node along with its siblings and children
9897c478bd9Sstevel@tonic-gate  */
9907c478bd9Sstevel@tonic-gate static void
rn_free(rsrc_node_t * node)9917c478bd9Sstevel@tonic-gate rn_free(rsrc_node_t *node)
9927c478bd9Sstevel@tonic-gate {
9937c478bd9Sstevel@tonic-gate 	if (node == NULL) {
9947c478bd9Sstevel@tonic-gate 		return;
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	if (node->child) {
9987c478bd9Sstevel@tonic-gate 		rn_free(node->child);
9997c478bd9Sstevel@tonic-gate 	}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	if (node->sibling) {
10027c478bd9Sstevel@tonic-gate 		rn_free(node->sibling);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	rsrc_clients_free(node->users);
10067c478bd9Sstevel@tonic-gate 	free(node->name);
10077c478bd9Sstevel@tonic-gate 	free(node);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate  * Find next sibling
10127c478bd9Sstevel@tonic-gate  */
10137c478bd9Sstevel@tonic-gate static rsrc_node_t *
rn_get_sibling(rsrc_node_t * node)10147c478bd9Sstevel@tonic-gate rn_get_sibling(rsrc_node_t *node)
10157c478bd9Sstevel@tonic-gate {
10167c478bd9Sstevel@tonic-gate 	return (node->sibling);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate /*
10207c478bd9Sstevel@tonic-gate  * Find first child
10217c478bd9Sstevel@tonic-gate  */
10227c478bd9Sstevel@tonic-gate static rsrc_node_t *
rn_get_child(rsrc_node_t * node)10237c478bd9Sstevel@tonic-gate rn_get_child(rsrc_node_t *node)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	return (node->child);
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate  * Find child named childname. Create it if flag is RSRC_NODE_CRTEATE
10307c478bd9Sstevel@tonic-gate  */
10317c478bd9Sstevel@tonic-gate static rsrc_node_t *
rn_find_child(rsrc_node_t * parent,char * childname,int flag,int type)10327c478bd9Sstevel@tonic-gate rn_find_child(rsrc_node_t *parent, char *childname, int flag, int type)
10337c478bd9Sstevel@tonic-gate {
10347c478bd9Sstevel@tonic-gate 	rsrc_node_t *child = parent->child;
10357c478bd9Sstevel@tonic-gate 	rsrc_node_t *new, *prev = NULL;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4,
10387c478bd9Sstevel@tonic-gate 	    "rn_find_child(parent=%s, child=%s, 0x%x, %d)\n",
10397c478bd9Sstevel@tonic-gate 	    parent->name, childname, flag, type);
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	/*
10427c478bd9Sstevel@tonic-gate 	 * Children are ordered based on strcmp.
10437c478bd9Sstevel@tonic-gate 	 */
10447c478bd9Sstevel@tonic-gate 	while (child && (strcmp(child->name, childname) < 0)) {
10457c478bd9Sstevel@tonic-gate 		prev = child;
10467c478bd9Sstevel@tonic-gate 		child = child->sibling;
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (child && (strcmp(child->name, childname) == 0)) {
10507c478bd9Sstevel@tonic-gate 		return (child);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	if (flag != RSRC_NODE_CREATE)
10547c478bd9Sstevel@tonic-gate 		return (NULL);
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 	new = rn_alloc(childname, type);
10577c478bd9Sstevel@tonic-gate 	new->parent = parent;
10587c478bd9Sstevel@tonic-gate 	new->sibling = child;
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	/*
10617c478bd9Sstevel@tonic-gate 	 * Set this linkage last so we don't break ongoing operations.
10627c478bd9Sstevel@tonic-gate 	 *
10637c478bd9Sstevel@tonic-gate 	 * N.B. Assume setting a pointer is an atomic operation.
10647c478bd9Sstevel@tonic-gate 	 */
10657c478bd9Sstevel@tonic-gate 	if (prev == NULL) {
10667c478bd9Sstevel@tonic-gate 		parent->child = new;
10677c478bd9Sstevel@tonic-gate 	} else {
10687c478bd9Sstevel@tonic-gate 		prev->sibling = new;
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	return (new);
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate /*
10757c478bd9Sstevel@tonic-gate  * Pathname related help functions
10767c478bd9Sstevel@tonic-gate  */
10777c478bd9Sstevel@tonic-gate static void
pn_preprocess(char * pathname,int type)10787c478bd9Sstevel@tonic-gate pn_preprocess(char *pathname, int type)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	char *tmp;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if (type != RSRC_TYPE_DEVICE)
10837c478bd9Sstevel@tonic-gate 		return;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/*
10867c478bd9Sstevel@tonic-gate 	 * For devices, convert ':' to '/' (treat minor nodes and children)
10877c478bd9Sstevel@tonic-gate 	 */
10887c478bd9Sstevel@tonic-gate 	tmp = strchr(pathname, ':');
10897c478bd9Sstevel@tonic-gate 	if (tmp == NULL)
10907c478bd9Sstevel@tonic-gate 		return;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	*tmp = '/';
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate static char *
pn_getnextcomp(char * pathname,char ** lasts)10967c478bd9Sstevel@tonic-gate pn_getnextcomp(char *pathname, char **lasts)
10977c478bd9Sstevel@tonic-gate {
10987c478bd9Sstevel@tonic-gate 	char *slash;
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
11017c478bd9Sstevel@tonic-gate 		return (NULL);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	/* skip slashes' */
11047c478bd9Sstevel@tonic-gate 	while (*pathname == '/')
11057c478bd9Sstevel@tonic-gate 		++pathname;
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	if (*pathname == '\0')
11087c478bd9Sstevel@tonic-gate 		return (NULL);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	slash = strchr(pathname, '/');
11117c478bd9Sstevel@tonic-gate 	if (slash != NULL) {
11127c478bd9Sstevel@tonic-gate 		*slash = '\0';
11137c478bd9Sstevel@tonic-gate 		*lasts = slash + 1;
11147c478bd9Sstevel@tonic-gate 	} else {
11157c478bd9Sstevel@tonic-gate 		*lasts = NULL;
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	return (pathname);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate /*
11227c478bd9Sstevel@tonic-gate  * Find a node in tree based on device, which is the physical pathname
11237c478bd9Sstevel@tonic-gate  * of the form /sbus@.../esp@.../sd@...
11247c478bd9Sstevel@tonic-gate  */
11257c478bd9Sstevel@tonic-gate int
rsrc_node_find(char * rsrcname,int flag,rsrc_node_t ** nodep)11267c478bd9Sstevel@tonic-gate rsrc_node_find(char *rsrcname, int flag, rsrc_node_t **nodep)
11277c478bd9Sstevel@tonic-gate {
11287c478bd9Sstevel@tonic-gate 	char *pathname, *nodename, *lasts;
11297c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
11307c478bd9Sstevel@tonic-gate 	int type;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "rn_node_find(%s, 0x%x)\n", rsrcname, flag);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	/*
11357c478bd9Sstevel@tonic-gate 	 * For RSRC_TYPE_ABSTRACT, look under /ABSTRACT. For other types,
11367c478bd9Sstevel@tonic-gate 	 * look under /SYSTEM.
11377c478bd9Sstevel@tonic-gate 	 */
11387c478bd9Sstevel@tonic-gate 	pathname = resolve_name(rsrcname);
11397c478bd9Sstevel@tonic-gate 	if (pathname == NULL)
11407c478bd9Sstevel@tonic-gate 		return (EINVAL);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	type = rsrc_get_type(pathname);
11437c478bd9Sstevel@tonic-gate 	switch (type) {
11447c478bd9Sstevel@tonic-gate 	case RSRC_TYPE_DEVICE:
11457c478bd9Sstevel@tonic-gate 	case RSRC_TYPE_NORMAL:
11467c478bd9Sstevel@tonic-gate 		node = rn_find_child(rsrc_root, "SYSTEM", RSRC_NODE_CREATE,
11477c478bd9Sstevel@tonic-gate 		    RSRC_TYPE_NORMAL);
11487c478bd9Sstevel@tonic-gate 		break;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	case RSRC_TYPE_ABSTRACT:
11517c478bd9Sstevel@tonic-gate 		node = rn_find_child(rsrc_root, "ABSTRACT", RSRC_NODE_CREATE,
11527c478bd9Sstevel@tonic-gate 		    RSRC_TYPE_NORMAL);
11537c478bd9Sstevel@tonic-gate 		break;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	default:
11567c478bd9Sstevel@tonic-gate 		/* just to make sure */
11577c478bd9Sstevel@tonic-gate 		free(pathname);
11587c478bd9Sstevel@tonic-gate 		return (EINVAL);
11597c478bd9Sstevel@tonic-gate 	}
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	/*
11627c478bd9Sstevel@tonic-gate 	 * Find position of device within tree. Upon exiting the loop, device
11637c478bd9Sstevel@tonic-gate 	 * should be placed between prev and curr.
11647c478bd9Sstevel@tonic-gate 	 */
11657c478bd9Sstevel@tonic-gate 	pn_preprocess(pathname, type);
11667c478bd9Sstevel@tonic-gate 	lasts = pathname;
11677c478bd9Sstevel@tonic-gate 	while ((nodename = pn_getnextcomp(lasts, &lasts)) != NULL) {
11687c478bd9Sstevel@tonic-gate 		rsrc_node_t *parent = node;
11697c478bd9Sstevel@tonic-gate 		node = rn_find_child(parent, nodename, flag, type);
11707c478bd9Sstevel@tonic-gate 		if (node == NULL) {
11717c478bd9Sstevel@tonic-gate 			assert((flag & RSRC_NODE_CREATE) == 0);
11727c478bd9Sstevel@tonic-gate 			free(pathname);
11737c478bd9Sstevel@tonic-gate 			*nodep = NULL;
11747c478bd9Sstevel@tonic-gate 			return (RCM_SUCCESS);
11757c478bd9Sstevel@tonic-gate 		}
11767c478bd9Sstevel@tonic-gate 	}
11777c478bd9Sstevel@tonic-gate 	free(pathname);
11787c478bd9Sstevel@tonic-gate 	*nodep = node;
11797c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
11807c478bd9Sstevel@tonic-gate }
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate  * add a usage client to a node
11847c478bd9Sstevel@tonic-gate  */
11857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11867c478bd9Sstevel@tonic-gate int
rsrc_node_add_user(rsrc_node_t * node,char * alias,char * modname,pid_t pid,uint_t flag)11877c478bd9Sstevel@tonic-gate rsrc_node_add_user(rsrc_node_t *node, char *alias, char *modname, pid_t pid,
11887c478bd9Sstevel@tonic-gate     uint_t flag)
11897c478bd9Sstevel@tonic-gate {
11907c478bd9Sstevel@tonic-gate 	client_t *user;
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3,
11937c478bd9Sstevel@tonic-gate 	    "rsrc_node_add_user(%s, %s, %s, %ld, 0x%x)\n",
11947c478bd9Sstevel@tonic-gate 	    node->name, alias, modname, pid, flag);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	user = rsrc_client_find(modname, pid, &node->users);
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/*
11997c478bd9Sstevel@tonic-gate 	 * If a client_t already exists, add the registration and return
12007c478bd9Sstevel@tonic-gate 	 * success if it's a valid registration request.
12017c478bd9Sstevel@tonic-gate 	 *
12027c478bd9Sstevel@tonic-gate 	 * Return EALREADY if the resource is already registered.
12037c478bd9Sstevel@tonic-gate 	 * This means either the client_t already has the requested
12047c478bd9Sstevel@tonic-gate 	 * registration flagged, or that a DR registration was attempted
12057c478bd9Sstevel@tonic-gate 	 * on a resource already in use in the DR operations state model.
12067c478bd9Sstevel@tonic-gate 	 */
12077c478bd9Sstevel@tonic-gate 	if (user != NULL) {
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		if (user->flag & (flag & RCM_REGISTER_MASK)) {
12107c478bd9Sstevel@tonic-gate 			return (EALREADY);
12117c478bd9Sstevel@tonic-gate 		}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		if ((flag & RCM_REGISTER_DR) &&
12147c478bd9Sstevel@tonic-gate 		    (user->state != RCM_STATE_REMOVE)) {
12157c478bd9Sstevel@tonic-gate 			return (EALREADY);
12167c478bd9Sstevel@tonic-gate 		}
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 		user->flag |= (flag & RCM_REGISTER_MASK);
12197c478bd9Sstevel@tonic-gate 		if ((flag & RCM_REGISTER_DR) ||
12207c478bd9Sstevel@tonic-gate 		    (user->state == RCM_STATE_REMOVE)) {
12217c478bd9Sstevel@tonic-gate 			user->state = RCM_STATE_ONLINE;
12227c478bd9Sstevel@tonic-gate 		}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	/*
12287c478bd9Sstevel@tonic-gate 	 * Otherwise create a new client_t and create a new registration.
12297c478bd9Sstevel@tonic-gate 	 */
12307c478bd9Sstevel@tonic-gate 	if ((user = rsrc_client_alloc(alias, modname, pid, flag)) != NULL) {
12317c478bd9Sstevel@tonic-gate 		rsrc_client_add(user, &node->users);
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 	if (flag & RCM_FILESYS)
12347c478bd9Sstevel@tonic-gate 		node->type = RSRC_TYPE_FILESYS;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate  * remove a usage client of a node
12417c478bd9Sstevel@tonic-gate  */
12427c478bd9Sstevel@tonic-gate int
rsrc_node_remove_user(rsrc_node_t * node,char * modname,pid_t pid,uint_t flag)12437c478bd9Sstevel@tonic-gate rsrc_node_remove_user(rsrc_node_t *node, char *modname, pid_t pid, uint_t flag)
12447c478bd9Sstevel@tonic-gate {
12457c478bd9Sstevel@tonic-gate 	client_t *user;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3,
12487c478bd9Sstevel@tonic-gate 	    "rsrc_node_remove_user(%s, %s, %ld, 0x%x)\n", node->name, modname,
12497c478bd9Sstevel@tonic-gate 	    pid, flag);
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	user = rsrc_client_find(modname, pid, &node->users);
12527c478bd9Sstevel@tonic-gate 	if ((user == NULL) || (user->state == RCM_STATE_REMOVE)) {
12537c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_NOTICE, gettext(
12547c478bd9Sstevel@tonic-gate 		    "client not registered: module=%s, pid=%d, dev=%s\n"),
12557c478bd9Sstevel@tonic-gate 		    modname, pid, node->name);
12567c478bd9Sstevel@tonic-gate 		return (ENOENT);
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	/* Strip off the registration being removed (DR, event, capacity) */
12607c478bd9Sstevel@tonic-gate 	user->flag = user->flag & (~(flag & RCM_REGISTER_MASK));
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 	/*
12637c478bd9Sstevel@tonic-gate 	 * Mark the client as removed if all registrations have been removed
12647c478bd9Sstevel@tonic-gate 	 */
12657c478bd9Sstevel@tonic-gate 	if ((user->flag & RCM_REGISTER_MASK) == 0)
12667c478bd9Sstevel@tonic-gate 		user->state = RCM_STATE_REMOVE;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  * Tree walking function - rsrc_walk
12737c478bd9Sstevel@tonic-gate  */
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate #define	MAX_TREE_DEPTH		32
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate #define	RN_WALK_CONTINUE	0
12787c478bd9Sstevel@tonic-gate #define	RN_WALK_PRUNESIB	1
12797c478bd9Sstevel@tonic-gate #define	RN_WALK_PRUNECHILD	2
12807c478bd9Sstevel@tonic-gate #define	RN_WALK_TERMINATE	3
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate #define	EMPTY_STACK(sp)		((sp)->depth == 0)
12837c478bd9Sstevel@tonic-gate #define	TOP_NODE(sp)		((sp)->node[(sp)->depth - 1])
12847c478bd9Sstevel@tonic-gate #define	PRUNE_SIB(sp)		((sp)->prunesib[(sp)->depth - 1])
12857c478bd9Sstevel@tonic-gate #define	PRUNE_CHILD(sp)		((sp)->prunechild[(sp)->depth - 1])
12867c478bd9Sstevel@tonic-gate #define	POP_STACK(sp)		((sp)->depth)--
12877c478bd9Sstevel@tonic-gate #define	PUSH_STACK(sp, rn)	\
12887c478bd9Sstevel@tonic-gate 	(sp)->node[(sp)->depth] = (rn);	\
12897c478bd9Sstevel@tonic-gate 	(sp)->prunesib[(sp)->depth] = 0;	\
12907c478bd9Sstevel@tonic-gate 	(sp)->prunechild[(sp)->depth] = 0;	\
12917c478bd9Sstevel@tonic-gate 	((sp)->depth)++
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate struct rn_stack {
12947c478bd9Sstevel@tonic-gate 	rsrc_node_t *node[MAX_TREE_DEPTH];
12957c478bd9Sstevel@tonic-gate 	char	prunesib[MAX_TREE_DEPTH];
12967c478bd9Sstevel@tonic-gate 	char	prunechild[MAX_TREE_DEPTH];
12977c478bd9Sstevel@tonic-gate 	int	depth;
12987c478bd9Sstevel@tonic-gate };
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate /* walking one node and update node stack */
13017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
13027c478bd9Sstevel@tonic-gate static void
walk_one_node(struct rn_stack * sp,void * arg,int (* node_callback)(rsrc_node_t *,void *))13037c478bd9Sstevel@tonic-gate walk_one_node(struct rn_stack *sp, void *arg,
13047c478bd9Sstevel@tonic-gate     int (*node_callback)(rsrc_node_t *, void *))
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate 	int prunesib;
13077c478bd9Sstevel@tonic-gate 	rsrc_node_t *child, *sibling;
13087c478bd9Sstevel@tonic-gate 	rsrc_node_t *node = TOP_NODE(sp);
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "walk_one_node(%s)\n", node->name);
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	switch (node_callback(node, arg)) {
13137c478bd9Sstevel@tonic-gate 	case RN_WALK_TERMINATE:
13147c478bd9Sstevel@tonic-gate 		POP_STACK(sp);
13157c478bd9Sstevel@tonic-gate 		while (!EMPTY_STACK(sp)) {
13167c478bd9Sstevel@tonic-gate 			node = TOP_NODE(sp);
13177c478bd9Sstevel@tonic-gate 			POP_STACK(sp);
13187c478bd9Sstevel@tonic-gate 		}
13197c478bd9Sstevel@tonic-gate 		return;
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	case RN_WALK_PRUNESIB:
13227c478bd9Sstevel@tonic-gate 		PRUNE_SIB(sp) = 1;
13237c478bd9Sstevel@tonic-gate 		break;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	case RN_WALK_PRUNECHILD:
13267c478bd9Sstevel@tonic-gate 		PRUNE_CHILD(sp) = 1;
13277c478bd9Sstevel@tonic-gate 		break;
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	case RN_WALK_CONTINUE:
13307c478bd9Sstevel@tonic-gate 	default:
13317c478bd9Sstevel@tonic-gate 		break;
13327c478bd9Sstevel@tonic-gate 	}
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	/*
13357c478bd9Sstevel@tonic-gate 	 * Push child on the stack
13367c478bd9Sstevel@tonic-gate 	 */
13377c478bd9Sstevel@tonic-gate 	if (!PRUNE_CHILD(sp) && (child = rn_get_child(node)) != NULL) {
13387c478bd9Sstevel@tonic-gate 		PUSH_STACK(sp, child);
13397c478bd9Sstevel@tonic-gate 		return;
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	/*
13437c478bd9Sstevel@tonic-gate 	 * Pop the stack till a node's sibling can be pushed
13447c478bd9Sstevel@tonic-gate 	 */
13457c478bd9Sstevel@tonic-gate 	prunesib = PRUNE_SIB(sp);
13467c478bd9Sstevel@tonic-gate 	POP_STACK(sp);
13477c478bd9Sstevel@tonic-gate 	while (!EMPTY_STACK(sp) &&
13487c478bd9Sstevel@tonic-gate 	    (prunesib || (sibling = rn_get_sibling(node)) == NULL)) {
13497c478bd9Sstevel@tonic-gate 		node = TOP_NODE(sp);
13507c478bd9Sstevel@tonic-gate 		prunesib = PRUNE_SIB(sp);
13517c478bd9Sstevel@tonic-gate 		POP_STACK(sp);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	if (EMPTY_STACK(sp)) {
13557c478bd9Sstevel@tonic-gate 		return;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	/*
13597c478bd9Sstevel@tonic-gate 	 * push sibling onto the stack
13607c478bd9Sstevel@tonic-gate 	 */
13617c478bd9Sstevel@tonic-gate 	PUSH_STACK(sp, sibling);
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate /*
13657c478bd9Sstevel@tonic-gate  * walk tree rooted at root in child-first order
13667c478bd9Sstevel@tonic-gate  */
13677c478bd9Sstevel@tonic-gate static void
rsrc_walk(rsrc_node_t * root,void * arg,int (* node_callback)(rsrc_node_t *,void *))13687c478bd9Sstevel@tonic-gate rsrc_walk(rsrc_node_t *root, void *arg,
13697c478bd9Sstevel@tonic-gate     int (*node_callback)(rsrc_node_t *, void *))
13707c478bd9Sstevel@tonic-gate {
13717c478bd9Sstevel@tonic-gate 	struct rn_stack stack;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "rsrc_walk(%s)\n", root->name);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	/*
13767c478bd9Sstevel@tonic-gate 	 * Push root on stack and walk in child-first order
13777c478bd9Sstevel@tonic-gate 	 */
13787c478bd9Sstevel@tonic-gate 	stack.depth = 0;
13797c478bd9Sstevel@tonic-gate 	PUSH_STACK(&stack, root);
13807c478bd9Sstevel@tonic-gate 	PRUNE_SIB(&stack) = 1;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	while (!EMPTY_STACK(&stack)) {
13837c478bd9Sstevel@tonic-gate 		walk_one_node(&stack, arg, node_callback);
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate /*
13887c478bd9Sstevel@tonic-gate  * Callback for a command action on a node
13897c478bd9Sstevel@tonic-gate  */
13907c478bd9Sstevel@tonic-gate static int
node_action(rsrc_node_t * node,void * arg)13917c478bd9Sstevel@tonic-gate node_action(rsrc_node_t *node, void *arg)
13927c478bd9Sstevel@tonic-gate {
13937c478bd9Sstevel@tonic-gate 	tree_walk_arg_t *targ = (tree_walk_arg_t *)arg;
13947c478bd9Sstevel@tonic-gate 	uint_t flag = targ->flag;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "node_action(%s)\n", node->name);
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	/*
13997c478bd9Sstevel@tonic-gate 	 * If flag indicates operation on a filesystem, we don't callback on
14007c478bd9Sstevel@tonic-gate 	 * the filesystem root to avoid infinite recursion on filesystem module.
14017c478bd9Sstevel@tonic-gate 	 *
14027c478bd9Sstevel@tonic-gate 	 * N.B. Such request should only come from filesystem RCM module.
14037c478bd9Sstevel@tonic-gate 	 */
14047c478bd9Sstevel@tonic-gate 	if (flag & RCM_FILESYS) {
14057c478bd9Sstevel@tonic-gate 		assert(node->type == RSRC_TYPE_FILESYS);
14067c478bd9Sstevel@tonic-gate 		targ->flag &= ~RCM_FILESYS;
14077c478bd9Sstevel@tonic-gate 		return (RN_WALK_CONTINUE);
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	/*
14117c478bd9Sstevel@tonic-gate 	 * Execute state change callback
14127c478bd9Sstevel@tonic-gate 	 */
14137c478bd9Sstevel@tonic-gate 	(void) rsrc_client_action_list(node->users, targ->cmd, arg);
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	/*
14167c478bd9Sstevel@tonic-gate 	 * Upon hitting a filesys root, prune children.
14177c478bd9Sstevel@tonic-gate 	 * The filesys module should have taken care of
14187c478bd9Sstevel@tonic-gate 	 * children by now.
14197c478bd9Sstevel@tonic-gate 	 */
14207c478bd9Sstevel@tonic-gate 	if (node->type == RSRC_TYPE_FILESYS)
14217c478bd9Sstevel@tonic-gate 		return (RN_WALK_PRUNECHILD);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	return (RN_WALK_CONTINUE);
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate /*
14277c478bd9Sstevel@tonic-gate  * Execute a command on a subtree under root.
14287c478bd9Sstevel@tonic-gate  */
14297c478bd9Sstevel@tonic-gate int
rsrc_tree_action(rsrc_node_t * root,int cmd,tree_walk_arg_t * arg)14307c478bd9Sstevel@tonic-gate rsrc_tree_action(rsrc_node_t *root, int cmd, tree_walk_arg_t *arg)
14317c478bd9Sstevel@tonic-gate {
14327c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "tree_action(%s, %d)\n", root->name, cmd);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	arg->cmd = cmd;
143525e8c5aaSvikram 
143625e8c5aaSvikram 	/*
143725e8c5aaSvikram 	 * If RCM_RETIRE_REQUEST is set, just walk one node and preset
143825e8c5aaSvikram 	 * retcode to NO_CONSTRAINT
143925e8c5aaSvikram 	 */
144025e8c5aaSvikram 	if (arg->flag & RCM_RETIRE_REQUEST) {
144125e8c5aaSvikram 		rcm_log_message(RCM_TRACE1, "tree_action: RETIRE_REQ: walking "
144225e8c5aaSvikram 		    "only root node: %s\n", root->name);
144325e8c5aaSvikram 		arg->retcode = RCM_NO_CONSTRAINT;
144425e8c5aaSvikram 		(void) node_action(root, arg);
144525e8c5aaSvikram 	} else {
144625e8c5aaSvikram 		arg->retcode = RCM_SUCCESS;
144725e8c5aaSvikram 		rsrc_walk(root, (void *)arg, node_action);
144825e8c5aaSvikram 	}
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	return (arg->retcode);
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate /*
14547c478bd9Sstevel@tonic-gate  * Get info on current regsitrations
14557c478bd9Sstevel@tonic-gate  */
14567c478bd9Sstevel@tonic-gate int
rsrc_usage_info(char ** rsrcnames,uint_t flag,int seq_num,rcm_info_t ** info)14577c478bd9Sstevel@tonic-gate rsrc_usage_info(char **rsrcnames, uint_t flag, int seq_num, rcm_info_t **info)
14587c478bd9Sstevel@tonic-gate {
14597c478bd9Sstevel@tonic-gate 	rsrc_node_t *node;
14607c478bd9Sstevel@tonic-gate 	rcm_info_t *result = NULL;
14617c478bd9Sstevel@tonic-gate 	tree_walk_arg_t arg;
14627c478bd9Sstevel@tonic-gate 	int initial_req;
14637c478bd9Sstevel@tonic-gate 	int rv;
14647c478bd9Sstevel@tonic-gate 	int i;
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	arg.flag = flag;
14677c478bd9Sstevel@tonic-gate 	arg.info = &result;
14687c478bd9Sstevel@tonic-gate 	arg.seq_num = seq_num;
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	for (i = 0; rsrcnames[i] != NULL; i++) {
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "rsrc_usage_info(%s, 0x%x, %d)\n",
14737c478bd9Sstevel@tonic-gate 		    rsrcnames[i], flag, seq_num);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 		if (flag & RCM_INCLUDE_DEPENDENT) {
14767c478bd9Sstevel@tonic-gate 			initial_req = ((seq_num & SEQ_NUM_MASK) == 0);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 			/*
14797c478bd9Sstevel@tonic-gate 			 * if redundant request, skip the operation
14807c478bd9Sstevel@tonic-gate 			 */
14817c478bd9Sstevel@tonic-gate 			if (info_req_add(rsrcnames[i], flag, seq_num) != 0) {
14827c478bd9Sstevel@tonic-gate 				continue;
14837c478bd9Sstevel@tonic-gate 			}
14847c478bd9Sstevel@tonic-gate 		}
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 		rv = rsrc_node_find(rsrcnames[i], 0, &node);
14877c478bd9Sstevel@tonic-gate 		if ((rv != RCM_SUCCESS) || (node == NULL)) {
14887c478bd9Sstevel@tonic-gate 			if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req)
14897c478bd9Sstevel@tonic-gate 				info_req_remove(seq_num);
14907c478bd9Sstevel@tonic-gate 			continue;
14917c478bd9Sstevel@tonic-gate 		}
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 		/*
14947c478bd9Sstevel@tonic-gate 		 * Based on RCM_INCLUDE_SUBTREE flag, query either the subtree
14957c478bd9Sstevel@tonic-gate 		 * or just the node.
14967c478bd9Sstevel@tonic-gate 		 */
14977c478bd9Sstevel@tonic-gate 		if (flag & RCM_INCLUDE_SUBTREE) {
14987c478bd9Sstevel@tonic-gate 			(void) rsrc_tree_action(node, CMD_GETINFO, &arg);
14997c478bd9Sstevel@tonic-gate 		} else {
15007c478bd9Sstevel@tonic-gate 			arg.cmd = CMD_GETINFO;
15017c478bd9Sstevel@tonic-gate 			(void) node_action(node, (void *)&arg);
15027c478bd9Sstevel@tonic-gate 		}
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 		if ((flag & RCM_INCLUDE_DEPENDENT) && initial_req)
15057c478bd9Sstevel@tonic-gate 			info_req_remove(seq_num);
15067c478bd9Sstevel@tonic-gate 	}
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate out:
15097c478bd9Sstevel@tonic-gate 	(void) rcm_append_info(info, result);
15107c478bd9Sstevel@tonic-gate 	return (rv);
15117c478bd9Sstevel@tonic-gate }
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate /*
15147c478bd9Sstevel@tonic-gate  * Get the list of currently loaded module
15157c478bd9Sstevel@tonic-gate  */
15167c478bd9Sstevel@tonic-gate rcm_info_t *
rsrc_mod_info()15177c478bd9Sstevel@tonic-gate rsrc_mod_info()
15187c478bd9Sstevel@tonic-gate {
15197c478bd9Sstevel@tonic-gate 	module_t *mod;
15207c478bd9Sstevel@tonic-gate 	rcm_info_t *info = NULL;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mod_lock);
15237c478bd9Sstevel@tonic-gate 	mod = module_head;
15247c478bd9Sstevel@tonic-gate 	while (mod) {
15257c478bd9Sstevel@tonic-gate 		char *modinfo = s_strdup(module_info(mod));
15267c478bd9Sstevel@tonic-gate 		add_busy_rsrc_to_list("dummy", 0, 0, 0, mod->name,
15277c478bd9Sstevel@tonic-gate 		    modinfo, NULL, NULL, &info);
15287c478bd9Sstevel@tonic-gate 		mod = mod->next;
15297c478bd9Sstevel@tonic-gate 	}
15307c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mod_lock);
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	return (info);
15337c478bd9Sstevel@tonic-gate }
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate  * Initialize resource map - load all modules
15377c478bd9Sstevel@tonic-gate  */
15387c478bd9Sstevel@tonic-gate void
rcmd_db_init()15397c478bd9Sstevel@tonic-gate rcmd_db_init()
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate 	char *tmp;
15427c478bd9Sstevel@tonic-gate 	DIR *mod_dir;
15434bc0a2efScasper 	struct dirent *entp;
15447c478bd9Sstevel@tonic-gate 	int i;
15457c478bd9Sstevel@tonic-gate 	char *dir_name;
15467c478bd9Sstevel@tonic-gate 	int rcm_script;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "rcmd_db_init(): initialize database\n");
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if (script_main_init() == -1)
15517c478bd9Sstevel@tonic-gate 		rcmd_exit(errno);
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	rsrc_root = rn_alloc("/", RSRC_TYPE_NORMAL);
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	for (i = 0; (dir_name = rcm_dir(i, &rcm_script)) != NULL; i++) {
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		if ((mod_dir = opendir(dir_name)) == NULL) {
15587c478bd9Sstevel@tonic-gate 			continue;	/* try next directory */
15597c478bd9Sstevel@tonic-gate 		}
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "search directory %s\n", dir_name);
15627c478bd9Sstevel@tonic-gate 
15634bc0a2efScasper 		while ((entp = readdir(mod_dir)) != NULL) {
15647c478bd9Sstevel@tonic-gate 			module_t *module;
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 			if (strcmp(entp->d_name, ".") == 0 ||
156746fbc806SToomas Soome 			    strcmp(entp->d_name, "..") == 0)
15687c478bd9Sstevel@tonic-gate 				continue;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 			if (rcm_script == 0) {
15717c478bd9Sstevel@tonic-gate 				/* rcm module */
15727c478bd9Sstevel@tonic-gate 				if (((tmp = strstr(entp->d_name,
15737c478bd9Sstevel@tonic-gate 				    RCM_MODULE_SUFFIX)) == NULL) ||
15747c478bd9Sstevel@tonic-gate 				    (tmp[strlen(RCM_MODULE_SUFFIX)] != '\0')) {
15757c478bd9Sstevel@tonic-gate 					continue;
15767c478bd9Sstevel@tonic-gate 				}
15777c478bd9Sstevel@tonic-gate 			}
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 			module = cli_module_hold(entp->d_name);
15807c478bd9Sstevel@tonic-gate 			if (module == NULL) {
15817c478bd9Sstevel@tonic-gate 				if (rcm_script == 0)
15827c478bd9Sstevel@tonic-gate 					rcm_log_message(RCM_ERROR,
15837c478bd9Sstevel@tonic-gate 					    gettext("%s: failed to load\n"),
15847c478bd9Sstevel@tonic-gate 					    entp->d_name);
15857c478bd9Sstevel@tonic-gate 				continue;
15867c478bd9Sstevel@tonic-gate 			}
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 			if (module->ref_count == MOD_REFCNT_INIT) {
15897c478bd9Sstevel@tonic-gate 				/*
15907c478bd9Sstevel@tonic-gate 				 * ask module to register for resource 1st time
15917c478bd9Sstevel@tonic-gate 				 */
15927c478bd9Sstevel@tonic-gate 				module_attach(module);
15937c478bd9Sstevel@tonic-gate 			}
15947c478bd9Sstevel@tonic-gate 			cli_module_rele(module);
15957c478bd9Sstevel@tonic-gate 		}
15967c478bd9Sstevel@tonic-gate 		(void) closedir(mod_dir);
15977c478bd9Sstevel@tonic-gate 	}
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	rcmd_db_print();
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate /*
16037c478bd9Sstevel@tonic-gate  * sync resource map - ask all modules to register again
16047c478bd9Sstevel@tonic-gate  */
16057c478bd9Sstevel@tonic-gate void
rcmd_db_sync()16067c478bd9Sstevel@tonic-gate rcmd_db_sync()
16077c478bd9Sstevel@tonic-gate {
16087c478bd9Sstevel@tonic-gate 	static time_t sync_time = (time_t)-1;
16097c478bd9Sstevel@tonic-gate 	const time_t interval = 5;	/* resync at most every 5 sec */
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	module_t *mod;
16127c478bd9Sstevel@tonic-gate 	time_t curr = time(NULL);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	if ((sync_time != (time_t)-1) && (curr - sync_time < interval))
16157c478bd9Sstevel@tonic-gate 		return;
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	sync_time = curr;
16187c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mod_lock);
16197c478bd9Sstevel@tonic-gate 	mod = module_head;
16207c478bd9Sstevel@tonic-gate 	while (mod) {
16217c478bd9Sstevel@tonic-gate 		/*
16227c478bd9Sstevel@tonic-gate 		 * Hold module by incrementing ref count and release
16237c478bd9Sstevel@tonic-gate 		 * mod_lock to avoid deadlock, since rcmop_register()
16247c478bd9Sstevel@tonic-gate 		 * may callback into the daemon and request mod_lock.
16257c478bd9Sstevel@tonic-gate 		 */
16267c478bd9Sstevel@tonic-gate 		mod->ref_count++;
16277c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mod_lock);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 		mod->modops->rcmop_register(mod->rcmhandle);
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&mod_lock);
16327c478bd9Sstevel@tonic-gate 		mod->ref_count--;
16337c478bd9Sstevel@tonic-gate 		mod = mod->next;
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mod_lock);
16367c478bd9Sstevel@tonic-gate }
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate /*
16397c478bd9Sstevel@tonic-gate  * Determine if a process is alive
16407c478bd9Sstevel@tonic-gate  */
16417c478bd9Sstevel@tonic-gate int
proc_exist(pid_t pid)16427c478bd9Sstevel@tonic-gate proc_exist(pid_t pid)
16437c478bd9Sstevel@tonic-gate {
16447c478bd9Sstevel@tonic-gate 	char path[64];
16457c478bd9Sstevel@tonic-gate 	const char *procfs = "/proc";
16467c478bd9Sstevel@tonic-gate 	struct stat sb;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	if (pid == (pid_t)0) {
16497c478bd9Sstevel@tonic-gate 		return (1);
16507c478bd9Sstevel@tonic-gate 	}
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/%ld", procfs, pid);
16537c478bd9Sstevel@tonic-gate 	return (stat(path, &sb) == 0);
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate /*
16577c478bd9Sstevel@tonic-gate  * Cleaup client list
16587c478bd9Sstevel@tonic-gate  *
16597c478bd9Sstevel@tonic-gate  * N.B. This routine runs in a single-threaded environment only. It is only
16607c478bd9Sstevel@tonic-gate  *	called by the cleanup thread, which never runs in parallel with other
16617c478bd9Sstevel@tonic-gate  *	threads.
16627c478bd9Sstevel@tonic-gate  */
16637c478bd9Sstevel@tonic-gate static void
clean_client_list(client_t ** listp)16647c478bd9Sstevel@tonic-gate clean_client_list(client_t **listp)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	client_t *client = *listp;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	/*
16697c478bd9Sstevel@tonic-gate 	 * Cleanup notification clients for which pid no longer exists
16707c478bd9Sstevel@tonic-gate 	 */
16717c478bd9Sstevel@tonic-gate 	while (client) {
16727c478bd9Sstevel@tonic-gate 		if ((client->state != RCM_STATE_REMOVE) &&
16737c478bd9Sstevel@tonic-gate 		    proc_exist(client->pid)) {
16747c478bd9Sstevel@tonic-gate 			listp = &client->next;
16757c478bd9Sstevel@tonic-gate 			client = *listp;
16767c478bd9Sstevel@tonic-gate 			continue;
16777c478bd9Sstevel@tonic-gate 		}
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 		/*
16807c478bd9Sstevel@tonic-gate 		 * Destroy this client_t. rsrc_client_remove updates
16817c478bd9Sstevel@tonic-gate 		 * listp to point to the next client.
16827c478bd9Sstevel@tonic-gate 		 */
16837c478bd9Sstevel@tonic-gate 		rsrc_client_remove(client, listp);
16847c478bd9Sstevel@tonic-gate 		client = *listp;
16857c478bd9Sstevel@tonic-gate 	}
16867c478bd9Sstevel@tonic-gate }
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
16897c478bd9Sstevel@tonic-gate static int
clean_node(rsrc_node_t * node,void * arg)16907c478bd9Sstevel@tonic-gate clean_node(rsrc_node_t *node, void *arg)
16917c478bd9Sstevel@tonic-gate {
16927c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4, "clean_node(%s)\n", node->name);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	clean_client_list(&node->users);
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	return (RN_WALK_CONTINUE);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate static void
clean_rsrc_tree()17007c478bd9Sstevel@tonic-gate clean_rsrc_tree()
17017c478bd9Sstevel@tonic-gate {
17027c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE4,
17037c478bd9Sstevel@tonic-gate 	    "clean_rsrc_tree(): delete stale dr clients\n");
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	rsrc_walk(rsrc_root, NULL, clean_node);
17067c478bd9Sstevel@tonic-gate }
17077c478bd9Sstevel@tonic-gate 
1708*0e540600SToomas Soome static void *
db_clean(void * arg __unused)1709*0e540600SToomas Soome db_clean(void *arg __unused)
17107c478bd9Sstevel@tonic-gate {
17117c478bd9Sstevel@tonic-gate 	extern barrier_t barrier;
17127c478bd9Sstevel@tonic-gate 	extern void clean_dr_list();
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	for (;;) {
17157c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&rcm_req_lock);
17167c478bd9Sstevel@tonic-gate 		start_polling_thread();
17177c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rcm_req_lock);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&barrier.lock);
17207c478bd9Sstevel@tonic-gate 		while (need_cleanup == 0)
17217c478bd9Sstevel@tonic-gate 			(void) cond_wait(&barrier.cv, &barrier.lock);
17227c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&barrier.lock);
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 		/*
17257c478bd9Sstevel@tonic-gate 		 * Make sure all other threads are either blocked or exited.
17267c478bd9Sstevel@tonic-gate 		 */
17277c478bd9Sstevel@tonic-gate 		rcmd_set_state(RCMD_CLEANUP);
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 		need_cleanup = 0;
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 		/*
17327c478bd9Sstevel@tonic-gate 		 * clean dr_req_list
17337c478bd9Sstevel@tonic-gate 		 */
17347c478bd9Sstevel@tonic-gate 		clean_dr_list();
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 		/*
17377c478bd9Sstevel@tonic-gate 		 * clean resource tree
17387c478bd9Sstevel@tonic-gate 		 */
17397c478bd9Sstevel@tonic-gate 		clean_rsrc_tree();
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 		rcmd_set_state(RCMD_NORMAL);
17427c478bd9Sstevel@tonic-gate 	}
1743*0e540600SToomas Soome 	return (NULL);
17447c478bd9Sstevel@tonic-gate }
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate void
rcmd_db_clean(void)1747*0e540600SToomas Soome rcmd_db_clean(void)
17487c478bd9Sstevel@tonic-gate {
17497c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG,
17507c478bd9Sstevel@tonic-gate 	    "rcm_db_clean(): launch thread to clean database\n");
17517c478bd9Sstevel@tonic-gate 
1752*0e540600SToomas Soome 	if (thr_create(NULL, 0, db_clean, NULL, THR_DETACHED, NULL) != 0) {
17537c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
17547c478bd9Sstevel@tonic-gate 		    gettext("failed to create cleanup thread %s\n"),
17557c478bd9Sstevel@tonic-gate 		    strerror(errno));
17567c478bd9Sstevel@tonic-gate 	}
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17607c478bd9Sstevel@tonic-gate static int
print_node(rsrc_node_t * node,void * arg)17617c478bd9Sstevel@tonic-gate print_node(rsrc_node_t *node, void *arg)
17627c478bd9Sstevel@tonic-gate {
17637c478bd9Sstevel@tonic-gate 	client_t *user;
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "rscname: %s, state = 0x%x\n", node->name);
17667c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "	users:\n");
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	if ((user = node->users) == NULL) {
17697c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "    none\n");
17707c478bd9Sstevel@tonic-gate 		return (RN_WALK_CONTINUE);
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	while (user) {
17747c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "	%s, %d, %s\n",
17757c478bd9Sstevel@tonic-gate 		    user->module->name, user->pid, user->alias);
17767c478bd9Sstevel@tonic-gate 		user = user->next;
17777c478bd9Sstevel@tonic-gate 	}
17787c478bd9Sstevel@tonic-gate 	return (RN_WALK_CONTINUE);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate static void
rcmd_db_print()17827c478bd9Sstevel@tonic-gate rcmd_db_print()
17837c478bd9Sstevel@tonic-gate {
17847c478bd9Sstevel@tonic-gate 	module_t *mod;
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "modules:\n");
17877c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mod_lock);
17887c478bd9Sstevel@tonic-gate 	mod = module_head;
17897c478bd9Sstevel@tonic-gate 	while (mod) {
17907c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "	%s\n", mod->name);
17917c478bd9Sstevel@tonic-gate 		mod = mod->next;
17927c478bd9Sstevel@tonic-gate 	}
17937c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&mod_lock);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "\nresource tree:\n");
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	rsrc_walk(rsrc_root, NULL, print_node);
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "\n");
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate /*
18037c478bd9Sstevel@tonic-gate  * Allocate handle from calling into each RCM module
18047c478bd9Sstevel@tonic-gate  */
18057c478bd9Sstevel@tonic-gate static rcm_handle_t *
rcm_handle_alloc(module_t * module)18067c478bd9Sstevel@tonic-gate rcm_handle_alloc(module_t *module)
18077c478bd9Sstevel@tonic-gate {
18087c478bd9Sstevel@tonic-gate 	rcm_handle_t *hdl;
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	hdl = s_malloc(sizeof (rcm_handle_t));
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	hdl->modname = module->name;
18137c478bd9Sstevel@tonic-gate 	hdl->pid = 0;
18147c478bd9Sstevel@tonic-gate 	hdl->lrcm_ops = &rcm_ops;	/* for callback into daemon directly */
18157c478bd9Sstevel@tonic-gate 	hdl->module = module;
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	return (hdl);
18187c478bd9Sstevel@tonic-gate }
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate /*
18217c478bd9Sstevel@tonic-gate  * Free rcm_handle_t
18227c478bd9Sstevel@tonic-gate  */
18237c478bd9Sstevel@tonic-gate static void
rcm_handle_free(rcm_handle_t * handle)18247c478bd9Sstevel@tonic-gate rcm_handle_free(rcm_handle_t *handle)
18257c478bd9Sstevel@tonic-gate {
18267c478bd9Sstevel@tonic-gate 	free(handle);
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate /*
18307c478bd9Sstevel@tonic-gate  * help function that exit on memory outage
18317c478bd9Sstevel@tonic-gate  */
18327c478bd9Sstevel@tonic-gate void *
s_malloc(size_t size)18337c478bd9Sstevel@tonic-gate s_malloc(size_t size)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate 	void *buf = malloc(size);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
18387c478bd9Sstevel@tonic-gate 		rcmd_exit(ENOMEM);
18397c478bd9Sstevel@tonic-gate 	}
18407c478bd9Sstevel@tonic-gate 	return (buf);
18417c478bd9Sstevel@tonic-gate }
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate void *
s_calloc(int n,size_t size)18447c478bd9Sstevel@tonic-gate s_calloc(int n, size_t size)
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate 	void *buf = calloc(n, size);
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
18497c478bd9Sstevel@tonic-gate 		rcmd_exit(ENOMEM);
18507c478bd9Sstevel@tonic-gate 	}
18517c478bd9Sstevel@tonic-gate 	return (buf);
18527c478bd9Sstevel@tonic-gate }
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate void *
s_realloc(void * ptr,size_t size)18557c478bd9Sstevel@tonic-gate s_realloc(void *ptr, size_t size)
18567c478bd9Sstevel@tonic-gate {
18577c478bd9Sstevel@tonic-gate 	void *new = realloc(ptr, size);
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	if (new == NULL) {
18607c478bd9Sstevel@tonic-gate 		rcmd_exit(ENOMEM);
18617c478bd9Sstevel@tonic-gate 	}
18627c478bd9Sstevel@tonic-gate 	return (new);
18637c478bd9Sstevel@tonic-gate }
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate char *
s_strdup(const char * str)18667c478bd9Sstevel@tonic-gate s_strdup(const char *str)
18677c478bd9Sstevel@tonic-gate {
18687c478bd9Sstevel@tonic-gate 	char *buf = strdup(str);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
18717c478bd9Sstevel@tonic-gate 		rcmd_exit(ENOMEM);
18727c478bd9Sstevel@tonic-gate 	}
18737c478bd9Sstevel@tonic-gate 	return (buf);
18747c478bd9Sstevel@tonic-gate }
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate /*
18777c478bd9Sstevel@tonic-gate  * Convert a version 1 ops vector to current ops vector
18787c478bd9Sstevel@tonic-gate  * Fields missing in version 1 are set to NULL.
18797c478bd9Sstevel@tonic-gate  */
18807c478bd9Sstevel@tonic-gate static struct rcm_mod_ops *
modops_from_v1(void * ops_v1)18817c478bd9Sstevel@tonic-gate modops_from_v1(void *ops_v1)
18827c478bd9Sstevel@tonic-gate {
18837c478bd9Sstevel@tonic-gate 	struct rcm_mod_ops *ops;
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	ops = s_calloc(1, sizeof (struct rcm_mod_ops));
18867c478bd9Sstevel@tonic-gate 	bcopy(ops_v1, ops, sizeof (struct rcm_mod_ops_v1));
18877c478bd9Sstevel@tonic-gate 	return (ops);
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate /* call a module's getinfo routine; detects v1 ops and adjusts the call */
18917c478bd9Sstevel@tonic-gate static int
call_getinfo(struct rcm_mod_ops * ops,rcm_handle_t * hdl,char * alias,id_t pid,uint_t flag,char ** info,char ** error,nvlist_t * client_props,rcm_info_t ** infop)18927c478bd9Sstevel@tonic-gate call_getinfo(struct rcm_mod_ops *ops, rcm_handle_t *hdl, char *alias, id_t pid,
18937c478bd9Sstevel@tonic-gate     uint_t flag, char **info, char **error, nvlist_t *client_props,
18947c478bd9Sstevel@tonic-gate     rcm_info_t **infop)
18957c478bd9Sstevel@tonic-gate {
18967c478bd9Sstevel@tonic-gate 	int rval;
18977c478bd9Sstevel@tonic-gate 	struct rcm_mod_ops_v1 *v1_ops;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	if (ops->version == RCM_MOD_OPS_V1) {
19007c478bd9Sstevel@tonic-gate 		v1_ops = (struct rcm_mod_ops_v1 *)ops;
19017c478bd9Sstevel@tonic-gate 		rval = v1_ops->rcmop_get_info(hdl, alias, pid, flag, info,
19027c478bd9Sstevel@tonic-gate 		    infop);
19037c478bd9Sstevel@tonic-gate 		if (rval != RCM_SUCCESS && *info != NULL)
19047c478bd9Sstevel@tonic-gate 			*error = strdup(*info);
19057c478bd9Sstevel@tonic-gate 		return (rval);
19067c478bd9Sstevel@tonic-gate 	} else {
19077c478bd9Sstevel@tonic-gate 		return (ops->rcmop_get_info(hdl, alias, pid, flag, info, error,
19087c478bd9Sstevel@tonic-gate 		    client_props, infop));
19097c478bd9Sstevel@tonic-gate 	}
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate void
rcm_init_queue(rcm_queue_t * head)19137c478bd9Sstevel@tonic-gate rcm_init_queue(rcm_queue_t *head)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	head->next = head->prev = head;
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate void
rcm_enqueue_head(rcm_queue_t * head,rcm_queue_t * element)19197c478bd9Sstevel@tonic-gate rcm_enqueue_head(rcm_queue_t *head, rcm_queue_t *element)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate 	rcm_enqueue(head, element);
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate void
rcm_enqueue_tail(rcm_queue_t * head,rcm_queue_t * element)19257c478bd9Sstevel@tonic-gate rcm_enqueue_tail(rcm_queue_t *head, rcm_queue_t *element)
19267c478bd9Sstevel@tonic-gate {
19277c478bd9Sstevel@tonic-gate 	rcm_enqueue(head->prev, element);
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate void
rcm_enqueue(rcm_queue_t * list_element,rcm_queue_t * element)19317c478bd9Sstevel@tonic-gate rcm_enqueue(rcm_queue_t *list_element, rcm_queue_t *element)
19327c478bd9Sstevel@tonic-gate {
19337c478bd9Sstevel@tonic-gate 	element->next = list_element->next;
19347c478bd9Sstevel@tonic-gate 	element->prev = list_element;
19357c478bd9Sstevel@tonic-gate 	element->next->prev = element;
19367c478bd9Sstevel@tonic-gate 	list_element->next = element;
19377c478bd9Sstevel@tonic-gate }
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate rcm_queue_t *
rcm_dequeue_head(rcm_queue_t * head)19407c478bd9Sstevel@tonic-gate rcm_dequeue_head(rcm_queue_t *head)
19417c478bd9Sstevel@tonic-gate {
19427c478bd9Sstevel@tonic-gate 	rcm_queue_t	*element = head->next;
19437c478bd9Sstevel@tonic-gate 	rcm_dequeue(element);
19447c478bd9Sstevel@tonic-gate 	return (element);
19457c478bd9Sstevel@tonic-gate }
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate rcm_queue_t *
rcm_dequeue_tail(rcm_queue_t * head)19487c478bd9Sstevel@tonic-gate rcm_dequeue_tail(rcm_queue_t *head)
19497c478bd9Sstevel@tonic-gate {
19507c478bd9Sstevel@tonic-gate 	rcm_queue_t	*element = head->prev;
19517c478bd9Sstevel@tonic-gate 	rcm_dequeue(element);
19527c478bd9Sstevel@tonic-gate 	return (element);
19537c478bd9Sstevel@tonic-gate }
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate void
rcm_dequeue(rcm_queue_t * element)19567c478bd9Sstevel@tonic-gate rcm_dequeue(rcm_queue_t *element)
19577c478bd9Sstevel@tonic-gate {
19587c478bd9Sstevel@tonic-gate 	element->prev->next = element->next;
19597c478bd9Sstevel@tonic-gate 	element->next->prev = element->prev;
19607c478bd9Sstevel@tonic-gate 	element->next = element->prev = NULL;
19617c478bd9Sstevel@tonic-gate }
1962