xref: /illumos-gate/usr/src/cmd/drd/drd_rcm.c (revision 1d4b38e0077763e7c9b20768eacb841957e787bc)
1*1d4b38e0Srsmaeda /*
2*1d4b38e0Srsmaeda  * CDDL HEADER START
3*1d4b38e0Srsmaeda  *
4*1d4b38e0Srsmaeda  * The contents of this file are subject to the terms of the
5*1d4b38e0Srsmaeda  * Common Development and Distribution License (the "License").
6*1d4b38e0Srsmaeda  * You may not use this file except in compliance with the License.
7*1d4b38e0Srsmaeda  *
8*1d4b38e0Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1d4b38e0Srsmaeda  * or http://www.opensolaris.org/os/licensing.
10*1d4b38e0Srsmaeda  * See the License for the specific language governing permissions
11*1d4b38e0Srsmaeda  * and limitations under the License.
12*1d4b38e0Srsmaeda  *
13*1d4b38e0Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
14*1d4b38e0Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1d4b38e0Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
16*1d4b38e0Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
17*1d4b38e0Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1d4b38e0Srsmaeda  *
19*1d4b38e0Srsmaeda  * CDDL HEADER END
20*1d4b38e0Srsmaeda  */
21*1d4b38e0Srsmaeda 
22*1d4b38e0Srsmaeda /*
23*1d4b38e0Srsmaeda  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1d4b38e0Srsmaeda  * Use is subject to license terms.
25*1d4b38e0Srsmaeda  */
26*1d4b38e0Srsmaeda 
27*1d4b38e0Srsmaeda #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1d4b38e0Srsmaeda 
29*1d4b38e0Srsmaeda /*
30*1d4b38e0Srsmaeda  * RCM backend for the DR Daemon
31*1d4b38e0Srsmaeda  */
32*1d4b38e0Srsmaeda 
33*1d4b38e0Srsmaeda #include <unistd.h>
34*1d4b38e0Srsmaeda #include <strings.h>
35*1d4b38e0Srsmaeda #include <errno.h>
36*1d4b38e0Srsmaeda #include <kstat.h>
37*1d4b38e0Srsmaeda #include <libnvpair.h>
38*1d4b38e0Srsmaeda #include <librcm.h>
39*1d4b38e0Srsmaeda 
40*1d4b38e0Srsmaeda #include "drd.h"
41*1d4b38e0Srsmaeda 
42*1d4b38e0Srsmaeda /*
43*1d4b38e0Srsmaeda  * RCM Backend Support
44*1d4b38e0Srsmaeda  */
45*1d4b38e0Srsmaeda static int drd_rcm_init(void);
46*1d4b38e0Srsmaeda static int drd_rcm_fini(void);
47*1d4b38e0Srsmaeda static int drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc);
48*1d4b38e0Srsmaeda static int drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc);
49*1d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc);
50*1d4b38e0Srsmaeda static int drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc);
51*1d4b38e0Srsmaeda 
52*1d4b38e0Srsmaeda drd_backend_t drd_rcm_backend = {
53*1d4b38e0Srsmaeda 	drd_rcm_init,			/* init */
54*1d4b38e0Srsmaeda 	drd_rcm_fini,			/* fini */
55*1d4b38e0Srsmaeda 	drd_rcm_cpu_config_request,	/* cpu_config_request */
56*1d4b38e0Srsmaeda 	drd_rcm_cpu_config_notify,	/* cpu_config_notify */
57*1d4b38e0Srsmaeda 	drd_rcm_cpu_unconfig_request,	/* cpu_unconfig_request */
58*1d4b38e0Srsmaeda 	drd_rcm_cpu_unconfig_notify	/* cpu_unconfig_notify */
59*1d4b38e0Srsmaeda };
60*1d4b38e0Srsmaeda 
61*1d4b38e0Srsmaeda #define	RCM_CPU_ALL		"SUNW_cpu"
62*1d4b38e0Srsmaeda #define	RCM_CPU			RCM_CPU_ALL"/cpu"
63*1d4b38e0Srsmaeda #define	RCM_CPU_MAX_LEN		(32)
64*1d4b38e0Srsmaeda 
65*1d4b38e0Srsmaeda /* global RCM handle used in all RCM operations */
66*1d4b38e0Srsmaeda static rcm_handle_t *rcm_hdl;
67*1d4b38e0Srsmaeda 
68*1d4b38e0Srsmaeda /* functions that call into RCM */
69*1d4b38e0Srsmaeda static int drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
70*1d4b38e0Srsmaeda static int drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
71*1d4b38e0Srsmaeda static int drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
72*1d4b38e0Srsmaeda static int drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc);
73*1d4b38e0Srsmaeda static int drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
74*1d4b38e0Srsmaeda static int drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
75*1d4b38e0Srsmaeda static int drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc);
76*1d4b38e0Srsmaeda 
77*1d4b38e0Srsmaeda /* utility functions */
78*1d4b38e0Srsmaeda static char **drd_rcm_cpu_rlist_init(drctl_rsrc_t *, int nrsrc, int status);
79*1d4b38e0Srsmaeda static void drd_rcm_cpu_rlist_fini(char **rlist);
80*1d4b38e0Srsmaeda static drctl_rsrc_t *cpu_rsrcstr_to_rsrc(const char *, drctl_rsrc_t *, int);
81*1d4b38e0Srsmaeda static int get_sys_cpuids(cpuid_t **cpuids, int *ncpuids);
82*1d4b38e0Srsmaeda static boolean_t is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len);
83*1d4b38e0Srsmaeda 
84*1d4b38e0Srsmaeda /* debugging utility functions */
85*1d4b38e0Srsmaeda static void dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids);
86*1d4b38e0Srsmaeda static void dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *, int nrsrc);
87*1d4b38e0Srsmaeda static void dump_cpu_rlist(char **rlist);
88*1d4b38e0Srsmaeda 
89*1d4b38e0Srsmaeda static int
90*1d4b38e0Srsmaeda drd_rcm_init(void)
91*1d4b38e0Srsmaeda {
92*1d4b38e0Srsmaeda 	int	rv;
93*1d4b38e0Srsmaeda 
94*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_init...");
95*1d4b38e0Srsmaeda 
96*1d4b38e0Srsmaeda 	rv = rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl);
97*1d4b38e0Srsmaeda 	if (rv == RCM_FAILURE) {
98*1d4b38e0Srsmaeda 		drd_err("unable to allocate RCM handle: %s", strerror(errno));
99*1d4b38e0Srsmaeda 		return (-1);
100*1d4b38e0Srsmaeda 	}
101*1d4b38e0Srsmaeda 
102*1d4b38e0Srsmaeda 	return (0);
103*1d4b38e0Srsmaeda }
104*1d4b38e0Srsmaeda 
105*1d4b38e0Srsmaeda static int
106*1d4b38e0Srsmaeda drd_rcm_fini(void)
107*1d4b38e0Srsmaeda {
108*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_fini...");
109*1d4b38e0Srsmaeda 
110*1d4b38e0Srsmaeda 	if (rcm_hdl != NULL)
111*1d4b38e0Srsmaeda 		rcm_free_handle(rcm_hdl);
112*1d4b38e0Srsmaeda 
113*1d4b38e0Srsmaeda 	return (0);
114*1d4b38e0Srsmaeda }
115*1d4b38e0Srsmaeda 
116*1d4b38e0Srsmaeda static int
117*1d4b38e0Srsmaeda drd_rcm_cpu_config_request(drctl_rsrc_t *rsrcs, int nrsrc)
118*1d4b38e0Srsmaeda {
119*1d4b38e0Srsmaeda 	int	idx;
120*1d4b38e0Srsmaeda 
121*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_config_request...");
122*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
123*1d4b38e0Srsmaeda 
124*1d4b38e0Srsmaeda 	/*
125*1d4b38e0Srsmaeda 	 * There is no RCM operation to request the addition
126*1d4b38e0Srsmaeda 	 * of resources. So, by definition, the operation for
127*1d4b38e0Srsmaeda 	 * all the CPUs is allowed.
128*1d4b38e0Srsmaeda 	 */
129*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++)
130*1d4b38e0Srsmaeda 		rsrcs[idx].status = DRCTL_STATUS_ALLOW;
131*1d4b38e0Srsmaeda 
132*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
133*1d4b38e0Srsmaeda 
134*1d4b38e0Srsmaeda 	return (0);
135*1d4b38e0Srsmaeda }
136*1d4b38e0Srsmaeda 
137*1d4b38e0Srsmaeda static int
138*1d4b38e0Srsmaeda drd_rcm_cpu_config_notify(drctl_rsrc_t *rsrcs, int nrsrc)
139*1d4b38e0Srsmaeda {
140*1d4b38e0Srsmaeda 	int	rv = 0;
141*1d4b38e0Srsmaeda 
142*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_config_notify...");
143*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
144*1d4b38e0Srsmaeda 
145*1d4b38e0Srsmaeda 	/* notify RCM about the newly added CPUs */
146*1d4b38e0Srsmaeda 	if (drd_rcm_online_cpu_notify(rsrcs, nrsrc) != 0) {
147*1d4b38e0Srsmaeda 		rv = -1;
148*1d4b38e0Srsmaeda 		goto done;
149*1d4b38e0Srsmaeda 	}
150*1d4b38e0Srsmaeda 
151*1d4b38e0Srsmaeda 	/* notify RCM about the increased CPU capacity */
152*1d4b38e0Srsmaeda 	if (drd_rcm_add_cpu_notify(rsrcs, nrsrc) != 0) {
153*1d4b38e0Srsmaeda 		rv = -1;
154*1d4b38e0Srsmaeda 	}
155*1d4b38e0Srsmaeda 
156*1d4b38e0Srsmaeda done:
157*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
158*1d4b38e0Srsmaeda 
159*1d4b38e0Srsmaeda 	return (rv);
160*1d4b38e0Srsmaeda }
161*1d4b38e0Srsmaeda 
162*1d4b38e0Srsmaeda static int
163*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_request(drctl_rsrc_t *rsrcs, int nrsrc)
164*1d4b38e0Srsmaeda {
165*1d4b38e0Srsmaeda 	int	rv = 0;
166*1d4b38e0Srsmaeda 	int	idx;
167*1d4b38e0Srsmaeda 
168*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_request...");
169*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
170*1d4b38e0Srsmaeda 
171*1d4b38e0Srsmaeda 	/* contact RCM to request a decrease in CPU capacity */
172*1d4b38e0Srsmaeda 	if (drd_rcm_del_cpu_request(rsrcs, nrsrc) != 0) {
173*1d4b38e0Srsmaeda 		rv = -1;
174*1d4b38e0Srsmaeda 		goto done;
175*1d4b38e0Srsmaeda 	}
176*1d4b38e0Srsmaeda 
177*1d4b38e0Srsmaeda 	/* contact RCM to request the removal of CPUs */
178*1d4b38e0Srsmaeda 	if (drd_rcm_offline_cpu_request(rsrcs, nrsrc) != 0) {
179*1d4b38e0Srsmaeda 		rv = -1;
180*1d4b38e0Srsmaeda 		goto done;
181*1d4b38e0Srsmaeda 	}
182*1d4b38e0Srsmaeda 
183*1d4b38e0Srsmaeda done:
184*1d4b38e0Srsmaeda 	/*
185*1d4b38e0Srsmaeda 	 * If any errors occurred, the status field for
186*1d4b38e0Srsmaeda 	 * a CPU may still be in the INIT state. Set the
187*1d4b38e0Srsmaeda 	 * status for any such CPU to DENY to ensure it
188*1d4b38e0Srsmaeda 	 * gets processed properly.
189*1d4b38e0Srsmaeda 	 */
190*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
191*1d4b38e0Srsmaeda 		if (rsrcs[idx].status == DRCTL_STATUS_INIT)
192*1d4b38e0Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
193*1d4b38e0Srsmaeda 	}
194*1d4b38e0Srsmaeda 
195*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
196*1d4b38e0Srsmaeda 
197*1d4b38e0Srsmaeda 	return (rv);
198*1d4b38e0Srsmaeda }
199*1d4b38e0Srsmaeda 
200*1d4b38e0Srsmaeda static int
201*1d4b38e0Srsmaeda drd_rcm_cpu_unconfig_notify(drctl_rsrc_t *rsrcs, int nrsrc)
202*1d4b38e0Srsmaeda {
203*1d4b38e0Srsmaeda 	int	rv = 0;
204*1d4b38e0Srsmaeda 
205*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_unconfig_notify...");
206*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list(NULL, rsrcs, nrsrc);
207*1d4b38e0Srsmaeda 
208*1d4b38e0Srsmaeda 	/*
209*1d4b38e0Srsmaeda 	 * Notify RCM about the CPUs that were removed.
210*1d4b38e0Srsmaeda 	 * Failures are ignored so that CPUs that could
211*1d4b38e0Srsmaeda 	 * not be unconfigured can be processed by RCM.
212*1d4b38e0Srsmaeda 	 */
213*1d4b38e0Srsmaeda 	(void) drd_rcm_remove_cpu_notify(rsrcs, nrsrc);
214*1d4b38e0Srsmaeda 
215*1d4b38e0Srsmaeda 	/*
216*1d4b38e0Srsmaeda 	 * Notify RCM about any CPUs that did not make it
217*1d4b38e0Srsmaeda 	 * in to the unconfigured state.
218*1d4b38e0Srsmaeda 	 */
219*1d4b38e0Srsmaeda 	if (drd_rcm_restore_cpu_notify(rsrcs, nrsrc) != 0) {
220*1d4b38e0Srsmaeda 		rv = -1;
221*1d4b38e0Srsmaeda 		goto done;
222*1d4b38e0Srsmaeda 	}
223*1d4b38e0Srsmaeda 
224*1d4b38e0Srsmaeda 	/* notify RCM about the decreased CPU capacity */
225*1d4b38e0Srsmaeda 	if (drd_rcm_del_cpu_notify(rsrcs, nrsrc) != 0) {
226*1d4b38e0Srsmaeda 		rv = -1;
227*1d4b38e0Srsmaeda 	}
228*1d4b38e0Srsmaeda 
229*1d4b38e0Srsmaeda done:
230*1d4b38e0Srsmaeda 	dump_cpu_rsrc_list("returning:", rsrcs, nrsrc);
231*1d4b38e0Srsmaeda 
232*1d4b38e0Srsmaeda 	return (rv);
233*1d4b38e0Srsmaeda }
234*1d4b38e0Srsmaeda 
235*1d4b38e0Srsmaeda static int
236*1d4b38e0Srsmaeda drd_rcm_online_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
237*1d4b38e0Srsmaeda {
238*1d4b38e0Srsmaeda 	char		**rlist;
239*1d4b38e0Srsmaeda 	int		rv = 0;
240*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
241*1d4b38e0Srsmaeda 
242*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_online_cpu_notify...");
243*1d4b38e0Srsmaeda 
244*1d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
245*1d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
246*1d4b38e0Srsmaeda 		drd_dbg("  no CPUs were successfully added, nothing to do");
247*1d4b38e0Srsmaeda 		return (0);
248*1d4b38e0Srsmaeda 	}
249*1d4b38e0Srsmaeda 
250*1d4b38e0Srsmaeda 	rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
251*1d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
252*1d4b38e0Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
253*1d4b38e0Srsmaeda 		rcm_free_info(rinfo);
254*1d4b38e0Srsmaeda 		rv = -1;
255*1d4b38e0Srsmaeda 	}
256*1d4b38e0Srsmaeda 
257*1d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
258*1d4b38e0Srsmaeda 
259*1d4b38e0Srsmaeda 	return (rv);
260*1d4b38e0Srsmaeda }
261*1d4b38e0Srsmaeda 
262*1d4b38e0Srsmaeda static int
263*1d4b38e0Srsmaeda drd_rcm_add_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
264*1d4b38e0Srsmaeda {
265*1d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
266*1d4b38e0Srsmaeda 	int		ncpus;
267*1d4b38e0Srsmaeda 	int		rv = -1;
268*1d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
269*1d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
270*1d4b38e0Srsmaeda 	int		oldncpus = 0;
271*1d4b38e0Srsmaeda 	int		newncpus = 0;
272*1d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
273*1d4b38e0Srsmaeda 	int		idx;
274*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
275*1d4b38e0Srsmaeda 
276*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_add_cpu_notify...");
277*1d4b38e0Srsmaeda 
278*1d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
279*1d4b38e0Srsmaeda 		drd_err("add_cpu_notify: cpu list empty");
280*1d4b38e0Srsmaeda 		goto done;
281*1d4b38e0Srsmaeda 	}
282*1d4b38e0Srsmaeda 
283*1d4b38e0Srsmaeda 	ncpus = nrsrc;
284*1d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
285*1d4b38e0Srsmaeda 
286*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
287*1d4b38e0Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
288*1d4b38e0Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
289*1d4b38e0Srsmaeda 	}
290*1d4b38e0Srsmaeda 
291*1d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
292*1d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
293*1d4b38e0Srsmaeda 		goto done;
294*1d4b38e0Srsmaeda 
295*1d4b38e0Srsmaeda 	/*
296*1d4b38e0Srsmaeda 	 * Added CPU capacity, so newcpus is the current list
297*1d4b38e0Srsmaeda 	 * of CPUs in the system.
298*1d4b38e0Srsmaeda 	 */
299*1d4b38e0Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1)
300*1d4b38e0Srsmaeda 		goto done;
301*1d4b38e0Srsmaeda 
302*1d4b38e0Srsmaeda 	/*
303*1d4b38e0Srsmaeda 	 * Since the operation added CPU capacity, the old CPU
304*1d4b38e0Srsmaeda 	 * list is the new CPU list with the CPUs involved in
305*1d4b38e0Srsmaeda 	 * the operation removed.
306*1d4b38e0Srsmaeda 	 */
307*1d4b38e0Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus, sizeof (cpuid_t));
308*1d4b38e0Srsmaeda 	if (oldcpus == NULL)
309*1d4b38e0Srsmaeda 		goto done;
310*1d4b38e0Srsmaeda 
311*1d4b38e0Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
312*1d4b38e0Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, ncpus))
313*1d4b38e0Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
314*1d4b38e0Srsmaeda 	}
315*1d4b38e0Srsmaeda 
316*1d4b38e0Srsmaeda 	/* dump pre and post lists */
317*1d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
318*1d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
319*1d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
320*1d4b38e0Srsmaeda 
321*1d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
322*1d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
323*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
324*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
325*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
326*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
327*1d4b38e0Srsmaeda 		goto done;
328*1d4b38e0Srsmaeda 	}
329*1d4b38e0Srsmaeda 
330*1d4b38e0Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
331*1d4b38e0Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
332*1d4b38e0Srsmaeda 
333*1d4b38e0Srsmaeda done:
334*1d4b38e0Srsmaeda 	s_nvfree(nvl);
335*1d4b38e0Srsmaeda 	s_free(cpus);
336*1d4b38e0Srsmaeda 	s_free(oldcpus);
337*1d4b38e0Srsmaeda 	s_free(newcpus);
338*1d4b38e0Srsmaeda 
339*1d4b38e0Srsmaeda 	return (rv);
340*1d4b38e0Srsmaeda }
341*1d4b38e0Srsmaeda 
342*1d4b38e0Srsmaeda static int
343*1d4b38e0Srsmaeda drd_rcm_del_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
344*1d4b38e0Srsmaeda {
345*1d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
346*1d4b38e0Srsmaeda 	int		ncpus;
347*1d4b38e0Srsmaeda 	int		rv = -1;
348*1d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
349*1d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
350*1d4b38e0Srsmaeda 	int		oldncpus = 0;
351*1d4b38e0Srsmaeda 	int		newncpus = 0;
352*1d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
353*1d4b38e0Srsmaeda 	int		idx;
354*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
355*1d4b38e0Srsmaeda 
356*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_del_cpu_request...");
357*1d4b38e0Srsmaeda 
358*1d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
359*1d4b38e0Srsmaeda 		drd_err("del_cpu_request: cpu list empty");
360*1d4b38e0Srsmaeda 		goto done;
361*1d4b38e0Srsmaeda 	}
362*1d4b38e0Srsmaeda 
363*1d4b38e0Srsmaeda 	ncpus = nrsrc;
364*1d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
365*1d4b38e0Srsmaeda 
366*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
367*1d4b38e0Srsmaeda 		cpus[idx] = rsrcs[idx].res_cpu_id;
368*1d4b38e0Srsmaeda 	}
369*1d4b38e0Srsmaeda 
370*1d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
371*1d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
372*1d4b38e0Srsmaeda 		goto done;
373*1d4b38e0Srsmaeda 	}
374*1d4b38e0Srsmaeda 
375*1d4b38e0Srsmaeda 	/*
376*1d4b38e0Srsmaeda 	 * Removing CPU capacity, so oldcpus is the current
377*1d4b38e0Srsmaeda 	 * list of CPUs in the system.
378*1d4b38e0Srsmaeda 	 */
379*1d4b38e0Srsmaeda 	if (get_sys_cpuids(&oldcpus, &oldncpus) == -1) {
380*1d4b38e0Srsmaeda 		goto done;
381*1d4b38e0Srsmaeda 	}
382*1d4b38e0Srsmaeda 
383*1d4b38e0Srsmaeda 	/*
384*1d4b38e0Srsmaeda 	 * Since this is a request to remove CPU capacity,
385*1d4b38e0Srsmaeda 	 * the new CPU list is the old CPU list with the CPUs
386*1d4b38e0Srsmaeda 	 * involved in the operation removed.
387*1d4b38e0Srsmaeda 	 */
388*1d4b38e0Srsmaeda 	newcpus = (cpuid_t *)calloc(oldncpus, sizeof (cpuid_t));
389*1d4b38e0Srsmaeda 	if (newcpus == NULL) {
390*1d4b38e0Srsmaeda 		goto done;
391*1d4b38e0Srsmaeda 	}
392*1d4b38e0Srsmaeda 
393*1d4b38e0Srsmaeda 	for (idx = 0; idx < oldncpus; idx++) {
394*1d4b38e0Srsmaeda 		if (!is_cpu_in_list(oldcpus[idx], cpus, ncpus))
395*1d4b38e0Srsmaeda 			newcpus[newncpus++] = oldcpus[idx];
396*1d4b38e0Srsmaeda 	}
397*1d4b38e0Srsmaeda 
398*1d4b38e0Srsmaeda 	/* dump pre and post lists */
399*1d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
400*1d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
401*1d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, ncpus);
402*1d4b38e0Srsmaeda 
403*1d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
404*1d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
405*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
406*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
407*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
408*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
409*1d4b38e0Srsmaeda 		goto done;
410*1d4b38e0Srsmaeda 	}
411*1d4b38e0Srsmaeda 
412*1d4b38e0Srsmaeda 	rv = rcm_request_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
413*1d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
414*1d4b38e0Srsmaeda 		drd_dbg("RCM call failed: %d", rv);
415*1d4b38e0Srsmaeda 		/*
416*1d4b38e0Srsmaeda 		 * Since the capcity change was blocked, we
417*1d4b38e0Srsmaeda 		 * mark all CPUs as blocked. It is up to the
418*1d4b38e0Srsmaeda 		 * user to reframe the query so that it can
419*1d4b38e0Srsmaeda 		 * succeed.
420*1d4b38e0Srsmaeda 		 */
421*1d4b38e0Srsmaeda 		for (idx = 0; idx < nrsrc; idx++) {
422*1d4b38e0Srsmaeda 			rsrcs[idx].status = DRCTL_STATUS_DENY;
423*1d4b38e0Srsmaeda 		}
424*1d4b38e0Srsmaeda 
425*1d4b38e0Srsmaeda 		/* tack on message to first resource */
426*1d4b38e0Srsmaeda 		rsrcs[0].offset = (uintptr_t)strdup("unable to remove "
427*1d4b38e0Srsmaeda 		    "specified number of CPUs");
428*1d4b38e0Srsmaeda 		drd_dbg("  unable to remove specified number of CPUs");
429*1d4b38e0Srsmaeda 		goto done;
430*1d4b38e0Srsmaeda 	}
431*1d4b38e0Srsmaeda 
432*1d4b38e0Srsmaeda 	rv = 0;
433*1d4b38e0Srsmaeda 
434*1d4b38e0Srsmaeda done:
435*1d4b38e0Srsmaeda 	s_nvfree(nvl);
436*1d4b38e0Srsmaeda 	s_free(cpus);
437*1d4b38e0Srsmaeda 	s_free(oldcpus);
438*1d4b38e0Srsmaeda 	s_free(newcpus);
439*1d4b38e0Srsmaeda 
440*1d4b38e0Srsmaeda 	return (rv);
441*1d4b38e0Srsmaeda }
442*1d4b38e0Srsmaeda 
443*1d4b38e0Srsmaeda static int
444*1d4b38e0Srsmaeda drd_rcm_offline_cpu_request(drctl_rsrc_t *rsrcs, int nrsrc)
445*1d4b38e0Srsmaeda {
446*1d4b38e0Srsmaeda 	char		**rlist;
447*1d4b38e0Srsmaeda 	drctl_rsrc_t	*rsrc;
448*1d4b38e0Srsmaeda 	int		idx;
449*1d4b38e0Srsmaeda 	int		state;
450*1d4b38e0Srsmaeda 	int		rv = 0;
451*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo = NULL;
452*1d4b38e0Srsmaeda 	rcm_info_tuple_t *tuple = NULL;
453*1d4b38e0Srsmaeda 	const char	*rsrcstr;
454*1d4b38e0Srsmaeda 	const char	*errstr;
455*1d4b38e0Srsmaeda 
456*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_offline_cpu_request...");
457*1d4b38e0Srsmaeda 
458*1d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
459*1d4b38e0Srsmaeda 	    DRCTL_STATUS_INIT)) == NULL) {
460*1d4b38e0Srsmaeda 		drd_err("unable to generate resource list");
461*1d4b38e0Srsmaeda 		return (-1);
462*1d4b38e0Srsmaeda 	}
463*1d4b38e0Srsmaeda 
464*1d4b38e0Srsmaeda 	rv = rcm_request_offline_list(rcm_hdl, rlist, 0, &rinfo);
465*1d4b38e0Srsmaeda 	if (rv == RCM_SUCCESS) {
466*1d4b38e0Srsmaeda 		drd_dbg("RCM success, rinfo=%p", rinfo);
467*1d4b38e0Srsmaeda 		goto done;
468*1d4b38e0Srsmaeda 	}
469*1d4b38e0Srsmaeda 
470*1d4b38e0Srsmaeda 	drd_dbg("RCM call failed (%d):", rv);
471*1d4b38e0Srsmaeda 
472*1d4b38e0Srsmaeda 	/*
473*1d4b38e0Srsmaeda 	 * Loop through the result of the operation and add
474*1d4b38e0Srsmaeda 	 * any error messages to the resource structure.
475*1d4b38e0Srsmaeda 	 */
476*1d4b38e0Srsmaeda 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
477*1d4b38e0Srsmaeda 
478*1d4b38e0Srsmaeda 		/* find the resource of interest */
479*1d4b38e0Srsmaeda 		rsrcstr = rcm_info_rsrc(tuple);
480*1d4b38e0Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rsrcstr, rsrcs, nrsrc);
481*1d4b38e0Srsmaeda 
482*1d4b38e0Srsmaeda 		if (rsrc == NULL) {
483*1d4b38e0Srsmaeda 			drd_dbg("unable to find resource for %s", rsrcstr);
484*1d4b38e0Srsmaeda 			continue;
485*1d4b38e0Srsmaeda 		}
486*1d4b38e0Srsmaeda 
487*1d4b38e0Srsmaeda 		errstr = rcm_info_error(tuple);
488*1d4b38e0Srsmaeda 
489*1d4b38e0Srsmaeda 		if (errstr) {
490*1d4b38e0Srsmaeda 			drd_dbg("  %s: '%s'", rsrcstr, errstr);
491*1d4b38e0Srsmaeda 			rsrc->offset = (uintptr_t)strdup(errstr);
492*1d4b38e0Srsmaeda 		}
493*1d4b38e0Srsmaeda 	}
494*1d4b38e0Srsmaeda 
495*1d4b38e0Srsmaeda 	rcm_free_info(rinfo);
496*1d4b38e0Srsmaeda 	rv = 0;
497*1d4b38e0Srsmaeda 
498*1d4b38e0Srsmaeda done:
499*1d4b38e0Srsmaeda 	/*
500*1d4b38e0Srsmaeda 	 * Set the state of the resource based on the RCM
501*1d4b38e0Srsmaeda 	 * state. CPUs in the offline state have the ok to
502*1d4b38e0Srsmaeda 	 * proceed. All others have been blocked.
503*1d4b38e0Srsmaeda 	 */
504*1d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
505*1d4b38e0Srsmaeda 
506*1d4b38e0Srsmaeda 		state = 0;
507*1d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
508*1d4b38e0Srsmaeda 
509*1d4b38e0Srsmaeda 		/* find the resource of interest */
510*1d4b38e0Srsmaeda 		rsrc = cpu_rsrcstr_to_rsrc(rlist[idx], rsrcs, nrsrc);
511*1d4b38e0Srsmaeda 
512*1d4b38e0Srsmaeda 		if (rsrc == NULL) {
513*1d4b38e0Srsmaeda 			drd_dbg("unable to find resource for %s", rlist[idx]);
514*1d4b38e0Srsmaeda 			continue;
515*1d4b38e0Srsmaeda 		}
516*1d4b38e0Srsmaeda 
517*1d4b38e0Srsmaeda 		rsrc->status = ((state == RCM_STATE_OFFLINE) ?
518*1d4b38e0Srsmaeda 		    DRCTL_STATUS_ALLOW : DRCTL_STATUS_DENY);
519*1d4b38e0Srsmaeda 	}
520*1d4b38e0Srsmaeda 
521*1d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
522*1d4b38e0Srsmaeda 
523*1d4b38e0Srsmaeda 	return (rv);
524*1d4b38e0Srsmaeda }
525*1d4b38e0Srsmaeda 
526*1d4b38e0Srsmaeda static int
527*1d4b38e0Srsmaeda drd_rcm_remove_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
528*1d4b38e0Srsmaeda {
529*1d4b38e0Srsmaeda 	char		**rlist;
530*1d4b38e0Srsmaeda 	int		rv = 0;
531*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
532*1d4b38e0Srsmaeda 
533*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_remove_cpu_notify...");
534*1d4b38e0Srsmaeda 
535*1d4b38e0Srsmaeda 	if ((rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
536*1d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_SUCCESS)) == NULL) {
537*1d4b38e0Srsmaeda 		drd_dbg("  no CPUs in the success state, nothing to do");
538*1d4b38e0Srsmaeda 		return (0);
539*1d4b38e0Srsmaeda 	}
540*1d4b38e0Srsmaeda 
541*1d4b38e0Srsmaeda 	rv = rcm_notify_remove_list(rcm_hdl, rlist, 0, &rinfo);
542*1d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
543*1d4b38e0Srsmaeda 		drd_info("rcm_notify_remove_list failed: %d", rv);
544*1d4b38e0Srsmaeda 		rcm_free_info(rinfo);
545*1d4b38e0Srsmaeda 		rv = -1;
546*1d4b38e0Srsmaeda 	}
547*1d4b38e0Srsmaeda 
548*1d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(rlist);
549*1d4b38e0Srsmaeda 
550*1d4b38e0Srsmaeda 	return (rv);
551*1d4b38e0Srsmaeda }
552*1d4b38e0Srsmaeda 
553*1d4b38e0Srsmaeda static int
554*1d4b38e0Srsmaeda drd_rcm_restore_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
555*1d4b38e0Srsmaeda {
556*1d4b38e0Srsmaeda 	char		**rlist;
557*1d4b38e0Srsmaeda 	char		**full_rlist;
558*1d4b38e0Srsmaeda 	int		idx;
559*1d4b38e0Srsmaeda 	int		ridx;
560*1d4b38e0Srsmaeda 	int		state;
561*1d4b38e0Srsmaeda 	int		rv = 0;
562*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
563*1d4b38e0Srsmaeda 
564*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_restore_cpu_notify...");
565*1d4b38e0Srsmaeda 
566*1d4b38e0Srsmaeda 	if ((full_rlist = drd_rcm_cpu_rlist_init(rsrcs, nrsrc,
567*1d4b38e0Srsmaeda 	    DRCTL_STATUS_CONFIG_FAILURE)) == NULL) {
568*1d4b38e0Srsmaeda 		drd_dbg("  no CPUs in the failed state, nothing to do");
569*1d4b38e0Srsmaeda 		return (0);
570*1d4b38e0Srsmaeda 	}
571*1d4b38e0Srsmaeda 
572*1d4b38e0Srsmaeda 	/*
573*1d4b38e0Srsmaeda 	 * Since the desired result of this operation is to
574*1d4b38e0Srsmaeda 	 * restore resources to the online state, filter out
575*1d4b38e0Srsmaeda 	 * the resources already in the online state before
576*1d4b38e0Srsmaeda 	 * passing the list to RCM.
577*1d4b38e0Srsmaeda 	 */
578*1d4b38e0Srsmaeda 
579*1d4b38e0Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
580*1d4b38e0Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
581*1d4b38e0Srsmaeda 	if (rlist == NULL) {
582*1d4b38e0Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
583*1d4b38e0Srsmaeda 		rv = -1;
584*1d4b38e0Srsmaeda 		goto done;
585*1d4b38e0Srsmaeda 	}
586*1d4b38e0Srsmaeda 
587*1d4b38e0Srsmaeda 	for (idx = 0, ridx = 0; full_rlist[idx] != NULL; idx++) {
588*1d4b38e0Srsmaeda 		state = 0;
589*1d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, full_rlist[idx], &state);
590*1d4b38e0Srsmaeda 		if (state != RCM_STATE_ONLINE) {
591*1d4b38e0Srsmaeda 			rlist[ridx] = full_rlist[idx];
592*1d4b38e0Srsmaeda 			ridx++;
593*1d4b38e0Srsmaeda 		}
594*1d4b38e0Srsmaeda 	}
595*1d4b38e0Srsmaeda 
596*1d4b38e0Srsmaeda 	/* check if everything got filtered out */
597*1d4b38e0Srsmaeda 	if (ridx == 0) {
598*1d4b38e0Srsmaeda 		drd_dbg("  all CPUs already online, nothing to do");
599*1d4b38e0Srsmaeda 		goto done;
600*1d4b38e0Srsmaeda 	}
601*1d4b38e0Srsmaeda 
602*1d4b38e0Srsmaeda 	rv = rcm_notify_online_list(rcm_hdl, rlist, 0, &rinfo);
603*1d4b38e0Srsmaeda 	if (rv != RCM_SUCCESS) {
604*1d4b38e0Srsmaeda 		drd_info("rcm_notify_online_list failed: %d", rv);
605*1d4b38e0Srsmaeda 		rcm_free_info(rinfo);
606*1d4b38e0Srsmaeda 		rv = -1;
607*1d4b38e0Srsmaeda 	}
608*1d4b38e0Srsmaeda 
609*1d4b38e0Srsmaeda done:
610*1d4b38e0Srsmaeda 	drd_rcm_cpu_rlist_fini(full_rlist);
611*1d4b38e0Srsmaeda 	s_free(rlist);
612*1d4b38e0Srsmaeda 
613*1d4b38e0Srsmaeda 	return (rv);
614*1d4b38e0Srsmaeda }
615*1d4b38e0Srsmaeda 
616*1d4b38e0Srsmaeda static int
617*1d4b38e0Srsmaeda drd_rcm_del_cpu_notify(drctl_rsrc_t *rsrcs, int nrsrc)
618*1d4b38e0Srsmaeda {
619*1d4b38e0Srsmaeda 	cpuid_t		*cpus = NULL;
620*1d4b38e0Srsmaeda 	int		rv = -1;
621*1d4b38e0Srsmaeda 	cpuid_t		*oldcpus = NULL;
622*1d4b38e0Srsmaeda 	cpuid_t		*newcpus = NULL;
623*1d4b38e0Srsmaeda 	int		oldncpus = 0;
624*1d4b38e0Srsmaeda 	int		newncpus = 0;
625*1d4b38e0Srsmaeda 	nvlist_t	*nvl = NULL;
626*1d4b38e0Srsmaeda 	int		idx;
627*1d4b38e0Srsmaeda 	int		cidx;
628*1d4b38e0Srsmaeda 	rcm_info_t	*rinfo;
629*1d4b38e0Srsmaeda 
630*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_del_cpu_notify...");
631*1d4b38e0Srsmaeda 
632*1d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
633*1d4b38e0Srsmaeda 		drd_err("del_cpu_notify: cpu list empty");
634*1d4b38e0Srsmaeda 		goto done;
635*1d4b38e0Srsmaeda 	}
636*1d4b38e0Srsmaeda 
637*1d4b38e0Srsmaeda 	cpus = (cpuid_t *)malloc(nrsrc * sizeof (cpuid_t));
638*1d4b38e0Srsmaeda 
639*1d4b38e0Srsmaeda 	/*
640*1d4b38e0Srsmaeda 	 * Filter out the CPUs that could not be unconfigured.
641*1d4b38e0Srsmaeda 	 */
642*1d4b38e0Srsmaeda 	for (idx = 0, cidx = 0; idx < nrsrc; idx++) {
643*1d4b38e0Srsmaeda 		if (rsrcs[idx].status != DRCTL_STATUS_CONFIG_SUCCESS)
644*1d4b38e0Srsmaeda 			continue;
645*1d4b38e0Srsmaeda 		drd_dbg("  cpu[%d] = %d", idx, rsrcs[idx].res_cpu_id);
646*1d4b38e0Srsmaeda 		cpus[cidx] = rsrcs[idx].res_cpu_id;
647*1d4b38e0Srsmaeda 		cidx++;
648*1d4b38e0Srsmaeda 	}
649*1d4b38e0Srsmaeda 
650*1d4b38e0Srsmaeda 	drd_dbg("  ncpus = %d", cidx);
651*1d4b38e0Srsmaeda 
652*1d4b38e0Srsmaeda 	/* nothing to do */
653*1d4b38e0Srsmaeda 	if (cidx == 0) {
654*1d4b38e0Srsmaeda 		rv = 0;
655*1d4b38e0Srsmaeda 		goto done;
656*1d4b38e0Srsmaeda 	}
657*1d4b38e0Srsmaeda 
658*1d4b38e0Srsmaeda 	/* allocate an nvlist for the RCM call */
659*1d4b38e0Srsmaeda 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
660*1d4b38e0Srsmaeda 		goto done;
661*1d4b38e0Srsmaeda 	}
662*1d4b38e0Srsmaeda 
663*1d4b38e0Srsmaeda 	/*
664*1d4b38e0Srsmaeda 	 * Removed CPU capacity, so newcpus is the current list
665*1d4b38e0Srsmaeda 	 * of CPUs in the system.
666*1d4b38e0Srsmaeda 	 */
667*1d4b38e0Srsmaeda 	if (get_sys_cpuids(&newcpus, &newncpus) == -1) {
668*1d4b38e0Srsmaeda 		goto done;
669*1d4b38e0Srsmaeda 	}
670*1d4b38e0Srsmaeda 
671*1d4b38e0Srsmaeda 	/*
672*1d4b38e0Srsmaeda 	 * Since the operation removed CPU capacity, the old CPU
673*1d4b38e0Srsmaeda 	 * list is the new CPU list with the CPUs involved in
674*1d4b38e0Srsmaeda 	 * the operation added.
675*1d4b38e0Srsmaeda 	 */
676*1d4b38e0Srsmaeda 	oldcpus = (cpuid_t *)calloc(newncpus + cidx, sizeof (cpuid_t));
677*1d4b38e0Srsmaeda 	if (oldcpus == NULL) {
678*1d4b38e0Srsmaeda 		goto done;
679*1d4b38e0Srsmaeda 	}
680*1d4b38e0Srsmaeda 
681*1d4b38e0Srsmaeda 	for (idx = 0; idx < newncpus; idx++) {
682*1d4b38e0Srsmaeda 		if (!is_cpu_in_list(newcpus[idx], cpus, cidx))
683*1d4b38e0Srsmaeda 			oldcpus[oldncpus++] = newcpus[idx];
684*1d4b38e0Srsmaeda 	}
685*1d4b38e0Srsmaeda 
686*1d4b38e0Srsmaeda 	for (idx = 0; idx < cidx; idx++) {
687*1d4b38e0Srsmaeda 		oldcpus[oldncpus++] = cpus[idx];
688*1d4b38e0Srsmaeda 	}
689*1d4b38e0Srsmaeda 
690*1d4b38e0Srsmaeda 	/* dump pre and post lists */
691*1d4b38e0Srsmaeda 	dump_cpu_list("oldcpus: ", oldcpus, oldncpus);
692*1d4b38e0Srsmaeda 	dump_cpu_list("newcpus: ", newcpus, newncpus);
693*1d4b38e0Srsmaeda 	dump_cpu_list("delta:   ", cpus, cidx);
694*1d4b38e0Srsmaeda 
695*1d4b38e0Srsmaeda 	/* setup the nvlist for the RCM call */
696*1d4b38e0Srsmaeda 	if (nvlist_add_string(nvl, "state", "capacity") ||
697*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "old_total", oldncpus) ||
698*1d4b38e0Srsmaeda 	    nvlist_add_int32(nvl, "new_total", newncpus) ||
699*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "old_cpu_list", oldcpus, oldncpus) ||
700*1d4b38e0Srsmaeda 	    nvlist_add_int32_array(nvl, "new_cpu_list", newcpus, newncpus)) {
701*1d4b38e0Srsmaeda 		goto done;
702*1d4b38e0Srsmaeda 	}
703*1d4b38e0Srsmaeda 
704*1d4b38e0Srsmaeda 	rv = rcm_notify_capacity_change(rcm_hdl, RCM_CPU_ALL, 0, nvl, &rinfo);
705*1d4b38e0Srsmaeda 	rv = (rv == RCM_SUCCESS) ? 0 : -1;
706*1d4b38e0Srsmaeda 
707*1d4b38e0Srsmaeda done:
708*1d4b38e0Srsmaeda 	s_nvfree(nvl);
709*1d4b38e0Srsmaeda 	s_free(cpus);
710*1d4b38e0Srsmaeda 	s_free(oldcpus);
711*1d4b38e0Srsmaeda 	s_free(newcpus);
712*1d4b38e0Srsmaeda 
713*1d4b38e0Srsmaeda 	return (rv);
714*1d4b38e0Srsmaeda }
715*1d4b38e0Srsmaeda 
716*1d4b38e0Srsmaeda /*
717*1d4b38e0Srsmaeda  * Given a list of resource structures, create a list of CPU
718*1d4b38e0Srsmaeda  * resource strings formatted as expected by RCM. Only resources
719*1d4b38e0Srsmaeda  * that are in the state specified by the status argument are
720*1d4b38e0Srsmaeda  * included in the resulting list.
721*1d4b38e0Srsmaeda  */
722*1d4b38e0Srsmaeda static char **
723*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_init(drctl_rsrc_t *rsrcs, int nrsrc, int status)
724*1d4b38e0Srsmaeda {
725*1d4b38e0Srsmaeda 	char	rbuf[RCM_CPU_MAX_LEN];
726*1d4b38e0Srsmaeda 	char	**rlist;
727*1d4b38e0Srsmaeda 	int	idx;
728*1d4b38e0Srsmaeda 	int	ridx;
729*1d4b38e0Srsmaeda 
730*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_init...");
731*1d4b38e0Srsmaeda 
732*1d4b38e0Srsmaeda 	if ((rsrcs == NULL) || (nrsrc == 0)) {
733*1d4b38e0Srsmaeda 		drd_dbg("cpu list is empty");
734*1d4b38e0Srsmaeda 		return (NULL);
735*1d4b38e0Srsmaeda 	}
736*1d4b38e0Srsmaeda 
737*1d4b38e0Srsmaeda 	/* allocate a zero filled array to ensure NULL terminated list */
738*1d4b38e0Srsmaeda 	rlist = (char **)calloc((nrsrc + 1), sizeof (char *));
739*1d4b38e0Srsmaeda 	if (rlist == NULL) {
740*1d4b38e0Srsmaeda 		drd_err("calloc failed: %s", strerror(errno));
741*1d4b38e0Srsmaeda 		return (NULL);
742*1d4b38e0Srsmaeda 	}
743*1d4b38e0Srsmaeda 
744*1d4b38e0Srsmaeda 	for (idx = 0, ridx = 0; idx < nrsrc; idx++) {
745*1d4b38e0Srsmaeda 
746*1d4b38e0Srsmaeda 		drd_dbg("  checking cpu %d, status=%d, expected status=%d",
747*1d4b38e0Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status, status);
748*1d4b38e0Srsmaeda 
749*1d4b38e0Srsmaeda 		/*
750*1d4b38e0Srsmaeda 		 * Filter out the CPUs that are not in
751*1d4b38e0Srsmaeda 		 * the requested state.
752*1d4b38e0Srsmaeda 		 */
753*1d4b38e0Srsmaeda 		if (rsrcs[idx].status != status)
754*1d4b38e0Srsmaeda 			continue;
755*1d4b38e0Srsmaeda 
756*1d4b38e0Srsmaeda 		/* generate the resource string */
757*1d4b38e0Srsmaeda 		(void) sprintf(rbuf, "%s%d", RCM_CPU, rsrcs[idx].res_cpu_id);
758*1d4b38e0Srsmaeda 
759*1d4b38e0Srsmaeda 		rlist[ridx] = strdup(rbuf);
760*1d4b38e0Srsmaeda 		if (rlist[ridx] == NULL) {
761*1d4b38e0Srsmaeda 			drd_err("strdup failed: %s", strerror(errno));
762*1d4b38e0Srsmaeda 			drd_rcm_cpu_rlist_fini(rlist);
763*1d4b38e0Srsmaeda 			return (NULL);
764*1d4b38e0Srsmaeda 		}
765*1d4b38e0Srsmaeda 
766*1d4b38e0Srsmaeda 		ridx++;
767*1d4b38e0Srsmaeda 	}
768*1d4b38e0Srsmaeda 
769*1d4b38e0Srsmaeda 	/* cleanup if the list is empty */
770*1d4b38e0Srsmaeda 	if (ridx == 0) {
771*1d4b38e0Srsmaeda 		s_free(rlist);
772*1d4b38e0Srsmaeda 	}
773*1d4b38e0Srsmaeda 
774*1d4b38e0Srsmaeda 	drd_dbg("final rlist:");
775*1d4b38e0Srsmaeda 	dump_cpu_rlist(rlist);
776*1d4b38e0Srsmaeda 
777*1d4b38e0Srsmaeda 	return (rlist);
778*1d4b38e0Srsmaeda }
779*1d4b38e0Srsmaeda 
780*1d4b38e0Srsmaeda static void
781*1d4b38e0Srsmaeda drd_rcm_cpu_rlist_fini(char **rlist)
782*1d4b38e0Srsmaeda {
783*1d4b38e0Srsmaeda 	int idx;
784*1d4b38e0Srsmaeda 
785*1d4b38e0Srsmaeda 	drd_dbg("drd_rcm_cpu_rlist_fini...");
786*1d4b38e0Srsmaeda 
787*1d4b38e0Srsmaeda 	dump_cpu_rlist(rlist);
788*1d4b38e0Srsmaeda 
789*1d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
790*1d4b38e0Srsmaeda 		s_free(rlist[idx]);
791*1d4b38e0Srsmaeda 	}
792*1d4b38e0Srsmaeda 
793*1d4b38e0Srsmaeda 	s_free(rlist);
794*1d4b38e0Srsmaeda }
795*1d4b38e0Srsmaeda 
796*1d4b38e0Srsmaeda /*
797*1d4b38e0Srsmaeda  * Convert an RCM CPU resource string into a numerical cpuid.
798*1d4b38e0Srsmaeda  * Assumes the resource string has the form: "SUNW_cpu/cpu<C>"
799*1d4b38e0Srsmaeda  * where "<C>" is the numerical cpuid of interest.
800*1d4b38e0Srsmaeda  */
801*1d4b38e0Srsmaeda static cpuid_t
802*1d4b38e0Srsmaeda cpu_rsrcstr_to_cpuid(const char *rsrc)
803*1d4b38e0Srsmaeda {
804*1d4b38e0Srsmaeda 	char	*cpuid_off;
805*1d4b38e0Srsmaeda 	cpuid_t	cpuid;
806*1d4b38e0Srsmaeda 
807*1d4b38e0Srsmaeda 	/*
808*1d4b38e0Srsmaeda 	 * Search for the last occurrance of 'u' in the
809*1d4b38e0Srsmaeda 	 * expected RCM resource string "SUNW_cpu/cpu<C>".
810*1d4b38e0Srsmaeda 	 * This will give a pointer to the cpuid portion.
811*1d4b38e0Srsmaeda 	 */
812*1d4b38e0Srsmaeda 	cpuid_off = strrchr(rsrc, 'u');
813*1d4b38e0Srsmaeda 	cpuid_off++;
814*1d4b38e0Srsmaeda 
815*1d4b38e0Srsmaeda 	cpuid = atoi(cpuid_off);
816*1d4b38e0Srsmaeda 
817*1d4b38e0Srsmaeda 	return (cpuid);
818*1d4b38e0Srsmaeda }
819*1d4b38e0Srsmaeda 
820*1d4b38e0Srsmaeda /*
821*1d4b38e0Srsmaeda  * Given an RCM CPU resource string, return a pointer to the
822*1d4b38e0Srsmaeda  * corresponding resource structure from the given resource list.
823*1d4b38e0Srsmaeda  * NULL is returned if no matching resource structure can be
824*1d4b38e0Srsmaeda  * found.
825*1d4b38e0Srsmaeda  */
826*1d4b38e0Srsmaeda static drctl_rsrc_t *
827*1d4b38e0Srsmaeda cpu_rsrcstr_to_rsrc(const char *rsrcstr, drctl_rsrc_t *rsrcs, int nrsrc)
828*1d4b38e0Srsmaeda {
829*1d4b38e0Srsmaeda 	cpuid_t	cpuid;
830*1d4b38e0Srsmaeda 	int	idx;
831*1d4b38e0Srsmaeda 
832*1d4b38e0Srsmaeda 	cpuid = cpu_rsrcstr_to_cpuid(rsrcstr);
833*1d4b38e0Srsmaeda 
834*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
835*1d4b38e0Srsmaeda 		if (rsrcs[idx].res_cpu_id == cpuid)
836*1d4b38e0Srsmaeda 			return (&rsrcs[idx]);
837*1d4b38e0Srsmaeda 	}
838*1d4b38e0Srsmaeda 
839*1d4b38e0Srsmaeda 	return (NULL);
840*1d4b38e0Srsmaeda }
841*1d4b38e0Srsmaeda 
842*1d4b38e0Srsmaeda static int
843*1d4b38e0Srsmaeda get_sys_cpuids(cpuid_t **cpuids, int *ncpuids)
844*1d4b38e0Srsmaeda {
845*1d4b38e0Srsmaeda 	int		ncpu = 0;
846*1d4b38e0Srsmaeda 	int		maxncpu;
847*1d4b38e0Srsmaeda 	kstat_t		*ksp;
848*1d4b38e0Srsmaeda 	kstat_ctl_t	*kc = NULL;
849*1d4b38e0Srsmaeda 	cpuid_t		*cp;
850*1d4b38e0Srsmaeda 
851*1d4b38e0Srsmaeda 	drd_dbg("get_sys_cpuids...");
852*1d4b38e0Srsmaeda 
853*1d4b38e0Srsmaeda 	if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1)
854*1d4b38e0Srsmaeda 		return (-1);
855*1d4b38e0Srsmaeda 
856*1d4b38e0Srsmaeda 	if ((kc = kstat_open()) == NULL)
857*1d4b38e0Srsmaeda 		return (-1);
858*1d4b38e0Srsmaeda 
859*1d4b38e0Srsmaeda 	if ((cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
860*1d4b38e0Srsmaeda 		(void) kstat_close(kc);
861*1d4b38e0Srsmaeda 		return (-1);
862*1d4b38e0Srsmaeda 	}
863*1d4b38e0Srsmaeda 
864*1d4b38e0Srsmaeda 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
865*1d4b38e0Srsmaeda 		if (strcmp(ksp->ks_module, "cpu_info") == 0)
866*1d4b38e0Srsmaeda 			cp[ncpu++] = ksp->ks_instance;
867*1d4b38e0Srsmaeda 	}
868*1d4b38e0Srsmaeda 
869*1d4b38e0Srsmaeda 	dump_cpu_list("syscpus: ", cp, ncpu);
870*1d4b38e0Srsmaeda 
871*1d4b38e0Srsmaeda 	(void) kstat_close(kc);
872*1d4b38e0Srsmaeda 
873*1d4b38e0Srsmaeda 	*cpuids = cp;
874*1d4b38e0Srsmaeda 	*ncpuids = ncpu;
875*1d4b38e0Srsmaeda 
876*1d4b38e0Srsmaeda 	return (0);
877*1d4b38e0Srsmaeda }
878*1d4b38e0Srsmaeda 
879*1d4b38e0Srsmaeda static boolean_t
880*1d4b38e0Srsmaeda is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int len)
881*1d4b38e0Srsmaeda {
882*1d4b38e0Srsmaeda 	int idx;
883*1d4b38e0Srsmaeda 
884*1d4b38e0Srsmaeda 	if (list == NULL)
885*1d4b38e0Srsmaeda 		return (B_FALSE);
886*1d4b38e0Srsmaeda 
887*1d4b38e0Srsmaeda 	for (idx = 0; idx < len; idx++) {
888*1d4b38e0Srsmaeda 		if (list[idx] == cpuid)
889*1d4b38e0Srsmaeda 			return (B_TRUE);
890*1d4b38e0Srsmaeda 	}
891*1d4b38e0Srsmaeda 
892*1d4b38e0Srsmaeda 	return (B_FALSE);
893*1d4b38e0Srsmaeda }
894*1d4b38e0Srsmaeda 
895*1d4b38e0Srsmaeda #define	CPUIDS_PER_LINE		16
896*1d4b38e0Srsmaeda #define	LINEWIDTH		(2 * (CPUIDS_PER_LINE * 4))
897*1d4b38e0Srsmaeda 
898*1d4b38e0Srsmaeda static void
899*1d4b38e0Srsmaeda dump_cpu_list(char *prefix, cpuid_t *cpuids, int ncpuids)
900*1d4b38e0Srsmaeda {
901*1d4b38e0Srsmaeda 	char	line[LINEWIDTH];
902*1d4b38e0Srsmaeda 	char	*curr;
903*1d4b38e0Srsmaeda 	int	i, j;
904*1d4b38e0Srsmaeda 
905*1d4b38e0Srsmaeda 	/* return if not debugging */
906*1d4b38e0Srsmaeda 	if (drd_debug == 0)
907*1d4b38e0Srsmaeda 		return;
908*1d4b38e0Srsmaeda 
909*1d4b38e0Srsmaeda 	/* print just the prefix if CPU list is empty */
910*1d4b38e0Srsmaeda 	if (ncpuids == 0) {
911*1d4b38e0Srsmaeda 		if (prefix)
912*1d4b38e0Srsmaeda 			drd_dbg("%s", prefix);
913*1d4b38e0Srsmaeda 		return;
914*1d4b38e0Srsmaeda 	}
915*1d4b38e0Srsmaeda 
916*1d4b38e0Srsmaeda 	for (i = 0; i < ncpuids; i += CPUIDS_PER_LINE) {
917*1d4b38e0Srsmaeda 
918*1d4b38e0Srsmaeda 		bzero(line, LINEWIDTH);
919*1d4b38e0Srsmaeda 		curr = line;
920*1d4b38e0Srsmaeda 
921*1d4b38e0Srsmaeda 		/* start with the prefix */
922*1d4b38e0Srsmaeda 		(void) sprintf(curr, "%s", (prefix) ? prefix : "");
923*1d4b38e0Srsmaeda 		curr = line + strlen(line);
924*1d4b38e0Srsmaeda 
925*1d4b38e0Srsmaeda 		/* format the CPUs for this line */
926*1d4b38e0Srsmaeda 		for (j = 0; (j < CPUIDS_PER_LINE) && ((i + j) < ncpuids); j++) {
927*1d4b38e0Srsmaeda 			(void) sprintf(curr, "%3d ", cpuids[i + j]);
928*1d4b38e0Srsmaeda 			curr = line + strlen(line);
929*1d4b38e0Srsmaeda 		}
930*1d4b38e0Srsmaeda 
931*1d4b38e0Srsmaeda 		drd_dbg("%s", line);
932*1d4b38e0Srsmaeda 	}
933*1d4b38e0Srsmaeda }
934*1d4b38e0Srsmaeda 
935*1d4b38e0Srsmaeda static void
936*1d4b38e0Srsmaeda dump_cpu_rsrc_list(char *prefix, drctl_rsrc_t *rsrcs, int nrsrc)
937*1d4b38e0Srsmaeda {
938*1d4b38e0Srsmaeda 	int	idx;
939*1d4b38e0Srsmaeda 	char	*errstr;
940*1d4b38e0Srsmaeda 
941*1d4b38e0Srsmaeda 	/* just return if not debugging */
942*1d4b38e0Srsmaeda 	if (drd_debug == 0)
943*1d4b38e0Srsmaeda 		return;
944*1d4b38e0Srsmaeda 
945*1d4b38e0Srsmaeda 	if (prefix)
946*1d4b38e0Srsmaeda 		drd_dbg("%s", prefix);
947*1d4b38e0Srsmaeda 
948*1d4b38e0Srsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
949*1d4b38e0Srsmaeda 
950*1d4b38e0Srsmaeda 		/* get a pointer to the error string */
951*1d4b38e0Srsmaeda 		errstr = (char *)(uintptr_t)rsrcs[idx].offset;
952*1d4b38e0Srsmaeda 
953*1d4b38e0Srsmaeda 		drd_dbg("  cpu[%d]: cpuid=%d, status=%d, errstr='%s'", idx,
954*1d4b38e0Srsmaeda 		    rsrcs[idx].res_cpu_id, rsrcs[idx].status,
955*1d4b38e0Srsmaeda 		    (errstr != NULL) ? errstr : "");
956*1d4b38e0Srsmaeda 	}
957*1d4b38e0Srsmaeda }
958*1d4b38e0Srsmaeda 
959*1d4b38e0Srsmaeda static void
960*1d4b38e0Srsmaeda dump_cpu_rlist(char **rlist)
961*1d4b38e0Srsmaeda {
962*1d4b38e0Srsmaeda 	int	idx;
963*1d4b38e0Srsmaeda 	int	state;
964*1d4b38e0Srsmaeda 
965*1d4b38e0Srsmaeda 	static char *rcm_state_str[] = {
966*1d4b38e0Srsmaeda 		"UNKNOWN",		"ONLINE",		"ONLINING",
967*1d4b38e0Srsmaeda 		"OFFLINE_FAIL",		"OFFLINING",		"OFFLINE",
968*1d4b38e0Srsmaeda 		"REMOVING",		"INVALID_7",		"INVALID_8",
969*1d4b38e0Srsmaeda 		"INVALID_9",		"RESUMING",		"SUSPEND_FAIL",
970*1d4b38e0Srsmaeda 		"SUSPENDING",		"SUSPEND",		"REMOVE",
971*1d4b38e0Srsmaeda 		"OFFLINE_QUERYING",	"OFFLINE_QUERY_FAIL",	"OFFLINE_QUERY",
972*1d4b38e0Srsmaeda 		"SUSPEND_QUERYING",	"SUSPEND_QUERY_FAIL",	"SUSPEND_QUERY"
973*1d4b38e0Srsmaeda 	};
974*1d4b38e0Srsmaeda 
975*1d4b38e0Srsmaeda 	/* just return if not debugging */
976*1d4b38e0Srsmaeda 	if (drd_debug == 0)
977*1d4b38e0Srsmaeda 		return;
978*1d4b38e0Srsmaeda 
979*1d4b38e0Srsmaeda 	if (rlist == NULL) {
980*1d4b38e0Srsmaeda 		drd_dbg("  empty rlist");
981*1d4b38e0Srsmaeda 		return;
982*1d4b38e0Srsmaeda 	}
983*1d4b38e0Srsmaeda 
984*1d4b38e0Srsmaeda 	for (idx = 0; rlist[idx] != NULL; idx++) {
985*1d4b38e0Srsmaeda 		state = 0;
986*1d4b38e0Srsmaeda 		rcm_get_rsrcstate(rcm_hdl, rlist[idx], &state);
987*1d4b38e0Srsmaeda 		drd_dbg("  rlist[%d]: rsrc=%s, state=%-2d (%s)", idx,
988*1d4b38e0Srsmaeda 		    rlist[idx], state, rcm_state_str[state]);
989*1d4b38e0Srsmaeda 	}
990*1d4b38e0Srsmaeda }
991