xref: /titanic_50/usr/src/uts/sun4v/io/dr_cpu.c (revision 4a9fd251254a5d3b654717d88da3fc34a79bba8c)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
237de586caSJames Marks - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo /*
281ae08745Sheppo  * sun4v CPU DR Module
291ae08745Sheppo  */
301ae08745Sheppo 
311ae08745Sheppo #include <sys/modctl.h>
321ae08745Sheppo #include <sys/processor.h>
331ae08745Sheppo #include <sys/cpuvar.h>
340c86d1bbSrsmaeda #include <sys/cpupart.h>
351ae08745Sheppo #include <sys/sunddi.h>
361ae08745Sheppo #include <sys/sunndi.h>
371ae08745Sheppo #include <sys/note.h>
381ae08745Sheppo #include <sys/sysevent/dr.h>
391ae08745Sheppo #include <sys/hypervisor_api.h>
401ae08745Sheppo #include <sys/mach_descrip.h>
411ae08745Sheppo #include <sys/mdesc.h>
421ae08745Sheppo #include <sys/ds.h>
431d4b38e0Srsmaeda #include <sys/drctl.h>
441ae08745Sheppo #include <sys/dr_util.h>
451ae08745Sheppo #include <sys/dr_cpu.h>
461ae08745Sheppo #include <sys/promif.h>
471ae08745Sheppo #include <sys/machsystm.h>
481ae08745Sheppo 
491ae08745Sheppo 
501ae08745Sheppo static struct modlmisc modlmisc = {
511ae08745Sheppo 	&mod_miscops,
52f500b196SRichard Bean 	"sun4v CPU DR"
531ae08745Sheppo };
541ae08745Sheppo 
551ae08745Sheppo static struct modlinkage modlinkage = {
561ae08745Sheppo 	MODREV_1,
571ae08745Sheppo 	(void *)&modlmisc,
581ae08745Sheppo 	NULL
591ae08745Sheppo };
601ae08745Sheppo 
611d4b38e0Srsmaeda typedef int (*fn_t)(processorid_t, int *, boolean_t);
621d4b38e0Srsmaeda 
631ae08745Sheppo /*
641ae08745Sheppo  * Global DS Handle
651ae08745Sheppo  */
661ae08745Sheppo static ds_svc_hdl_t ds_handle;
671ae08745Sheppo 
681ae08745Sheppo /*
691ae08745Sheppo  * Supported DS Capability Versions
701ae08745Sheppo  */
7199c7e855SJames Marks - Sun Microsystems static ds_ver_t		dr_cpu_vers[] = { { 1, 1 }, { 1, 0 } };
721ae08745Sheppo #define	DR_CPU_NVERS	(sizeof (dr_cpu_vers) / sizeof (dr_cpu_vers[0]))
731ae08745Sheppo 
7499c7e855SJames Marks - Sun Microsystems static ds_ver_t		version;
7599c7e855SJames Marks - Sun Microsystems 
761ae08745Sheppo /*
771ae08745Sheppo  * DS Capability Description
781ae08745Sheppo  */
791ae08745Sheppo static ds_capability_t dr_cpu_cap = {
801ae08745Sheppo 	DR_CPU_DS_ID,		/* svc_id */
811ae08745Sheppo 	dr_cpu_vers,		/* vers */
821ae08745Sheppo 	DR_CPU_NVERS		/* nvers */
831ae08745Sheppo };
841ae08745Sheppo 
8599c7e855SJames Marks - Sun Microsystems #define	DRCPU_VERS_EQ(_maj, _min) \
8699c7e855SJames Marks - Sun Microsystems 	((version.major == (_maj)) && (version.minor == (_min)))
8799c7e855SJames Marks - Sun Microsystems 
8899c7e855SJames Marks - Sun Microsystems #define	DRCPU_VERS_GTEQ(_maj, _min) \
8999c7e855SJames Marks - Sun Microsystems 	((version.major > (_maj)) ||					\
9099c7e855SJames Marks - Sun Microsystems 	((version.major == (_maj)) && (version.minor >= (_min))))
9199c7e855SJames Marks - Sun Microsystems 
921ae08745Sheppo /*
931ae08745Sheppo  * DS Callbacks
941ae08745Sheppo  */
951ae08745Sheppo static void dr_cpu_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
961ae08745Sheppo static void dr_cpu_unreg_handler(ds_cb_arg_t arg);
971ae08745Sheppo static void dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
981ae08745Sheppo 
991ae08745Sheppo /*
1001ae08745Sheppo  * DS Client Ops Vector
1011ae08745Sheppo  */
1021ae08745Sheppo static ds_clnt_ops_t dr_cpu_ops = {
1031ae08745Sheppo 	dr_cpu_reg_handler,	/* ds_reg_cb */
1041ae08745Sheppo 	dr_cpu_unreg_handler,	/* ds_unreg_cb */
1051ae08745Sheppo 	dr_cpu_data_handler,	/* ds_data_cb */
1061ae08745Sheppo 	NULL			/* cb_arg */
1071ae08745Sheppo };
1081ae08745Sheppo 
1091ae08745Sheppo /*
1100c86d1bbSrsmaeda  * Operation Results
1110c86d1bbSrsmaeda  *
1120c86d1bbSrsmaeda  * Used internally to gather results while an operation on a
1130c86d1bbSrsmaeda  * list of CPUs is in progress. In particular, it is used to
1140c86d1bbSrsmaeda  * keep track of which CPUs have already failed so that they are
1150c86d1bbSrsmaeda  * not processed further, and the manner in which they failed.
1160c86d1bbSrsmaeda  */
1170c86d1bbSrsmaeda typedef struct {
1180c86d1bbSrsmaeda 	uint32_t	cpuid;
1190c86d1bbSrsmaeda 	uint32_t	result;
1200c86d1bbSrsmaeda 	uint32_t	status;
1210c86d1bbSrsmaeda 	char		*string;
1220c86d1bbSrsmaeda } dr_cpu_res_t;
1230c86d1bbSrsmaeda 
1240c86d1bbSrsmaeda #define	DR_CPU_MAX_ERR_LEN	64	/* maximum error string length */
1250c86d1bbSrsmaeda 
1260c86d1bbSrsmaeda /*
1271ae08745Sheppo  * Internal Functions
1281ae08745Sheppo  */
1291ae08745Sheppo static int dr_cpu_init(void);
1301ae08745Sheppo static int dr_cpu_fini(void);
1311ae08745Sheppo 
1320c86d1bbSrsmaeda static int dr_cpu_list_wrk(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1331ae08745Sheppo static int dr_cpu_list_status(dr_cpu_hdr_t *, dr_cpu_hdr_t **, int *);
1341ae08745Sheppo 
1351ae08745Sheppo static int dr_cpu_unconfigure(processorid_t, int *status, boolean_t force);
1361d4b38e0Srsmaeda static int dr_cpu_configure(processorid_t, int *status, boolean_t force);
1371ae08745Sheppo static int dr_cpu_status(processorid_t, int *status);
1381ae08745Sheppo 
1390c86d1bbSrsmaeda static void dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res);
1400c86d1bbSrsmaeda static void dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres);
1410c86d1bbSrsmaeda static int dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res);
1420c86d1bbSrsmaeda 
1430c86d1bbSrsmaeda static dr_cpu_res_t *dr_cpu_res_array_init(dr_cpu_hdr_t *, drctl_rsrc_t *, int);
1440c86d1bbSrsmaeda static void dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres);
1450c86d1bbSrsmaeda static size_t dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res,
1460c86d1bbSrsmaeda     dr_cpu_hdr_t **respp);
1470c86d1bbSrsmaeda 
1481ae08745Sheppo static int dr_cpu_probe(processorid_t newcpuid);
1491ae08745Sheppo static int dr_cpu_deprobe(processorid_t cpuid);
1501ae08745Sheppo 
1511ae08745Sheppo static dev_info_t *dr_cpu_find_node(processorid_t cpuid);
1521ae08745Sheppo static mde_cookie_t dr_cpu_find_node_md(processorid_t, md_t *, mde_cookie_t *);
1531ae08745Sheppo 
1541ae08745Sheppo int
_init(void)1551ae08745Sheppo _init(void)
1561ae08745Sheppo {
1571ae08745Sheppo 	int	status;
1581ae08745Sheppo 
1591ae08745Sheppo 	/* check that CPU DR is enabled */
1601ae08745Sheppo 	if (dr_is_disabled(DR_TYPE_CPU)) {
1611ae08745Sheppo 		cmn_err(CE_CONT, "!CPU DR is disabled\n");
1621ae08745Sheppo 		return (-1);
1631ae08745Sheppo 	}
1641ae08745Sheppo 
1651ae08745Sheppo 	if ((status = dr_cpu_init()) != 0) {
1661ae08745Sheppo 		cmn_err(CE_NOTE, "CPU DR initialization failed");
1671ae08745Sheppo 		return (status);
1681ae08745Sheppo 	}
1691ae08745Sheppo 
1701ae08745Sheppo 	if ((status = mod_install(&modlinkage)) != 0) {
1711ae08745Sheppo 		(void) dr_cpu_fini();
1721ae08745Sheppo 	}
1731ae08745Sheppo 
1741ae08745Sheppo 	return (status);
1751ae08745Sheppo }
1761ae08745Sheppo 
1771ae08745Sheppo int
_info(struct modinfo * modinfop)1781ae08745Sheppo _info(struct modinfo *modinfop)
1791ae08745Sheppo {
1801ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
1811ae08745Sheppo }
1821ae08745Sheppo 
1831ae08745Sheppo int dr_cpu_allow_unload;
1841ae08745Sheppo 
1851ae08745Sheppo int
_fini(void)1861ae08745Sheppo _fini(void)
1871ae08745Sheppo {
1881ae08745Sheppo 	int	status;
1891ae08745Sheppo 
1901ae08745Sheppo 	if (dr_cpu_allow_unload == 0)
1911ae08745Sheppo 		return (EBUSY);
1921ae08745Sheppo 
1931ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) == 0) {
1941ae08745Sheppo 		(void) dr_cpu_fini();
1951ae08745Sheppo 	}
1961ae08745Sheppo 
1971ae08745Sheppo 	return (status);
1981ae08745Sheppo }
1991ae08745Sheppo 
2001ae08745Sheppo static int
dr_cpu_init(void)2011ae08745Sheppo dr_cpu_init(void)
2021ae08745Sheppo {
2031ae08745Sheppo 	int	rv;
2041ae08745Sheppo 
2051ae08745Sheppo 	if ((rv = ds_cap_init(&dr_cpu_cap, &dr_cpu_ops)) != 0) {
2061ae08745Sheppo 		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
2071ae08745Sheppo 		return (-1);
2081ae08745Sheppo 	}
2091ae08745Sheppo 
2101ae08745Sheppo 	return (0);
2111ae08745Sheppo }
2121ae08745Sheppo 
2131ae08745Sheppo static int
dr_cpu_fini(void)2141ae08745Sheppo dr_cpu_fini(void)
2151ae08745Sheppo {
2161ae08745Sheppo 	int	rv;
2171ae08745Sheppo 
2181ae08745Sheppo 	if ((rv = ds_cap_fini(&dr_cpu_cap)) != 0) {
2191ae08745Sheppo 		cmn_err(CE_NOTE, "ds_cap_fini failed: %d", rv);
2201ae08745Sheppo 		return (-1);
2211ae08745Sheppo 	}
2221ae08745Sheppo 
2231ae08745Sheppo 	return (0);
2241ae08745Sheppo }
2251ae08745Sheppo 
2261ae08745Sheppo static void
dr_cpu_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)2271ae08745Sheppo dr_cpu_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
2281ae08745Sheppo {
2291ae08745Sheppo 	DR_DBG_CPU("reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", arg,
2301ae08745Sheppo 	    ver->major, ver->minor, hdl);
2311ae08745Sheppo 
23299c7e855SJames Marks - Sun Microsystems 	version.major = ver->major;
23399c7e855SJames Marks - Sun Microsystems 	version.minor = ver->minor;
2341ae08745Sheppo 	ds_handle = hdl;
2351ae08745Sheppo }
2361ae08745Sheppo 
2371ae08745Sheppo static void
dr_cpu_unreg_handler(ds_cb_arg_t arg)2381ae08745Sheppo dr_cpu_unreg_handler(ds_cb_arg_t arg)
2391ae08745Sheppo {
2401ae08745Sheppo 	DR_DBG_CPU("unreg_handler: arg=0x%p\n", arg);
2411ae08745Sheppo 
2421ae08745Sheppo 	ds_handle = DS_INVALID_HDL;
2431ae08745Sheppo }
2441ae08745Sheppo 
2451ae08745Sheppo static void
dr_cpu_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)2461ae08745Sheppo dr_cpu_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2471ae08745Sheppo {
2481ae08745Sheppo 	_NOTE(ARGUNUSED(arg))
2491ae08745Sheppo 
2501ae08745Sheppo 	dr_cpu_hdr_t	*req = buf;
2511ae08745Sheppo 	dr_cpu_hdr_t	err_resp;
2521ae08745Sheppo 	dr_cpu_hdr_t	*resp = &err_resp;
2531ae08745Sheppo 	int		resp_len = 0;
2541ae08745Sheppo 	int		rv;
2551ae08745Sheppo 
2561ae08745Sheppo 	/*
2571ae08745Sheppo 	 * Sanity check the message
2581ae08745Sheppo 	 */
2591ae08745Sheppo 	if (buflen < sizeof (dr_cpu_hdr_t)) {
2601ae08745Sheppo 		DR_DBG_CPU("incoming message short: expected at least %ld "
2611ae08745Sheppo 		    "bytes, received %ld\n", sizeof (dr_cpu_hdr_t), buflen);
2621ae08745Sheppo 		goto done;
2631ae08745Sheppo 	}
2641ae08745Sheppo 
2651ae08745Sheppo 	if (req == NULL) {
2661ae08745Sheppo 		DR_DBG_CPU("empty message: expected at least %ld bytes\n",
2671ae08745Sheppo 		    sizeof (dr_cpu_hdr_t));
2681ae08745Sheppo 		goto done;
2691ae08745Sheppo 	}
2701ae08745Sheppo 
2711ae08745Sheppo 	DR_DBG_CPU("incoming request:\n");
2721ae08745Sheppo 	DR_DBG_DUMP_MSG(buf, buflen);
2731ae08745Sheppo 
2741ae08745Sheppo 	if (req->num_records > NCPU) {
2751ae08745Sheppo 		DR_DBG_CPU("CPU list too long: %d when %d is the maximum\n",
2761ae08745Sheppo 		    req->num_records, NCPU);
2771ae08745Sheppo 		goto done;
2781ae08745Sheppo 	}
2791ae08745Sheppo 
2801ae08745Sheppo 	if (req->num_records == 0) {
2811ae08745Sheppo 		DR_DBG_CPU("No CPU specified for operation\n");
2821ae08745Sheppo 		goto done;
2831ae08745Sheppo 	}
2841ae08745Sheppo 
2851ae08745Sheppo 	/*
2861ae08745Sheppo 	 * Process the command
2871ae08745Sheppo 	 */
2881ae08745Sheppo 	switch (req->msg_type) {
2891ae08745Sheppo 	case DR_CPU_CONFIGURE:
2901ae08745Sheppo 	case DR_CPU_UNCONFIGURE:
2911ae08745Sheppo 	case DR_CPU_FORCE_UNCONFIG:
2920c86d1bbSrsmaeda 		if ((rv = dr_cpu_list_wrk(req, &resp, &resp_len)) != 0) {
2930c86d1bbSrsmaeda 			DR_DBG_CPU("%s%s failed (%d)\n",
2940c86d1bbSrsmaeda 			    (req->msg_type == DR_CPU_CONFIGURE) ?
2950c86d1bbSrsmaeda 			    "CPU configure" : "CPU unconfigure",
2960c86d1bbSrsmaeda 			    (req->msg_type == DR_CPU_FORCE_UNCONFIG) ?
2970c86d1bbSrsmaeda 			    " (forced)" : "", rv);
2980c86d1bbSrsmaeda 		}
2991ae08745Sheppo 		break;
3001ae08745Sheppo 
3011ae08745Sheppo 	case DR_CPU_STATUS:
3021ae08745Sheppo 		if ((rv = dr_cpu_list_status(req, &resp, &resp_len)) != 0)
3030c86d1bbSrsmaeda 			DR_DBG_CPU("CPU status failed (%d)\n", rv);
3041ae08745Sheppo 		break;
3051ae08745Sheppo 
3061ae08745Sheppo 	default:
3071ae08745Sheppo 		cmn_err(CE_NOTE, "unsupported DR operation (%d)",
3081ae08745Sheppo 		    req->msg_type);
3091ae08745Sheppo 		break;
3101ae08745Sheppo 	}
3111ae08745Sheppo 
3121ae08745Sheppo done:
3131ae08745Sheppo 	/* check if an error occurred */
3141ae08745Sheppo 	if (resp == &err_resp) {
3151ae08745Sheppo 		resp->req_num = (req) ? req->req_num : 0;
3161ae08745Sheppo 		resp->msg_type = DR_CPU_ERROR;
3171ae08745Sheppo 		resp->num_records = 0;
3181ae08745Sheppo 		resp_len = sizeof (dr_cpu_hdr_t);
3191ae08745Sheppo 	}
3201ae08745Sheppo 
3210c86d1bbSrsmaeda 	DR_DBG_CPU("outgoing response:\n");
3220c86d1bbSrsmaeda 	DR_DBG_DUMP_MSG(resp, resp_len);
3230c86d1bbSrsmaeda 
3241ae08745Sheppo 	/* send back the response */
3251ae08745Sheppo 	if (ds_cap_send(ds_handle, resp, resp_len) != 0) {
3261ae08745Sheppo 		DR_DBG_CPU("ds_send failed\n");
3271ae08745Sheppo 	}
3281ae08745Sheppo 
3291ae08745Sheppo 	/* free any allocated memory */
33099c7e855SJames Marks - Sun Microsystems 	if (DRCPU_VERS_GTEQ(1, 1) || (resp != &err_resp)) {
33199c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %d\n",
33299c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)resp, resp_len);
3331ae08745Sheppo 		kmem_free(resp, resp_len);
3341ae08745Sheppo 	}
3351ae08745Sheppo }
3361ae08745Sheppo 
3371ae08745Sheppo /*
33899c7e855SJames Marks - Sun Microsystems  * Create a response message which consists of a header followed
33999c7e855SJames Marks - Sun Microsystems  * by the error string passed in.
34099c7e855SJames Marks - Sun Microsystems  */
34199c7e855SJames Marks - Sun Microsystems static size_t
dr_cpu_err_resp(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** respp,char * msg)34299c7e855SJames Marks - Sun Microsystems dr_cpu_err_resp(dr_cpu_hdr_t *req, dr_cpu_hdr_t **respp, char *msg)
34399c7e855SJames Marks - Sun Microsystems {
34499c7e855SJames Marks - Sun Microsystems 	size_t size;
34599c7e855SJames Marks - Sun Microsystems 	dr_cpu_hdr_t *resp;
34699c7e855SJames Marks - Sun Microsystems 
34799c7e855SJames Marks - Sun Microsystems 	ASSERT((msg != NULL) && (strlen(msg) > 0));
34899c7e855SJames Marks - Sun Microsystems 
34999c7e855SJames Marks - Sun Microsystems 	size = sizeof (*req) + strlen(msg) + 1;
35099c7e855SJames Marks - Sun Microsystems 	resp = kmem_alloc(size, KM_SLEEP);
35199c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
35299c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)resp, size);
35399c7e855SJames Marks - Sun Microsystems 
35499c7e855SJames Marks - Sun Microsystems 	resp->req_num = req->req_num;
35599c7e855SJames Marks - Sun Microsystems 	resp->msg_type = DR_CPU_ERROR;
35699c7e855SJames Marks - Sun Microsystems 	resp->num_records = 0;
35799c7e855SJames Marks - Sun Microsystems 
35899c7e855SJames Marks - Sun Microsystems 	(void) strcpy((char *)(resp) + sizeof (*resp), msg);
35999c7e855SJames Marks - Sun Microsystems 
36099c7e855SJames Marks - Sun Microsystems 	*respp = resp;
36199c7e855SJames Marks - Sun Microsystems 
36299c7e855SJames Marks - Sun Microsystems 	return (size);
36399c7e855SJames Marks - Sun Microsystems }
36499c7e855SJames Marks - Sun Microsystems 
36599c7e855SJames Marks - Sun Microsystems /*
3661d4b38e0Srsmaeda  * Common routine to config or unconfig multiple cpus.  The unconfig
3671d4b38e0Srsmaeda  * case checks with the OS to see if the removal of cpus will be
3681d4b38e0Srsmaeda  * permitted, but can be overridden by the "force" version of the
3691d4b38e0Srsmaeda  * command.  Otherwise, the logic for both cases is identical.
3701d4b38e0Srsmaeda  *
3711d4b38e0Srsmaeda  * Note: Do not modify result buffer or length on error.
3721ae08745Sheppo  */
3731ae08745Sheppo static int
dr_cpu_list_wrk(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)3740c86d1bbSrsmaeda dr_cpu_list_wrk(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
3751ae08745Sheppo {
3761d4b38e0Srsmaeda 	int		rv;
3770c86d1bbSrsmaeda 	int		idx;
3780c86d1bbSrsmaeda 	int		count;
3790c86d1bbSrsmaeda 	fn_t		dr_fn;
3800c86d1bbSrsmaeda 	int		se_hint;
3810c86d1bbSrsmaeda 	boolean_t	force = B_FALSE;
3820c86d1bbSrsmaeda 	uint32_t	*req_cpus;
3830c86d1bbSrsmaeda 	dr_cpu_res_t	*res;
3840c86d1bbSrsmaeda 	int		drctl_cmd;
3850c86d1bbSrsmaeda 	int		drctl_flags = 0;
3860c86d1bbSrsmaeda 	drctl_rsrc_t	*drctl_req;
3870c86d1bbSrsmaeda 	size_t		drctl_req_len;
38899c7e855SJames Marks - Sun Microsystems 	drctl_resp_t	*drctl_resp;
38999c7e855SJames Marks - Sun Microsystems 	drctl_rsrc_t	*drctl_rsrc;
39099c7e855SJames Marks - Sun Microsystems 	size_t		drctl_resp_len = 0;
3910c86d1bbSrsmaeda 	drctl_cookie_t	drctl_res_ck;
3920c86d1bbSrsmaeda 
3930c86d1bbSrsmaeda 	ASSERT((req != NULL) && (req->num_records != 0));
3941ae08745Sheppo 
3950c86d1bbSrsmaeda 	count = req->num_records;
3961ae08745Sheppo 
3970c86d1bbSrsmaeda 	/*
3980c86d1bbSrsmaeda 	 * Extract all information that is specific
3990c86d1bbSrsmaeda 	 * to the various types of operations.
4000c86d1bbSrsmaeda 	 */
4010c86d1bbSrsmaeda 	switch (req->msg_type) {
4021d4b38e0Srsmaeda 	case DR_CPU_CONFIGURE:
4030c86d1bbSrsmaeda 		dr_fn = dr_cpu_configure;
4040c86d1bbSrsmaeda 		drctl_cmd = DRCTL_CPU_CONFIG_REQUEST;
4050c86d1bbSrsmaeda 		se_hint = SE_HINT_INSERT;
4061d4b38e0Srsmaeda 		break;
4071d4b38e0Srsmaeda 	case DR_CPU_FORCE_UNCONFIG:
4080c86d1bbSrsmaeda 		drctl_flags = DRCTL_FLAG_FORCE;
4091d4b38e0Srsmaeda 		force = B_TRUE;
4101d4b38e0Srsmaeda 		_NOTE(FALLTHROUGH)
4111d4b38e0Srsmaeda 	case DR_CPU_UNCONFIGURE:
4120c86d1bbSrsmaeda 		dr_fn = dr_cpu_unconfigure;
4130c86d1bbSrsmaeda 		drctl_cmd = DRCTL_CPU_UNCONFIG_REQUEST;
4140c86d1bbSrsmaeda 		se_hint = SE_HINT_REMOVE;
4151d4b38e0Srsmaeda 		break;
4161d4b38e0Srsmaeda 	default:
4171d4b38e0Srsmaeda 		/* Programming error if we reach this. */
41899c7e855SJames Marks - Sun Microsystems 		cmn_err(CE_NOTE,
41999c7e855SJames Marks - Sun Microsystems 		    "%s: bad msg_type %d\n", __func__, req->msg_type);
4201d4b38e0Srsmaeda 		ASSERT(0);
4211d4b38e0Srsmaeda 		return (-1);
4221ae08745Sheppo 	}
4231ae08745Sheppo 
4240c86d1bbSrsmaeda 	/* the incoming array of cpuids to operate on */
4250c86d1bbSrsmaeda 	req_cpus = DR_CPU_CMD_CPUIDS(req);
4261d4b38e0Srsmaeda 
4271d4b38e0Srsmaeda 	/* allocate drctl request msg based on incoming resource count */
4280c86d1bbSrsmaeda 	drctl_req_len = sizeof (drctl_rsrc_t) * count;
4290c86d1bbSrsmaeda 	drctl_req = kmem_zalloc(drctl_req_len, KM_SLEEP);
43099c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
43199c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
4321d4b38e0Srsmaeda 
4331d4b38e0Srsmaeda 	/* copy the cpuids for the drctl call from the incoming request msg */
4341d4b38e0Srsmaeda 	for (idx = 0; idx < count; idx++)
4350c86d1bbSrsmaeda 		drctl_req[idx].res_cpu_id = req_cpus[idx];
4361d4b38e0Srsmaeda 
43799c7e855SJames Marks - Sun Microsystems 	rv = drctl_config_init(drctl_cmd, drctl_flags, drctl_req,
43899c7e855SJames Marks - Sun Microsystems 	    count, &drctl_resp, &drctl_resp_len, &drctl_res_ck);
43999c7e855SJames Marks - Sun Microsystems 
44099c7e855SJames Marks - Sun Microsystems 	ASSERT((drctl_resp != NULL) && (drctl_resp_len != 0));
44199c7e855SJames Marks - Sun Microsystems 
44299c7e855SJames Marks - Sun Microsystems 	if (rv != 0) {
44399c7e855SJames Marks - Sun Microsystems 		DR_DBG_CPU("%s: drctl_config_init "
44499c7e855SJames Marks - Sun Microsystems 		    "returned: %d\n", __func__, rv);
44599c7e855SJames Marks - Sun Microsystems 
44699c7e855SJames Marks - Sun Microsystems 		if (DRCPU_VERS_EQ(1, 0)) {
44799c7e855SJames Marks - Sun Microsystems 			rv = -1;
44899c7e855SJames Marks - Sun Microsystems 		} else {
44999c7e855SJames Marks - Sun Microsystems 			ASSERT(DRCPU_VERS_GTEQ(1, 1));
45099c7e855SJames Marks - Sun Microsystems 			ASSERT(drctl_resp->resp_type == DRCTL_RESP_ERR);
45199c7e855SJames Marks - Sun Microsystems 
45299c7e855SJames Marks - Sun Microsystems 			*resp_len = dr_cpu_err_resp(req,
45399c7e855SJames Marks - Sun Microsystems 			    resp, drctl_resp->resp_err_msg);
4541d4b38e0Srsmaeda 		}
4551d4b38e0Srsmaeda 
45699c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
45799c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)drctl_resp, drctl_resp_len);
45899c7e855SJames Marks - Sun Microsystems 		kmem_free(drctl_resp, drctl_resp_len);
45999c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
46099c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)drctl_req, drctl_req_len);
46199c7e855SJames Marks - Sun Microsystems 		kmem_free(drctl_req, drctl_req_len);
46299c7e855SJames Marks - Sun Microsystems 
46399c7e855SJames Marks - Sun Microsystems 		return (rv);
46499c7e855SJames Marks - Sun Microsystems 	}
46599c7e855SJames Marks - Sun Microsystems 
46699c7e855SJames Marks - Sun Microsystems 	ASSERT(drctl_resp->resp_type == DRCTL_RESP_OK);
46799c7e855SJames Marks - Sun Microsystems 
46899c7e855SJames Marks - Sun Microsystems 	drctl_rsrc = drctl_resp->resp_resources;
4690c86d1bbSrsmaeda 
4700c86d1bbSrsmaeda 	/* create the result scratch array */
47199c7e855SJames Marks - Sun Microsystems 	res = dr_cpu_res_array_init(req, drctl_rsrc, count);
4721d4b38e0Srsmaeda 
4731d4b38e0Srsmaeda 	/*
4740c86d1bbSrsmaeda 	 * For unconfigure, check if there are any conditions
4750c86d1bbSrsmaeda 	 * that will cause the operation to fail. These are
4760c86d1bbSrsmaeda 	 * performed before the actual unconfigure attempt so
4770c86d1bbSrsmaeda 	 * that a meaningful error message can be generated.
4781d4b38e0Srsmaeda 	 */
4790c86d1bbSrsmaeda 	if (req->msg_type != DR_CPU_CONFIGURE)
4800c86d1bbSrsmaeda 		dr_cpu_check_cpus(req, res);
4811d4b38e0Srsmaeda 
4820c86d1bbSrsmaeda 	/* perform the specified operation on each of the CPUs */
4831d4b38e0Srsmaeda 	for (idx = 0; idx < count; idx++) {
4840c86d1bbSrsmaeda 		int result;
4850c86d1bbSrsmaeda 		int status;
4861d4b38e0Srsmaeda 
4871d4b38e0Srsmaeda 		/*
4880c86d1bbSrsmaeda 		 * If no action will be taken against the current
4890c86d1bbSrsmaeda 		 * CPU, update the drctl resource information to
4900c86d1bbSrsmaeda 		 * ensure that it gets recovered properly during
4910c86d1bbSrsmaeda 		 * the drctl fini() call.
4921d4b38e0Srsmaeda 		 */
4930c86d1bbSrsmaeda 		if (res[idx].result != DR_CPU_RES_OK) {
4940c86d1bbSrsmaeda 			drctl_req[idx].status = DRCTL_STATUS_CONFIG_FAILURE;
4950c86d1bbSrsmaeda 			continue;
4961d4b38e0Srsmaeda 		}
4971d4b38e0Srsmaeda 
4980c86d1bbSrsmaeda 		/* call the function to perform the actual operation */
4990c86d1bbSrsmaeda 		result = (*dr_fn)(req_cpus[idx], &status, force);
5001d4b38e0Srsmaeda 
5010c86d1bbSrsmaeda 		/* save off results of the operation */
5020c86d1bbSrsmaeda 		res[idx].result = result;
5030c86d1bbSrsmaeda 		res[idx].status = status;
5041d4b38e0Srsmaeda 
5050c86d1bbSrsmaeda 		/* save result for drctl fini() reusing init() msg memory */
5060c86d1bbSrsmaeda 		drctl_req[idx].status = (result != DR_CPU_RES_OK) ?
5070c86d1bbSrsmaeda 		    DRCTL_STATUS_CONFIG_FAILURE : DRCTL_STATUS_CONFIG_SUCCESS;
5081d4b38e0Srsmaeda 
5090c86d1bbSrsmaeda 		DR_DBG_CPU("%s: cpuid %d status %d result %d off '%s'\n",
51099c7e855SJames Marks - Sun Microsystems 		    __func__, req_cpus[idx], drctl_req[idx].status, result,
5110c86d1bbSrsmaeda 		    (res[idx].string) ? res[idx].string : "");
5120c86d1bbSrsmaeda 	}
5131d4b38e0Srsmaeda 
5140c86d1bbSrsmaeda 	if ((rv = drctl_config_fini(&drctl_res_ck, drctl_req, count)) != 0)
51599c7e855SJames Marks - Sun Microsystems 		DR_DBG_CPU("%s: drctl_config_fini "
51699c7e855SJames Marks - Sun Microsystems 		    "returned: %d\n", __func__, rv);
5171ae08745Sheppo 
5180c86d1bbSrsmaeda 	/*
5190c86d1bbSrsmaeda 	 * Operation completed without any fatal errors.
5200c86d1bbSrsmaeda 	 * Pack the response for transmission.
5210c86d1bbSrsmaeda 	 */
5220c86d1bbSrsmaeda 	*resp_len = dr_cpu_pack_response(req, res, resp);
5230c86d1bbSrsmaeda 
5240c86d1bbSrsmaeda 	/* notify interested parties about the operation */
5250c86d1bbSrsmaeda 	dr_generate_event(DR_TYPE_CPU, se_hint);
5260c86d1bbSrsmaeda 
5270c86d1bbSrsmaeda 	/*
5280c86d1bbSrsmaeda 	 * Deallocate any scratch memory.
5290c86d1bbSrsmaeda 	 */
53099c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
53199c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_resp, drctl_resp_len);
53299c7e855SJames Marks - Sun Microsystems 	kmem_free(drctl_resp, drctl_resp_len);
53399c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
53499c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)drctl_req, drctl_req_len);
5350c86d1bbSrsmaeda 	kmem_free(drctl_req, drctl_req_len);
5360c86d1bbSrsmaeda 
5370c86d1bbSrsmaeda 	dr_cpu_res_array_fini(res, count);
5381ae08745Sheppo 
5391ae08745Sheppo 	return (0);
5401ae08745Sheppo }
5411ae08745Sheppo 
5420c86d1bbSrsmaeda /*
5430c86d1bbSrsmaeda  * Allocate and initialize a result array based on the initial
5440c86d1bbSrsmaeda  * drctl operation. A valid result array is always returned.
5450c86d1bbSrsmaeda  */
5460c86d1bbSrsmaeda static dr_cpu_res_t *
dr_cpu_res_array_init(dr_cpu_hdr_t * req,drctl_rsrc_t * rsrc,int nrsrc)5470c86d1bbSrsmaeda dr_cpu_res_array_init(dr_cpu_hdr_t *req, drctl_rsrc_t *rsrc, int nrsrc)
5481ae08745Sheppo {
5491ae08745Sheppo 	int		idx;
5500c86d1bbSrsmaeda 	dr_cpu_res_t	*res;
5510c86d1bbSrsmaeda 	char		*err_str;
5520c86d1bbSrsmaeda 	size_t		err_len;
5530c86d1bbSrsmaeda 
5540c86d1bbSrsmaeda 	/* allocate zero filled buffer to initialize fields */
5550c86d1bbSrsmaeda 	res = kmem_zalloc(nrsrc * sizeof (dr_cpu_res_t), KM_SLEEP);
55699c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
55799c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)res, nrsrc * sizeof (dr_cpu_res_t));
5580c86d1bbSrsmaeda 
5590c86d1bbSrsmaeda 	/*
5600c86d1bbSrsmaeda 	 * Fill in the result information for each resource.
5610c86d1bbSrsmaeda 	 */
5620c86d1bbSrsmaeda 	for (idx = 0; idx < nrsrc; idx++) {
5630c86d1bbSrsmaeda 		res[idx].cpuid = rsrc[idx].res_cpu_id;
5640c86d1bbSrsmaeda 		res[idx].result = DR_CPU_RES_OK;
5650c86d1bbSrsmaeda 
5660c86d1bbSrsmaeda 		if (rsrc[idx].status == DRCTL_STATUS_ALLOW)
5670c86d1bbSrsmaeda 			continue;
5680c86d1bbSrsmaeda 
5690c86d1bbSrsmaeda 		/*
5700c86d1bbSrsmaeda 		 * Update the state information for this CPU.
5710c86d1bbSrsmaeda 		 */
5720c86d1bbSrsmaeda 		res[idx].result = DR_CPU_RES_BLOCKED;
5730c86d1bbSrsmaeda 		res[idx].status = (req->msg_type == DR_CPU_CONFIGURE) ?
5740c86d1bbSrsmaeda 		    DR_CPU_STAT_UNCONFIGURED : DR_CPU_STAT_CONFIGURED;
5750c86d1bbSrsmaeda 
5760c86d1bbSrsmaeda 		/*
5770c86d1bbSrsmaeda 		 * If an error string exists, copy it out of the
5780c86d1bbSrsmaeda 		 * message buffer. This eliminates any dependency
5790c86d1bbSrsmaeda 		 * on the memory allocated for the message buffer
5800c86d1bbSrsmaeda 		 * itself.
5810c86d1bbSrsmaeda 		 */
5820c86d1bbSrsmaeda 		if (rsrc[idx].offset != NULL) {
5830c86d1bbSrsmaeda 			err_str = (char *)rsrc + rsrc[idx].offset;
5840c86d1bbSrsmaeda 			err_len = strlen(err_str) + 1;
5850c86d1bbSrsmaeda 
5860c86d1bbSrsmaeda 			res[idx].string = kmem_alloc(err_len, KM_SLEEP);
58799c7e855SJames Marks - Sun Microsystems 			DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
58899c7e855SJames Marks - Sun Microsystems 			    __func__, (void *)(res[idx].string), err_len);
5890c86d1bbSrsmaeda 			bcopy(err_str, res[idx].string, err_len);
5900c86d1bbSrsmaeda 		}
5910c86d1bbSrsmaeda 	}
5920c86d1bbSrsmaeda 
5930c86d1bbSrsmaeda 	return (res);
5940c86d1bbSrsmaeda }
5950c86d1bbSrsmaeda 
5960c86d1bbSrsmaeda static void
dr_cpu_res_array_fini(dr_cpu_res_t * res,int nres)5970c86d1bbSrsmaeda dr_cpu_res_array_fini(dr_cpu_res_t *res, int nres)
5980c86d1bbSrsmaeda {
5990c86d1bbSrsmaeda 	int	idx;
6000c86d1bbSrsmaeda 	size_t	str_len;
6010c86d1bbSrsmaeda 
6020c86d1bbSrsmaeda 	for (idx = 0; idx < nres; idx++) {
6030c86d1bbSrsmaeda 		/* deallocate the error string if present */
6040c86d1bbSrsmaeda 		if (res[idx].string) {
6050c86d1bbSrsmaeda 			str_len = strlen(res[idx].string) + 1;
60699c7e855SJames Marks - Sun Microsystems 			DR_DBG_KMEM("%s: free addr %p size %ld\n",
60799c7e855SJames Marks - Sun Microsystems 			    __func__, (void *)(res[idx].string), str_len);
6080c86d1bbSrsmaeda 			kmem_free(res[idx].string, str_len);
6090c86d1bbSrsmaeda 		}
6100c86d1bbSrsmaeda 	}
6110c86d1bbSrsmaeda 
6120c86d1bbSrsmaeda 	/* deallocate the result array itself */
61399c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
61499c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)res, sizeof (dr_cpu_res_t) * nres);
6150c86d1bbSrsmaeda 	kmem_free(res, sizeof (dr_cpu_res_t) * nres);
6160c86d1bbSrsmaeda }
6170c86d1bbSrsmaeda 
6180c86d1bbSrsmaeda /*
6190c86d1bbSrsmaeda  * Allocate and pack a response message for transmission based
6200c86d1bbSrsmaeda  * on the specified result array. A valid response message and
6210c86d1bbSrsmaeda  * valid size information is always returned.
6220c86d1bbSrsmaeda  */
6230c86d1bbSrsmaeda static size_t
dr_cpu_pack_response(dr_cpu_hdr_t * req,dr_cpu_res_t * res,dr_cpu_hdr_t ** respp)6240c86d1bbSrsmaeda dr_cpu_pack_response(dr_cpu_hdr_t *req, dr_cpu_res_t *res, dr_cpu_hdr_t **respp)
6250c86d1bbSrsmaeda {
6260c86d1bbSrsmaeda 	int		idx;
6270c86d1bbSrsmaeda 	dr_cpu_hdr_t	*resp;
6280c86d1bbSrsmaeda 	dr_cpu_stat_t	*resp_stat;
6290c86d1bbSrsmaeda 	size_t		resp_len;
6300c86d1bbSrsmaeda 	uint32_t	curr_off;
6310c86d1bbSrsmaeda 	caddr_t		curr_str;
6320c86d1bbSrsmaeda 	size_t		str_len;
6330c86d1bbSrsmaeda 	size_t		stat_len;
6340c86d1bbSrsmaeda 	int		nstat = req->num_records;
6350c86d1bbSrsmaeda 
6360c86d1bbSrsmaeda 	/*
6370c86d1bbSrsmaeda 	 * Calculate the size of the response message
6380c86d1bbSrsmaeda 	 * and allocate an appropriately sized buffer.
6390c86d1bbSrsmaeda 	 */
6400c86d1bbSrsmaeda 	resp_len = 0;
6410c86d1bbSrsmaeda 
6420c86d1bbSrsmaeda 	/* add the header size */
6430c86d1bbSrsmaeda 	resp_len += sizeof (dr_cpu_hdr_t);
6440c86d1bbSrsmaeda 
6450c86d1bbSrsmaeda 	/* add the stat array size */
6460c86d1bbSrsmaeda 	stat_len = sizeof (dr_cpu_stat_t) * nstat;
6470c86d1bbSrsmaeda 	resp_len += stat_len;
6480c86d1bbSrsmaeda 
6490c86d1bbSrsmaeda 	/* add the size of any error strings */
6500c86d1bbSrsmaeda 	for (idx = 0; idx < nstat; idx++) {
6510c86d1bbSrsmaeda 		if (res[idx].string != NULL) {
6520c86d1bbSrsmaeda 			resp_len += strlen(res[idx].string) + 1;
6530c86d1bbSrsmaeda 		}
6540c86d1bbSrsmaeda 	}
6550c86d1bbSrsmaeda 
6560c86d1bbSrsmaeda 	/* allocate the message buffer */
6570c86d1bbSrsmaeda 	resp = kmem_zalloc(resp_len, KM_SLEEP);
65899c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
65999c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)resp, resp_len);
6600c86d1bbSrsmaeda 
6610c86d1bbSrsmaeda 	/*
6620c86d1bbSrsmaeda 	 * Fill in the header information.
6630c86d1bbSrsmaeda 	 */
6640c86d1bbSrsmaeda 	resp->req_num = req->req_num;
6650c86d1bbSrsmaeda 	resp->msg_type = DR_CPU_OK;
6660c86d1bbSrsmaeda 	resp->num_records = nstat;
6670c86d1bbSrsmaeda 
6680c86d1bbSrsmaeda 	/*
6690c86d1bbSrsmaeda 	 * Fill in the stat information.
6700c86d1bbSrsmaeda 	 */
6710c86d1bbSrsmaeda 	resp_stat = DR_CPU_RESP_STATS(resp);
6720c86d1bbSrsmaeda 
6730c86d1bbSrsmaeda 	/* string offsets start immediately after stat array */
6740c86d1bbSrsmaeda 	curr_off = sizeof (dr_cpu_hdr_t) + stat_len;
6750c86d1bbSrsmaeda 	curr_str = (char *)resp_stat + stat_len;
6760c86d1bbSrsmaeda 
6770c86d1bbSrsmaeda 	for (idx = 0; idx < nstat; idx++) {
6780c86d1bbSrsmaeda 		resp_stat[idx].cpuid = res[idx].cpuid;
6790c86d1bbSrsmaeda 		resp_stat[idx].result = res[idx].result;
6800c86d1bbSrsmaeda 		resp_stat[idx].status = res[idx].status;
6810c86d1bbSrsmaeda 
6820c86d1bbSrsmaeda 		if (res[idx].string != NULL) {
6830c86d1bbSrsmaeda 			/* copy over the error string */
6840c86d1bbSrsmaeda 			str_len = strlen(res[idx].string) + 1;
6850c86d1bbSrsmaeda 			bcopy(res[idx].string, curr_str, str_len);
6860c86d1bbSrsmaeda 			resp_stat[idx].string_off = curr_off;
6870c86d1bbSrsmaeda 
6880c86d1bbSrsmaeda 			curr_off += str_len;
6890c86d1bbSrsmaeda 			curr_str += str_len;
6900c86d1bbSrsmaeda 		}
6910c86d1bbSrsmaeda 	}
6920c86d1bbSrsmaeda 
6930c86d1bbSrsmaeda 	/* buffer should be exactly filled */
6940c86d1bbSrsmaeda 	ASSERT(curr_off == resp_len);
6950c86d1bbSrsmaeda 
6960c86d1bbSrsmaeda 	*respp = resp;
6970c86d1bbSrsmaeda 	return (resp_len);
6980c86d1bbSrsmaeda }
6990c86d1bbSrsmaeda 
7000c86d1bbSrsmaeda /*
7010c86d1bbSrsmaeda  * Check for conditions that will prevent a CPU from being offlined.
7020c86d1bbSrsmaeda  * This provides the opportunity to generate useful information to
7030c86d1bbSrsmaeda  * help diagnose the failure rather than letting the offline attempt
7040c86d1bbSrsmaeda  * fail in a more generic way.
7050c86d1bbSrsmaeda  */
7060c86d1bbSrsmaeda static void
dr_cpu_check_cpus(dr_cpu_hdr_t * req,dr_cpu_res_t * res)7070c86d1bbSrsmaeda dr_cpu_check_cpus(dr_cpu_hdr_t *req, dr_cpu_res_t *res)
7080c86d1bbSrsmaeda {
7090c86d1bbSrsmaeda 	int		idx;
7100c86d1bbSrsmaeda 	cpu_t		*cp;
7110c86d1bbSrsmaeda 	uint32_t	*cpuids;
7120c86d1bbSrsmaeda 
7130c86d1bbSrsmaeda 	ASSERT((req->msg_type == DR_CPU_UNCONFIGURE) ||
7140c86d1bbSrsmaeda 	    (req->msg_type == DR_CPU_FORCE_UNCONFIG));
7151ae08745Sheppo 
7161ae08745Sheppo 	DR_DBG_CPU("dr_cpu_check_cpus...\n");
7171ae08745Sheppo 
7180c86d1bbSrsmaeda 	/* array of cpuids start just after the header */
7190c86d1bbSrsmaeda 	cpuids = DR_CPU_CMD_CPUIDS(req);
7200c86d1bbSrsmaeda 
7211ae08745Sheppo 	mutex_enter(&cpu_lock);
7221ae08745Sheppo 
7230c86d1bbSrsmaeda 	/*
7240c86d1bbSrsmaeda 	 * Always check processor set membership first. The
7250c86d1bbSrsmaeda 	 * last CPU in a processor set will fail to offline
7260c86d1bbSrsmaeda 	 * even if the operation if forced, so any failures
7270c86d1bbSrsmaeda 	 * should always be reported.
7280c86d1bbSrsmaeda 	 */
7290c86d1bbSrsmaeda 	dr_cpu_check_psrset(cpuids, res, req->num_records);
7301ae08745Sheppo 
7310c86d1bbSrsmaeda 	/* process each cpu that is part of the request */
7320c86d1bbSrsmaeda 	for (idx = 0; idx < req->num_records; idx++) {
7330c86d1bbSrsmaeda 
7340c86d1bbSrsmaeda 		/* nothing to check if the CPU has already failed */
7350c86d1bbSrsmaeda 		if (res[idx].result != DR_CPU_RES_OK)
7361ae08745Sheppo 			continue;
7371ae08745Sheppo 
7380c86d1bbSrsmaeda 		if ((cp = cpu_get(cpuids[idx])) == NULL)
7390c86d1bbSrsmaeda 			continue;
7401ae08745Sheppo 
7411ae08745Sheppo 		/*
7420c86d1bbSrsmaeda 		 * Only check if there are bound threads if the
7430c86d1bbSrsmaeda 		 * operation is not a forced unconfigure. In a
7440c86d1bbSrsmaeda 		 * forced request, threads are automatically
7450c86d1bbSrsmaeda 		 * unbound before they are offlined.
7461ae08745Sheppo 		 */
7470c86d1bbSrsmaeda 		if (req->msg_type == DR_CPU_UNCONFIGURE) {
7480c86d1bbSrsmaeda 			/*
7490c86d1bbSrsmaeda 			 * The return value is only interesting if other
7500c86d1bbSrsmaeda 			 * checks are added to this loop and a decision
7510c86d1bbSrsmaeda 			 * is needed on whether to continue checking.
7520c86d1bbSrsmaeda 			 */
7530c86d1bbSrsmaeda 			(void) dr_cpu_check_bound_thr(cp, &res[idx]);
7541ae08745Sheppo 		}
7551ae08745Sheppo 	}
7561ae08745Sheppo 
7571ae08745Sheppo 	mutex_exit(&cpu_lock);
7581ae08745Sheppo }
7591ae08745Sheppo 
7600c86d1bbSrsmaeda /*
7610c86d1bbSrsmaeda  * Examine the processor set configuration for the specified
7620c86d1bbSrsmaeda  * CPUs and see if the unconfigure operation would result in
7630c86d1bbSrsmaeda  * trying to remove the last CPU in any processor set.
7640c86d1bbSrsmaeda  */
7650c86d1bbSrsmaeda static void
dr_cpu_check_psrset(uint32_t * cpuids,dr_cpu_res_t * res,int nres)7660c86d1bbSrsmaeda dr_cpu_check_psrset(uint32_t *cpuids, dr_cpu_res_t *res, int nres)
7670c86d1bbSrsmaeda {
7680c86d1bbSrsmaeda 	int		cpu_idx;
7690c86d1bbSrsmaeda 	int		set_idx;
7700c86d1bbSrsmaeda 	cpu_t		*cp;
7710c86d1bbSrsmaeda 	cpupart_t	*cpp;
7720c86d1bbSrsmaeda 	char		err_str[DR_CPU_MAX_ERR_LEN];
7730c86d1bbSrsmaeda 	size_t		err_len;
7740c86d1bbSrsmaeda 	struct {
7750c86d1bbSrsmaeda 		cpupart_t	*cpp;
7760c86d1bbSrsmaeda 		int		ncpus;
7770c86d1bbSrsmaeda 	} *psrset;
7780c86d1bbSrsmaeda 
7790c86d1bbSrsmaeda 	ASSERT(MUTEX_HELD(&cpu_lock));
7800c86d1bbSrsmaeda 
7810c86d1bbSrsmaeda 	/*
7820c86d1bbSrsmaeda 	 * Allocate a scratch array to count the CPUs in
7830c86d1bbSrsmaeda 	 * the various processor sets. A CPU always belongs
7840c86d1bbSrsmaeda 	 * to exactly one processor set, so by definition,
7850c86d1bbSrsmaeda 	 * the scratch array never needs to be larger than
7860c86d1bbSrsmaeda 	 * the number of CPUs.
7870c86d1bbSrsmaeda 	 */
7880c86d1bbSrsmaeda 	psrset = kmem_zalloc(sizeof (*psrset) * nres, KM_SLEEP);
78999c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
79099c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)psrset, sizeof (*psrset) * nres);
7910c86d1bbSrsmaeda 
7920c86d1bbSrsmaeda 	for (cpu_idx = 0; cpu_idx < nres; cpu_idx++) {
7930c86d1bbSrsmaeda 
7940c86d1bbSrsmaeda 		/* skip any CPUs that have already failed */
7950c86d1bbSrsmaeda 		if (res[cpu_idx].result != DR_CPU_RES_OK)
7960c86d1bbSrsmaeda 			continue;
7970c86d1bbSrsmaeda 
7980c86d1bbSrsmaeda 		if ((cp = cpu_get(cpuids[cpu_idx])) == NULL)
7990c86d1bbSrsmaeda 			continue;
8000c86d1bbSrsmaeda 
8010c86d1bbSrsmaeda 		cpp = cp->cpu_part;
8020c86d1bbSrsmaeda 
8030c86d1bbSrsmaeda 		/* lookup the set this CPU belongs to */
8040c86d1bbSrsmaeda 		for (set_idx = 0; set_idx < nres; set_idx++) {
8050c86d1bbSrsmaeda 
8060c86d1bbSrsmaeda 			/* matching set found */
8070c86d1bbSrsmaeda 			if (cpp == psrset[set_idx].cpp)
8080c86d1bbSrsmaeda 				break;
8090c86d1bbSrsmaeda 
8100c86d1bbSrsmaeda 			/* set not found, start a new entry */
8110c86d1bbSrsmaeda 			if (psrset[set_idx].cpp == NULL) {
8120c86d1bbSrsmaeda 				psrset[set_idx].cpp = cpp;
8130c86d1bbSrsmaeda 				psrset[set_idx].ncpus = cpp->cp_ncpus;
8140c86d1bbSrsmaeda 				break;
8150c86d1bbSrsmaeda 			}
8160c86d1bbSrsmaeda 		}
8170c86d1bbSrsmaeda 
8180c86d1bbSrsmaeda 		ASSERT(set_idx != nres);
8190c86d1bbSrsmaeda 
8200c86d1bbSrsmaeda 		/*
8210c86d1bbSrsmaeda 		 * Remove the current CPU from the set total but only
8220c86d1bbSrsmaeda 		 * generate an error for the last CPU. The correct CPU
8230c86d1bbSrsmaeda 		 * will get the error because the unconfigure attempts
8240c86d1bbSrsmaeda 		 * will occur in the same order in which the CPUs are
8255f1655c9SJames Marks - Sun Microsystems 		 * examined in this loop.  The cp_ncpus field of a
8265f1655c9SJames Marks - Sun Microsystems 		 * cpupart_t counts only online cpus, so it is safe
8275f1655c9SJames Marks - Sun Microsystems 		 * to remove an offline cpu without testing ncpus.
8280c86d1bbSrsmaeda 		 */
8297de586caSJames Marks - Sun Microsystems 		if (cpu_is_offline(cp))
8305f1655c9SJames Marks - Sun Microsystems 			continue;
8315f1655c9SJames Marks - Sun Microsystems 
8320c86d1bbSrsmaeda 		if (--psrset[set_idx].ncpus == 0) {
8330c86d1bbSrsmaeda 			/*
8340c86d1bbSrsmaeda 			 * Fill in the various pieces of information
8350c86d1bbSrsmaeda 			 * to report that the operation will fail.
8360c86d1bbSrsmaeda 			 */
8370c86d1bbSrsmaeda 			res[cpu_idx].result = DR_CPU_RES_BLOCKED;
8380c86d1bbSrsmaeda 			res[cpu_idx].status = DR_CPU_STAT_CONFIGURED;
8390c86d1bbSrsmaeda 
8400c86d1bbSrsmaeda 			(void) snprintf(err_str, DR_CPU_MAX_ERR_LEN,
8410c86d1bbSrsmaeda 			    "last online cpu in processor set %d", cpp->cp_id);
8420c86d1bbSrsmaeda 
8430c86d1bbSrsmaeda 			err_len = strlen(err_str) + 1;
8440c86d1bbSrsmaeda 
8450c86d1bbSrsmaeda 			res[cpu_idx].string = kmem_alloc(err_len, KM_SLEEP);
84699c7e855SJames Marks - Sun Microsystems 			DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
84799c7e855SJames Marks - Sun Microsystems 			    __func__, (void *)(res[cpu_idx].string), err_len);
8480c86d1bbSrsmaeda 			bcopy(err_str, res[cpu_idx].string, err_len);
8490c86d1bbSrsmaeda 
8500c86d1bbSrsmaeda 			DR_DBG_CPU("cpu %d: %s\n", cpuids[cpu_idx], err_str);
8510c86d1bbSrsmaeda 		}
8520c86d1bbSrsmaeda 	}
8530c86d1bbSrsmaeda 
85499c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %ld\n",
85599c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)psrset, sizeof (*psrset) * nres);
8560c86d1bbSrsmaeda 	kmem_free(psrset, sizeof (*psrset) * nres);
8570c86d1bbSrsmaeda }
8580c86d1bbSrsmaeda 
8590c86d1bbSrsmaeda /*
8600c86d1bbSrsmaeda  * Check if any threads are bound to the specified CPU. If the
8610c86d1bbSrsmaeda  * condition is true, DR_CPU_RES_BLOCKED is returned and an error
8620c86d1bbSrsmaeda  * string is generated and placed in the specified result structure.
8630c86d1bbSrsmaeda  * Otherwise, DR_CPU_RES_OK is returned.
8640c86d1bbSrsmaeda  */
8650c86d1bbSrsmaeda static int
dr_cpu_check_bound_thr(cpu_t * cp,dr_cpu_res_t * res)8660c86d1bbSrsmaeda dr_cpu_check_bound_thr(cpu_t *cp, dr_cpu_res_t *res)
8670c86d1bbSrsmaeda {
8680c86d1bbSrsmaeda 	int		nbound;
8690c86d1bbSrsmaeda 	proc_t		*pp;
8700c86d1bbSrsmaeda 	kthread_t	*tp;
8710c86d1bbSrsmaeda 	char		err_str[DR_CPU_MAX_ERR_LEN];
8720c86d1bbSrsmaeda 	size_t		err_len;
8730c86d1bbSrsmaeda 
8740c86d1bbSrsmaeda 	/*
8750c86d1bbSrsmaeda 	 * Error string allocation makes an assumption
8760c86d1bbSrsmaeda 	 * that no blocking condition has been identified.
8770c86d1bbSrsmaeda 	 */
8780c86d1bbSrsmaeda 	ASSERT(res->result == DR_CPU_RES_OK);
8790c86d1bbSrsmaeda 	ASSERT(res->string == NULL);
8800c86d1bbSrsmaeda 
8810c86d1bbSrsmaeda 	ASSERT(MUTEX_HELD(&cpu_lock));
8820c86d1bbSrsmaeda 
8830c86d1bbSrsmaeda 	mutex_enter(&pidlock);
8840c86d1bbSrsmaeda 
8850c86d1bbSrsmaeda 	nbound = 0;
8860c86d1bbSrsmaeda 
8870c86d1bbSrsmaeda 	/*
8880c86d1bbSrsmaeda 	 * Walk the active processes, checking if each
8890c86d1bbSrsmaeda 	 * thread belonging to the process is bound.
8900c86d1bbSrsmaeda 	 */
8910c86d1bbSrsmaeda 	for (pp = practive; (pp != NULL) && (nbound <= 1); pp = pp->p_next) {
8920c86d1bbSrsmaeda 		mutex_enter(&pp->p_lock);
8930c86d1bbSrsmaeda 
8940c86d1bbSrsmaeda 		tp = pp->p_tlist;
8950c86d1bbSrsmaeda 
8960c86d1bbSrsmaeda 		if ((tp == NULL) || (pp->p_flag & SSYS)) {
8970c86d1bbSrsmaeda 			mutex_exit(&pp->p_lock);
8980c86d1bbSrsmaeda 			continue;
8990c86d1bbSrsmaeda 		}
9000c86d1bbSrsmaeda 
9010c86d1bbSrsmaeda 		do {
9020c86d1bbSrsmaeda 			if (tp->t_bind_cpu != cp->cpu_id)
9030c86d1bbSrsmaeda 				continue;
9040c86d1bbSrsmaeda 
9050c86d1bbSrsmaeda 			/*
9060c86d1bbSrsmaeda 			 * Update the running total of bound
9070c86d1bbSrsmaeda 			 * threads. Continue the search until
9080c86d1bbSrsmaeda 			 * it can be determined if more than
9090c86d1bbSrsmaeda 			 * one thread is bound to the CPU.
9100c86d1bbSrsmaeda 			 */
9110c86d1bbSrsmaeda 			if (++nbound > 1)
9120c86d1bbSrsmaeda 				break;
9130c86d1bbSrsmaeda 
9140c86d1bbSrsmaeda 		} while ((tp = tp->t_forw) != pp->p_tlist);
9150c86d1bbSrsmaeda 
9160c86d1bbSrsmaeda 		mutex_exit(&pp->p_lock);
9170c86d1bbSrsmaeda 	}
9180c86d1bbSrsmaeda 
9190c86d1bbSrsmaeda 	mutex_exit(&pidlock);
9200c86d1bbSrsmaeda 
9210c86d1bbSrsmaeda 	if (nbound) {
9220c86d1bbSrsmaeda 		/*
9230c86d1bbSrsmaeda 		 * Threads are bound to the CPU. Fill in
9240c86d1bbSrsmaeda 		 * various pieces of information to report
9250c86d1bbSrsmaeda 		 * that the operation will fail.
9260c86d1bbSrsmaeda 		 */
9270c86d1bbSrsmaeda 		res->result = DR_CPU_RES_BLOCKED;
9280c86d1bbSrsmaeda 		res->status = DR_CPU_STAT_CONFIGURED;
9290c86d1bbSrsmaeda 
9300c86d1bbSrsmaeda 		(void) snprintf(err_str, DR_CPU_MAX_ERR_LEN, "cpu has bound "
9310c86d1bbSrsmaeda 		    "thread%s", (nbound > 1) ? "s" : "");
9320c86d1bbSrsmaeda 
9330c86d1bbSrsmaeda 		err_len = strlen(err_str) + 1;
9340c86d1bbSrsmaeda 
9350c86d1bbSrsmaeda 		res->string = kmem_alloc(err_len, KM_SLEEP);
93699c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
93799c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)(res->string), err_len);
9380c86d1bbSrsmaeda 		bcopy(err_str, res->string, err_len);
9390c86d1bbSrsmaeda 
9400c86d1bbSrsmaeda 		DR_DBG_CPU("cpu %d: %s\n", cp->cpu_id, err_str);
9410c86d1bbSrsmaeda 	}
9420c86d1bbSrsmaeda 
9430c86d1bbSrsmaeda 	return (res->result);
9440c86d1bbSrsmaeda }
9451ae08745Sheppo 
9461ae08745Sheppo /*
9471ae08745Sheppo  * Do not modify result buffer or length on error.
9481ae08745Sheppo  */
9491ae08745Sheppo static int
dr_cpu_list_status(dr_cpu_hdr_t * req,dr_cpu_hdr_t ** resp,int * resp_len)9501ae08745Sheppo dr_cpu_list_status(dr_cpu_hdr_t *req, dr_cpu_hdr_t **resp, int *resp_len)
9511ae08745Sheppo {
9521ae08745Sheppo 	int		idx;
9531ae08745Sheppo 	int		result;
9541ae08745Sheppo 	int		status;
9551ae08745Sheppo 	int		rlen;
9561ae08745Sheppo 	uint32_t	*cpuids;
9571ae08745Sheppo 	dr_cpu_hdr_t	*rp;
9581ae08745Sheppo 	dr_cpu_stat_t	*stat;
9591ae08745Sheppo 	md_t		*mdp = NULL;
9601ae08745Sheppo 	int		num_nodes;
9611ae08745Sheppo 	int		listsz;
9621ae08745Sheppo 	mde_cookie_t	*listp = NULL;
9631ae08745Sheppo 	mde_cookie_t	cpunode;
9641ae08745Sheppo 	boolean_t	walk_md = B_FALSE;
9651ae08745Sheppo 
9661ae08745Sheppo 	/* the incoming array of cpuids to configure */
9670c86d1bbSrsmaeda 	cpuids = DR_CPU_CMD_CPUIDS(req);
9681ae08745Sheppo 
9691ae08745Sheppo 	/* allocate a response message */
9701ae08745Sheppo 	rlen = sizeof (dr_cpu_hdr_t);
9711ae08745Sheppo 	rlen += req->num_records * sizeof (dr_cpu_stat_t);
9721ae08745Sheppo 	rp = kmem_zalloc(rlen, KM_SLEEP);
97399c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %d\n", __func__, (void *)rp, rlen);
9741ae08745Sheppo 
9751ae08745Sheppo 	/* fill in the known data */
9761ae08745Sheppo 	rp->req_num = req->req_num;
9771ae08745Sheppo 	rp->msg_type = DR_CPU_STATUS;
9781ae08745Sheppo 	rp->num_records = req->num_records;
9791ae08745Sheppo 
9801ae08745Sheppo 	/* stat array for the response */
9810c86d1bbSrsmaeda 	stat = DR_CPU_RESP_STATS(rp);
9821ae08745Sheppo 
9831ae08745Sheppo 	/* get the status for each of the CPUs */
9841ae08745Sheppo 	for (idx = 0; idx < req->num_records; idx++) {
9851ae08745Sheppo 
9861ae08745Sheppo 		result = dr_cpu_status(cpuids[idx], &status);
9871ae08745Sheppo 
9881ae08745Sheppo 		if (result == DR_CPU_RES_FAILURE)
9891ae08745Sheppo 			walk_md = B_TRUE;
9901ae08745Sheppo 
9911ae08745Sheppo 		/* save off results of the status */
9921ae08745Sheppo 		stat[idx].cpuid = cpuids[idx];
9931ae08745Sheppo 		stat[idx].result = result;
9941ae08745Sheppo 		stat[idx].status = status;
9951ae08745Sheppo 	}
9961ae08745Sheppo 
9971ae08745Sheppo 	if (walk_md == B_FALSE)
9981ae08745Sheppo 		goto done;
9991ae08745Sheppo 
10001ae08745Sheppo 	/*
10011ae08745Sheppo 	 * At least one of the cpus did not have a CPU
10021ae08745Sheppo 	 * structure. So, consult the MD to determine if
10031ae08745Sheppo 	 * they are present.
10041ae08745Sheppo 	 */
10051ae08745Sheppo 
10061ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
10071ae08745Sheppo 		DR_DBG_CPU("unable to initialize MD\n");
10081ae08745Sheppo 		goto done;
10091ae08745Sheppo 	}
10101ae08745Sheppo 
10111ae08745Sheppo 	num_nodes = md_node_count(mdp);
10121ae08745Sheppo 	ASSERT(num_nodes > 0);
10131ae08745Sheppo 
10141ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
10151ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
101699c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %d\n",
101799c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
10181ae08745Sheppo 
10191ae08745Sheppo 	for (idx = 0; idx < req->num_records; idx++) {
10201ae08745Sheppo 
10211ae08745Sheppo 		if (stat[idx].result != DR_CPU_RES_FAILURE)
10221ae08745Sheppo 			continue;
10231ae08745Sheppo 
10241ae08745Sheppo 		/* check the MD for the current cpuid */
10251ae08745Sheppo 		cpunode = dr_cpu_find_node_md(stat[idx].cpuid, mdp, listp);
10261ae08745Sheppo 
10271ae08745Sheppo 		stat[idx].result = DR_CPU_RES_OK;
10281ae08745Sheppo 
10291ae08745Sheppo 		if (cpunode == MDE_INVAL_ELEM_COOKIE) {
10301ae08745Sheppo 			stat[idx].status = DR_CPU_STAT_NOT_PRESENT;
10311ae08745Sheppo 		} else {
10321ae08745Sheppo 			stat[idx].status = DR_CPU_STAT_UNCONFIGURED;
10331ae08745Sheppo 		}
10341ae08745Sheppo 	}
10351ae08745Sheppo 
103699c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: free addr %p size %d\n",
103799c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
10381ae08745Sheppo 	kmem_free(listp, listsz);
10391ae08745Sheppo 
10401ae08745Sheppo 	(void) md_fini_handle(mdp);
10411ae08745Sheppo 
10421ae08745Sheppo done:
10431ae08745Sheppo 	*resp = rp;
10441ae08745Sheppo 	*resp_len = rlen;
10451ae08745Sheppo 
10461ae08745Sheppo 	return (0);
10471ae08745Sheppo }
10481ae08745Sheppo 
10491ae08745Sheppo static int
dr_cpu_configure(processorid_t cpuid,int * status,boolean_t force)10501d4b38e0Srsmaeda dr_cpu_configure(processorid_t cpuid, int *status, boolean_t force)
10511ae08745Sheppo {
10521d4b38e0Srsmaeda 	 _NOTE(ARGUNUSED(force))
10531ae08745Sheppo 	struct cpu	*cp;
10541ae08745Sheppo 	int		rv = 0;
10551ae08745Sheppo 
10561ae08745Sheppo 	DR_DBG_CPU("dr_cpu_configure...\n");
10571ae08745Sheppo 
10581ae08745Sheppo 	/*
10591ae08745Sheppo 	 * Build device tree node for the CPU
10601ae08745Sheppo 	 */
10611ae08745Sheppo 	if ((rv = dr_cpu_probe(cpuid)) != 0) {
10621ae08745Sheppo 		DR_DBG_CPU("failed to probe CPU %d (%d)\n", cpuid, rv);
10631ae08745Sheppo 		if (rv == EINVAL) {
10641ae08745Sheppo 			*status = DR_CPU_STAT_NOT_PRESENT;
10651ae08745Sheppo 			return (DR_CPU_RES_NOT_IN_MD);
10661ae08745Sheppo 		}
10671ae08745Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
10681ae08745Sheppo 		return (DR_CPU_RES_FAILURE);
10691ae08745Sheppo 	}
10701ae08745Sheppo 
10711ae08745Sheppo 	mutex_enter(&cpu_lock);
10721ae08745Sheppo 
10731ae08745Sheppo 	/*
10741ae08745Sheppo 	 * Configure the CPU
10751ae08745Sheppo 	 */
10761ae08745Sheppo 	if ((cp = cpu_get(cpuid)) == NULL) {
10771ae08745Sheppo 
10781ae08745Sheppo 		if ((rv = cpu_configure(cpuid)) != 0) {
10791ae08745Sheppo 			DR_DBG_CPU("failed to configure CPU %d (%d)\n",
10801ae08745Sheppo 			    cpuid, rv);
10811ae08745Sheppo 			rv = DR_CPU_RES_FAILURE;
10821ae08745Sheppo 			*status = DR_CPU_STAT_UNCONFIGURED;
10831ae08745Sheppo 			goto done;
10841ae08745Sheppo 		}
10851ae08745Sheppo 
10861ae08745Sheppo 		DR_DBG_CPU("CPU %d configured\n", cpuid);
10871ae08745Sheppo 
10881ae08745Sheppo 		/* CPU struct should exist now */
10891ae08745Sheppo 		cp = cpu_get(cpuid);
10901ae08745Sheppo 	}
10911ae08745Sheppo 
10921ae08745Sheppo 	ASSERT(cp);
10931ae08745Sheppo 
10941ae08745Sheppo 	/*
10951ae08745Sheppo 	 * Power on the CPU. In sun4v, this brings the stopped
10961ae08745Sheppo 	 * CPU into the guest from the Hypervisor.
10971ae08745Sheppo 	 */
10981ae08745Sheppo 	if (cpu_is_poweredoff(cp)) {
10991ae08745Sheppo 
11001ae08745Sheppo 		if ((rv = cpu_poweron(cp)) != 0) {
11011ae08745Sheppo 			DR_DBG_CPU("failed to power on CPU %d (%d)\n",
11021ae08745Sheppo 			    cpuid, rv);
11031ae08745Sheppo 			rv = DR_CPU_RES_FAILURE;
11041ae08745Sheppo 			*status = DR_CPU_STAT_UNCONFIGURED;
11051ae08745Sheppo 			goto done;
11061ae08745Sheppo 		}
11071ae08745Sheppo 
11081ae08745Sheppo 		DR_DBG_CPU("CPU %d powered on\n", cpuid);
11091ae08745Sheppo 	}
11101ae08745Sheppo 
11111ae08745Sheppo 	/*
11121ae08745Sheppo 	 * Online the CPU
11131ae08745Sheppo 	 */
11141ae08745Sheppo 	if (cpu_is_offline(cp)) {
11151ae08745Sheppo 
11161ae08745Sheppo 		if ((rv = cpu_online(cp)) != 0) {
11171ae08745Sheppo 			DR_DBG_CPU("failed to online CPU %d (%d)\n",
11181ae08745Sheppo 			    cpuid, rv);
11191ae08745Sheppo 			rv = DR_CPU_RES_FAILURE;
11201ae08745Sheppo 			/* offline is still configured */
11211ae08745Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
11221ae08745Sheppo 			goto done;
11231ae08745Sheppo 		}
11241ae08745Sheppo 
11251ae08745Sheppo 		DR_DBG_CPU("CPU %d online\n", cpuid);
11261ae08745Sheppo 	}
11271ae08745Sheppo 
11281ae08745Sheppo 	rv = DR_CPU_RES_OK;
11291ae08745Sheppo 	*status = DR_CPU_STAT_CONFIGURED;
11301ae08745Sheppo 
11311ae08745Sheppo done:
11321ae08745Sheppo 	mutex_exit(&cpu_lock);
11331ae08745Sheppo 
11341ae08745Sheppo 	return (rv);
11351ae08745Sheppo }
11361ae08745Sheppo 
11371ae08745Sheppo static int
dr_cpu_unconfigure(processorid_t cpuid,int * status,boolean_t force)11381ae08745Sheppo dr_cpu_unconfigure(processorid_t cpuid, int *status, boolean_t force)
11391ae08745Sheppo {
11401ae08745Sheppo 	struct cpu	*cp;
11411ae08745Sheppo 	int		rv = 0;
11421ae08745Sheppo 	int		cpu_flags;
11431ae08745Sheppo 
11441ae08745Sheppo 	DR_DBG_CPU("dr_cpu_unconfigure%s...\n", (force) ? " (force)" : "");
11451ae08745Sheppo 
11461ae08745Sheppo 	mutex_enter(&cpu_lock);
11471ae08745Sheppo 
11481ae08745Sheppo 	cp = cpu_get(cpuid);
11491ae08745Sheppo 
11501ae08745Sheppo 	if (cp == NULL) {
11511ae08745Sheppo 		/*
1152*4a9fd251SVijay Balakrishna, SG-RPE 		 * As OS CPU structures are already torn down proceed
1153*4a9fd251SVijay Balakrishna, SG-RPE 		 * to deprobe device tree to make sure the device tree
1154*4a9fd251SVijay Balakrishna, SG-RPE 		 * is up do date.
11551ae08745Sheppo 		 */
1156*4a9fd251SVijay Balakrishna, SG-RPE 		goto deprobe;
11571ae08745Sheppo 	}
11581ae08745Sheppo 
11591ae08745Sheppo 	ASSERT(cp->cpu_id == cpuid);
11601ae08745Sheppo 
11611ae08745Sheppo 	/*
11621ae08745Sheppo 	 * Offline the CPU
11631ae08745Sheppo 	 */
11641ae08745Sheppo 	if (cpu_is_active(cp)) {
11651ae08745Sheppo 
11661ae08745Sheppo 		/* set the force flag correctly */
11671ae08745Sheppo 		cpu_flags = (force) ? CPU_FORCED : 0;
11681ae08745Sheppo 
11697de586caSJames Marks - Sun Microsystems 		/*
11707de586caSJames Marks - Sun Microsystems 		 * Before we take the CPU offline, we first enable interrupts.
11717de586caSJames Marks - Sun Microsystems 		 * Otherwise, cpu_offline() might reject the request.  Note:
11727de586caSJames Marks - Sun Microsystems 		 * if the offline subsequently fails, the target cpu will be
11737de586caSJames Marks - Sun Microsystems 		 * left with interrupts enabled.  This is consistent with the
11747de586caSJames Marks - Sun Microsystems 		 * behavior of psradm(1M) and p_online(2).
11757de586caSJames Marks - Sun Microsystems 		 */
11767de586caSJames Marks - Sun Microsystems 		cpu_intr_enable(cp);
11777de586caSJames Marks - Sun Microsystems 
11781ae08745Sheppo 		if ((rv = cpu_offline(cp, cpu_flags)) != 0) {
11791ae08745Sheppo 			DR_DBG_CPU("failed to offline CPU %d (%d)\n",
11801ae08745Sheppo 			    cpuid, rv);
11811ae08745Sheppo 
11821ae08745Sheppo 			rv = DR_CPU_RES_FAILURE;
11831ae08745Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
1184*4a9fd251SVijay Balakrishna, SG-RPE 			mutex_exit(&cpu_lock);
1185*4a9fd251SVijay Balakrishna, SG-RPE 			return (rv);
11861ae08745Sheppo 		}
11871ae08745Sheppo 
11881ae08745Sheppo 		DR_DBG_CPU("CPU %d offline\n", cpuid);
11891ae08745Sheppo 	}
11901ae08745Sheppo 
11911ae08745Sheppo 	/*
11921ae08745Sheppo 	 * Power off the CPU. In sun4v, this puts the running
11931ae08745Sheppo 	 * CPU into the stopped state in the Hypervisor.
11941ae08745Sheppo 	 */
11951ae08745Sheppo 	if (!cpu_is_poweredoff(cp)) {
11961ae08745Sheppo 
11971ae08745Sheppo 		if ((rv = cpu_poweroff(cp)) != 0) {
11981ae08745Sheppo 			DR_DBG_CPU("failed to power off CPU %d (%d)\n",
11991ae08745Sheppo 			    cpuid, rv);
12001ae08745Sheppo 			rv = DR_CPU_RES_FAILURE;
12011ae08745Sheppo 			*status = DR_CPU_STAT_CONFIGURED;
1202*4a9fd251SVijay Balakrishna, SG-RPE 			mutex_exit(&cpu_lock);
1203*4a9fd251SVijay Balakrishna, SG-RPE 			return (rv);
12041ae08745Sheppo 		}
12051ae08745Sheppo 
12061ae08745Sheppo 		DR_DBG_CPU("CPU %d powered off\n", cpuid);
12071ae08745Sheppo 	}
12081ae08745Sheppo 
12091ae08745Sheppo 	/*
12101ae08745Sheppo 	 * Unconfigure the CPU
12111ae08745Sheppo 	 */
12121ae08745Sheppo 	if ((rv = cpu_unconfigure(cpuid)) != 0) {
12131ae08745Sheppo 		DR_DBG_CPU("failed to unconfigure CPU %d (%d)\n", cpuid, rv);
12141ae08745Sheppo 		rv = DR_CPU_RES_FAILURE;
12151ae08745Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
1216*4a9fd251SVijay Balakrishna, SG-RPE 		mutex_exit(&cpu_lock);
1217*4a9fd251SVijay Balakrishna, SG-RPE 		return (rv);
12181ae08745Sheppo 	}
12191ae08745Sheppo 
12201ae08745Sheppo 	DR_DBG_CPU("CPU %d unconfigured\n", cpuid);
12211ae08745Sheppo 
1222*4a9fd251SVijay Balakrishna, SG-RPE deprobe:
1223*4a9fd251SVijay Balakrishna, SG-RPE 	mutex_exit(&cpu_lock);
12241ae08745Sheppo 	/*
12251ae08745Sheppo 	 * Tear down device tree.
12261ae08745Sheppo 	 */
12271ae08745Sheppo 	if ((rv = dr_cpu_deprobe(cpuid)) != 0) {
12281ae08745Sheppo 		DR_DBG_CPU("failed to deprobe CPU %d (%d)\n", cpuid, rv);
12291ae08745Sheppo 		rv = DR_CPU_RES_FAILURE;
12301ae08745Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
1231*4a9fd251SVijay Balakrishna, SG-RPE 		return (rv);
12321ae08745Sheppo 	}
12331ae08745Sheppo 
12341ae08745Sheppo 	rv = DR_CPU_RES_OK;
12351ae08745Sheppo 	*status = DR_CPU_STAT_UNCONFIGURED;
12361ae08745Sheppo 
12371ae08745Sheppo 	return (rv);
12381ae08745Sheppo }
12391ae08745Sheppo 
12401ae08745Sheppo /*
12411ae08745Sheppo  * Determine the state of a CPU. If the CPU structure is not present,
12421ae08745Sheppo  * it does not attempt to determine whether or not the CPU is in the
12431ae08745Sheppo  * MD. It is more efficient to do this at the higher level for all
12441ae08745Sheppo  * CPUs since it may not even be necessary to search the MD if all
12451ae08745Sheppo  * the CPUs are accounted for. Returns DR_CPU_RES_OK if the CPU
12461ae08745Sheppo  * structure is present, and DR_CPU_RES_FAILURE otherwise as a signal
12471ae08745Sheppo  * that an MD walk is necessary.
12481ae08745Sheppo  */
12491ae08745Sheppo static int
dr_cpu_status(processorid_t cpuid,int * status)12501ae08745Sheppo dr_cpu_status(processorid_t cpuid, int *status)
12511ae08745Sheppo {
12521ae08745Sheppo 	int		rv;
12531ae08745Sheppo 	struct cpu	*cp;
12541ae08745Sheppo 
12551ae08745Sheppo 	DR_DBG_CPU("dr_cpu_status...\n");
12561ae08745Sheppo 
12571ae08745Sheppo 	mutex_enter(&cpu_lock);
12581ae08745Sheppo 
12591ae08745Sheppo 	if ((cp = cpu_get(cpuid)) == NULL) {
12601ae08745Sheppo 		/* need to check if cpu is in the MD */
12611ae08745Sheppo 		rv = DR_CPU_RES_FAILURE;
12621ae08745Sheppo 		goto done;
12631ae08745Sheppo 	}
12641ae08745Sheppo 
12651ae08745Sheppo 	if (cpu_is_poweredoff(cp)) {
12661ae08745Sheppo 		/*
12671ae08745Sheppo 		 * The CPU is powered off, so it is considered
12681ae08745Sheppo 		 * unconfigured from the service entity point of
12691ae08745Sheppo 		 * view. The CPU is not available to the system
12701ae08745Sheppo 		 * and intervention by the service entity would
12711ae08745Sheppo 		 * be required to change that.
12721ae08745Sheppo 		 */
12731ae08745Sheppo 		*status = DR_CPU_STAT_UNCONFIGURED;
12741ae08745Sheppo 	} else {
12751ae08745Sheppo 		/*
12761ae08745Sheppo 		 * The CPU is powered on, so it is considered
12771ae08745Sheppo 		 * configured from the service entity point of
12781ae08745Sheppo 		 * view. It is available for use by the system
12791ae08745Sheppo 		 * and service entities are not concerned about
12801ae08745Sheppo 		 * the operational status (offline, online, etc.)
12811ae08745Sheppo 		 * of the CPU in terms of DR.
12821ae08745Sheppo 		 */
12831ae08745Sheppo 		*status = DR_CPU_STAT_CONFIGURED;
12841ae08745Sheppo 	}
12851ae08745Sheppo 
12861ae08745Sheppo 	rv = DR_CPU_RES_OK;
12871ae08745Sheppo 
12881ae08745Sheppo done:
12891ae08745Sheppo 	mutex_exit(&cpu_lock);
12901ae08745Sheppo 
12911ae08745Sheppo 	return (rv);
12921ae08745Sheppo }
12931ae08745Sheppo 
12941ae08745Sheppo typedef struct {
12951ae08745Sheppo 	md_t		*mdp;
12961ae08745Sheppo 	mde_cookie_t	cpunode;
12971ae08745Sheppo 	dev_info_t	*dip;
12981ae08745Sheppo } cb_arg_t;
12991ae08745Sheppo 
13001ae08745Sheppo #define	STR_ARR_LEN	5
13011ae08745Sheppo 
13021ae08745Sheppo static int
new_cpu_node(dev_info_t * new_node,void * arg,uint_t flags)13031ae08745Sheppo new_cpu_node(dev_info_t *new_node, void *arg, uint_t flags)
13041ae08745Sheppo {
13051ae08745Sheppo 	_NOTE(ARGUNUSED(flags))
13061ae08745Sheppo 
13071ae08745Sheppo 	char		*compat;
13081ae08745Sheppo 	uint64_t	freq;
13091ae08745Sheppo 	uint64_t	cpuid = 0;
13101ae08745Sheppo 	int		regbuf[4];
13111ae08745Sheppo 	int		len = 0;
13121ae08745Sheppo 	cb_arg_t	*cba;
13131ae08745Sheppo 	char		*str_arr[STR_ARR_LEN];
13141ae08745Sheppo 	char		*curr;
13151ae08745Sheppo 	int		idx = 0;
13161ae08745Sheppo 
13171ae08745Sheppo 	DR_DBG_CPU("new_cpu_node...\n");
13181ae08745Sheppo 
13191ae08745Sheppo 	cba = (cb_arg_t *)arg;
13201ae08745Sheppo 
13211ae08745Sheppo 	/*
13221ae08745Sheppo 	 * Add 'name' property
13231ae08745Sheppo 	 */
13241ae08745Sheppo 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13251ae08745Sheppo 	    "name", "cpu") != DDI_SUCCESS) {
13261ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'name' property\n");
13271ae08745Sheppo 		return (DDI_WALK_ERROR);
13281ae08745Sheppo 	}
13291ae08745Sheppo 
13301ae08745Sheppo 	/*
13311ae08745Sheppo 	 * Add 'compatible' property
13321ae08745Sheppo 	 */
13331ae08745Sheppo 	if (md_get_prop_data(cba->mdp, cba->cpunode, "compatible",
13341ae08745Sheppo 	    (uint8_t **)(&compat), &len)) {
13351ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'compatible' property "
13361ae08745Sheppo 		    "from MD\n");
13371ae08745Sheppo 		return (DDI_WALK_ERROR);
13381ae08745Sheppo 	}
13391ae08745Sheppo 
13401ae08745Sheppo 	DR_DBG_CPU("'compatible' len is %d\n", len);
13411ae08745Sheppo 
13421ae08745Sheppo 	/* parse the MD string array */
13431ae08745Sheppo 	curr = compat;
13441ae08745Sheppo 	while (curr < (compat + len)) {
13451ae08745Sheppo 
13461ae08745Sheppo 		DR_DBG_CPU("adding '%s' to 'compatible' property\n", curr);
13471ae08745Sheppo 
13481ae08745Sheppo 		str_arr[idx++] = curr;
13491ae08745Sheppo 		curr += strlen(curr) + 1;
13501ae08745Sheppo 
13511ae08745Sheppo 		if (idx == STR_ARR_LEN) {
13521ae08745Sheppo 			DR_DBG_CPU("exceeded str_arr len (%d)\n", STR_ARR_LEN);
13531ae08745Sheppo 			break;
13541ae08745Sheppo 		}
13551ae08745Sheppo 	}
13561ae08745Sheppo 
13571ae08745Sheppo 	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, new_node,
13581ae08745Sheppo 	    "compatible", str_arr, idx) != DDI_SUCCESS) {
13591ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'compatible' "
13601ae08745Sheppo 		    "property\n");
13611ae08745Sheppo 		return (DDI_WALK_ERROR);
13621ae08745Sheppo 	}
13631ae08745Sheppo 
13641ae08745Sheppo 	/*
13651ae08745Sheppo 	 * Add 'device_type' property
13661ae08745Sheppo 	 */
13671ae08745Sheppo 	if (ndi_prop_update_string(DDI_DEV_T_NONE, new_node,
13681ae08745Sheppo 	    "device_type", "cpu") != DDI_SUCCESS) {
13691ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'device_type' "
13701ae08745Sheppo 		    "property\n");
13711ae08745Sheppo 		return (DDI_WALK_ERROR);
13721ae08745Sheppo 	}
13731ae08745Sheppo 
13741ae08745Sheppo 	/*
13751ae08745Sheppo 	 * Add 'clock-frequency' property
13761ae08745Sheppo 	 */
13771ae08745Sheppo 	if (md_get_prop_val(cba->mdp, cba->cpunode, "clock-frequency", &freq)) {
13781ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'clock-frequency' "
13791ae08745Sheppo 		    "property from MD\n");
13801ae08745Sheppo 		return (DDI_WALK_ERROR);
13811ae08745Sheppo 	}
13821ae08745Sheppo 
13831ae08745Sheppo 	if (ndi_prop_update_int(DDI_DEV_T_NONE, new_node,
13841ae08745Sheppo 	    "clock-frequency", freq) != DDI_SUCCESS) {
13851ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'clock-frequency' "
13861ae08745Sheppo 		    "property\n");
13871ae08745Sheppo 		return (DDI_WALK_ERROR);
13881ae08745Sheppo 	}
13891ae08745Sheppo 
13901ae08745Sheppo 	/*
13911ae08745Sheppo 	 * Add 'reg' (cpuid) property
13921ae08745Sheppo 	 */
13931ae08745Sheppo 	if (md_get_prop_val(cba->mdp, cba->cpunode, "id", &cpuid)) {
13941ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to read 'id' property "
13951ae08745Sheppo 		    "from MD\n");
13961ae08745Sheppo 		return (DDI_WALK_ERROR);
13971ae08745Sheppo 	}
13981ae08745Sheppo 
13991ae08745Sheppo 	DR_DBG_CPU("new cpuid=0x%lx\n", cpuid);
14001ae08745Sheppo 
14011ae08745Sheppo 	bzero(regbuf, 4 * sizeof (int));
14021ae08745Sheppo 	regbuf[0] = 0xc0000000 | cpuid;
14031ae08745Sheppo 
14041ae08745Sheppo 	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, new_node,
14051ae08745Sheppo 	    "reg", regbuf, 4) != DDI_SUCCESS) {
14061ae08745Sheppo 		DR_DBG_CPU("new_cpu_node: failed to create 'reg' property\n");
14071ae08745Sheppo 		return (DDI_WALK_ERROR);
14081ae08745Sheppo 	}
14091ae08745Sheppo 
14101ae08745Sheppo 	cba->dip = new_node;
14111ae08745Sheppo 
14121ae08745Sheppo 	return (DDI_WALK_TERMINATE);
14131ae08745Sheppo }
14141ae08745Sheppo 
14151ae08745Sheppo static int
dr_cpu_probe(processorid_t cpuid)14161ae08745Sheppo dr_cpu_probe(processorid_t cpuid)
14171ae08745Sheppo {
14181ae08745Sheppo 	dev_info_t	*pdip;
14191ae08745Sheppo 	dev_info_t	*dip;
14201ae08745Sheppo 	devi_branch_t	br;
14211ae08745Sheppo 	md_t		*mdp = NULL;
14221ae08745Sheppo 	int		num_nodes;
14231ae08745Sheppo 	int		rv = 0;
14241ae08745Sheppo 	int		listsz;
14251ae08745Sheppo 	mde_cookie_t	*listp = NULL;
14261ae08745Sheppo 	cb_arg_t	cba;
14271ae08745Sheppo 	mde_cookie_t	cpunode;
14281ae08745Sheppo 
14291ae08745Sheppo 	if ((dip = dr_cpu_find_node(cpuid)) != NULL) {
14301ae08745Sheppo 		/* nothing to do */
14311ae08745Sheppo 		e_ddi_branch_rele(dip);
14321ae08745Sheppo 		return (0);
14331ae08745Sheppo 	}
14341ae08745Sheppo 
14351ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
14361ae08745Sheppo 		DR_DBG_CPU("unable to initialize machine description\n");
14371ae08745Sheppo 		return (-1);
14381ae08745Sheppo 	}
14391ae08745Sheppo 
14401ae08745Sheppo 	num_nodes = md_node_count(mdp);
14411ae08745Sheppo 	ASSERT(num_nodes > 0);
14421ae08745Sheppo 
14431ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
14441ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
144599c7e855SJames Marks - Sun Microsystems 	DR_DBG_KMEM("%s: alloc addr %p size %d\n",
144699c7e855SJames Marks - Sun Microsystems 	    __func__, (void *)listp, listsz);
14471ae08745Sheppo 
14481ae08745Sheppo 	cpunode = dr_cpu_find_node_md(cpuid, mdp, listp);
14491ae08745Sheppo 
14501ae08745Sheppo 	if (cpunode == MDE_INVAL_ELEM_COOKIE) {
14511ae08745Sheppo 		rv = EINVAL;
14521ae08745Sheppo 		goto done;
14531ae08745Sheppo 	}
14541ae08745Sheppo 
14551ae08745Sheppo 	/* pass in MD cookie for CPU */
14561ae08745Sheppo 	cba.mdp = mdp;
14571ae08745Sheppo 	cba.cpunode = cpunode;
14581ae08745Sheppo 
14591ae08745Sheppo 	br.arg = (void *)&cba;
14601ae08745Sheppo 	br.type = DEVI_BRANCH_SID;
14611ae08745Sheppo 	br.create.sid_branch_create = new_cpu_node;
14621ae08745Sheppo 	br.devi_branch_callback = NULL;
14631ae08745Sheppo 	pdip = ddi_root_node();
14641ae08745Sheppo 
14651ae08745Sheppo 	if ((rv = e_ddi_branch_create(pdip, &br, NULL, 0))) {
14661ae08745Sheppo 		DR_DBG_CPU("e_ddi_branch_create failed: %d\n", rv);
14671ae08745Sheppo 		rv = -1;
14681ae08745Sheppo 		goto done;
14691ae08745Sheppo 	}
14701ae08745Sheppo 
14711ae08745Sheppo 	DR_DBG_CPU("CPU %d probed\n", cpuid);
14721ae08745Sheppo 
14731ae08745Sheppo 	rv = 0;
14741ae08745Sheppo 
14751ae08745Sheppo done:
147699c7e855SJames Marks - Sun Microsystems 	if (listp) {
147799c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %d\n",
147899c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)listp, listsz);
14791ae08745Sheppo 		kmem_free(listp, listsz);
148099c7e855SJames Marks - Sun Microsystems 	}
14811ae08745Sheppo 
14821ae08745Sheppo 	if (mdp)
14831ae08745Sheppo 		(void) md_fini_handle(mdp);
14841ae08745Sheppo 
14851ae08745Sheppo 	return (rv);
14861ae08745Sheppo }
14871ae08745Sheppo 
14881ae08745Sheppo static int
dr_cpu_deprobe(processorid_t cpuid)14891ae08745Sheppo dr_cpu_deprobe(processorid_t cpuid)
14901ae08745Sheppo {
14911ae08745Sheppo 	dev_info_t	*fdip = NULL;
14921ae08745Sheppo 	dev_info_t	*dip;
14931ae08745Sheppo 
14941ae08745Sheppo 	if ((dip = dr_cpu_find_node(cpuid)) == NULL) {
14951ae08745Sheppo 		DR_DBG_CPU("cpuid %d already deprobed\n", cpuid);
14961ae08745Sheppo 		return (0);
14971ae08745Sheppo 	}
14981ae08745Sheppo 
14991ae08745Sheppo 	ASSERT(e_ddi_branch_held(dip));
15001ae08745Sheppo 
15011ae08745Sheppo 	if (e_ddi_branch_destroy(dip, &fdip, 0)) {
15021ae08745Sheppo 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
15031ae08745Sheppo 
150499c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: alloc addr %p size %d\n",
150599c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)path, MAXPATHLEN);
15061ae08745Sheppo 		/*
15071ae08745Sheppo 		 * If non-NULL, fdip is held and must be released.
15081ae08745Sheppo 		 */
15091ae08745Sheppo 		if (fdip != NULL) {
15101ae08745Sheppo 			(void) ddi_pathname(fdip, path);
15111ae08745Sheppo 			ddi_release_devi(fdip);
15121ae08745Sheppo 		} else {
15131ae08745Sheppo 			(void) ddi_pathname(dip, path);
15141ae08745Sheppo 		}
15151ae08745Sheppo 		cmn_err(CE_NOTE, "node removal failed: %s (%p)",
15161ae08745Sheppo 		    path, (fdip) ? (void *)fdip : (void *)dip);
15171ae08745Sheppo 
151899c7e855SJames Marks - Sun Microsystems 		DR_DBG_KMEM("%s: free addr %p size %d\n",
151999c7e855SJames Marks - Sun Microsystems 		    __func__, (void *)path, MAXPATHLEN);
15201ae08745Sheppo 		kmem_free(path, MAXPATHLEN);
15211ae08745Sheppo 
15221ae08745Sheppo 		return (-1);
15231ae08745Sheppo 	}
15241ae08745Sheppo 
15251ae08745Sheppo 	DR_DBG_CPU("CPU %d deprobed\n", cpuid);
15261ae08745Sheppo 
15271ae08745Sheppo 	return (0);
15281ae08745Sheppo }
15291ae08745Sheppo 
15301ae08745Sheppo typedef struct {
15311ae08745Sheppo 	processorid_t	cpuid;
15321ae08745Sheppo 	dev_info_t	*dip;
15331ae08745Sheppo } dr_search_arg_t;
15341ae08745Sheppo 
15351ae08745Sheppo static int
dr_cpu_check_node(dev_info_t * dip,void * arg)15361ae08745Sheppo dr_cpu_check_node(dev_info_t *dip, void *arg)
15371ae08745Sheppo {
15381ae08745Sheppo 	char 		*name;
15391ae08745Sheppo 	processorid_t	cpuid;
15401ae08745Sheppo 	dr_search_arg_t	*sarg = (dr_search_arg_t *)arg;
15411ae08745Sheppo 
15421ae08745Sheppo 	if (dip == ddi_root_node()) {
15431ae08745Sheppo 		return (DDI_WALK_CONTINUE);
15441ae08745Sheppo 	}
15451ae08745Sheppo 
15461ae08745Sheppo 	name = ddi_node_name(dip);
15471ae08745Sheppo 
15481ae08745Sheppo 	if (strcmp(name, "cpu") != 0) {
15491ae08745Sheppo 		return (DDI_WALK_PRUNECHILD);
15501ae08745Sheppo 	}
15511ae08745Sheppo 
15521ae08745Sheppo 	cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
15531ae08745Sheppo 	    "reg", -1);
15541ae08745Sheppo 
15551ae08745Sheppo 	cpuid = PROM_CFGHDL_TO_CPUID(cpuid);
15561ae08745Sheppo 
15571ae08745Sheppo 	DR_DBG_CPU("found cpuid=0x%x, looking for 0x%x\n", cpuid, sarg->cpuid);
15581ae08745Sheppo 
15591ae08745Sheppo 	if (cpuid == sarg->cpuid) {
15601ae08745Sheppo 		DR_DBG_CPU("matching node\n");
15611ae08745Sheppo 
15621ae08745Sheppo 		/* matching node must be returned held */
15631ae08745Sheppo 		if (!e_ddi_branch_held(dip))
15641ae08745Sheppo 			e_ddi_branch_hold(dip);
15651ae08745Sheppo 
15661ae08745Sheppo 		sarg->dip = dip;
15671ae08745Sheppo 		return (DDI_WALK_TERMINATE);
15681ae08745Sheppo 	}
15691ae08745Sheppo 
15701ae08745Sheppo 	return (DDI_WALK_CONTINUE);
15711ae08745Sheppo }
15721ae08745Sheppo 
15731ae08745Sheppo /*
15741ae08745Sheppo  * Walk the device tree to find the dip corresponding to the cpuid
15751ae08745Sheppo  * passed in. If present, the dip is returned held. The caller must
15761ae08745Sheppo  * release the hold on the dip once it is no longer required. If no
15771ae08745Sheppo  * matching node if found, NULL is returned.
15781ae08745Sheppo  */
15791ae08745Sheppo static dev_info_t *
dr_cpu_find_node(processorid_t cpuid)15801ae08745Sheppo dr_cpu_find_node(processorid_t cpuid)
15811ae08745Sheppo {
15821ae08745Sheppo 	dr_search_arg_t	arg;
15831ae08745Sheppo 
15841ae08745Sheppo 	DR_DBG_CPU("dr_cpu_find_node...\n");
15851ae08745Sheppo 
15861ae08745Sheppo 	arg.cpuid = cpuid;
15871ae08745Sheppo 	arg.dip = NULL;
15881ae08745Sheppo 
15891ae08745Sheppo 	ddi_walk_devs(ddi_root_node(), dr_cpu_check_node, &arg);
15901ae08745Sheppo 
15911ae08745Sheppo 	ASSERT((arg.dip == NULL) || (e_ddi_branch_held(arg.dip)));
15921ae08745Sheppo 
15931ae08745Sheppo 	return ((arg.dip) ? arg.dip : NULL);
15941ae08745Sheppo }
15951ae08745Sheppo 
15961ae08745Sheppo /*
15971ae08745Sheppo  * Look up a particular cpuid in the MD. Returns the mde_cookie_t
15981ae08745Sheppo  * representing that CPU if present, and MDE_INVAL_ELEM_COOKIE
15991ae08745Sheppo  * otherwise. It is assumed the scratch array has already been
16001ae08745Sheppo  * allocated so that it can accommodate the worst case scenario,
16011ae08745Sheppo  * every node in the MD.
16021ae08745Sheppo  */
16031ae08745Sheppo static mde_cookie_t
dr_cpu_find_node_md(processorid_t cpuid,md_t * mdp,mde_cookie_t * listp)16041ae08745Sheppo dr_cpu_find_node_md(processorid_t cpuid, md_t *mdp, mde_cookie_t *listp)
16051ae08745Sheppo {
16061ae08745Sheppo 	int		idx;
16071ae08745Sheppo 	int		nnodes;
16081ae08745Sheppo 	mde_cookie_t	rootnode;
16091ae08745Sheppo 	uint64_t	cpuid_prop;
16101ae08745Sheppo 	mde_cookie_t	result = MDE_INVAL_ELEM_COOKIE;
16111ae08745Sheppo 
16121ae08745Sheppo 	rootnode = md_root_node(mdp);
16131ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
16141ae08745Sheppo 
16151ae08745Sheppo 	/*
16161ae08745Sheppo 	 * Scan the DAG for all the CPU nodes
16171ae08745Sheppo 	 */
16181ae08745Sheppo 	nnodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
16191ae08745Sheppo 	    md_find_name(mdp, "fwd"), listp);
16201ae08745Sheppo 
16211ae08745Sheppo 	if (nnodes < 0) {
16221ae08745Sheppo 		DR_DBG_CPU("Scan for CPUs failed\n");
16231ae08745Sheppo 		return (result);
16241ae08745Sheppo 	}
16251ae08745Sheppo 
16261ae08745Sheppo 	DR_DBG_CPU("dr_cpu_find_node_md: found %d CPUs in the MD\n", nnodes);
16271ae08745Sheppo 
16281ae08745Sheppo 	/*
16291ae08745Sheppo 	 * Find the CPU of interest
16301ae08745Sheppo 	 */
16311ae08745Sheppo 	for (idx = 0; idx < nnodes; idx++) {
16321ae08745Sheppo 
16331ae08745Sheppo 		if (md_get_prop_val(mdp, listp[idx], "id", &cpuid_prop)) {
16341ae08745Sheppo 			DR_DBG_CPU("Missing 'id' property for CPU node %d\n",
16351ae08745Sheppo 			    idx);
16361ae08745Sheppo 			break;
16371ae08745Sheppo 		}
16381ae08745Sheppo 
16391ae08745Sheppo 		if (cpuid_prop == cpuid) {
16401ae08745Sheppo 			/* found a match */
16411ae08745Sheppo 			DR_DBG_CPU("dr_cpu_find_node_md: found CPU %d "
16421ae08745Sheppo 			    "in MD\n", cpuid);
16431ae08745Sheppo 			result = listp[idx];
16441ae08745Sheppo 			break;
16451ae08745Sheppo 		}
16461ae08745Sheppo 	}
16471ae08745Sheppo 
16481ae08745Sheppo 	if (result == MDE_INVAL_ELEM_COOKIE) {
16491ae08745Sheppo 		DR_DBG_CPU("CPU %d not in MD\n", cpuid);
16501ae08745Sheppo 	}
16511ae08745Sheppo 
16521ae08745Sheppo 	return (result);
16531ae08745Sheppo }
1654