xref: /onnv-gate/usr/src/cmd/drd/drd_rcm.c (revision 10106:b235491976d3)
12309Srsmaeda /*
22309Srsmaeda  * CDDL HEADER START
32309Srsmaeda  *
42309Srsmaeda  * The contents of this file are subject to the terms of the
52309Srsmaeda  * Common Development and Distribution License (the "License").
62309Srsmaeda  * You may not use this file except in compliance with the License.
72309Srsmaeda  *
82309Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92309Srsmaeda  * or http://www.opensolaris.org/os/licensing.
102309Srsmaeda  * See the License for the specific language governing permissions
112309Srsmaeda  * and limitations under the License.
122309Srsmaeda  *
132309Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
142309Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152309Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
162309Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
172309Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
182309Srsmaeda  *
192309Srsmaeda  * CDDL HEADER END
202309Srsmaeda  */
212309Srsmaeda 
222309Srsmaeda /*
23*10106SJason.Beloro@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242309Srsmaeda  * Use is subject to license terms.
252309Srsmaeda  */
262309Srsmaeda 
272309Srsmaeda /*
282309Srsmaeda  * RCM backend for the DR Daemon
292309Srsmaeda  */
302309Srsmaeda 
312309Srsmaeda #include <unistd.h>
322309Srsmaeda #include <strings.h>
332309Srsmaeda #include <errno.h>
342309Srsmaeda #include <kstat.h>
352309Srsmaeda #include <libnvpair.h>
362309Srsmaeda #include <librcm.h>
376441Sjm22469 #include <locale.h>
38*10106SJason.Beloro@Sun.COM #include <assert.h>
392309Srsmaeda 
402309Srsmaeda #include "drd.h"
412309Srsmaeda 
422309Srsmaeda /*
432309Srsmaeda  * RCM Backend Support
442309Srsmaeda  */
452309Srsmaeda static int drd_rcm_init(void);
462309Srsmaeda static int drd_rcm_fini(void);
472309Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
482309Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
492309Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
502309Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
516441Sjm22469 static int drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc);
526441Sjm22469 static int drd_rcm_io_config_notify(drctl_rsrc_t *rsrc, int nrsrc);
536441Sjm22469 static int drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc);
546441Sjm22469 static int drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc);
55*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
56*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
57*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
58*10106SJason.Beloro@Sun.COM static int drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
592309Srsmaeda 
602309Srsmaeda drd_backend_t drd_rcm_backend = {
612309Srsmaeda 	drd_rcm_init,			/* init */
622309Srsmaeda 	drd_rcm_fini,			/* fini */
632309Srsmaeda 	drd_rcm_cpu_config_request,	/* cpu_config_request */
642309Srsmaeda 	drd_rcm_cpu_config_notify,	/* cpu_config_notify */
652309Srsmaeda 	drd_rcm_cpu_unconfig_request,	/* cpu_unconfig_request */
666441Sjm22469 	drd_rcm_cpu_unconfig_notify,	/* cpu_unconfig_notify */
676441Sjm22469 	drd_rcm_io_config_request,	/* io_config_request */
686441Sjm22469 	drd_rcm_io_config_notify,	/* io_config_notify */
696441Sjm22469 	drd_rcm_io_unconfig_request,	/* io_unconfig_request */
70*10106SJason.Beloro@Sun.COM 	drd_rcm_io_unconfig_notify,	/* io_unconfig_notify */
71*10106SJason.Beloro@Sun.COM 	drd_rcm_mem_config_request,	/* mem_config_request */
72*10106SJason.Beloro@Sun.COM 	drd_rcm_mem_config_notify,	/* mem_config_notify */
73*10106SJason.Beloro@Sun.COM 	drd_rcm_mem_unconfig_request,	/* mem_unconfig_request */
74*10106SJason.Beloro@Sun.COM 	drd_rcm_mem_unconfig_notify	/* mem_unconfig_notify */
752309Srsmaeda };
762309Srsmaeda 
77*10106SJason.Beloro@Sun.COM typedef int (*rcm_op_t)(rcm_handle_t *, char *, uint_t, nvlist_t *,
78*10106SJason.Beloro@Sun.COM 	rcm_info_t **);
79*10106SJason.Beloro@Sun.COM 
80*10106SJason.Beloro@Sun.COM #define	RCM_MEM_ALL		"SUNW_memory"
812309Srsmaeda #define	RCM_CPU_ALL		"SUNW_cpu"
822309Srsmaeda #define	RCM_CPU			RCM_CPU_ALL"/cpu"
832309Srsmaeda #define	RCM_CPU_MAX_LEN		(32)
842309Srsmaeda 
852309Srsmaeda /* global RCM handle used in all RCM operations */
862309Srsmaeda static rcm_handle_t *rcm_hdl;
872309Srsmaeda 
882309Srsmaeda /* functions that call into RCM */
892309Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
902309Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
912309Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
922309Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
932309Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
942309Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
952309Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
962309Srsmaeda 
972309Srsmaeda /* utility functions */
982309Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status);
992309Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist);
1002309Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int);
1012309Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids);
1022309Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len);
1036441Sjm22469 static char *rcm_info_table(rcm_info_t *rinfo);
1042309Srsmaeda 
1052309Srsmaeda /* debugging utility functions */
1062309Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids);
1072309Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc);
1082309Srsmaeda static void dump_cpu_rlist(char **rlist);
1092309Srsmaeda 
1102309Srsmaeda static int
drd_rcm_init(void)1112309Srsmaeda drd_rcm_init(void)
1122309Srsmaeda {
1132309Srsmaeda 	int	rv;
1142309Srsmaeda 
1152309Srsmaeda 	drd_dbg("drd_rcm_init...");
1162309Srsmaeda 
1172309Srsmaeda 	rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl);
1182309Srsmaeda 	if (rv == RCM_FAILURE) {
1192309Srsmaeda 		drd_err("unable to allocate RCM handle: %s", strerror(errno));
1202309Srsmaeda 		return (-1);
1212309Srsmaeda 	}
1222309Srsmaeda 
1232309Srsmaeda 	return (0);
1242309Srsmaeda }
1252309Srsmaeda 
1262309Srsmaeda static int
drd_rcm_fini(void)1272309Srsmaeda drd_rcm_fini(void)
1282309Srsmaeda {
1292309Srsmaeda 	drd_dbg("drd_rcm_fini...");
1302309Srsmaeda 
1312309Srsmaeda 	if (rcm_hdl != NULL)
1322309Srsmaeda 		rcm_free_handle(rcm_hdl);
1332309Srsmaeda 
1342309Srsmaeda 	return (0);
1352309Srsmaeda }
1362309Srsmaeda 
1372309Srsmaeda static int
drd_rcm_cpu_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1382309Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1392309Srsmaeda {
1402309Srsmaeda 	int	idx;
1412309Srsmaeda 
1422309Srsmaeda 	drd_dbg("drd_rcm_cpu_config_request...");
1432309Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1442309Srsmaeda 
1452309Srsmaeda 	/*
1462309Srsmaeda 	 * There is no RCM operation to request the addition
1476441Sjm22469 	 * of resources.  So, by definition, the operation for
1482309Srsmaeda 	 * all the CPUs is allowed.
1492309Srsmaeda 	 */
1502309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++)
1512309Srsmaeda 		rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1522309Srsmaeda 
1532309Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1542309Srsmaeda 
1552309Srsmaeda 	return (0);
1562309Srsmaeda }
1572309Srsmaeda 
1582309Srsmaeda static int
drd_rcm_cpu_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1592309Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1602309Srsmaeda {
1612309Srsmaeda 	int	rv = 0;
1622309Srsmaeda 
1632309Srsmaeda 	drd_dbg("drd_rcm_cpu_config_notify...");
1642309Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1652309Srsmaeda 
1662309Srsmaeda 	/* notify RCM about the newly added CPUs */
1672309Srsmaeda 	if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) {
1682309Srsmaeda 		rv = -1;
1692309Srsmaeda 		goto done;
1702309Srsmaeda 	}
1712309Srsmaeda 
1722309Srsmaeda 	/* notify RCM about the increased CPU capacity */
1732309Srsmaeda 	if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) {
1742309Srsmaeda 		rv = -1;
1752309Srsmaeda 	}
1762309Srsmaeda 
1772309Srsmaeda done:
1782309Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
1792309Srsmaeda 
1802309Srsmaeda 	return (rv);
1812309Srsmaeda }
1822309Srsmaeda 
1832309Srsmaeda static int
drd_rcm_cpu_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1842309Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1852309Srsmaeda {
1862309Srsmaeda 	int	rv = 0;
1872309Srsmaeda 	int	idx;
1882309Srsmaeda 
1892309Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_request...");
1902309Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
1912309Srsmaeda 
1922309Srsmaeda 	/* contact RCM to request a decrease in CPU capacity */
1932309Srsmaeda 	if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) {
1942309Srsmaeda 		rv = -1;
1952309Srsmaeda 		goto done;
1962309Srsmaeda 	}
1972309Srsmaeda 
1982309Srsmaeda 	/* contact RCM to request the removal of CPUs */
1992309Srsmaeda 	if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) {
2002309Srsmaeda 		rv = -1;
2012309Srsmaeda 		goto done;
2022309Srsmaeda 	}
2032309Srsmaeda 
2042309Srsmaeda done:
2052309Srsmaeda 	/*
2062309Srsmaeda 	 * If any errors occurred, the status field for
2072309Srsmaeda 	 * a CPU may still be in the INIT state. Set the
2082309Srsmaeda 	 * status for any such CPU to DENY to ensure it
2092309Srsmaeda 	 * gets processed properly.
2102309Srsmaeda 	 */
2112309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
2122309Srsmaeda 		if (rsrcs[idx].status == DRCTL_STATUS_INIT)
2132309Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
2142309Srsmaeda 	}
2152309Srsmaeda 
2162309Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2172309Srsmaeda 
2182309Srsmaeda 	return (rv);
2192309Srsmaeda }
2202309Srsmaeda 
2212309Srsmaeda static int
drd_rcm_cpu_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)2222309Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2232309Srsmaeda {
2242309Srsmaeda 	int	rv = 0;
2252309Srsmaeda 
2262309Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_notify...");
2272309Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
2282309Srsmaeda 
2292309Srsmaeda 	/*
2302309Srsmaeda 	 * Notify RCM about the CPUs that were removed.
2312309Srsmaeda 	 * Failures are ignored so that CPUs that could
2322309Srsmaeda 	 * not be unconfigured can be processed by RCM.
2332309Srsmaeda 	 */
2342309Srsmaeda 	(void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc);
2352309Srsmaeda 
2362309Srsmaeda 	/*
2372309Srsmaeda 	 * Notify RCM about any CPUs that did not make it
2382309Srsmaeda 	 * in to the unconfigured state.
2392309Srsmaeda 	 */
2402309Srsmaeda 	if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) {
2412309Srsmaeda 		rv = -1;
2422309Srsmaeda 		goto done;
2432309Srsmaeda 	}
2442309Srsmaeda 
2452309Srsmaeda 	/* notify RCM about the decreased CPU capacity */
2462309Srsmaeda 	if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) {
2472309Srsmaeda 		rv = -1;
2482309Srsmaeda 	}
2492309Srsmaeda 
2502309Srsmaeda done:
2512309Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
2522309Srsmaeda 
2532309Srsmaeda 	return (rv);
2542309Srsmaeda }
2552309Srsmaeda 
2562309Srsmaeda static int
drd_rcm_online_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2572309Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2582309Srsmaeda {
2592309Srsmaeda 	char		**rlist;
2602309Srsmaeda 	int		rv = 0;
2612309Srsmaeda 	rcm_info_t	*rinfo;
2622309Srsmaeda 
2632309Srsmaeda 	drd_dbg("drd_rcm_online_cpu_notify...");
2642309Srsmaeda 
2652309Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
2662309Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
2672309Srsmaeda 		drd_dbg("  no CPUs were successfully added, nothing to do");
2682309Srsmaeda 		return (0);
2692309Srsmaeda 	}
2702309Srsmaeda 
2712309Srsmaeda 	rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
2722309Srsmaeda 	if (rv != RCM_SUCCESS) {
2732309Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
2742309Srsmaeda 		rcm_free_info(rinfo);
2752309Srsmaeda 		rv = -1;
2762309Srsmaeda 	}
2772309Srsmaeda 
2782309Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
2792309Srsmaeda 
2802309Srsmaeda 	return (rv);
2812309Srsmaeda }
2822309Srsmaeda 
2832309Srsmaeda static int
drd_rcm_add_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)2842309Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
2852309Srsmaeda {
2862309Srsmaeda 	cpuid_t		*cpus = NULL;
2872309Srsmaeda 	int		ncpus;
2882309Srsmaeda 	int		rv = -1;
2892309Srsmaeda 	cpuid_t		*oldcpus = NULL;
2902309Srsmaeda 	cpuid_t		*newcpus = NULL;
2912309Srsmaeda 	int		oldncpus = 0;
2922309Srsmaeda 	int		newncpus = 0;
2932309Srsmaeda 	nvlist_t	*nvl = NULL;
2942309Srsmaeda 	int		idx;
2952309Srsmaeda 	rcm_info_t	*rinfo;
2962309Srsmaeda 
2972309Srsmaeda 	drd_dbg("drd_rcm_add_cpu_notify...");
2982309Srsmaeda 
2992309Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
3002309Srsmaeda 		drd_err("add_cpu_notify: cpu list empty");
3012309Srsmaeda 		goto done;
3022309Srsmaeda 	}
3032309Srsmaeda 
3042309Srsmaeda 	ncpus = nrsrc;
3052309Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3062309Srsmaeda 
3072309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
3082309Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
3092309Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
3102309Srsmaeda 	}
3112309Srsmaeda 
3122309Srsmaeda 	/* allocate an nvlist for the RCM call */
3132309Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3142309Srsmaeda 		goto done;
3152309Srsmaeda 
3162309Srsmaeda 	/*
3172309Srsmaeda 	 * Added CPU capacity, so newcpus is the current list
3182309Srsmaeda 	 * of CPUs in the system.
3192309Srsmaeda 	 */
3202309Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1)
3212309Srsmaeda 		goto done;
3222309Srsmaeda 
3232309Srsmaeda 	/*
3242309Srsmaeda 	 * Since the operation added CPU capacity, the old CPU
3252309Srsmaeda 	 * list is the new CPU list with the CPUs involved in
3262309Srsmaeda 	 * the operation removed.
3272309Srsmaeda 	 */
3282309Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t));
3292309Srsmaeda 	if (oldcpus == NULL)
3302309Srsmaeda 		goto done;
3312309Srsmaeda 
3322309Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
3332309Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, ncpus))
3342309Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
3352309Srsmaeda 	}
3362309Srsmaeda 
3372309Srsmaeda 	/* dump pre and post lists */
3382309Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
3392309Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
3402309Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
3412309Srsmaeda 
3422309Srsmaeda 	/* setup the nvlist for the RCM call */
3432309Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
3442309Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
3452309Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
3462309Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
3472309Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
3482309Srsmaeda 		goto done;
3492309Srsmaeda 	}
3502309Srsmaeda 
3512309Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
3522309Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
3532309Srsmaeda 
3542309Srsmaeda done:
3552309Srsmaeda 	s_nvfree(nvl);
3562309Srsmaeda 	s_free(cpus);
3572309Srsmaeda 	s_free(oldcpus);
3582309Srsmaeda 	s_free(newcpus);
3592309Srsmaeda 
3602309Srsmaeda 	return (rv);
3612309Srsmaeda }
3622309Srsmaeda 
3632309Srsmaeda static int
drd_rcm_del_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)3642309Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
3652309Srsmaeda {
3662309Srsmaeda 	cpuid_t		*cpus = NULL;
3672309Srsmaeda 	int		ncpus;
3682309Srsmaeda 	int		rv = -1;
3692309Srsmaeda 	cpuid_t		*oldcpus = NULL;
3702309Srsmaeda 	cpuid_t		*newcpus = NULL;
3712309Srsmaeda 	int		oldncpus = 0;
3722309Srsmaeda 	int		newncpus = 0;
3732309Srsmaeda 	nvlist_t	*nvl = NULL;
3742309Srsmaeda 	int		idx;
3752309Srsmaeda 	rcm_info_t	*rinfo;
3762309Srsmaeda 
3772309Srsmaeda 	drd_dbg("drd_rcm_del_cpu_request...");
3782309Srsmaeda 
3792309Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
3802309Srsmaeda 		drd_err("del_cpu_request: cpu list empty");
3812309Srsmaeda 		goto done;
3822309Srsmaeda 	}
3832309Srsmaeda 
3842309Srsmaeda 	ncpus = nrsrc;
3852309Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
3862309Srsmaeda 
3872309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
3882309Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
3892309Srsmaeda 	}
3902309Srsmaeda 
3912309Srsmaeda 	/* allocate an nvlist for the RCM call */
3922309Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
3932309Srsmaeda 		goto done;
3942309Srsmaeda 	}
3952309Srsmaeda 
3962309Srsmaeda 	/*
3972309Srsmaeda 	 * Removing CPU capacity, so oldcpus is the current
3982309Srsmaeda 	 * list of CPUs in the system.
3992309Srsmaeda 	 */
4002309Srsmaeda 	if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) {
4012309Srsmaeda 		goto done;
4022309Srsmaeda 	}
4032309Srsmaeda 
4042309Srsmaeda 	/*
4052309Srsmaeda 	 * Since this is a request to remove CPU capacity,
4062309Srsmaeda 	 * the new CPU list is the old CPU list with the CPUs
4072309Srsmaeda 	 * involved in the operation removed.
4082309Srsmaeda 	 */
4092309Srsmaeda 	newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t));
4102309Srsmaeda 	if (newcpus == NULL) {
4112309Srsmaeda 		goto done;
4122309Srsmaeda 	}
4132309Srsmaeda 
4142309Srsmaeda 	for (idx = 0; idx < oldncpus; idx++) {
4152309Srsmaeda 		if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus))
4162309Srsmaeda 			newcpus[newncpus++] = oldcpus[idx];
4172309Srsmaeda 	}
4182309Srsmaeda 
4192309Srsmaeda 	/* dump pre and post lists */
4202309Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
4212309Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
4222309Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
4232309Srsmaeda 
4242309Srsmaeda 	/* setup the nvlist for the RCM call */
4252309Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
4262309Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
4272309Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
4282309Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
4292309Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
4302309Srsmaeda 		goto done;
4312309Srsmaeda 	}
4322309Srsmaeda 
4332309Srsmaeda 	rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
4342309Srsmaeda 	if (rv != RCM_SUCCESS) {
4352309Srsmaeda 		drd_dbg("RCM call failed: %d", rv);
4362309Srsmaeda 		/*
437*10106SJason.Beloro@Sun.COM 		 * Since the capacity change was blocked, we
4382309Srsmaeda 		 * mark all CPUs as blocked. It is up to the
4392309Srsmaeda 		 * user to reframe the query so that it can
4402309Srsmaeda 		 * succeed.
4412309Srsmaeda 		 */
4422309Srsmaeda 		for (idx = 0; idx < nrsrc; idx++) {
4432309Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
4442309Srsmaeda 		}
4452309Srsmaeda 
4462309Srsmaeda 		/* tack on message to first resource */
4472309Srsmaeda 		rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
4482309Srsmaeda 		    "specified number of CPUs");
4492309Srsmaeda 		drd_dbg("  unable to remove specified number of CPUs");
4502309Srsmaeda 		goto done;
4512309Srsmaeda 	}
4522309Srsmaeda 
4532309Srsmaeda 	rv = 0;
4542309Srsmaeda 
4552309Srsmaeda done:
4562309Srsmaeda 	s_nvfree(nvl);
4572309Srsmaeda 	s_free(cpus);
4582309Srsmaeda 	s_free(oldcpus);
4592309Srsmaeda 	s_free(newcpus);
4602309Srsmaeda 
4612309Srsmaeda 	return (rv);
4622309Srsmaeda }
4632309Srsmaeda 
4642309Srsmaeda static int
drd_rcm_offline_cpu_request(drctl_rsrc_t * rsrcs,int nrsrc)4652309Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
4662309Srsmaeda {
4672309Srsmaeda 	char		**rlist;
4682309Srsmaeda 	drctl_rsrc_t	*rsrc;
4692309Srsmaeda 	int		idx;
4702309Srsmaeda 	int		state;
4712309Srsmaeda 	int		rv = 0;
4722309Srsmaeda 	rcm_info_t	*rinfo = NULL;
4732309Srsmaeda 	rcm_info_tuple_t *tuple = NULL;
4742309Srsmaeda 	const char	*rsrcstr;
4752309Srsmaeda 	const char	*errstr;
4762309Srsmaeda 
4772309Srsmaeda 	drd_dbg("drd_rcm_offline_cpu_request...");
4782309Srsmaeda 
4792309Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
4802309Srsmaeda 	    DRCTL_STATUS_INIT)) == NULL) {
4812309Srsmaeda 		drd_err("unable to generate resource list");
4822309Srsmaeda 		return (-1);
4832309Srsmaeda 	}
4842309Srsmaeda 
4852309Srsmaeda 	rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo);
4862309Srsmaeda 	if (rv == RCM_SUCCESS) {
4872309Srsmaeda 		drd_dbg("RCM success, rinfo=%p", rinfo);
4882309Srsmaeda 		goto done;
4892309Srsmaeda 	}
4902309Srsmaeda 
4912309Srsmaeda 	drd_dbg("RCM call failed (%d):", rv);
4922309Srsmaeda 
4932309Srsmaeda 	/*
4942309Srsmaeda 	 * Loop through the result of the operation and add
4952309Srsmaeda 	 * any error messages to the resource structure.
4962309Srsmaeda 	 */
4972309Srsmaeda 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
4982309Srsmaeda 
4992309Srsmaeda 		/* find the resource of interest */
5002309Srsmaeda 		rsrcstr = rcm_info_rsrc(tuple);
5012309Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc);
5022309Srsmaeda 
5032309Srsmaeda 		if (rsrc == NULL) {
5042309Srsmaeda 			drd_dbg("unable to find resource for %s", rsrcstr);
5052309Srsmaeda 			continue;
5062309Srsmaeda 		}
5072309Srsmaeda 
5082309Srsmaeda 		errstr = rcm_info_error(tuple);
5092309Srsmaeda 
5102309Srsmaeda 		if (errstr) {
5112309Srsmaeda 			drd_dbg("  %s: '%s'", rsrcstr, errstr);
5122309Srsmaeda 			rsrc->offset = (uintptr_t)strdup(errstr);
5132309Srsmaeda 		}
5142309Srsmaeda 	}
5152309Srsmaeda 
5162309Srsmaeda 	rcm_free_info(rinfo);
5172309Srsmaeda 	rv = 0;
5182309Srsmaeda 
5192309Srsmaeda done:
5202309Srsmaeda 	/*
5212309Srsmaeda 	 * Set the state of the resource based on the RCM
5222309Srsmaeda 	 * state. CPUs in the offline state have the ok to
5232309Srsmaeda 	 * proceed. All others have been blocked.
5242309Srsmaeda 	 */
5252309Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
5262309Srsmaeda 
5272309Srsmaeda 		state = 0;
5282309Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
5292309Srsmaeda 
5302309Srsmaeda 		/* find the resource of interest */
5312309Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc);
5322309Srsmaeda 
5332309Srsmaeda 		if (rsrc == NULL) {
5342309Srsmaeda 			drd_dbg("unable to find resource for %s", rlist[idx]);
5352309Srsmaeda 			continue;
5362309Srsmaeda 		}
5372309Srsmaeda 
5382309Srsmaeda 		rsrc->status = ((state == RCM_STATE_OFFLINE) ?
5392309Srsmaeda 		    DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY);
5402309Srsmaeda 	}
5412309Srsmaeda 
5422309Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
5432309Srsmaeda 
5442309Srsmaeda 	return (rv);
5452309Srsmaeda }
5462309Srsmaeda 
5472309Srsmaeda static int
drd_rcm_remove_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5482309Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5492309Srsmaeda {
5502309Srsmaeda 	char		**rlist;
5512309Srsmaeda 	int		rv = 0;
5522309Srsmaeda 	rcm_info_t	*rinfo;
5532309Srsmaeda 
5542309Srsmaeda 	drd_dbg("drd_rcm_remove_cpu_notify...");
5552309Srsmaeda 
5562309Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5572309Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
5582309Srsmaeda 		drd_dbg("  no CPUs in the success state, nothing to do");
5592309Srsmaeda 		return (0);
5602309Srsmaeda 	}
5612309Srsmaeda 
5622309Srsmaeda 	rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo);
5632309Srsmaeda 	if (rv != RCM_SUCCESS) {
5642309Srsmaeda 		drd_info("rcm_notify_remove_list failed: %d", rv);
5652309Srsmaeda 		rcm_free_info(rinfo);
5662309Srsmaeda 		rv = -1;
5672309Srsmaeda 	}
5682309Srsmaeda 
5692309Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
5702309Srsmaeda 
5712309Srsmaeda 	return (rv);
5722309Srsmaeda }
5732309Srsmaeda 
5742309Srsmaeda static int
drd_rcm_restore_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)5752309Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
5762309Srsmaeda {
5772309Srsmaeda 	char		**rlist;
5782309Srsmaeda 	char		**full_rlist;
5792309Srsmaeda 	int		idx;
5802309Srsmaeda 	int		ridx;
5812309Srsmaeda 	int		state;
5822309Srsmaeda 	int		rv = 0;
5832309Srsmaeda 	rcm_info_t	*rinfo;
5842309Srsmaeda 
5852309Srsmaeda 	drd_dbg("drd_rcm_restore_cpu_notify...");
5862309Srsmaeda 
5872309Srsmaeda 	if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
5882309Srsmaeda 	    DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
5892309Srsmaeda 		drd_dbg("  no CPUs in the failed state, nothing to do");
5902309Srsmaeda 		return (0);
5912309Srsmaeda 	}
5922309Srsmaeda 
5932309Srsmaeda 	/*
5942309Srsmaeda 	 * Since the desired result of this operation is to
5952309Srsmaeda 	 * restore resources to the online state, filter out
5962309Srsmaeda 	 * the resources already in the online state before
5972309Srsmaeda 	 * passing the list to RCM.
5982309Srsmaeda 	 */
5992309Srsmaeda 
6002309Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
6012309Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
6022309Srsmaeda 	if (rlist == NULL) {
6032309Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
6042309Srsmaeda 		rv = -1;
6052309Srsmaeda 		goto done;
6062309Srsmaeda 	}
6072309Srsmaeda 
6082309Srsmaeda 	for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) {
6092309Srsmaeda 		state = 0;
6102309Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state);
6112309Srsmaeda 		if (state != RCM_STATE_ONLINE) {
6122309Srsmaeda 			rlist[ridx] = full_rlist[idx];
6132309Srsmaeda 			ridx++;
6142309Srsmaeda 		}
6152309Srsmaeda 	}
6162309Srsmaeda 
6172309Srsmaeda 	/* check if everything got filtered out */
6182309Srsmaeda 	if (ridx == 0) {
6192309Srsmaeda 		drd_dbg("  all CPUs already online, nothing to do");
6202309Srsmaeda 		goto done;
6212309Srsmaeda 	}
6222309Srsmaeda 
6232309Srsmaeda 	rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
6242309Srsmaeda 	if (rv != RCM_SUCCESS) {
6252309Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
6262309Srsmaeda 		rcm_free_info(rinfo);
6272309Srsmaeda 		rv = -1;
6282309Srsmaeda 	}
6292309Srsmaeda 
6302309Srsmaeda done:
6312309Srsmaeda 	drd_rcm_cpu_rlist_fini(full_rlist);
6322309Srsmaeda 	s_free(rlist);
6332309Srsmaeda 
6342309Srsmaeda 	return (rv);
6352309Srsmaeda }
6362309Srsmaeda 
6372309Srsmaeda static int
drd_rcm_del_cpu_notify(drctl_rsrc_t * rsrcs,int nrsrc)6382309Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
6392309Srsmaeda {
6402309Srsmaeda 	cpuid_t		*cpus = NULL;
6412309Srsmaeda 	int		rv = -1;
6422309Srsmaeda 	cpuid_t		*oldcpus = NULL;
6432309Srsmaeda 	cpuid_t		*newcpus = NULL;
6442309Srsmaeda 	int		oldncpus = 0;
6452309Srsmaeda 	int		newncpus = 0;
6462309Srsmaeda 	nvlist_t	*nvl = NULL;
6472309Srsmaeda 	int		idx;
6482309Srsmaeda 	int		cidx;
6492309Srsmaeda 	rcm_info_t	*rinfo;
6502309Srsmaeda 
6512309Srsmaeda 	drd_dbg("drd_rcm_del_cpu_notify...");
6522309Srsmaeda 
6532309Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
6542309Srsmaeda 		drd_err("del_cpu_notify: cpu list empty");
6552309Srsmaeda 		goto done;
6562309Srsmaeda 	}
6572309Srsmaeda 
6582309Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
6592309Srsmaeda 
6602309Srsmaeda 	/*
6612309Srsmaeda 	 * Filter out the CPUs that could not be unconfigured.
6622309Srsmaeda 	 */
6632309Srsmaeda 	for (idx = 0, cidx = 0; idx < nrsrc; idx++) {
6642309Srsmaeda 		if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
6652309Srsmaeda 			continue;
6662309Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
6672309Srsmaeda 		cpus[cidx] = rsrcs[idx].res_cpu_id;
6682309Srsmaeda 		cidx++;
6692309Srsmaeda 	}
6702309Srsmaeda 
6712309Srsmaeda 	drd_dbg("  ncpus = %d", cidx);
6722309Srsmaeda 
6732309Srsmaeda 	/* nothing to do */
6742309Srsmaeda 	if (cidx == 0) {
6752309Srsmaeda 		rv = 0;
6762309Srsmaeda 		goto done;
6772309Srsmaeda 	}
6782309Srsmaeda 
6792309Srsmaeda 	/* allocate an nvlist for the RCM call */
6802309Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
6812309Srsmaeda 		goto done;
6822309Srsmaeda 	}
6832309Srsmaeda 
6842309Srsmaeda 	/*
6852309Srsmaeda 	 * Removed CPU capacity, so newcpus is the current list
6862309Srsmaeda 	 * of CPUs in the system.
6872309Srsmaeda 	 */
6882309Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1) {
6892309Srsmaeda 		goto done;
6902309Srsmaeda 	}
6912309Srsmaeda 
6922309Srsmaeda 	/*
6932309Srsmaeda 	 * Since the operation removed CPU capacity, the old CPU
6942309Srsmaeda 	 * list is the new CPU list with the CPUs involved in
6952309Srsmaeda 	 * the operation added.
6962309Srsmaeda 	 */
6972309Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t));
6982309Srsmaeda 	if (oldcpus == NULL) {
6992309Srsmaeda 		goto done;
7002309Srsmaeda 	}
7012309Srsmaeda 
7022309Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
7032309Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, cidx))
7042309Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
7052309Srsmaeda 	}
7062309Srsmaeda 
7072309Srsmaeda 	for (idx = 0; idx < cidx; idx++) {
7082309Srsmaeda 		oldcpus[oldncpus++] = cpus[idx];
7092309Srsmaeda 	}
7102309Srsmaeda 
7112309Srsmaeda 	/* dump pre and post lists */
7122309Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
7132309Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
7142309Srsmaeda 	dump_cpu_list("delta:   ", cpus, cidx);
7152309Srsmaeda 
7162309Srsmaeda 	/* setup the nvlist for the RCM call */
7172309Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
7182309Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
7192309Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
7202309Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
7212309Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
7222309Srsmaeda 		goto done;
7232309Srsmaeda 	}
7242309Srsmaeda 
7252309Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
7262309Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
7272309Srsmaeda 
7282309Srsmaeda done:
7292309Srsmaeda 	s_nvfree(nvl);
7302309Srsmaeda 	s_free(cpus);
7312309Srsmaeda 	s_free(oldcpus);
7322309Srsmaeda 	s_free(newcpus);
7332309Srsmaeda 
7342309Srsmaeda 	return (rv);
7352309Srsmaeda }
7362309Srsmaeda 
7372309Srsmaeda /*
7382309Srsmaeda  * Given a list of resource structures, create a list of CPU
7392309Srsmaeda  * resource strings formatted as expected by RCM. Only resources
7402309Srsmaeda  * that are in the state specified by the status argument are
7412309Srsmaeda  * included in the resulting list.
7422309Srsmaeda  */
7432309Srsmaeda static char **
drd_rcm_cpu_rlist_init(drctl_rsrc_t * rsrcs,int nrsrc,int status)7442309Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status)
7452309Srsmaeda {
7462309Srsmaeda 	char	rbuf[RCM_CPU_MAX_LEN];
7472309Srsmaeda 	char	**rlist;
7482309Srsmaeda 	int	idx;
7492309Srsmaeda 	int	ridx;
7502309Srsmaeda 
7512309Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_init...");
7522309Srsmaeda 
7532309Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
7542309Srsmaeda 		drd_dbg("cpu list is empty");
7552309Srsmaeda 		return (NULL);
7562309Srsmaeda 	}
7572309Srsmaeda 
7582309Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
7592309Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
7602309Srsmaeda 	if (rlist == NULL) {
7612309Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
7622309Srsmaeda 		return (NULL);
7632309Srsmaeda 	}
7642309Srsmaeda 
7652309Srsmaeda 	for (idx = 0, ridx = 0; idx < nrsrc; idx++) {
7662309Srsmaeda 
7672309Srsmaeda 		drd_dbg("  checking cpu %d, status=%d, expected status=%d",
7682309Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status, status);
7692309Srsmaeda 
7702309Srsmaeda 		/*
7712309Srsmaeda 		 * Filter out the CPUs that are not in
7722309Srsmaeda 		 * the requested state.
7732309Srsmaeda 		 */
7742309Srsmaeda 		if (rsrcs[idx].status != status)
7752309Srsmaeda 			continue;
7762309Srsmaeda 
7772309Srsmaeda 		/* generate the resource string */
7782309Srsmaeda 		(void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id);
7792309Srsmaeda 
7802309Srsmaeda 		rlist[ridx] = strdup(rbuf);
7812309Srsmaeda 		if (rlist[ridx] == NULL) {
7822309Srsmaeda 			drd_err("strdup failed: %s", strerror(errno));
7832309Srsmaeda 			drd_rcm_cpu_rlist_fini(rlist);
7842309Srsmaeda 			return (NULL);
7852309Srsmaeda 		}
7862309Srsmaeda 
7872309Srsmaeda 		ridx++;
7882309Srsmaeda 	}
7892309Srsmaeda 
7902309Srsmaeda 	/* cleanup if the list is empty */
7912309Srsmaeda 	if (ridx == 0) {
7922309Srsmaeda 		s_free(rlist);
7932309Srsmaeda 	}
7942309Srsmaeda 
7952309Srsmaeda 	drd_dbg("final rlist:");
7962309Srsmaeda 	dump_cpu_rlist(rlist);
7972309Srsmaeda 
7982309Srsmaeda 	return (rlist);
7992309Srsmaeda }
8002309Srsmaeda 
8012309Srsmaeda static void
drd_rcm_cpu_rlist_fini(char ** rlist)8022309Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist)
8032309Srsmaeda {
8042309Srsmaeda 	int idx;
8052309Srsmaeda 
8062309Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_fini...");
8072309Srsmaeda 
8082309Srsmaeda 	dump_cpu_rlist(rlist);
8092309Srsmaeda 
8102309Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
8112309Srsmaeda 		s_free(rlist[idx]);
8122309Srsmaeda 	}
8132309Srsmaeda 
8142309Srsmaeda 	s_free(rlist);
8152309Srsmaeda }
8162309Srsmaeda 
8172309Srsmaeda /*
8182309Srsmaeda  * Convert an RCM CPU resource string into a numerical cpuid.
8192309Srsmaeda  * Assumes the resource string has the form: "SUNW_cpu/cpu<C>"
8202309Srsmaeda  * where "<C>" is the numerical cpuid of interest.
8212309Srsmaeda  */
8222309Srsmaeda static cpuid_t
cpu_rsrcstr_to_cpuid(const char * rsrc)8232309Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc)
8242309Srsmaeda {
8252309Srsmaeda 	char	*cpuid_off;
8262309Srsmaeda 	cpuid_t	cpuid;
8272309Srsmaeda 
8282309Srsmaeda 	/*
8292309Srsmaeda 	 * Search for the last occurrance of 'u' in the
8302309Srsmaeda 	 * expected RCM resource string "SUNW_cpu/cpu<C>".
8312309Srsmaeda 	 * This will give a pointer to the cpuid portion.
8322309Srsmaeda 	 */
8332309Srsmaeda 	cpuid_off = strrchr(rsrc, 'u');
8342309Srsmaeda 	cpuid_off++;
8352309Srsmaeda 
8362309Srsmaeda 	cpuid = atoi(cpuid_off);
8372309Srsmaeda 
8382309Srsmaeda 	return (cpuid);
8392309Srsmaeda }
8402309Srsmaeda 
8412309Srsmaeda /*
8422309Srsmaeda  * Given an RCM CPU resource string, return a pointer to the
8432309Srsmaeda  * corresponding resource structure from the given resource list.
8442309Srsmaeda  * NULL is returned if no matching resource structure can be
8452309Srsmaeda  * found.
8462309Srsmaeda  */
8472309Srsmaeda static drctl_rsrc_t *
cpu_rsrcstr_to_rsrc(const char * rsrcstr,drctl_rsrc_t * rsrcs,int nrsrc)8482309Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc)
8492309Srsmaeda {
8502309Srsmaeda 	cpuid_t	cpuid;
8512309Srsmaeda 	int	idx;
8522309Srsmaeda 
8532309Srsmaeda 	cpuid = cpu_rsrcstr_to_cpuid(rsrcstr);
8542309Srsmaeda 
8552309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
8562309Srsmaeda 		if (rsrcs[idx].res_cpu_id == cpuid)
8572309Srsmaeda 			return (&rsrcs[idx]);
8582309Srsmaeda 	}
8592309Srsmaeda 
8602309Srsmaeda 	return (NULL);
8612309Srsmaeda }
8622309Srsmaeda 
8632309Srsmaeda static int
get_sys_cpuids(cpuid_t ** cpuids,int * ncpuids)8642309Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids)
8652309Srsmaeda {
8662309Srsmaeda 	int		ncpu = 0;
8672309Srsmaeda 	int		maxncpu;
8682309Srsmaeda 	kstat_t		*ksp;
8692309Srsmaeda 	kstat_ctl_t	*kc = NULL;
8702309Srsmaeda 	cpuid_t		*cp;
8712309Srsmaeda 
8722309Srsmaeda 	drd_dbg("get_sys_cpuids...");
8732309Srsmaeda 
8742309Srsmaeda 	if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1)
8752309Srsmaeda 		return (-1);
8762309Srsmaeda 
8772309Srsmaeda 	if ((kc = kstat_open()) == NULL)
8782309Srsmaeda 		return (-1);
8792309Srsmaeda 
8802309Srsmaeda 	if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
8812309Srsmaeda 		(void) kstat_close(kc);
8822309Srsmaeda 		return (-1);
8832309Srsmaeda 	}
8842309Srsmaeda 
8852309Srsmaeda 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
8862309Srsmaeda 		if (strcmp(ksp->ks_module, "cpu_info") == 0)
8872309Srsmaeda 			cp[ncpu++] = ksp->ks_instance;
8882309Srsmaeda 	}
8892309Srsmaeda 
8902309Srsmaeda 	dump_cpu_list("syscpus: ", cp, ncpu);
8912309Srsmaeda 
8922309Srsmaeda 	(void) kstat_close(kc);
8932309Srsmaeda 
8942309Srsmaeda 	*cpuids = cp;
8952309Srsmaeda 	*ncpuids = ncpu;
8962309Srsmaeda 
8972309Srsmaeda 	return (0);
8982309Srsmaeda }
8992309Srsmaeda 
9002309Srsmaeda static boolean_t
is_cpu_in_list(cpuid_t cpuid,cpuid_t * list,int len)9012309Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len)
9022309Srsmaeda {
9032309Srsmaeda 	int idx;
9042309Srsmaeda 
9052309Srsmaeda 	if (list == NULL)
9062309Srsmaeda 		return (B_FALSE);
9072309Srsmaeda 
9082309Srsmaeda 	for (idx = 0; idx < len; idx++) {
9092309Srsmaeda 		if (list[idx] == cpuid)
9102309Srsmaeda 			return (B_TRUE);
9112309Srsmaeda 	}
9122309Srsmaeda 
9132309Srsmaeda 	return (B_FALSE);
9142309Srsmaeda }
9152309Srsmaeda 
9162309Srsmaeda #define	CPUIDS_PER_LINE		16
9172309Srsmaeda #define	LINEWIDTH		(2 * (CPUIDS_PER_LINE * 4))
9182309Srsmaeda 
9192309Srsmaeda static void
dump_cpu_list(char * prefix,cpuid_t * cpuids,int ncpuids)9202309Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids)
9212309Srsmaeda {
9222309Srsmaeda 	char	line[LINEWIDTH];
9232309Srsmaeda 	char	*curr;
9242309Srsmaeda 	int	i, j;
9252309Srsmaeda 
9262309Srsmaeda 	/* return if not debugging */
9272309Srsmaeda 	if (drd_debug == 0)
9282309Srsmaeda 		return;
9292309Srsmaeda 
9302309Srsmaeda 	/* print just the prefix if CPU list is empty */
9312309Srsmaeda 	if (ncpuids == 0) {
9322309Srsmaeda 		if (prefix)
9332309Srsmaeda 			drd_dbg("%s", prefix);
9342309Srsmaeda 		return;
9352309Srsmaeda 	}
9362309Srsmaeda 
9372309Srsmaeda 	for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
9382309Srsmaeda 
9392309Srsmaeda 		bzero(line, LINEWIDTH);
9402309Srsmaeda 		curr = line;
9412309Srsmaeda 
9422309Srsmaeda 		/* start with the prefix */
9432309Srsmaeda 		(void) sprintf(curr, "%s", (prefix) ? prefix : "");
9442309Srsmaeda 		curr = line + strlen(line);
9452309Srsmaeda 
9462309Srsmaeda 		/* format the CPUs for this line */
9472309Srsmaeda 		for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
9482309Srsmaeda 			(void) sprintf(curr, "%3d ", cpuids[i + j]);
9492309Srsmaeda 			curr = line + strlen(line);
9502309Srsmaeda 		}
9512309Srsmaeda 
9522309Srsmaeda 		drd_dbg("%s", line);
9532309Srsmaeda 	}
9542309Srsmaeda }
9552309Srsmaeda 
9562309Srsmaeda static void
dump_cpu_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)9572309Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
9582309Srsmaeda {
9592309Srsmaeda 	int	idx;
9602309Srsmaeda 	char	*errstr;
9612309Srsmaeda 
9622309Srsmaeda 	/* just return if not debugging */
9632309Srsmaeda 	if (drd_debug == 0)
9642309Srsmaeda 		return;
9652309Srsmaeda 
9662309Srsmaeda 	if (prefix)
9672309Srsmaeda 		drd_dbg("%s", prefix);
9682309Srsmaeda 
9692309Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
9702309Srsmaeda 
9712309Srsmaeda 		/* get a pointer to the error string */
9722309Srsmaeda 		errstr = (char *)(uintptr_t)rsrcs[idx].offset;
9732309Srsmaeda 
9742309Srsmaeda 		drd_dbg("  cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx,
9752309Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status,
9762309Srsmaeda 		    (errstr != NULL) ? errstr : "");
9772309Srsmaeda 	}
9782309Srsmaeda }
9792309Srsmaeda 
9802309Srsmaeda static void
dump_cpu_rlist(char ** rlist)9812309Srsmaeda dump_cpu_rlist(char **rlist)
9822309Srsmaeda {
9832309Srsmaeda 	int	idx;
9842309Srsmaeda 	int	state;
9852309Srsmaeda 
9862309Srsmaeda 	static char *rcm_state_str[] = {
9872309Srsmaeda 		"UNKNOWN",		"ONLINE",		"ONLINING",
9882309Srsmaeda 		"OFFLINE_FAIL",		"OFFLINING",		"OFFLINE",
9892309Srsmaeda 		"REMOVING",		"INVALID_7",		"INVALID_8",
9902309Srsmaeda 		"INVALID_9",		"RESUMING",		"SUSPEND_FAIL",
9912309Srsmaeda 		"SUSPENDING",		"SUSPEND",		"REMOVE",
9922309Srsmaeda 		"OFFLINE_QUERYING",	"OFFLINE_QUERY_FAIL",	"OFFLINE_QUERY",
9932309Srsmaeda 		"SUSPEND_QUERYING",	"SUSPEND_QUERY_FAIL",	"SUSPEND_QUERY"
9942309Srsmaeda 	};
9952309Srsmaeda 
9962309Srsmaeda 	/* just return if not debugging */
9972309Srsmaeda 	if (drd_debug == 0)
9982309Srsmaeda 		return;
9992309Srsmaeda 
10002309Srsmaeda 	if (rlist == NULL) {
10012309Srsmaeda 		drd_dbg("  empty rlist");
10022309Srsmaeda 		return;
10032309Srsmaeda 	}
10042309Srsmaeda 
10052309Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
10062309Srsmaeda 		state = 0;
10072309Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
10082309Srsmaeda 		drd_dbg("  rlist[%d]: rsrc=%s, state=%-2d (%s)", idx,
10092309Srsmaeda 		    rlist[idx], state, rcm_state_str[state]);
10102309Srsmaeda 	}
10112309Srsmaeda }
10126441Sjm22469 
10136441Sjm22469 static int
drd_rcm_io_config_request(drctl_rsrc_t * rsrc,int nrsrc)10146441Sjm22469 drd_rcm_io_config_request(drctl_rsrc_t *rsrc, int nrsrc)
10156441Sjm22469 {
10166441Sjm22469 	drd_dbg("drd_rcm_io_config_request...");
10176441Sjm22469 
10186441Sjm22469 	if (nrsrc != 1) {
10196441Sjm22469 		drd_dbg("drd_rcm_cpu_config_request: only 1 resource "
10206441Sjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
10216441Sjm22469 		rsrc->status = DRCTL_STATUS_DENY;
10226441Sjm22469 
10236441Sjm22469 		return (-1);
10246441Sjm22469 	}
10256441Sjm22469 
10266441Sjm22469 	/*
10276441Sjm22469 	 * There is no RCM operation to request the addition
10286441Sjm22469 	 * of resources.  So, by definition, the operation for
10296441Sjm22469 	 * the current resource is allowed.
10306441Sjm22469 	 */
10316441Sjm22469 	rsrc->status = DRCTL_STATUS_ALLOW;
10326441Sjm22469 
10336441Sjm22469 	return (0);
10346441Sjm22469 }
10356441Sjm22469 
10366441Sjm22469 /*ARGSUSED*/
10376441Sjm22469 static int
drd_rcm_io_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)10386441Sjm22469 drd_rcm_io_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
10396441Sjm22469 {
10406441Sjm22469 	drd_dbg("drd_rcm_io_config_notify...");
10416441Sjm22469 
10426441Sjm22469 	if (nrsrc != 1) {
10436441Sjm22469 		drd_dbg("drd_rcm_cpu_config_notify: only 1 resource "
10446441Sjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
10456441Sjm22469 
10466441Sjm22469 		return (-1);
10476441Sjm22469 	}
10486441Sjm22469 
10496441Sjm22469 	return (0);
10506441Sjm22469 }
10516441Sjm22469 
10526441Sjm22469 
10536441Sjm22469 static int
drd_rcm_io_unconfig_request(drctl_rsrc_t * rsrc,int nrsrc)10546441Sjm22469 drd_rcm_io_unconfig_request(drctl_rsrc_t *rsrc, int nrsrc)
10556441Sjm22469 {
10566441Sjm22469 	int		rv;
10576441Sjm22469 	char		*dev = rsrc->res_dev_path;
10586441Sjm22469 	rcm_info_t	*rinfo = NULL;
10596441Sjm22469 
10606441Sjm22469 	if (nrsrc != 1) {
10616441Sjm22469 		drd_dbg("drd_io_unconfig_request: only 1 resource "
10626441Sjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
10636441Sjm22469 		rsrc->status = DRCTL_STATUS_DENY;
10646441Sjm22469 
10656441Sjm22469 		return (-1);
10666441Sjm22469 	}
10676441Sjm22469 
10686441Sjm22469 	if ((rv = rcm_request_offline(rcm_hdl, dev, 0, &rinfo)) == RCM_SUCCESS)
10696441Sjm22469 		rsrc->status = DRCTL_STATUS_ALLOW;
10706441Sjm22469 	else {
10716441Sjm22469 		rcm_notify_online(rcm_hdl, dev, 0, NULL);
10726441Sjm22469 		rsrc->status = DRCTL_STATUS_DENY;
10736441Sjm22469 		rsrc->offset = (uintptr_t)rcm_info_table(rinfo);
10746441Sjm22469 
10756441Sjm22469 	}
10766441Sjm22469 
10776441Sjm22469 	rcm_free_info(rinfo);
10786441Sjm22469 	drd_dbg("drd_rcm_io_unconfig_request(%s) = %d", dev, rv);
10796441Sjm22469 
10806441Sjm22469 	return (rv);
10816441Sjm22469 }
10826441Sjm22469 
10836441Sjm22469 static int
drd_rcm_io_unconfig_notify(drctl_rsrc_t * rsrc,int nrsrc)10846441Sjm22469 drd_rcm_io_unconfig_notify(drctl_rsrc_t *rsrc, int nrsrc)
10856441Sjm22469 {
10866441Sjm22469 	drd_dbg("drd_rcm_io_unconfig_notify...");
10876441Sjm22469 
10886441Sjm22469 	if (nrsrc != 1) {
10896441Sjm22469 		drd_dbg("drd_io_cpu_unconfig_notify: only 1 resource "
10906441Sjm22469 		    "allowed for I/O requests, passed %d resources\n", nrsrc);
10916441Sjm22469 
10926441Sjm22469 		return (-1);
10936441Sjm22469 	}
10946441Sjm22469 
10956441Sjm22469 	return (rcm_notify_remove(rcm_hdl, rsrc->res_dev_path, 0, NULL));
10966441Sjm22469 }
10976441Sjm22469 
10986441Sjm22469 #define	MAX_FORMAT	80
10996441Sjm22469 
11006441Sjm22469 /*
11016441Sjm22469  * Convert rcm_info_t data into a printable table.
11026441Sjm22469  */
11036441Sjm22469 static char *
rcm_info_table(rcm_info_t * rinfo)11046441Sjm22469 rcm_info_table(rcm_info_t *rinfo)
11056441Sjm22469 {
11066441Sjm22469 	int		i;
11076441Sjm22469 	size_t		w;
11086441Sjm22469 	size_t		width = 0;
11096441Sjm22469 	size_t		w_rsrc = 0;
11106441Sjm22469 	size_t		w_info = 0;
11116441Sjm22469 	size_t		table_size = 0;
11126441Sjm22469 	uint_t		tuples = 0;
11136441Sjm22469 	rcm_info_tuple_t *tuple = NULL;
11146441Sjm22469 	char		*rsrc;
11156441Sjm22469 	char		*info;
11166441Sjm22469 	char		*table;
11176441Sjm22469 	static char	format[MAX_FORMAT];
11186441Sjm22469 	const char	*infostr;
11196441Sjm22469 
11206441Sjm22469 	/* Protect against invalid arguments */
11216441Sjm22469 	if (rinfo == NULL)
11226441Sjm22469 		return (NULL);
11236441Sjm22469 
11246441Sjm22469 	/* Set localized table header strings */
11256441Sjm22469 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
11266441Sjm22469 	info = dgettext(TEXT_DOMAIN, "Information");
11276441Sjm22469 
11286441Sjm22469 	/* A first pass, to size up the RCM information */
11296441Sjm22469 	while (tuple = rcm_info_next(rinfo, tuple)) {
11306441Sjm22469 		if ((infostr = rcm_info_info(tuple)) != NULL) {
11316441Sjm22469 			tuples++;
11326441Sjm22469 			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
11336441Sjm22469 				w_rsrc = w;
11346441Sjm22469 			if ((w = strlen(infostr)) > w_info)
11356441Sjm22469 				w_info = w;
11366441Sjm22469 		}
11376441Sjm22469 	}
11386441Sjm22469 
11396441Sjm22469 	/* If nothing was sized up above, stop early */
11406441Sjm22469 	if (tuples == 0)
11416441Sjm22469 		return (NULL);
11426441Sjm22469 
11436441Sjm22469 	/* Adjust column widths for column headings */
11446441Sjm22469 	if ((w = strlen(rsrc)) > w_rsrc)
11456441Sjm22469 		w_rsrc = w;
11466441Sjm22469 	else if ((w_rsrc - w) % 2)
11476441Sjm22469 		w_rsrc++;
11486441Sjm22469 	if ((w = strlen(info)) > w_info)
11496441Sjm22469 		w_info = w;
11506441Sjm22469 	else if ((w_info - w) % 2)
11516441Sjm22469 		w_info++;
11526441Sjm22469 
11536441Sjm22469 	/*
11546441Sjm22469 	 * Compute the total line width of each line,
11556441Sjm22469 	 * accounting for intercolumn spacing.
11566441Sjm22469 	 */
11576441Sjm22469 	width = w_info + w_rsrc + 4;
11586441Sjm22469 
11596441Sjm22469 	/* Allocate space for the table */
11606441Sjm22469 	table_size = (2 + tuples) * (width + 1) + 2;
11616441Sjm22469 
11626441Sjm22469 	/* zero fill for the strcat() call below */
11636441Sjm22469 	table = calloc(table_size, sizeof (char));
11646441Sjm22469 	if (table == NULL)
11656441Sjm22469 		return (NULL);
11666441Sjm22469 
11676441Sjm22469 	/* Place a table header into the string */
11686441Sjm22469 
11696441Sjm22469 	/* The resource header */
11706441Sjm22469 	(void) strcat(table, "\n");
11716441Sjm22469 	w = strlen(rsrc);
11726441Sjm22469 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
11736441Sjm22469 		(void) strcat(table, " ");
11746441Sjm22469 	(void) strcat(table, rsrc);
11756441Sjm22469 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
11766441Sjm22469 		(void) strcat(table, " ");
11776441Sjm22469 
11786441Sjm22469 	/* The information header */
11796441Sjm22469 	(void) strcat(table, "  ");
11806441Sjm22469 	w = strlen(info);
11816441Sjm22469 	for (i = 0; i < ((w_info - w) / 2); i++)
11826441Sjm22469 		(void) strcat(table, " ");
11836441Sjm22469 	(void) strcat(table, info);
11846441Sjm22469 	for (i = 0; i < ((w_info - w) / 2); i++)
11856441Sjm22469 		(void) strcat(table, " ");
11866441Sjm22469 	/* Underline the headers */
11876441Sjm22469 	(void) strcat(table, "\n");
11886441Sjm22469 	for (i = 0; i < w_rsrc; i++)
11896441Sjm22469 		(void) strcat(table, "-");
11906441Sjm22469 	(void) strcat(table, "  ");
11916441Sjm22469 	for (i = 0; i < w_info; i++)
11926441Sjm22469 		(void) strcat(table, "-");
11936441Sjm22469 
11946441Sjm22469 	/* Construct the format string */
11956441Sjm22469 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
11966441Sjm22469 	    (int)w_rsrc, (int)w_info);
11976441Sjm22469 
11986441Sjm22469 	/* Add the tuples to the table string */
11996441Sjm22469 	tuple = NULL;
12006441Sjm22469 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
12016441Sjm22469 		if ((infostr = rcm_info_info(tuple)) != NULL) {
12026441Sjm22469 			(void) strcat(table, "\n");
12036441Sjm22469 			(void) sprintf(&((table)[strlen(table)]),
12046441Sjm22469 			    format, rcm_info_rsrc(tuple),
12056441Sjm22469 			    infostr);
12066441Sjm22469 		}
12076441Sjm22469 	}
12086441Sjm22469 	drd_dbg("rcm_info_table: %s\n", table);
12096441Sjm22469 
12106441Sjm22469 	return (table);
12116441Sjm22469 }
1212*10106SJason.Beloro@Sun.COM 
1213*10106SJason.Beloro@Sun.COM static void
dump_mem_rsrc_list(char * prefix,drctl_rsrc_t * rsrcs,int nrsrc)1214*10106SJason.Beloro@Sun.COM dump_mem_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
1215*10106SJason.Beloro@Sun.COM {
1216*10106SJason.Beloro@Sun.COM 	int	idx;
1217*10106SJason.Beloro@Sun.COM 	char	*errstr;
1218*10106SJason.Beloro@Sun.COM 
1219*10106SJason.Beloro@Sun.COM 	/* just return if not debugging */
1220*10106SJason.Beloro@Sun.COM 	if (drd_debug == 0)
1221*10106SJason.Beloro@Sun.COM 		return;
1222*10106SJason.Beloro@Sun.COM 
1223*10106SJason.Beloro@Sun.COM 	if (prefix)
1224*10106SJason.Beloro@Sun.COM 		drd_dbg("%s", prefix);
1225*10106SJason.Beloro@Sun.COM 
1226*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
1227*10106SJason.Beloro@Sun.COM 
1228*10106SJason.Beloro@Sun.COM 		/* get a pointer to the error string */
1229*10106SJason.Beloro@Sun.COM 		errstr = (char *)(uintptr_t)rsrcs[idx].offset;
1230*10106SJason.Beloro@Sun.COM 
1231*10106SJason.Beloro@Sun.COM 		drd_dbg("  mem[%d]: addr=0x%llx, size=0x%llx"
1232*10106SJason.Beloro@Sun.COM 		    " status=%d, errstr='%s'", idx,
1233*10106SJason.Beloro@Sun.COM 		    rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size,
1234*10106SJason.Beloro@Sun.COM 		    rsrcs[idx].status, (errstr != NULL) ? errstr : "");
1235*10106SJason.Beloro@Sun.COM 	}
1236*10106SJason.Beloro@Sun.COM }
1237*10106SJason.Beloro@Sun.COM 
1238*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_op(rcm_op_t op,uint64_t change)1239*10106SJason.Beloro@Sun.COM drd_rcm_mem_op(rcm_op_t op, uint64_t change)
1240*10106SJason.Beloro@Sun.COM {
1241*10106SJason.Beloro@Sun.COM 	int		rv = -1;
1242*10106SJason.Beloro@Sun.COM 	int		pgsize;
1243*10106SJason.Beloro@Sun.COM 	long		oldpages;
1244*10106SJason.Beloro@Sun.COM 	long		newpages;
1245*10106SJason.Beloro@Sun.COM 	nvlist_t	*nvl = NULL;
1246*10106SJason.Beloro@Sun.COM 	rcm_info_t	*rinfo;
1247*10106SJason.Beloro@Sun.COM 
1248*10106SJason.Beloro@Sun.COM 	/* allocate an nvlist for the RCM call */
1249*10106SJason.Beloro@Sun.COM 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
1250*10106SJason.Beloro@Sun.COM 		goto done;
1251*10106SJason.Beloro@Sun.COM 
1252*10106SJason.Beloro@Sun.COM 	if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 ||
1253*10106SJason.Beloro@Sun.COM 	    (newpages = sysconf(_SC_PHYS_PAGES)) == -1)
1254*10106SJason.Beloro@Sun.COM 		goto done;
1255*10106SJason.Beloro@Sun.COM 
1256*10106SJason.Beloro@Sun.COM 	/*
1257*10106SJason.Beloro@Sun.COM 	 * If this is a notify add, the capacity change
1258*10106SJason.Beloro@Sun.COM 	 * was positive and the current page count reflects
1259*10106SJason.Beloro@Sun.COM 	 * the new capacity level.
1260*10106SJason.Beloro@Sun.COM 	 *
1261*10106SJason.Beloro@Sun.COM 	 * If this is a request del, the capacity change
1262*10106SJason.Beloro@Sun.COM 	 * is negative and the current page count will
1263*10106SJason.Beloro@Sun.COM 	 * reflect the old capacity level.
1264*10106SJason.Beloro@Sun.COM 	 */
1265*10106SJason.Beloro@Sun.COM 	assert(change % pgsize == 0);
1266*10106SJason.Beloro@Sun.COM 	if (change > 0) {
1267*10106SJason.Beloro@Sun.COM 		oldpages = newpages - (long)(change / pgsize);
1268*10106SJason.Beloro@Sun.COM 	} else {
1269*10106SJason.Beloro@Sun.COM 		assert(newpages >= change / pgsize);
1270*10106SJason.Beloro@Sun.COM 		oldpages = newpages;
1271*10106SJason.Beloro@Sun.COM 		newpages = oldpages + (long)(change / pgsize);
1272*10106SJason.Beloro@Sun.COM 	}
1273*10106SJason.Beloro@Sun.COM 
1274*10106SJason.Beloro@Sun.COM 	drd_dbg("oldpages=%lld newpages=%lld delta=%lld",
1275*10106SJason.Beloro@Sun.COM 	    oldpages, newpages, newpages - oldpages);
1276*10106SJason.Beloro@Sun.COM 
1277*10106SJason.Beloro@Sun.COM 	/* setup the nvlist for the RCM call */
1278*10106SJason.Beloro@Sun.COM 	if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
1279*10106SJason.Beloro@Sun.COM 	    nvlist_add_int32(nvl, "page_size", pgsize) != 0 ||
1280*10106SJason.Beloro@Sun.COM 	    nvlist_add_int32(nvl, "old_pages", oldpages) != 0 ||
1281*10106SJason.Beloro@Sun.COM 	    nvlist_add_int32(nvl, "new_pages", newpages) != 0) {
1282*10106SJason.Beloro@Sun.COM 		goto done;
1283*10106SJason.Beloro@Sun.COM 	}
1284*10106SJason.Beloro@Sun.COM 
1285*10106SJason.Beloro@Sun.COM 	rv = (*op)(rcm_hdl, RCM_MEM_ALL, 0, nvl, &rinfo);
1286*10106SJason.Beloro@Sun.COM 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
1287*10106SJason.Beloro@Sun.COM 
1288*10106SJason.Beloro@Sun.COM done:
1289*10106SJason.Beloro@Sun.COM 	s_nvfree(nvl);
1290*10106SJason.Beloro@Sun.COM 
1291*10106SJason.Beloro@Sun.COM 	return (rv);
1292*10106SJason.Beloro@Sun.COM }
1293*10106SJason.Beloro@Sun.COM 
1294*10106SJason.Beloro@Sun.COM /*
1295*10106SJason.Beloro@Sun.COM  * RCM clients can interpose only on removal of resources.
1296*10106SJason.Beloro@Sun.COM  */
1297*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_config_request(drctl_rsrc_t * rsrcs,int nrsrc)1298*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
1299*10106SJason.Beloro@Sun.COM {
1300*10106SJason.Beloro@Sun.COM 	int	idx;
1301*10106SJason.Beloro@Sun.COM 
1302*10106SJason.Beloro@Sun.COM 	drd_dbg("drd_rcm_mem_config_request...");
1303*10106SJason.Beloro@Sun.COM 
1304*10106SJason.Beloro@Sun.COM 	if ((rsrcs == NULL) || (nrsrc == 0))
1305*10106SJason.Beloro@Sun.COM 		return (0);
1306*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1307*10106SJason.Beloro@Sun.COM 
1308*10106SJason.Beloro@Sun.COM 	/*
1309*10106SJason.Beloro@Sun.COM 	 * There is no RCM operation to request the addition
1310*10106SJason.Beloro@Sun.COM 	 * of resources. So, by definition, the operation for
1311*10106SJason.Beloro@Sun.COM 	 * all the memory is allowed.
1312*10106SJason.Beloro@Sun.COM 	 */
1313*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++)
1314*10106SJason.Beloro@Sun.COM 		rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1315*10106SJason.Beloro@Sun.COM 
1316*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1317*10106SJason.Beloro@Sun.COM 
1318*10106SJason.Beloro@Sun.COM 	return (0);
1319*10106SJason.Beloro@Sun.COM }
1320*10106SJason.Beloro@Sun.COM 
1321*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_config_notify(drctl_rsrc_t * rsrcs,int nrsrc)1322*10106SJason.Beloro@Sun.COM drd_rcm_mem_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1323*10106SJason.Beloro@Sun.COM {
1324*10106SJason.Beloro@Sun.COM 	int		idx;
1325*10106SJason.Beloro@Sun.COM 	int		rv = -1;
1326*10106SJason.Beloro@Sun.COM 	uint64_t	change = 0;
1327*10106SJason.Beloro@Sun.COM 
1328*10106SJason.Beloro@Sun.COM 	drd_dbg("drd_rcm_mem_config_notify...");
1329*10106SJason.Beloro@Sun.COM 
1330*10106SJason.Beloro@Sun.COM 	if ((rsrcs == NULL) || (nrsrc == 0)) {
1331*10106SJason.Beloro@Sun.COM 		drd_err("mem_config_notify: mem list empty");
1332*10106SJason.Beloro@Sun.COM 		goto done;
1333*10106SJason.Beloro@Sun.COM 	}
1334*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1335*10106SJason.Beloro@Sun.COM 
1336*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
1337*10106SJason.Beloro@Sun.COM 		if (rsrcs[idx].status == DRCTL_STATUS_CONFIG_SUCCESS)
1338*10106SJason.Beloro@Sun.COM 			change += rsrcs[idx].res_mem_size;
1339*10106SJason.Beloro@Sun.COM 		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
1340*10106SJason.Beloro@Sun.COM 		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1341*10106SJason.Beloro@Sun.COM 	}
1342*10106SJason.Beloro@Sun.COM 
1343*10106SJason.Beloro@Sun.COM 	rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1344*10106SJason.Beloro@Sun.COM done:
1345*10106SJason.Beloro@Sun.COM 	return (rv);
1346*10106SJason.Beloro@Sun.COM }
1347*10106SJason.Beloro@Sun.COM 
1348*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_unconfig_request(drctl_rsrc_t * rsrcs,int nrsrc)1349*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
1350*10106SJason.Beloro@Sun.COM {
1351*10106SJason.Beloro@Sun.COM 	int		rv = -1;
1352*10106SJason.Beloro@Sun.COM 	int		idx;
1353*10106SJason.Beloro@Sun.COM 	uint64_t	change = 0;
1354*10106SJason.Beloro@Sun.COM 
1355*10106SJason.Beloro@Sun.COM 	drd_dbg("drd_rcm_del_mem_request...");
1356*10106SJason.Beloro@Sun.COM 
1357*10106SJason.Beloro@Sun.COM 	if ((rsrcs == NULL) || (nrsrc == 0)) {
1358*10106SJason.Beloro@Sun.COM 		drd_err("mem_unconfig_request: mem list empty");
1359*10106SJason.Beloro@Sun.COM 		goto done;
1360*10106SJason.Beloro@Sun.COM 	}
1361*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1362*10106SJason.Beloro@Sun.COM 
1363*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
1364*10106SJason.Beloro@Sun.COM 		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
1365*10106SJason.Beloro@Sun.COM 		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1366*10106SJason.Beloro@Sun.COM 		change += rsrcs[idx].res_mem_size;
1367*10106SJason.Beloro@Sun.COM 	}
1368*10106SJason.Beloro@Sun.COM 
1369*10106SJason.Beloro@Sun.COM 	rv = drd_rcm_mem_op(rcm_request_capacity_change, -change);
1370*10106SJason.Beloro@Sun.COM 
1371*10106SJason.Beloro@Sun.COM 	if (rv != RCM_SUCCESS) {
1372*10106SJason.Beloro@Sun.COM 		drd_dbg("RCM call failed: %d", rv);
1373*10106SJason.Beloro@Sun.COM 		/*
1374*10106SJason.Beloro@Sun.COM 		 * Since the capacity change was blocked, we
1375*10106SJason.Beloro@Sun.COM 		 * mark all mblocks as blocked. It is up to the
1376*10106SJason.Beloro@Sun.COM 		 * user to reframe the query so that it can
1377*10106SJason.Beloro@Sun.COM 		 * succeed.
1378*10106SJason.Beloro@Sun.COM 		 */
1379*10106SJason.Beloro@Sun.COM 		for (idx = 0; idx < nrsrc; idx++) {
1380*10106SJason.Beloro@Sun.COM 			rsrcs[idx].status = DRCTL_STATUS_DENY;
1381*10106SJason.Beloro@Sun.COM 		}
1382*10106SJason.Beloro@Sun.COM 
1383*10106SJason.Beloro@Sun.COM 		/* tack on message to first resource */
1384*10106SJason.Beloro@Sun.COM 		rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
1385*10106SJason.Beloro@Sun.COM 		    "specified amount of memory");
1386*10106SJason.Beloro@Sun.COM 		drd_dbg("  unable to remove specified amount of memory");
1387*10106SJason.Beloro@Sun.COM 	} else {
1388*10106SJason.Beloro@Sun.COM 		for (idx = 0; idx < nrsrc; idx++)
1389*10106SJason.Beloro@Sun.COM 			rsrcs[idx].status = DRCTL_STATUS_ALLOW;
1390*10106SJason.Beloro@Sun.COM 		rv = 0;
1391*10106SJason.Beloro@Sun.COM 	}
1392*10106SJason.Beloro@Sun.COM 
1393*10106SJason.Beloro@Sun.COM done:
1394*10106SJason.Beloro@Sun.COM 
1395*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list("returning:", rsrcs, nrsrc);
1396*10106SJason.Beloro@Sun.COM 	return (rv);
1397*10106SJason.Beloro@Sun.COM }
1398*10106SJason.Beloro@Sun.COM 
1399*10106SJason.Beloro@Sun.COM static int
drd_rcm_mem_unconfig_notify(drctl_rsrc_t * rsrcs,int nrsrc)1400*10106SJason.Beloro@Sun.COM drd_rcm_mem_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
1401*10106SJason.Beloro@Sun.COM {
1402*10106SJason.Beloro@Sun.COM 	int		idx;
1403*10106SJason.Beloro@Sun.COM 	int		rv = -1;
1404*10106SJason.Beloro@Sun.COM 	uint64_t	change = 0;
1405*10106SJason.Beloro@Sun.COM 
1406*10106SJason.Beloro@Sun.COM 	drd_dbg("drd_rcm_mem_unconfig_notify...");
1407*10106SJason.Beloro@Sun.COM 
1408*10106SJason.Beloro@Sun.COM 	if ((rsrcs == NULL) || (nrsrc == 0)) {
1409*10106SJason.Beloro@Sun.COM 		drd_err("unconfig_mem_notify: mem list empty");
1410*10106SJason.Beloro@Sun.COM 		goto done;
1411*10106SJason.Beloro@Sun.COM 	}
1412*10106SJason.Beloro@Sun.COM 	dump_mem_rsrc_list(NULL, rsrcs, nrsrc);
1413*10106SJason.Beloro@Sun.COM 
1414*10106SJason.Beloro@Sun.COM 	/*
1415*10106SJason.Beloro@Sun.COM 	 * Filter out the memory that was configured.
1416*10106SJason.Beloro@Sun.COM 	 *
1417*10106SJason.Beloro@Sun.COM 	 * We need to notify RCM about a memory capacity change
1418*10106SJason.Beloro@Sun.COM 	 * only if the memory unconfigure request wasn't successful
1419*10106SJason.Beloro@Sun.COM 	 * because if both the RCM capacity delete request and the
1420*10106SJason.Beloro@Sun.COM 	 * memory unconfigure succeed, this notify would give a
1421*10106SJason.Beloro@Sun.COM 	 * memory capacity identical to the delete request.
1422*10106SJason.Beloro@Sun.COM 	 */
1423*10106SJason.Beloro@Sun.COM 	for (idx = 0; idx < nrsrc; idx++) {
1424*10106SJason.Beloro@Sun.COM 		if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
1425*10106SJason.Beloro@Sun.COM 			change += rsrcs[idx].res_mem_size;
1426*10106SJason.Beloro@Sun.COM 		drd_dbg("  idx=%d addr=0x%llx size=0x%llx",
1427*10106SJason.Beloro@Sun.COM 		    idx, rsrcs[idx].res_mem_addr, rsrcs[idx].res_mem_size);
1428*10106SJason.Beloro@Sun.COM 	}
1429*10106SJason.Beloro@Sun.COM 
1430*10106SJason.Beloro@Sun.COM 	rv = drd_rcm_mem_op(rcm_notify_capacity_change, change);
1431*10106SJason.Beloro@Sun.COM done:
1432*10106SJason.Beloro@Sun.COM 	return (rv);
1433*10106SJason.Beloro@Sun.COM }
1434