xref: /illumos-gate/usr/src/cmd/drd/drd_rcm.c (revision 8fea755a86ff6c596183a4366bfbd59f1bfdfe55)
11d4b38e0Srsmaeda /*
21d4b38e0Srsmaeda  * CDDL HEADER START
31d4b38e0Srsmaeda  *
41d4b38e0Srsmaeda  * The contents of this file are subject to the terms of the
51d4b38e0Srsmaeda  * Common Development and Distribution License (the "License").
61d4b38e0Srsmaeda  * You may not use this file except in compliance with the License.
71d4b38e0Srsmaeda  *
81d4b38e0Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91d4b38e0Srsmaeda  * or http://www.opensolaris.org/os/licensing.
101d4b38e0Srsmaeda  * See the License for the specific language governing permissions
111d4b38e0Srsmaeda  * and limitations under the License.
121d4b38e0Srsmaeda  *
131d4b38e0Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
141d4b38e0Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151d4b38e0Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
161d4b38e0Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
171d4b38e0Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
181d4b38e0Srsmaeda  *
191d4b38e0Srsmaeda  * CDDL HEADER END
201d4b38e0Srsmaeda  */
211d4b38e0Srsmaeda 
221d4b38e0Srsmaeda /*
23*8fea755aSjm22469  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241d4b38e0Srsmaeda  * Use is subject to license terms.
251d4b38e0Srsmaeda  */
261d4b38e0Srsmaeda 
271d4b38e0Srsmaeda #pragma ident	"%Z%%M%	%I%	%E% SMI"
281d4b38e0Srsmaeda 
291d4b38e0Srsmaeda /*
301d4b38e0Srsmaeda  * RCM backend for the DR Daemon
311d4b38e0Srsmaeda  */
321d4b38e0Srsmaeda 
331d4b38e0Srsmaeda #include <unistd.h>
341d4b38e0Srsmaeda #include <strings.h>
351d4b38e0Srsmaeda #include <errno.h>
361d4b38e0Srsmaeda #include <kstat.h>
371d4b38e0Srsmaeda #include <libnvpair.h>
381d4b38e0Srsmaeda #include <librcm.h>
39*8fea755aSjm22469 #include <locale.h>
401d4b38e0Srsmaeda 
411d4b38e0Srsmaeda #include "drd.h"
421d4b38e0Srsmaeda 
431d4b38e0Srsmaeda /*
441d4b38e0Srsmaeda  * RCM Backend Support
451d4b38e0Srsmaeda  */
461d4b38e0Srsmaeda static int drd_rcm_init(void);
471d4b38e0Srsmaeda static int drd_rcm_fini(void);
481d4b38e0Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
491d4b38e0Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
501d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
511d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
52*8fea755aSjm22469 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc);
53*8fea755aSjm22469 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc);
54*8fea755aSjm22469 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc);
55*8fea755aSjm22469 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc);
561d4b38e0Srsmaeda 
571d4b38e0Srsmaeda drd_backend_t drd_rcm_backend = {
581d4b38e0Srsmaeda 	drd_rcm_init,			/* init */
591d4b38e0Srsmaeda 	drd_rcm_fini,			/* fini */
601d4b38e0Srsmaeda 	drd_rcm_cpu_config_request,	/* cpu_config_request */
611d4b38e0Srsmaeda 	drd_rcm_cpu_config_notify,	/* cpu_config_notify */
621d4b38e0Srsmaeda 	drd_rcm_cpu_unconfig_request,	/* cpu_unconfig_request */
63*8fea755aSjm22469 	drd_rcm_cpu_unconfig_notify,	/* cpu_unconfig_notify */
64*8fea755aSjm22469 	drd_rcm_io_config_request,	/* io_config_request */
65*8fea755aSjm22469 	drd_rcm_io_config_notify,	/* io_config_notify */
66*8fea755aSjm22469 	drd_rcm_io_unconfig_request,	/* io_unconfig_request */
67*8fea755aSjm22469 	drd_rcm_io_unconfig_notify	/* io_unconfig_notify */
681d4b38e0Srsmaeda };
691d4b38e0Srsmaeda 
701d4b38e0Srsmaeda #define	RCM_CPU_ALL		"SUNW_cpu"
711d4b38e0Srsmaeda #define	RCM_CPU			RCM_CPU_ALL"/cpu"
721d4b38e0Srsmaeda #define	RCM_CPU_MAX_LEN		(32)
731d4b38e0Srsmaeda 
741d4b38e0Srsmaeda /* global RCM handle used in all RCM operations */
751d4b38e0Srsmaeda static rcm_handle_t *rcm_hdl;
761d4b38e0Srsmaeda 
771d4b38e0Srsmaeda /* functions that call into RCM */
781d4b38e0Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
791d4b38e0Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
801d4b38e0Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
811d4b38e0Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
821d4b38e0Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
831d4b38e0Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
841d4b38e0Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
851d4b38e0Srsmaeda 
861d4b38e0Srsmaeda /* utility functions */
871d4b38e0Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status);
881d4b38e0Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist);
891d4b38e0Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int);
901d4b38e0Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids);
911d4b38e0Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len);
92*8fea755aSjm22469 static char *rcm_info_table(rcm_info_t *rinfo);
931d4b38e0Srsmaeda 
941d4b38e0Srsmaeda /* debugging utility functions */
951d4b38e0Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids);
961d4b38e0Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc);
971d4b38e0Srsmaeda static void dump_cpu_rlist(char **rlist);
981d4b38e0Srsmaeda 
991d4b38e0Srsmaeda static int
1001d4b38e0Srsmaeda drd_rcm_init(void)
1011d4b38e0Srsmaeda {
1021d4b38e0Srsmaeda 	int	rv;
1031d4b38e0Srsmaeda 
1041d4b38e0Srsmaeda 	drd_dbg("drd_rcm_init...");
1051d4b38e0Srsmaeda 
1061d4b38e0Srsmaeda 	rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl);
1071d4b38e0Srsmaeda 	if (rv == RCM_FAILURE) {
1081d4b38e0Srsmaeda 		drd_err("unable to allocate RCM handle: %s", strerror(errno));
1091d4b38e0Srsmaeda 		return (-1);
1101d4b38e0Srsmaeda 	}
1111d4b38e0Srsmaeda 
1121d4b38e0Srsmaeda 	return (0);
1131d4b38e0Srsmaeda }
1141d4b38e0Srsmaeda 
1151d4b38e0Srsmaeda static int
1161d4b38e0Srsmaeda drd_rcm_fini(void)
1171d4b38e0Srsmaeda {
1181d4b38e0Srsmaeda 	drd_dbg("drd_rcm_fini...");
1191d4b38e0Srsmaeda 
1201d4b38e0Srsmaeda 	if (rcm_hdl != NULL)
1211d4b38e0Srsmaeda 		rcm_free_handle(rcm_hdl);
1221d4b38e0Srsmaeda 
1231d4b38e0Srsmaeda 	return (0);
1241d4b38e0Srsmaeda }
1251d4b38e0Srsmaeda 
1261d4b38e0Srsmaeda static int
1271d4b38e0Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1281d4b38e0Srsmaeda {
1291d4b38e0Srsmaeda 	int	idx;
1301d4b38e0Srsmaeda 
1311d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_config_request...");
1321d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1331d4b38e0Srsmaeda 
1341d4b38e0Srsmaeda 	/*
1351d4b38e0Srsmaeda 	 * There is no RCM operation to request the addition
1361d4b38e0Srsmaeda 	 * of resources.  So, by definition, the operation for
1371d4b38e0Srsmaeda 	 * all the CPUs is allowed.
1381d4b38e0Srsmaeda 	 */
1391d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++)
1401d4b38e0Srsmaeda 		rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1411d4b38e0Srsmaeda 
1421d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1431d4b38e0Srsmaeda 
1441d4b38e0Srsmaeda 	return (0);
1451d4b38e0Srsmaeda }
1461d4b38e0Srsmaeda 
1471d4b38e0Srsmaeda static int
1481d4b38e0Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1491d4b38e0Srsmaeda {
1501d4b38e0Srsmaeda 	int	rv = 0;
1511d4b38e0Srsmaeda 
1521d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_config_notify...");
1531d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1541d4b38e0Srsmaeda 
1551d4b38e0Srsmaeda 	/* notify RCM about the newly added CPUs */
1561d4b38e0Srsmaeda 	if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) {
1571d4b38e0Srsmaeda 		rv = -1;
1581d4b38e0Srsmaeda 		goto done;
1591d4b38e0Srsmaeda 	}
1601d4b38e0Srsmaeda 
1611d4b38e0Srsmaeda 	/* notify RCM about the increased CPU capacity */
1621d4b38e0Srsmaeda 	if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) {
1631d4b38e0Srsmaeda 		rv = -1;
1641d4b38e0Srsmaeda 	}
1651d4b38e0Srsmaeda 
1661d4b38e0Srsmaeda done:
1671d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1681d4b38e0Srsmaeda 
1691d4b38e0Srsmaeda 	return (rv);
1701d4b38e0Srsmaeda }
1711d4b38e0Srsmaeda 
1721d4b38e0Srsmaeda static int
1731d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1741d4b38e0Srsmaeda {
1751d4b38e0Srsmaeda 	int	rv = 0;
1761d4b38e0Srsmaeda 	int	idx;
1771d4b38e0Srsmaeda 
1781d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_request...");
1791d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1801d4b38e0Srsmaeda 
1811d4b38e0Srsmaeda 	/* contact RCM to request a decrease in CPU capacity */
1821d4b38e0Srsmaeda 	if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) {
1831d4b38e0Srsmaeda 		rv = -1;
1841d4b38e0Srsmaeda 		goto done;
1851d4b38e0Srsmaeda 	}
1861d4b38e0Srsmaeda 
1871d4b38e0Srsmaeda 	/* contact RCM to request the removal of CPUs */
1881d4b38e0Srsmaeda 	if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) {
1891d4b38e0Srsmaeda 		rv = -1;
1901d4b38e0Srsmaeda 		goto done;
1911d4b38e0Srsmaeda 	}
1921d4b38e0Srsmaeda 
1931d4b38e0Srsmaeda done:
1941d4b38e0Srsmaeda 	/*
1951d4b38e0Srsmaeda 	 * If any errors occurred, the status field for
1961d4b38e0Srsmaeda 	 * a CPU may still be in the INIT state. Set the
1971d4b38e0Srsmaeda 	 * status for any such CPU to DENY to ensure it
1981d4b38e0Srsmaeda 	 * gets processed properly.
1991d4b38e0Srsmaeda 	 */
2001d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
2011d4b38e0Srsmaeda 		if (rsrcs[idx].status == DRCTL_STATUS_INIT)
2021d4b38e0Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
2031d4b38e0Srsmaeda 	}
2041d4b38e0Srsmaeda 
2051d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2061d4b38e0Srsmaeda 
2071d4b38e0Srsmaeda 	return (rv);
2081d4b38e0Srsmaeda }
2091d4b38e0Srsmaeda 
2101d4b38e0Srsmaeda static int
2111d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2121d4b38e0Srsmaeda {
2131d4b38e0Srsmaeda 	int	rv = 0;
2141d4b38e0Srsmaeda 
2151d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_notify...");
2161d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
2171d4b38e0Srsmaeda 
2181d4b38e0Srsmaeda 	/*
2191d4b38e0Srsmaeda 	 * Notify RCM about the CPUs that were removed.
2201d4b38e0Srsmaeda 	 * Failures are ignored so that CPUs that could
2211d4b38e0Srsmaeda 	 * not be unconfigured can be processed by RCM.
2221d4b38e0Srsmaeda 	 */
2231d4b38e0Srsmaeda 	(void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc);
2241d4b38e0Srsmaeda 
2251d4b38e0Srsmaeda 	/*
2261d4b38e0Srsmaeda 	 * Notify RCM about any CPUs that did not make it
2271d4b38e0Srsmaeda 	 * in to the unconfigured state.
2281d4b38e0Srsmaeda 	 */
2291d4b38e0Srsmaeda 	if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) {
2301d4b38e0Srsmaeda 		rv = -1;
2311d4b38e0Srsmaeda 		goto done;
2321d4b38e0Srsmaeda 	}
2331d4b38e0Srsmaeda 
2341d4b38e0Srsmaeda 	/* notify RCM about the decreased CPU capacity */
2351d4b38e0Srsmaeda 	if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) {
2361d4b38e0Srsmaeda 		rv = -1;
2371d4b38e0Srsmaeda 	}
2381d4b38e0Srsmaeda 
2391d4b38e0Srsmaeda done:
2401d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2411d4b38e0Srsmaeda 
2421d4b38e0Srsmaeda 	return (rv);
2431d4b38e0Srsmaeda }
2441d4b38e0Srsmaeda 
2451d4b38e0Srsmaeda static int
2461d4b38e0Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2471d4b38e0Srsmaeda {
2481d4b38e0Srsmaeda 	char		**rlist;
2491d4b38e0Srsmaeda 	int		rv = 0;
2501d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
2511d4b38e0Srsmaeda 
2521d4b38e0Srsmaeda 	drd_dbg("drd_rcm_online_cpu_notify...");
2531d4b38e0Srsmaeda 
2541d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
2551d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
2561d4b38e0Srsmaeda 		drd_dbg("  no CPUs were successfully added, nothing to do");
2571d4b38e0Srsmaeda 		return (0);
2581d4b38e0Srsmaeda 	}
2591d4b38e0Srsmaeda 
2601d4b38e0Srsmaeda 	rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
2611d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
2621d4b38e0Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
2631d4b38e0Srsmaeda 		rcm_free_info(rinfo);
2641d4b38e0Srsmaeda 		rv = -1;
2651d4b38e0Srsmaeda 	}
2661d4b38e0Srsmaeda 
2671d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
2681d4b38e0Srsmaeda 
2691d4b38e0Srsmaeda 	return (rv);
2701d4b38e0Srsmaeda }
2711d4b38e0Srsmaeda 
2721d4b38e0Srsmaeda static int
2731d4b38e0Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2741d4b38e0Srsmaeda {
2751d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
2761d4b38e0Srsmaeda 	int		ncpus;
2771d4b38e0Srsmaeda 	int		rv = -1;
2781d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
2791d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
2801d4b38e0Srsmaeda 	int		oldncpus = 0;
2811d4b38e0Srsmaeda 	int		newncpus = 0;
2821d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
2831d4b38e0Srsmaeda 	int		idx;
2841d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
2851d4b38e0Srsmaeda 
2861d4b38e0Srsmaeda 	drd_dbg("drd_rcm_add_cpu_notify...");
2871d4b38e0Srsmaeda 
2881d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
2891d4b38e0Srsmaeda 		drd_err("add_cpu_notify: cpu list empty");
2901d4b38e0Srsmaeda 		goto done;
2911d4b38e0Srsmaeda 	}
2921d4b38e0Srsmaeda 
2931d4b38e0Srsmaeda 	ncpus = nrsrc;
2941d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
2951d4b38e0Srsmaeda 
2961d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
2971d4b38e0Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
2981d4b38e0Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
2991d4b38e0Srsmaeda 	}
3001d4b38e0Srsmaeda 
3011d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
3021d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3031d4b38e0Srsmaeda 		goto done;
3041d4b38e0Srsmaeda 
3051d4b38e0Srsmaeda 	/*
3061d4b38e0Srsmaeda 	 * Added CPU capacity, so newcpus is the current list
3071d4b38e0Srsmaeda 	 * of CPUs in the system.
3081d4b38e0Srsmaeda 	 */
3091d4b38e0Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1)
3101d4b38e0Srsmaeda 		goto done;
3111d4b38e0Srsmaeda 
3121d4b38e0Srsmaeda 	/*
3131d4b38e0Srsmaeda 	 * Since the operation added CPU capacity, the old CPU
3141d4b38e0Srsmaeda 	 * list is the new CPU list with the CPUs involved in
3151d4b38e0Srsmaeda 	 * the operation removed.
3161d4b38e0Srsmaeda 	 */
3171d4b38e0Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t));
3181d4b38e0Srsmaeda 	if (oldcpus == NULL)
3191d4b38e0Srsmaeda 		goto done;
3201d4b38e0Srsmaeda 
3211d4b38e0Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
3221d4b38e0Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, ncpus))
3231d4b38e0Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
3241d4b38e0Srsmaeda 	}
3251d4b38e0Srsmaeda 
3261d4b38e0Srsmaeda 	/* dump pre and post lists */
3271d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
3281d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
3291d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
3301d4b38e0Srsmaeda 
3311d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
3321d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
3331d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
3341d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
3351d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
3361d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
3371d4b38e0Srsmaeda 		goto done;
3381d4b38e0Srsmaeda 	}
3391d4b38e0Srsmaeda 
3401d4b38e0Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
3411d4b38e0Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
3421d4b38e0Srsmaeda 
3431d4b38e0Srsmaeda done:
3441d4b38e0Srsmaeda 	s_nvfree(nvl);
3451d4b38e0Srsmaeda 	s_free(cpus);
3461d4b38e0Srsmaeda 	s_free(oldcpus);
3471d4b38e0Srsmaeda 	s_free(newcpus);
3481d4b38e0Srsmaeda 
3491d4b38e0Srsmaeda 	return (rv);
3501d4b38e0Srsmaeda }
3511d4b38e0Srsmaeda 
3521d4b38e0Srsmaeda static int
3531d4b38e0Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
3541d4b38e0Srsmaeda {
3551d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
3561d4b38e0Srsmaeda 	int		ncpus;
3571d4b38e0Srsmaeda 	int		rv = -1;
3581d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
3591d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
3601d4b38e0Srsmaeda 	int		oldncpus = 0;
3611d4b38e0Srsmaeda 	int		newncpus = 0;
3621d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
3631d4b38e0Srsmaeda 	int		idx;
3641d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
3651d4b38e0Srsmaeda 
3661d4b38e0Srsmaeda 	drd_dbg("drd_rcm_del_cpu_request...");
3671d4b38e0Srsmaeda 
3681d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
3691d4b38e0Srsmaeda 		drd_err("del_cpu_request: cpu list empty");
3701d4b38e0Srsmaeda 		goto done;
3711d4b38e0Srsmaeda 	}
3721d4b38e0Srsmaeda 
3731d4b38e0Srsmaeda 	ncpus = nrsrc;
3741d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3751d4b38e0Srsmaeda 
3761d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
3771d4b38e0Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
3781d4b38e0Srsmaeda 	}
3791d4b38e0Srsmaeda 
3801d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
3811d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
3821d4b38e0Srsmaeda 		goto done;
3831d4b38e0Srsmaeda 	}
3841d4b38e0Srsmaeda 
3851d4b38e0Srsmaeda 	/*
3861d4b38e0Srsmaeda 	 * Removing CPU capacity, so oldcpus is the current
3871d4b38e0Srsmaeda 	 * list of CPUs in the system.
3881d4b38e0Srsmaeda 	 */
3891d4b38e0Srsmaeda 	if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) {
3901d4b38e0Srsmaeda 		goto done;
3911d4b38e0Srsmaeda 	}
3921d4b38e0Srsmaeda 
3931d4b38e0Srsmaeda 	/*
3941d4b38e0Srsmaeda 	 * Since this is a request to remove CPU capacity,
3951d4b38e0Srsmaeda 	 * the new CPU list is the old CPU list with the CPUs
3961d4b38e0Srsmaeda 	 * involved in the operation removed.
3971d4b38e0Srsmaeda 	 */
3981d4b38e0Srsmaeda 	newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t));
3991d4b38e0Srsmaeda 	if (newcpus == NULL) {
4001d4b38e0Srsmaeda 		goto done;
4011d4b38e0Srsmaeda 	}
4021d4b38e0Srsmaeda 
4031d4b38e0Srsmaeda 	for (idx = 0; idx < oldncpus; idx++) {
4041d4b38e0Srsmaeda 		if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus))
4051d4b38e0Srsmaeda 			newcpus[newncpus++] = oldcpus[idx];
4061d4b38e0Srsmaeda 	}
4071d4b38e0Srsmaeda 
4081d4b38e0Srsmaeda 	/* dump pre and post lists */
4091d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
4101d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
4111d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
4121d4b38e0Srsmaeda 
4131d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
4141d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
4151d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
4161d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
4171d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
4181d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
4191d4b38e0Srsmaeda 		goto done;
4201d4b38e0Srsmaeda 	}
4211d4b38e0Srsmaeda 
4221d4b38e0Srsmaeda 	rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
4231d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
4241d4b38e0Srsmaeda 		drd_dbg("RCM call failed: %d", rv);
4251d4b38e0Srsmaeda 		/*
4261d4b38e0Srsmaeda 		 * Since the capcity change was blocked, we
4271d4b38e0Srsmaeda 		 * mark all CPUs as blocked. It is up to the
4281d4b38e0Srsmaeda 		 * user to reframe the query so that it can
4291d4b38e0Srsmaeda 		 * succeed.
4301d4b38e0Srsmaeda 		 */
4311d4b38e0Srsmaeda 		for (idx = 0; idx < nrsrc; idx++) {
4321d4b38e0Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
4331d4b38e0Srsmaeda 		}
4341d4b38e0Srsmaeda 
4351d4b38e0Srsmaeda 		/* tack on message to first resource */
4361d4b38e0Srsmaeda 		rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
4371d4b38e0Srsmaeda 		    "specified number of CPUs");
4381d4b38e0Srsmaeda 		drd_dbg("  unable to remove specified number of CPUs");
4391d4b38e0Srsmaeda 		goto done;
4401d4b38e0Srsmaeda 	}
4411d4b38e0Srsmaeda 
4421d4b38e0Srsmaeda 	rv = 0;
4431d4b38e0Srsmaeda 
4441d4b38e0Srsmaeda done:
4451d4b38e0Srsmaeda 	s_nvfree(nvl);
4461d4b38e0Srsmaeda 	s_free(cpus);
4471d4b38e0Srsmaeda 	s_free(oldcpus);
4481d4b38e0Srsmaeda 	s_free(newcpus);
4491d4b38e0Srsmaeda 
4501d4b38e0Srsmaeda 	return (rv);
4511d4b38e0Srsmaeda }
4521d4b38e0Srsmaeda 
4531d4b38e0Srsmaeda static int
4541d4b38e0Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
4551d4b38e0Srsmaeda {
4561d4b38e0Srsmaeda 	char		**rlist;
4571d4b38e0Srsmaeda 	drctl_rsrc_t	*rsrc;
4581d4b38e0Srsmaeda 	int		idx;
4591d4b38e0Srsmaeda 	int		state;
4601d4b38e0Srsmaeda 	int		rv = 0;
4611d4b38e0Srsmaeda 	rcm_info_t	*rinfo = NULL;
4621d4b38e0Srsmaeda 	rcm_info_tuple_t *tuple = NULL;
4631d4b38e0Srsmaeda 	const char	*rsrcstr;
4641d4b38e0Srsmaeda 	const char	*errstr;
4651d4b38e0Srsmaeda 
4661d4b38e0Srsmaeda 	drd_dbg("drd_rcm_offline_cpu_request...");
4671d4b38e0Srsmaeda 
4681d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
4691d4b38e0Srsmaeda 	    DRCTL_STATUS_INIT)) == NULL) {
4701d4b38e0Srsmaeda 		drd_err("unable to generate resource list");
4711d4b38e0Srsmaeda 		return (-1);
4721d4b38e0Srsmaeda 	}
4731d4b38e0Srsmaeda 
4741d4b38e0Srsmaeda 	rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo);
4751d4b38e0Srsmaeda 	if (rv == RCM_SUCCESS) {
4761d4b38e0Srsmaeda 		drd_dbg("RCM success, rinfo=%p", rinfo);
4771d4b38e0Srsmaeda 		goto done;
4781d4b38e0Srsmaeda 	}
4791d4b38e0Srsmaeda 
4801d4b38e0Srsmaeda 	drd_dbg("RCM call failed (%d):", rv);
4811d4b38e0Srsmaeda 
4821d4b38e0Srsmaeda 	/*
4831d4b38e0Srsmaeda 	 * Loop through the result of the operation and add
4841d4b38e0Srsmaeda 	 * any error messages to the resource structure.
4851d4b38e0Srsmaeda 	 */
4861d4b38e0Srsmaeda 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
4871d4b38e0Srsmaeda 
4881d4b38e0Srsmaeda 		/* find the resource of interest */
4891d4b38e0Srsmaeda 		rsrcstr = rcm_info_rsrc(tuple);
4901d4b38e0Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc);
4911d4b38e0Srsmaeda 
4921d4b38e0Srsmaeda 		if (rsrc == NULL) {
4931d4b38e0Srsmaeda 			drd_dbg("unable to find resource for %s", rsrcstr);
4941d4b38e0Srsmaeda 			continue;
4951d4b38e0Srsmaeda 		}
4961d4b38e0Srsmaeda 
4971d4b38e0Srsmaeda 		errstr = rcm_info_error(tuple);
4981d4b38e0Srsmaeda 
4991d4b38e0Srsmaeda 		if (errstr) {
5001d4b38e0Srsmaeda 			drd_dbg("  %s: '%s'", rsrcstr, errstr);
5011d4b38e0Srsmaeda 			rsrc->offset = (uintptr_t)strdup(errstr);
5021d4b38e0Srsmaeda 		}
5031d4b38e0Srsmaeda 	}
5041d4b38e0Srsmaeda 
5051d4b38e0Srsmaeda 	rcm_free_info(rinfo);
5061d4b38e0Srsmaeda 	rv = 0;
5071d4b38e0Srsmaeda 
5081d4b38e0Srsmaeda done:
5091d4b38e0Srsmaeda 	/*
5101d4b38e0Srsmaeda 	 * Set the state of the resource based on the RCM
5111d4b38e0Srsmaeda 	 * state. CPUs in the offline state have the ok to
5121d4b38e0Srsmaeda 	 * proceed. All others have been blocked.
5131d4b38e0Srsmaeda 	 */
5141d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
5151d4b38e0Srsmaeda 
5161d4b38e0Srsmaeda 		state = 0;
5171d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
5181d4b38e0Srsmaeda 
5191d4b38e0Srsmaeda 		/* find the resource of interest */
5201d4b38e0Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc);
5211d4b38e0Srsmaeda 
5221d4b38e0Srsmaeda 		if (rsrc == NULL) {
5231d4b38e0Srsmaeda 			drd_dbg("unable to find resource for %s", rlist[idx]);
5241d4b38e0Srsmaeda 			continue;
5251d4b38e0Srsmaeda 		}
5261d4b38e0Srsmaeda 
5271d4b38e0Srsmaeda 		rsrc->status = ((state == RCM_STATE_OFFLINE) ?
5281d4b38e0Srsmaeda 		    DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY);
5291d4b38e0Srsmaeda 	}
5301d4b38e0Srsmaeda 
5311d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
5321d4b38e0Srsmaeda 
5331d4b38e0Srsmaeda 	return (rv);
5341d4b38e0Srsmaeda }
5351d4b38e0Srsmaeda 
5361d4b38e0Srsmaeda static int
5371d4b38e0Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5381d4b38e0Srsmaeda {
5391d4b38e0Srsmaeda 	char		**rlist;
5401d4b38e0Srsmaeda 	int		rv = 0;
5411d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
5421d4b38e0Srsmaeda 
5431d4b38e0Srsmaeda 	drd_dbg("drd_rcm_remove_cpu_notify...");
5441d4b38e0Srsmaeda 
5451d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5461d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
5471d4b38e0Srsmaeda 		drd_dbg("  no CPUs in the success state, nothing to do");
5481d4b38e0Srsmaeda 		return (0);
5491d4b38e0Srsmaeda 	}
5501d4b38e0Srsmaeda 
5511d4b38e0Srsmaeda 	rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo);
5521d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
5531d4b38e0Srsmaeda 		drd_info("rcm_notify_remove_list failed: %d", rv);
5541d4b38e0Srsmaeda 		rcm_free_info(rinfo);
5551d4b38e0Srsmaeda 		rv = -1;
5561d4b38e0Srsmaeda 	}
5571d4b38e0Srsmaeda 
5581d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
5591d4b38e0Srsmaeda 
5601d4b38e0Srsmaeda 	return (rv);
5611d4b38e0Srsmaeda }
5621d4b38e0Srsmaeda 
5631d4b38e0Srsmaeda static int
5641d4b38e0Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5651d4b38e0Srsmaeda {
5661d4b38e0Srsmaeda 	char		**rlist;
5671d4b38e0Srsmaeda 	char		**full_rlist;
5681d4b38e0Srsmaeda 	int		idx;
5691d4b38e0Srsmaeda 	int		ridx;
5701d4b38e0Srsmaeda 	int		state;
5711d4b38e0Srsmaeda 	int		rv = 0;
5721d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
5731d4b38e0Srsmaeda 
5741d4b38e0Srsmaeda 	drd_dbg("drd_rcm_restore_cpu_notify...");
5751d4b38e0Srsmaeda 
5761d4b38e0Srsmaeda 	if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5771d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
5781d4b38e0Srsmaeda 		drd_dbg("  no CPUs in the failed state, nothing to do");
5791d4b38e0Srsmaeda 		return (0);
5801d4b38e0Srsmaeda 	}
5811d4b38e0Srsmaeda 
5821d4b38e0Srsmaeda 	/*
5831d4b38e0Srsmaeda 	 * Since the desired result of this operation is to
5841d4b38e0Srsmaeda 	 * restore resources to the online state, filter out
5851d4b38e0Srsmaeda 	 * the resources already in the online state before
5861d4b38e0Srsmaeda 	 * passing the list to RCM.
5871d4b38e0Srsmaeda 	 */
5881d4b38e0Srsmaeda 
5891d4b38e0Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
5901d4b38e0Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
5911d4b38e0Srsmaeda 	if (rlist == NULL) {
5921d4b38e0Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
5931d4b38e0Srsmaeda 		rv = -1;
5941d4b38e0Srsmaeda 		goto done;
5951d4b38e0Srsmaeda 	}
5961d4b38e0Srsmaeda 
5971d4b38e0Srsmaeda 	for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) {
5981d4b38e0Srsmaeda 		state = 0;
5991d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state);
6001d4b38e0Srsmaeda 		if (state != RCM_STATE_ONLINE) {
6011d4b38e0Srsmaeda 			rlist[ridx] = full_rlist[idx];
6021d4b38e0Srsmaeda 			ridx++;
6031d4b38e0Srsmaeda 		}
6041d4b38e0Srsmaeda 	}
6051d4b38e0Srsmaeda 
6061d4b38e0Srsmaeda 	/* check if everything got filtered out */
6071d4b38e0Srsmaeda 	if (ridx == 0) {
6081d4b38e0Srsmaeda 		drd_dbg("  all CPUs already online, nothing to do");
6091d4b38e0Srsmaeda 		goto done;
6101d4b38e0Srsmaeda 	}
6111d4b38e0Srsmaeda 
6121d4b38e0Srsmaeda 	rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
6131d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
6141d4b38e0Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
6151d4b38e0Srsmaeda 		rcm_free_info(rinfo);
6161d4b38e0Srsmaeda 		rv = -1;
6171d4b38e0Srsmaeda 	}
6181d4b38e0Srsmaeda 
6191d4b38e0Srsmaeda done:
6201d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(full_rlist);
6211d4b38e0Srsmaeda 	s_free(rlist);
6221d4b38e0Srsmaeda 
6231d4b38e0Srsmaeda 	return (rv);
6241d4b38e0Srsmaeda }
6251d4b38e0Srsmaeda 
6261d4b38e0Srsmaeda static int
6271d4b38e0Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
6281d4b38e0Srsmaeda {
6291d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
6301d4b38e0Srsmaeda 	int		rv = -1;
6311d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
6321d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
6331d4b38e0Srsmaeda 	int		oldncpus = 0;
6341d4b38e0Srsmaeda 	int		newncpus = 0;
6351d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
6361d4b38e0Srsmaeda 	int		idx;
6371d4b38e0Srsmaeda 	int		cidx;
6381d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
6391d4b38e0Srsmaeda 
6401d4b38e0Srsmaeda 	drd_dbg("drd_rcm_del_cpu_notify...");
6411d4b38e0Srsmaeda 
6421d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
6431d4b38e0Srsmaeda 		drd_err("del_cpu_notify: cpu list empty");
6441d4b38e0Srsmaeda 		goto done;
6451d4b38e0Srsmaeda 	}
6461d4b38e0Srsmaeda 
6471d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
6481d4b38e0Srsmaeda 
6491d4b38e0Srsmaeda 	/*
6501d4b38e0Srsmaeda 	 * Filter out the CPUs that could not be unconfigured.
6511d4b38e0Srsmaeda 	 */
6521d4b38e0Srsmaeda 	for (idx = 0, cidx = 0; idx < nrsrc; idx++) {
6531d4b38e0Srsmaeda 		if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
6541d4b38e0Srsmaeda 			continue;
6551d4b38e0Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
6561d4b38e0Srsmaeda 		cpus[cidx] = rsrcs[idx].res_cpu_id;
6571d4b38e0Srsmaeda 		cidx++;
6581d4b38e0Srsmaeda 	}
6591d4b38e0Srsmaeda 
6601d4b38e0Srsmaeda 	drd_dbg("  ncpus = %d", cidx);
6611d4b38e0Srsmaeda 
6621d4b38e0Srsmaeda 	/* nothing to do */
6631d4b38e0Srsmaeda 	if (cidx == 0) {
6641d4b38e0Srsmaeda 		rv = 0;
6651d4b38e0Srsmaeda 		goto done;
6661d4b38e0Srsmaeda 	}
6671d4b38e0Srsmaeda 
6681d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
6691d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
6701d4b38e0Srsmaeda 		goto done;
6711d4b38e0Srsmaeda 	}
6721d4b38e0Srsmaeda 
6731d4b38e0Srsmaeda 	/*
6741d4b38e0Srsmaeda 	 * Removed CPU capacity, so newcpus is the current list
6751d4b38e0Srsmaeda 	 * of CPUs in the system.
6761d4b38e0Srsmaeda 	 */
6771d4b38e0Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1) {
6781d4b38e0Srsmaeda 		goto done;
6791d4b38e0Srsmaeda 	}
6801d4b38e0Srsmaeda 
6811d4b38e0Srsmaeda 	/*
6821d4b38e0Srsmaeda 	 * Since the operation removed CPU capacity, the old CPU
6831d4b38e0Srsmaeda 	 * list is the new CPU list with the CPUs involved in
6841d4b38e0Srsmaeda 	 * the operation added.
6851d4b38e0Srsmaeda 	 */
6861d4b38e0Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t));
6871d4b38e0Srsmaeda 	if (oldcpus == NULL) {
6881d4b38e0Srsmaeda 		goto done;
6891d4b38e0Srsmaeda 	}
6901d4b38e0Srsmaeda 
6911d4b38e0Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
6921d4b38e0Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, cidx))
6931d4b38e0Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
6941d4b38e0Srsmaeda 	}
6951d4b38e0Srsmaeda 
6961d4b38e0Srsmaeda 	for (idx = 0; idx < cidx; idx++) {
6971d4b38e0Srsmaeda 		oldcpus[oldncpus++] = cpus[idx];
6981d4b38e0Srsmaeda 	}
6991d4b38e0Srsmaeda 
7001d4b38e0Srsmaeda 	/* dump pre and post lists */
7011d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
7021d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
7031d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, cidx);
7041d4b38e0Srsmaeda 
7051d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
7061d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
7071d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
7081d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
7091d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
7101d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
7111d4b38e0Srsmaeda 		goto done;
7121d4b38e0Srsmaeda 	}
7131d4b38e0Srsmaeda 
7141d4b38e0Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
7151d4b38e0Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
7161d4b38e0Srsmaeda 
7171d4b38e0Srsmaeda done:
7181d4b38e0Srsmaeda 	s_nvfree(nvl);
7191d4b38e0Srsmaeda 	s_free(cpus);
7201d4b38e0Srsmaeda 	s_free(oldcpus);
7211d4b38e0Srsmaeda 	s_free(newcpus);
7221d4b38e0Srsmaeda 
7231d4b38e0Srsmaeda 	return (rv);
7241d4b38e0Srsmaeda }
7251d4b38e0Srsmaeda 
7261d4b38e0Srsmaeda /*
7271d4b38e0Srsmaeda  * Given a list of resource structures, create a list of CPU
7281d4b38e0Srsmaeda  * resource strings formatted as expected by RCM. Only resources
7291d4b38e0Srsmaeda  * that are in the state specified by the status argument are
7301d4b38e0Srsmaeda  * included in the resulting list.
7311d4b38e0Srsmaeda  */
7321d4b38e0Srsmaeda static char **
7331d4b38e0Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status)
7341d4b38e0Srsmaeda {
7351d4b38e0Srsmaeda 	char	rbuf[RCM_CPU_MAX_LEN];
7361d4b38e0Srsmaeda 	char	**rlist;
7371d4b38e0Srsmaeda 	int	idx;
7381d4b38e0Srsmaeda 	int	ridx;
7391d4b38e0Srsmaeda 
7401d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_init...");
7411d4b38e0Srsmaeda 
7421d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
7431d4b38e0Srsmaeda 		drd_dbg("cpu list is empty");
7441d4b38e0Srsmaeda 		return (NULL);
7451d4b38e0Srsmaeda 	}
7461d4b38e0Srsmaeda 
7471d4b38e0Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
7481d4b38e0Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
7491d4b38e0Srsmaeda 	if (rlist == NULL) {
7501d4b38e0Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
7511d4b38e0Srsmaeda 		return (NULL);
7521d4b38e0Srsmaeda 	}
7531d4b38e0Srsmaeda 
7541d4b38e0Srsmaeda 	for (idx = 0, ridx = 0; idx < nrsrc; idx++) {
7551d4b38e0Srsmaeda 
7561d4b38e0Srsmaeda 		drd_dbg("  checking cpu %d, status=%d, expected status=%d",
7571d4b38e0Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status, status);
7581d4b38e0Srsmaeda 
7591d4b38e0Srsmaeda 		/*
7601d4b38e0Srsmaeda 		 * Filter out the CPUs that are not in
7611d4b38e0Srsmaeda 		 * the requested state.
7621d4b38e0Srsmaeda 		 */
7631d4b38e0Srsmaeda 		if (rsrcs[idx].status != status)
7641d4b38e0Srsmaeda 			continue;
7651d4b38e0Srsmaeda 
7661d4b38e0Srsmaeda 		/* generate the resource string */
7671d4b38e0Srsmaeda 		(void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id);
7681d4b38e0Srsmaeda 
7691d4b38e0Srsmaeda 		rlist[ridx] = strdup(rbuf);
7701d4b38e0Srsmaeda 		if (rlist[ridx] == NULL) {
7711d4b38e0Srsmaeda 			drd_err("strdup failed: %s", strerror(errno));
7721d4b38e0Srsmaeda 			drd_rcm_cpu_rlist_fini(rlist);
7731d4b38e0Srsmaeda 			return (NULL);
7741d4b38e0Srsmaeda 		}
7751d4b38e0Srsmaeda 
7761d4b38e0Srsmaeda 		ridx++;
7771d4b38e0Srsmaeda 	}
7781d4b38e0Srsmaeda 
7791d4b38e0Srsmaeda 	/* cleanup if the list is empty */
7801d4b38e0Srsmaeda 	if (ridx == 0) {
7811d4b38e0Srsmaeda 		s_free(rlist);
7821d4b38e0Srsmaeda 	}
7831d4b38e0Srsmaeda 
7841d4b38e0Srsmaeda 	drd_dbg("final rlist:");
7851d4b38e0Srsmaeda 	dump_cpu_rlist(rlist);
7861d4b38e0Srsmaeda 
7871d4b38e0Srsmaeda 	return (rlist);
7881d4b38e0Srsmaeda }
7891d4b38e0Srsmaeda 
7901d4b38e0Srsmaeda static void
7911d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist)
7921d4b38e0Srsmaeda {
7931d4b38e0Srsmaeda 	int idx;
7941d4b38e0Srsmaeda 
7951d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_fini...");
7961d4b38e0Srsmaeda 
7971d4b38e0Srsmaeda 	dump_cpu_rlist(rlist);
7981d4b38e0Srsmaeda 
7991d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
8001d4b38e0Srsmaeda 		s_free(rlist[idx]);
8011d4b38e0Srsmaeda 	}
8021d4b38e0Srsmaeda 
8031d4b38e0Srsmaeda 	s_free(rlist);
8041d4b38e0Srsmaeda }
8051d4b38e0Srsmaeda 
8061d4b38e0Srsmaeda /*
8071d4b38e0Srsmaeda  * Convert an RCM CPU resource string into a numerical cpuid.
8081d4b38e0Srsmaeda  * Assumes the resource string has the form: "SUNW_cpu/cpu<C>"
8091d4b38e0Srsmaeda  * where "<C>" is the numerical cpuid of interest.
8101d4b38e0Srsmaeda  */
8111d4b38e0Srsmaeda static cpuid_t
8121d4b38e0Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc)
8131d4b38e0Srsmaeda {
8141d4b38e0Srsmaeda 	char	*cpuid_off;
8151d4b38e0Srsmaeda 	cpuid_t	cpuid;
8161d4b38e0Srsmaeda 
8171d4b38e0Srsmaeda 	/*
8181d4b38e0Srsmaeda 	 * Search for the last occurrance of 'u' in the
8191d4b38e0Srsmaeda 	 * expected RCM resource string "SUNW_cpu/cpu<C>".
8201d4b38e0Srsmaeda 	 * This will give a pointer to the cpuid portion.
8211d4b38e0Srsmaeda 	 */
8221d4b38e0Srsmaeda 	cpuid_off = strrchr(rsrc, 'u');
8231d4b38e0Srsmaeda 	cpuid_off++;
8241d4b38e0Srsmaeda 
8251d4b38e0Srsmaeda 	cpuid = atoi(cpuid_off);
8261d4b38e0Srsmaeda 
8271d4b38e0Srsmaeda 	return (cpuid);
8281d4b38e0Srsmaeda }
8291d4b38e0Srsmaeda 
8301d4b38e0Srsmaeda /*
8311d4b38e0Srsmaeda  * Given an RCM CPU resource string, return a pointer to the
8321d4b38e0Srsmaeda  * corresponding resource structure from the given resource list.
8331d4b38e0Srsmaeda  * NULL is returned if no matching resource structure can be
8341d4b38e0Srsmaeda  * found.
8351d4b38e0Srsmaeda  */
8361d4b38e0Srsmaeda static drctl_rsrc_t *
8371d4b38e0Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc)
8381d4b38e0Srsmaeda {
8391d4b38e0Srsmaeda 	cpuid_t	cpuid;
8401d4b38e0Srsmaeda 	int	idx;
8411d4b38e0Srsmaeda 
8421d4b38e0Srsmaeda 	cpuid = cpu_rsrcstr_to_cpuid(rsrcstr);
8431d4b38e0Srsmaeda 
8441d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
8451d4b38e0Srsmaeda 		if (rsrcs[idx].res_cpu_id == cpuid)
8461d4b38e0Srsmaeda 			return (&rsrcs[idx]);
8471d4b38e0Srsmaeda 	}
8481d4b38e0Srsmaeda 
8491d4b38e0Srsmaeda 	return (NULL);
8501d4b38e0Srsmaeda }
8511d4b38e0Srsmaeda 
8521d4b38e0Srsmaeda static int
8531d4b38e0Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids)
8541d4b38e0Srsmaeda {
8551d4b38e0Srsmaeda 	int		ncpu = 0;
8561d4b38e0Srsmaeda 	int		maxncpu;
8571d4b38e0Srsmaeda 	kstat_t		*ksp;
8581d4b38e0Srsmaeda 	kstat_ctl_t	*kc = NULL;
8591d4b38e0Srsmaeda 	cpuid_t		*cp;
8601d4b38e0Srsmaeda 
8611d4b38e0Srsmaeda 	drd_dbg("get_sys_cpuids...");
8621d4b38e0Srsmaeda 
8631d4b38e0Srsmaeda 	if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1)
8641d4b38e0Srsmaeda 		return (-1);
8651d4b38e0Srsmaeda 
8661d4b38e0Srsmaeda 	if ((kc = kstat_open()) == NULL)
8671d4b38e0Srsmaeda 		return (-1);
8681d4b38e0Srsmaeda 
8691d4b38e0Srsmaeda 	if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
8701d4b38e0Srsmaeda 		(void) kstat_close(kc);
8711d4b38e0Srsmaeda 		return (-1);
8721d4b38e0Srsmaeda 	}
8731d4b38e0Srsmaeda 
8741d4b38e0Srsmaeda 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
8751d4b38e0Srsmaeda 		if (strcmp(ksp->ks_module, "cpu_info") == 0)
8761d4b38e0Srsmaeda 			cp[ncpu++] = ksp->ks_instance;
8771d4b38e0Srsmaeda 	}
8781d4b38e0Srsmaeda 
8791d4b38e0Srsmaeda 	dump_cpu_list("syscpus: ", cp, ncpu);
8801d4b38e0Srsmaeda 
8811d4b38e0Srsmaeda 	(void) kstat_close(kc);
8821d4b38e0Srsmaeda 
8831d4b38e0Srsmaeda 	*cpuids = cp;
8841d4b38e0Srsmaeda 	*ncpuids = ncpu;
8851d4b38e0Srsmaeda 
8861d4b38e0Srsmaeda 	return (0);
8871d4b38e0Srsmaeda }
8881d4b38e0Srsmaeda 
8891d4b38e0Srsmaeda static boolean_t
8901d4b38e0Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len)
8911d4b38e0Srsmaeda {
8921d4b38e0Srsmaeda 	int idx;
8931d4b38e0Srsmaeda 
8941d4b38e0Srsmaeda 	if (list == NULL)
8951d4b38e0Srsmaeda 		return (B_FALSE);
8961d4b38e0Srsmaeda 
8971d4b38e0Srsmaeda 	for (idx = 0; idx < len; idx++) {
8981d4b38e0Srsmaeda 		if (list[idx] == cpuid)
8991d4b38e0Srsmaeda 			return (B_TRUE);
9001d4b38e0Srsmaeda 	}
9011d4b38e0Srsmaeda 
9021d4b38e0Srsmaeda 	return (B_FALSE);
9031d4b38e0Srsmaeda }
9041d4b38e0Srsmaeda 
9051d4b38e0Srsmaeda #define	CPUIDS_PER_LINE		16
9061d4b38e0Srsmaeda #define	LINEWIDTH		(2 * (CPUIDS_PER_LINE * 4))
9071d4b38e0Srsmaeda 
9081d4b38e0Srsmaeda static void
9091d4b38e0Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids)
9101d4b38e0Srsmaeda {
9111d4b38e0Srsmaeda 	char	line[LINEWIDTH];
9121d4b38e0Srsmaeda 	char	*curr;
9131d4b38e0Srsmaeda 	int	i, j;
9141d4b38e0Srsmaeda 
9151d4b38e0Srsmaeda 	/* return if not debugging */
9161d4b38e0Srsmaeda 	if (drd_debug == 0)
9171d4b38e0Srsmaeda 		return;
9181d4b38e0Srsmaeda 
9191d4b38e0Srsmaeda 	/* print just the prefix if CPU list is empty */
9201d4b38e0Srsmaeda 	if (ncpuids == 0) {
9211d4b38e0Srsmaeda 		if (prefix)
9221d4b38e0Srsmaeda 			drd_dbg("%s", prefix);
9231d4b38e0Srsmaeda 		return;
9241d4b38e0Srsmaeda 	}
9251d4b38e0Srsmaeda 
9261d4b38e0Srsmaeda 	for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
9271d4b38e0Srsmaeda 
9281d4b38e0Srsmaeda 		bzero(line, LINEWIDTH);
9291d4b38e0Srsmaeda 		curr = line;
9301d4b38e0Srsmaeda 
9311d4b38e0Srsmaeda 		/* start with the prefix */
9321d4b38e0Srsmaeda 		(void) sprintf(curr, "%s", (prefix) ? prefix : "");
9331d4b38e0Srsmaeda 		curr = line + strlen(line);
9341d4b38e0Srsmaeda 
9351d4b38e0Srsmaeda 		/* format the CPUs for this line */
9361d4b38e0Srsmaeda 		for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
9371d4b38e0Srsmaeda 			(void) sprintf(curr, "%3d ", cpuids[i + j]);
9381d4b38e0Srsmaeda 			curr = line + strlen(line);
9391d4b38e0Srsmaeda 		}
9401d4b38e0Srsmaeda 
9411d4b38e0Srsmaeda 		drd_dbg("%s", line);
9421d4b38e0Srsmaeda 	}
9431d4b38e0Srsmaeda }
9441d4b38e0Srsmaeda 
9451d4b38e0Srsmaeda static void
9461d4b38e0Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
9471d4b38e0Srsmaeda {
9481d4b38e0Srsmaeda 	int	idx;
9491d4b38e0Srsmaeda 	char	*errstr;
9501d4b38e0Srsmaeda 
9511d4b38e0Srsmaeda 	/* just return if not debugging */
9521d4b38e0Srsmaeda 	if (drd_debug == 0)
9531d4b38e0Srsmaeda 		return;
9541d4b38e0Srsmaeda 
9551d4b38e0Srsmaeda 	if (prefix)
9561d4b38e0Srsmaeda 		drd_dbg("%s", prefix);
9571d4b38e0Srsmaeda 
9581d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
9591d4b38e0Srsmaeda 
9601d4b38e0Srsmaeda 		/* get a pointer to the error string */
9611d4b38e0Srsmaeda 		errstr = (char *)(uintptr_t)rsrcs[idx].offset;
9621d4b38e0Srsmaeda 
9631d4b38e0Srsmaeda 		drd_dbg("  cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx,
9641d4b38e0Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status,
9651d4b38e0Srsmaeda 		    (errstr != NULL) ? errstr : "");
9661d4b38e0Srsmaeda 	}
9671d4b38e0Srsmaeda }
9681d4b38e0Srsmaeda 
9691d4b38e0Srsmaeda static void
9701d4b38e0Srsmaeda dump_cpu_rlist(char **rlist)
9711d4b38e0Srsmaeda {
9721d4b38e0Srsmaeda 	int	idx;
9731d4b38e0Srsmaeda 	int	state;
9741d4b38e0Srsmaeda 
9751d4b38e0Srsmaeda 	static char *rcm_state_str[] = {
9761d4b38e0Srsmaeda 		"UNKNOWN",		"ONLINE",		"ONLINING",
9771d4b38e0Srsmaeda 		"OFFLINE_FAIL",		"OFFLINING",		"OFFLINE",
9781d4b38e0Srsmaeda 		"REMOVING",		"INVALID_7",		"INVALID_8",
9791d4b38e0Srsmaeda 		"INVALID_9",		"RESUMING",		"SUSPEND_FAIL",
9801d4b38e0Srsmaeda 		"SUSPENDING",		"SUSPEND",		"REMOVE",
9811d4b38e0Srsmaeda 		"OFFLINE_QUERYING",	"OFFLINE_QUERY_FAIL",	"OFFLINE_QUERY",
9821d4b38e0Srsmaeda 		"SUSPEND_QUERYING",	"SUSPEND_QUERY_FAIL",	"SUSPEND_QUERY"
9831d4b38e0Srsmaeda 	};
9841d4b38e0Srsmaeda 
9851d4b38e0Srsmaeda 	/* just return if not debugging */
9861d4b38e0Srsmaeda 	if (drd_debug == 0)
9871d4b38e0Srsmaeda 		return;
9881d4b38e0Srsmaeda 
9891d4b38e0Srsmaeda 	if (rlist == NULL) {
9901d4b38e0Srsmaeda 		drd_dbg("  empty rlist");
9911d4b38e0Srsmaeda 		return;
9921d4b38e0Srsmaeda 	}
9931d4b38e0Srsmaeda 
9941d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
9951d4b38e0Srsmaeda 		state = 0;
9961d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
9971d4b38e0Srsmaeda 		drd_dbg("  rlist[%d]: rsrc=%s, state=%-2d (%s)", idx,
9981d4b38e0Srsmaeda 		    rlist[idx], state, rcm_state_str[state]);
9991d4b38e0Srsmaeda 	}
10001d4b38e0Srsmaeda }
1001*8fea755aSjm22469 
1002*8fea755aSjm22469 static int
1003*8fea755aSjm22469 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc)
1004*8fea755aSjm22469 {
1005*8fea755aSjm22469 	drd_dbg("drd_rcm_io_config_request...");
1006*8fea755aSjm22469 
1007*8fea755aSjm22469 	if (nrsrc != 1) {
1008*8fea755aSjm22469 		drd_dbg("drd_rcm_cpu_config_request: only 1 resource "
1009*8fea755aSjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
1010*8fea755aSjm22469 		rsrc->status = DRCTL_STATUS_DENY;
1011*8fea755aSjm22469 
1012*8fea755aSjm22469 		return (-1);
1013*8fea755aSjm22469 	}
1014*8fea755aSjm22469 
1015*8fea755aSjm22469 	/*
1016*8fea755aSjm22469 	 * There is no RCM operation to request the addition
1017*8fea755aSjm22469 	 * of resources.  So, by definition, the operation for
1018*8fea755aSjm22469 	 * the current resource is allowed.
1019*8fea755aSjm22469 	 */
1020*8fea755aSjm22469 	rsrc->status = DRCTL_STATUS_ALLOW;
1021*8fea755aSjm22469 
1022*8fea755aSjm22469 	return (0);
1023*8fea755aSjm22469 }
1024*8fea755aSjm22469 
1025*8fea755aSjm22469 /*ARGSUSED*/
1026*8fea755aSjm22469 static int
1027*8fea755aSjm22469 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1028*8fea755aSjm22469 {
1029*8fea755aSjm22469 	drd_dbg("drd_rcm_io_config_notify...");
1030*8fea755aSjm22469 
1031*8fea755aSjm22469 	if (nrsrc != 1) {
1032*8fea755aSjm22469 		drd_dbg("drd_rcm_cpu_config_notify: only 1 resource "
1033*8fea755aSjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
1034*8fea755aSjm22469 
1035*8fea755aSjm22469 		return (-1);
1036*8fea755aSjm22469 	}
1037*8fea755aSjm22469 
1038*8fea755aSjm22469 	return (0);
1039*8fea755aSjm22469 }
1040*8fea755aSjm22469 
1041*8fea755aSjm22469 
1042*8fea755aSjm22469 static int
1043*8fea755aSjm22469 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc)
1044*8fea755aSjm22469 {
1045*8fea755aSjm22469 	int		rv;
1046*8fea755aSjm22469 	char		*dev = rsrc->res_dev_path;
1047*8fea755aSjm22469 	rcm_info_t	*rinfo = NULL;
1048*8fea755aSjm22469 
1049*8fea755aSjm22469 	if (nrsrc != 1) {
1050*8fea755aSjm22469 		drd_dbg("drd_io_unconfig_request: only 1 resource "
1051*8fea755aSjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
1052*8fea755aSjm22469 		rsrc->status = DRCTL_STATUS_DENY;
1053*8fea755aSjm22469 
1054*8fea755aSjm22469 		return (-1);
1055*8fea755aSjm22469 	}
1056*8fea755aSjm22469 
1057*8fea755aSjm22469 	if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS)
1058*8fea755aSjm22469 		rsrc->status = DRCTL_STATUS_ALLOW;
1059*8fea755aSjm22469 	else {
1060*8fea755aSjm22469 		rcm_notify_online(rcm_hdl, dev, 0, NULL);
1061*8fea755aSjm22469 		rsrc->status = DRCTL_STATUS_DENY;
1062*8fea755aSjm22469 		rsrc->offset = (uintptr_t)rcm_info_table(rinfo);
1063*8fea755aSjm22469 
1064*8fea755aSjm22469 	}
1065*8fea755aSjm22469 
1066*8fea755aSjm22469 	rcm_free_info(rinfo);
1067*8fea755aSjm22469 	drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv);
1068*8fea755aSjm22469 
1069*8fea755aSjm22469 	return (rv);
1070*8fea755aSjm22469 }
1071*8fea755aSjm22469 
1072*8fea755aSjm22469 static int
1073*8fea755aSjm22469 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc)
1074*8fea755aSjm22469 {
1075*8fea755aSjm22469 	drd_dbg("drd_rcm_io_unconfig_notify...");
1076*8fea755aSjm22469 
1077*8fea755aSjm22469 	if (nrsrc != 1) {
1078*8fea755aSjm22469 		drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource "
1079*8fea755aSjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
1080*8fea755aSjm22469 
1081*8fea755aSjm22469 		return (-1);
1082*8fea755aSjm22469 	}
1083*8fea755aSjm22469 
1084*8fea755aSjm22469 	return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL));
1085*8fea755aSjm22469 }
1086*8fea755aSjm22469 
1087*8fea755aSjm22469 #define	MAX_FORMAT	80
1088*8fea755aSjm22469 
1089*8fea755aSjm22469 /*
1090*8fea755aSjm22469  * Convert rcm_info_t data into a printable table.
1091*8fea755aSjm22469  */
1092*8fea755aSjm22469 static char *
1093*8fea755aSjm22469 rcm_info_table(rcm_info_t *rinfo)
1094*8fea755aSjm22469 {
1095*8fea755aSjm22469 	int		i;
1096*8fea755aSjm22469 	size_t		w;
1097*8fea755aSjm22469 	size_t		width = 0;
1098*8fea755aSjm22469 	size_t		w_rsrc = 0;
1099*8fea755aSjm22469 	size_t		w_info = 0;
1100*8fea755aSjm22469 	size_t		table_size = 0;
1101*8fea755aSjm22469 	uint_t		tuples = 0;
1102*8fea755aSjm22469 	rcm_info_tuple_t *tuple = NULL;
1103*8fea755aSjm22469 	char		*rsrc;
1104*8fea755aSjm22469 	char		*info;
1105*8fea755aSjm22469 	char		*table;
1106*8fea755aSjm22469 	static char	format[MAX_FORMAT];
1107*8fea755aSjm22469 	const char	*infostr;
1108*8fea755aSjm22469 
1109*8fea755aSjm22469 	/* Protect against invalid arguments */
1110*8fea755aSjm22469 	if (rinfo == NULL)
1111*8fea755aSjm22469 		return (NULL);
1112*8fea755aSjm22469 
1113*8fea755aSjm22469 	/* Set localized table header strings */
1114*8fea755aSjm22469 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
1115*8fea755aSjm22469 	info = dgettext(TEXT_DOMAIN, "Information");
1116*8fea755aSjm22469 
1117*8fea755aSjm22469 	/* A first pass, to size up the RCM information */
1118*8fea755aSjm22469 	while (tuple = rcm_info_next(rinfo, tuple)) {
1119*8fea755aSjm22469 		if ((infostr = rcm_info_info(tuple)) != NULL) {
1120*8fea755aSjm22469 			tuples++;
1121*8fea755aSjm22469 			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
1122*8fea755aSjm22469 				w_rsrc = w;
1123*8fea755aSjm22469 			if ((w = strlen(infostr)) > w_info)
1124*8fea755aSjm22469 				w_info = w;
1125*8fea755aSjm22469 		}
1126*8fea755aSjm22469 	}
1127*8fea755aSjm22469 
1128*8fea755aSjm22469 	/* If nothing was sized up above, stop early */
1129*8fea755aSjm22469 	if (tuples == 0)
1130*8fea755aSjm22469 		return (NULL);
1131*8fea755aSjm22469 
1132*8fea755aSjm22469 	/* Adjust column widths for column headings */
1133*8fea755aSjm22469 	if ((w = strlen(rsrc)) > w_rsrc)
1134*8fea755aSjm22469 		w_rsrc = w;
1135*8fea755aSjm22469 	else if ((w_rsrc - w) % 2)
1136*8fea755aSjm22469 		w_rsrc++;
1137*8fea755aSjm22469 	if ((w = strlen(info)) > w_info)
1138*8fea755aSjm22469 		w_info = w;
1139*8fea755aSjm22469 	else if ((w_info - w) % 2)
1140*8fea755aSjm22469 		w_info++;
1141*8fea755aSjm22469 
1142*8fea755aSjm22469 	/*
1143*8fea755aSjm22469 	 * Compute the total line width of each line,
1144*8fea755aSjm22469 	 * accounting for intercolumn spacing.
1145*8fea755aSjm22469 	 */
1146*8fea755aSjm22469 	width = w_info + w_rsrc + 4;
1147*8fea755aSjm22469 
1148*8fea755aSjm22469 	/* Allocate space for the table */
1149*8fea755aSjm22469 	table_size = (2 + tuples) * (width + 1) + 2;
1150*8fea755aSjm22469 
1151*8fea755aSjm22469 	/* zero fill for the strcat() call below */
1152*8fea755aSjm22469 	table = calloc(table_size, sizeof (char));
1153*8fea755aSjm22469 	if (table == NULL)
1154*8fea755aSjm22469 		return (NULL);
1155*8fea755aSjm22469 
1156*8fea755aSjm22469 	/* Place a table header into the string */
1157*8fea755aSjm22469 
1158*8fea755aSjm22469 	/* The resource header */
1159*8fea755aSjm22469 	(void) strcat(table, "\n");
1160*8fea755aSjm22469 	w = strlen(rsrc);
1161*8fea755aSjm22469 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
1162*8fea755aSjm22469 		(void) strcat(table, " ");
1163*8fea755aSjm22469 	(void) strcat(table, rsrc);
1164*8fea755aSjm22469 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
1165*8fea755aSjm22469 		(void) strcat(table, " ");
1166*8fea755aSjm22469 
1167*8fea755aSjm22469 	/* The information header */
1168*8fea755aSjm22469 	(void) strcat(table, "  ");
1169*8fea755aSjm22469 	w = strlen(info);
1170*8fea755aSjm22469 	for (i = 0; i < ((w_info - w) / 2); i++)
1171*8fea755aSjm22469 		(void) strcat(table, " ");
1172*8fea755aSjm22469 	(void) strcat(table, info);
1173*8fea755aSjm22469 	for (i = 0; i < ((w_info - w) / 2); i++)
1174*8fea755aSjm22469 		(void) strcat(table, " ");
1175*8fea755aSjm22469 	/* Underline the headers */
1176*8fea755aSjm22469 	(void) strcat(table, "\n");
1177*8fea755aSjm22469 	for (i = 0; i < w_rsrc; i++)
1178*8fea755aSjm22469 		(void) strcat(table, "-");
1179*8fea755aSjm22469 	(void) strcat(table, "  ");
1180*8fea755aSjm22469 	for (i = 0; i < w_info; i++)
1181*8fea755aSjm22469 		(void) strcat(table, "-");
1182*8fea755aSjm22469 
1183*8fea755aSjm22469 	/* Construct the format string */
1184*8fea755aSjm22469 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
1185*8fea755aSjm22469 	    (int)w_rsrc, (int)w_info);
1186*8fea755aSjm22469 
1187*8fea755aSjm22469 	/* Add the tuples to the table string */
1188*8fea755aSjm22469 	tuple = NULL;
1189*8fea755aSjm22469 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
1190*8fea755aSjm22469 		if ((infostr = rcm_info_info(tuple)) != NULL) {
1191*8fea755aSjm22469 			(void) strcat(table, "\n");
1192*8fea755aSjm22469 			(void) sprintf(&((table)[strlen(table)]),
1193*8fea755aSjm22469 			    format, rcm_info_rsrc(tuple),
1194*8fea755aSjm22469 			    infostr);
1195*8fea755aSjm22469 		}
1196*8fea755aSjm22469 	}
1197*8fea755aSjm22469 	drd_dbg("rcm_info_table: %s\n", table);
1198*8fea755aSjm22469 
1199*8fea755aSjm22469 	return (table);
1200*8fea755aSjm22469 }
1201