xref: /onnv-gate/usr/src/uts/i86pc/os/cmi.c (revision 10942:eaa343de0d06)
11642Sgavinm /*
21642Sgavinm  * CDDL HEADER START
31642Sgavinm  *
41642Sgavinm  * The contents of this file are subject to the terms of the
51642Sgavinm  * Common Development and Distribution License (the "License").
61642Sgavinm  * You may not use this file except in compliance with the License.
71642Sgavinm  *
81642Sgavinm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91642Sgavinm  * or http://www.opensolaris.org/os/licensing.
101642Sgavinm  * See the License for the specific language governing permissions
111642Sgavinm  * and limitations under the License.
121642Sgavinm  *
131642Sgavinm  * When distributing Covered Code, include this CDDL HEADER in each
141642Sgavinm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151642Sgavinm  * If applicable, add the following below this CDDL HEADER, with the
161642Sgavinm  * fields enclosed by brackets "[]" replaced with your own identifying
171642Sgavinm  * information: Portions Copyright [yyyy] [name of copyright owner]
181642Sgavinm  *
191642Sgavinm  * CDDL HEADER END
201642Sgavinm  */
211642Sgavinm 
221414Scindi /*
23*10942STom.Pothier@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241414Scindi  * Use is subject to license terms.
251414Scindi  */
261414Scindi 
271414Scindi /*
281414Scindi  * Public interface to routines implemented by CPU modules
291414Scindi  */
301414Scindi 
315254Sgavinm #include <sys/types.h>
325254Sgavinm #include <sys/atomic.h>
331414Scindi #include <sys/x86_archext.h>
341414Scindi #include <sys/cpu_module_impl.h>
355254Sgavinm #include <sys/cpu_module_ms.h>
361414Scindi #include <sys/fm/util.h>
371414Scindi #include <sys/reboot.h>
381414Scindi #include <sys/modctl.h>
391414Scindi #include <sys/param.h>
401414Scindi #include <sys/cmn_err.h>
411414Scindi #include <sys/systm.h>
425254Sgavinm #include <sys/fm/protocol.h>
435254Sgavinm #include <sys/pcb.h>
445254Sgavinm #include <sys/ontrap.h>
455254Sgavinm #include <sys/psw.h>
465254Sgavinm #include <sys/privregs.h>
477532SSean.Ye@Sun.COM #include <sys/machsystm.h>
481414Scindi 
495254Sgavinm /*
505254Sgavinm  * Set to force cmi_init to fail.
515254Sgavinm  */
525254Sgavinm int cmi_no_init = 0;
535254Sgavinm 
545254Sgavinm /*
555254Sgavinm  * Set to avoid MCA initialization.
565254Sgavinm  */
575254Sgavinm int cmi_no_mca_init = 0;
581414Scindi 
591414Scindi /*
602869Sgavinm  * If cleared for debugging we will not attempt to load a model-specific
612869Sgavinm  * cpu module but will load the generic cpu module instead.
622869Sgavinm  */
632869Sgavinm int cmi_force_generic = 0;
642869Sgavinm 
652869Sgavinm /*
661414Scindi  * If cleared for debugging, we will suppress panicking on fatal hardware
671414Scindi  * errors.  This should *only* be used for debugging; it use can and will
681414Scindi  * cause data corruption if actual hardware errors are detected by the system.
691414Scindi  */
701414Scindi int cmi_panic_on_uncorrectable_error = 1;
711414Scindi 
727532SSean.Ye@Sun.COM #ifndef __xpv
735254Sgavinm /*
747349SAdrian.Frost@Sun.COM  * Set to indicate whether we are able to enable cmci interrupt.
757349SAdrian.Frost@Sun.COM  */
767349SAdrian.Frost@Sun.COM int cmi_enable_cmci = 0;
777532SSean.Ye@Sun.COM #endif
787349SAdrian.Frost@Sun.COM 
797349SAdrian.Frost@Sun.COM /*
805254Sgavinm  * Subdirectory (relative to the module search path) in which we will
815254Sgavinm  * look for cpu modules.
825254Sgavinm  */
835254Sgavinm #define	CPUMOD_SUBDIR	"cpu"
845254Sgavinm 
855254Sgavinm /*
865254Sgavinm  * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and
875254Sgavinm  * "cpu.generic" - the "cpu" prefix is specified by the following.
885254Sgavinm  */
895254Sgavinm #define	CPUMOD_PREFIX	"cpu"
905254Sgavinm 
915254Sgavinm /*
925254Sgavinm  * Structure used to keep track of cpu modules we have loaded and their ops
935254Sgavinm  */
945254Sgavinm typedef struct cmi {
955254Sgavinm 	struct cmi *cmi_next;
965254Sgavinm 	struct cmi *cmi_prev;
975254Sgavinm 	const cmi_ops_t *cmi_ops;
985254Sgavinm 	struct modctl *cmi_modp;
995254Sgavinm 	uint_t cmi_refcnt;
1005254Sgavinm } cmi_t;
1015254Sgavinm 
1021414Scindi static cmi_t *cmi_list;
1031414Scindi static kmutex_t cmi_load_lock;
1041414Scindi 
1055254Sgavinm /*
1065254Sgavinm  * Functions we need from cmi_hw.c that are not part of the cpu_module.h
1075254Sgavinm  * interface.
1085254Sgavinm  */
1097532SSean.Ye@Sun.COM extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t);
1105254Sgavinm extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
1115254Sgavinm extern void *cmi_hdl_getcmi(cmi_hdl_t);
1125254Sgavinm extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
1137532SSean.Ye@Sun.COM extern void cmi_hdl_inj_begin(cmi_hdl_t);
1147532SSean.Ye@Sun.COM extern void cmi_hdl_inj_end(cmi_hdl_t);
115*10942STom.Pothier@Sun.COM extern void cmi_read_smbios(cmi_hdl_t);
1165254Sgavinm 
1175254Sgavinm #define	HDL2CMI(hdl)		cmi_hdl_getcmi(hdl)
1185254Sgavinm 
1195254Sgavinm #define	CMI_OPS(cmi)		(cmi)->cmi_ops
1205254Sgavinm #define	CMI_OP_PRESENT(cmi, op)	((cmi) && CMI_OPS(cmi)->op != NULL)
1215254Sgavinm 
1225254Sgavinm #define	CMI_MATCH_VENDOR	0	/* Just match on vendor */
1235254Sgavinm #define	CMI_MATCH_FAMILY	1	/* Match down to family */
1245254Sgavinm #define	CMI_MATCH_MODEL		2	/* Match down to model */
1255254Sgavinm #define	CMI_MATCH_STEPPING	3	/* Match down to stepping */
1265254Sgavinm 
1275254Sgavinm static void
1285254Sgavinm cmi_link(cmi_t *cmi)
1295254Sgavinm {
1305254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
1315254Sgavinm 
1325254Sgavinm 	cmi->cmi_prev = NULL;
1335254Sgavinm 	cmi->cmi_next = cmi_list;
1345254Sgavinm 	if (cmi_list != NULL)
1355254Sgavinm 		cmi_list->cmi_prev = cmi;
1365254Sgavinm 	cmi_list = cmi;
1375254Sgavinm }
1385254Sgavinm 
1395254Sgavinm static void
1405254Sgavinm cmi_unlink(cmi_t *cmi)
1411414Scindi {
1425254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
1435254Sgavinm 	ASSERT(cmi->cmi_refcnt == 0);
1445254Sgavinm 
1455254Sgavinm 	if (cmi->cmi_prev != NULL)
1465254Sgavinm 		cmi->cmi_prev = cmi->cmi_next;
1475254Sgavinm 
1485254Sgavinm 	if (cmi->cmi_next != NULL)
1495254Sgavinm 		cmi->cmi_next->cmi_prev = cmi->cmi_prev;
1505254Sgavinm 
1515254Sgavinm 	if (cmi_list == cmi)
1525254Sgavinm 		cmi_list = cmi->cmi_next;
1535254Sgavinm }
1545254Sgavinm 
1555254Sgavinm /*
1565254Sgavinm  * Hold the module in memory.  We call to CPU modules without using the
1575254Sgavinm  * stubs mechanism, so these modules must be manually held in memory.
1585254Sgavinm  * The mod_ref acts as if another loaded module has a dependency on us.
1595254Sgavinm  */
1605254Sgavinm static void
1615254Sgavinm cmi_hold(cmi_t *cmi)
1625254Sgavinm {
1635254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
1645254Sgavinm 
1655254Sgavinm 	mutex_enter(&mod_lock);
1665254Sgavinm 	cmi->cmi_modp->mod_ref++;
1675254Sgavinm 	mutex_exit(&mod_lock);
1685254Sgavinm 	cmi->cmi_refcnt++;
1695254Sgavinm }
1705254Sgavinm 
1715254Sgavinm static void
1725254Sgavinm cmi_rele(cmi_t *cmi)
1735254Sgavinm {
1745254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
1755254Sgavinm 
1765254Sgavinm 	mutex_enter(&mod_lock);
1775254Sgavinm 	cmi->cmi_modp->mod_ref--;
1785254Sgavinm 	mutex_exit(&mod_lock);
1795254Sgavinm 
1805254Sgavinm 	if (--cmi->cmi_refcnt == 0) {
1815254Sgavinm 		cmi_unlink(cmi);
1825254Sgavinm 		kmem_free(cmi, sizeof (cmi_t));
1835254Sgavinm 	}
1845254Sgavinm }
1855254Sgavinm 
1865254Sgavinm static cmi_ops_t *
1875254Sgavinm cmi_getops(modctl_t *modp)
1885254Sgavinm {
1895254Sgavinm 	cmi_ops_t *ops;
1905254Sgavinm 
1915254Sgavinm 	if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) ==
1925254Sgavinm 	    NULL) {
1935254Sgavinm 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops "
1945254Sgavinm 		    "found", modp->mod_modname);
1955254Sgavinm 		return (NULL);
1965254Sgavinm 	}
1975254Sgavinm 
1985254Sgavinm 	if (ops->cmi_init == NULL) {
1995254Sgavinm 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init "
2005254Sgavinm 		    "entry point", modp->mod_modname);
2015254Sgavinm 		return (NULL);
2025254Sgavinm 	}
2035254Sgavinm 
2045254Sgavinm 	return (ops);
2051414Scindi }
2061414Scindi 
2071414Scindi static cmi_t *
2081414Scindi cmi_load_modctl(modctl_t *modp)
2091414Scindi {
2105254Sgavinm 	cmi_ops_t *ops;
2115254Sgavinm 	uintptr_t ver;
2121414Scindi 	cmi_t *cmi;
2135254Sgavinm 	cmi_api_ver_t apiver;
2141414Scindi 
2151414Scindi 	ASSERT(MUTEX_HELD(&cmi_load_lock));
2161414Scindi 
2171414Scindi 	for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
2181414Scindi 		if (cmi->cmi_modp == modp)
2191414Scindi 			return (cmi);
2201414Scindi 	}
2211414Scindi 
2225254Sgavinm 	if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) {
2235254Sgavinm 		/*
2245254Sgavinm 		 * Apparently a cpu module before versioning was introduced -
2255254Sgavinm 		 * we call this version 0.
2265254Sgavinm 		 */
2275254Sgavinm 		apiver = CMI_API_VERSION_0;
2285254Sgavinm 	} else {
2295254Sgavinm 		apiver = *((cmi_api_ver_t *)ver);
2305254Sgavinm 		if (!CMI_API_VERSION_CHKMAGIC(apiver)) {
2315254Sgavinm 			cmn_err(CE_WARN, "cpu module '%s' is invalid: "
2325254Sgavinm 			    "_cmi_api_version 0x%x has bad magic",
2335254Sgavinm 			    modp->mod_modname, apiver);
2345254Sgavinm 			return (NULL);
2355254Sgavinm 		}
2365254Sgavinm 	}
2375254Sgavinm 
2385254Sgavinm 	if (apiver != CMI_API_VERSION) {
2395254Sgavinm 		cmn_err(CE_WARN, "cpu module '%s' has API version %d, "
2405254Sgavinm 		    "kernel requires API version %d", modp->mod_modname,
2415254Sgavinm 		    CMI_API_VERSION_TOPRINT(apiver),
2425254Sgavinm 		    CMI_API_VERSION_TOPRINT(CMI_API_VERSION));
2431414Scindi 		return (NULL);
2441414Scindi 	}
2451414Scindi 
2465254Sgavinm 	if ((ops = cmi_getops(modp)) == NULL)
2475254Sgavinm 		return (NULL);
2481414Scindi 
2495254Sgavinm 	cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP);
2505254Sgavinm 	cmi->cmi_ops = ops;
2511414Scindi 	cmi->cmi_modp = modp;
2521414Scindi 
2535254Sgavinm 	cmi_link(cmi);
2545254Sgavinm 
2555254Sgavinm 	return (cmi);
2565254Sgavinm }
2575254Sgavinm 
2585254Sgavinm static int
2595254Sgavinm cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
2605254Sgavinm {
2615254Sgavinm 	if (match >= CMI_MATCH_VENDOR &&
2625254Sgavinm 	    cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
2635254Sgavinm 		return (0);
2645254Sgavinm 
2655254Sgavinm 	if (match >= CMI_MATCH_FAMILY &&
2665254Sgavinm 	    cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
2675254Sgavinm 		return (0);
2685254Sgavinm 
2695254Sgavinm 	if (match >= CMI_MATCH_MODEL &&
2705254Sgavinm 	    cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
2715254Sgavinm 		return (0);
2725254Sgavinm 
2735254Sgavinm 	if (match >= CMI_MATCH_STEPPING &&
2745254Sgavinm 	    cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
2755254Sgavinm 		return (0);
2765254Sgavinm 
2775254Sgavinm 	return (1);
2785254Sgavinm }
2795254Sgavinm 
2805254Sgavinm static int
2815254Sgavinm cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
2825254Sgavinm {
2835254Sgavinm 	cmi_hdl_t thdl = (cmi_hdl_t)arg1;
2845254Sgavinm 	int match = *((int *)arg2);
2855254Sgavinm 	cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
2865254Sgavinm 
2875254Sgavinm 	if (cmi_cpu_match(thdl, whdl, match)) {
2885254Sgavinm 		cmi_hdl_hold(whdl);	/* short-term hold */
2895254Sgavinm 		*rsltp = whdl;
2905254Sgavinm 		return (CMI_HDL_WALK_DONE);
2915254Sgavinm 	} else {
2925254Sgavinm 		return (CMI_HDL_WALK_NEXT);
2935254Sgavinm 	}
2945254Sgavinm }
2955254Sgavinm 
2965254Sgavinm static cmi_t *
2975254Sgavinm cmi_search_list(cmi_hdl_t hdl, int match)
2985254Sgavinm {
2995254Sgavinm 	cmi_hdl_t dhdl = NULL;
3005254Sgavinm 	cmi_t *cmi = NULL;
3015254Sgavinm 
3025254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
3035254Sgavinm 
3045254Sgavinm 	cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
3055254Sgavinm 	if (dhdl) {
3065254Sgavinm 		cmi = HDL2CMI(dhdl);
3075254Sgavinm 		cmi_hdl_rele(dhdl);	/* held in cmi_search_list_cb */
3085254Sgavinm 	}
3091414Scindi 
3101414Scindi 	return (cmi);
3111414Scindi }
3121414Scindi 
3131414Scindi static cmi_t *
3145254Sgavinm cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp)
3151414Scindi {
3161414Scindi 	modctl_t *modp;
3171414Scindi 	cmi_t *cmi;
3185254Sgavinm 	int modid;
3191414Scindi 	uint_t s[3];
3201414Scindi 
3215254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
3225254Sgavinm 	ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL ||
3235254Sgavinm 	    match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR);
3245254Sgavinm 
3251414Scindi 	/*
3265254Sgavinm 	 * Have we already loaded a module for a cpu with the same
3275254Sgavinm 	 * vendor/family/model/stepping?
3281414Scindi 	 */
3295254Sgavinm 	if ((cmi = cmi_search_list(hdl, match)) != NULL) {
3305254Sgavinm 		cmi_hold(cmi);
3315254Sgavinm 		return (cmi);
3321414Scindi 	}
3331414Scindi 
3345254Sgavinm 	s[0] = cmi_hdl_family(hdl);
3355254Sgavinm 	s[1] = cmi_hdl_model(hdl);
3365254Sgavinm 	s[2] = cmi_hdl_stepping(hdl);
3371414Scindi 	modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
3385254Sgavinm 	    cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
3391414Scindi 
3401414Scindi 	if (modid == -1)
3411414Scindi 		return (NULL);
3421414Scindi 
3431414Scindi 	modp = mod_hold_by_id(modid);
3441414Scindi 	cmi = cmi_load_modctl(modp);
3455254Sgavinm 	if (cmi)
3465254Sgavinm 		cmi_hold(cmi);
3471414Scindi 	mod_release_mod(modp);
3481414Scindi 
3491414Scindi 	return (cmi);
3501414Scindi }
3511414Scindi 
3521414Scindi /*
3535254Sgavinm  * Try to load a cpu module with specific support for this chip type.
3541414Scindi  */
3555254Sgavinm static cmi_t *
3565254Sgavinm cmi_load_specific(cmi_hdl_t hdl, void **datap)
3571414Scindi {
3581414Scindi 	cmi_t *cmi;
3595254Sgavinm 	int err;
3605254Sgavinm 	int i;
3615254Sgavinm 
3625254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
3635254Sgavinm 
3645254Sgavinm 	for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) {
3655254Sgavinm 		int suffixlevel;
3665254Sgavinm 
3675254Sgavinm 		if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL)
3685254Sgavinm 			return (NULL);
3695254Sgavinm 
3705254Sgavinm 		/*
3715254Sgavinm 		 * A module has loaded and has a _cmi_ops structure, and the
3725254Sgavinm 		 * module has been held for this instance.  Call its cmi_init
3735254Sgavinm 		 * entry point - we expect success (0) or ENOTSUP.
3745254Sgavinm 		 */
3755254Sgavinm 		if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) {
3765254Sgavinm 			if (boothowto & RB_VERBOSE) {
3775254Sgavinm 				printf("initialized cpu module '%s' on "
3785254Sgavinm 				    "chip %d core %d strand %d\n",
3795254Sgavinm 				    cmi->cmi_modp->mod_modname,
3805254Sgavinm 				    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3815254Sgavinm 				    cmi_hdl_strandid(hdl));
3825254Sgavinm 			}
3835254Sgavinm 			return (cmi);
3845254Sgavinm 		} else if (err != ENOTSUP) {
3855254Sgavinm 			cmn_err(CE_WARN, "failed to init cpu module '%s' on "
3865254Sgavinm 			    "chip %d core %d strand %d: err=%d\n",
3875254Sgavinm 			    cmi->cmi_modp->mod_modname,
3885254Sgavinm 			    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
3895254Sgavinm 			    cmi_hdl_strandid(hdl), err);
3905254Sgavinm 		}
3915254Sgavinm 
3925254Sgavinm 		/*
3935254Sgavinm 		 * The module failed or declined to init, so release
3945254Sgavinm 		 * it and update i to be equal to the number
3955254Sgavinm 		 * of suffices actually used in the last module path.
3965254Sgavinm 		 */
3975254Sgavinm 		cmi_rele(cmi);
3985254Sgavinm 		i = suffixlevel;
3995254Sgavinm 	}
4005254Sgavinm 
4015254Sgavinm 	return (NULL);
4025254Sgavinm }
4035254Sgavinm 
4045254Sgavinm /*
4055254Sgavinm  * Load the generic IA32 MCA cpu module, which may still supplement
4065254Sgavinm  * itself with model-specific support through cpu model-specific modules.
4075254Sgavinm  */
4085254Sgavinm static cmi_t *
4095254Sgavinm cmi_load_generic(cmi_hdl_t hdl, void **datap)
4105254Sgavinm {
4115254Sgavinm 	modctl_t *modp;
4125254Sgavinm 	cmi_t *cmi;
4135254Sgavinm 	int modid;
4145254Sgavinm 	int err;
4155254Sgavinm 
4165254Sgavinm 	ASSERT(MUTEX_HELD(&cmi_load_lock));
4175254Sgavinm 
4185254Sgavinm 	if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
4195254Sgavinm 		return (NULL);
4205254Sgavinm 
4215254Sgavinm 	modp = mod_hold_by_id(modid);
4225254Sgavinm 	cmi = cmi_load_modctl(modp);
4235254Sgavinm 	if (cmi)
4245254Sgavinm 		cmi_hold(cmi);
4255254Sgavinm 	mod_release_mod(modp);
4265254Sgavinm 
4275254Sgavinm 	if (cmi == NULL)
4285254Sgavinm 		return (NULL);
4295254Sgavinm 
4305254Sgavinm 	if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) {
4315254Sgavinm 		if (err != ENOTSUP)
4325254Sgavinm 			cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to "
4335254Sgavinm 			    "init: err=%d", err);
4345254Sgavinm 		cmi_rele(cmi);
4355254Sgavinm 		return (NULL);
4365254Sgavinm 	}
4375254Sgavinm 
4385254Sgavinm 	return (cmi);
4395254Sgavinm }
4405254Sgavinm 
4415254Sgavinm cmi_hdl_t
4425254Sgavinm cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
4437532SSean.Ye@Sun.COM     uint_t strandid)
4445254Sgavinm {
4455254Sgavinm 	cmi_t *cmi = NULL;
4465254Sgavinm 	cmi_hdl_t hdl;
4471414Scindi 	void *data;
4481414Scindi 
4495254Sgavinm 	if (cmi_no_init) {
4505254Sgavinm 		cmi_no_mca_init = 1;
4515254Sgavinm 		return (NULL);
4525254Sgavinm 	}
4535254Sgavinm 
4541414Scindi 	mutex_enter(&cmi_load_lock);
4551414Scindi 
4567532SSean.Ye@Sun.COM 	if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) {
4571414Scindi 		mutex_exit(&cmi_load_lock);
4585254Sgavinm 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
4595254Sgavinm 		    "core %d strand %d (cmi_hdl_create returned NULL)\n",
4605254Sgavinm 		    chipid, coreid, strandid);
4615254Sgavinm 		return (NULL);
4621414Scindi 	}
4631414Scindi 
4645254Sgavinm 	if (!cmi_force_generic)
4655254Sgavinm 		cmi = cmi_load_specific(hdl, &data);
4665254Sgavinm 
4675254Sgavinm 	if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) {
4685254Sgavinm 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
4695254Sgavinm 		    "core %d strand %d\n", chipid, coreid, strandid);
4705254Sgavinm 		cmi_hdl_rele(hdl);
4711414Scindi 		mutex_exit(&cmi_load_lock);
4725254Sgavinm 		return (NULL);
4731414Scindi 	}
4741414Scindi 
4755254Sgavinm 	cmi_hdl_setcmi(hdl, cmi, data);
4761414Scindi 
4775254Sgavinm 	cms_init(hdl);
4785254Sgavinm 
479*10942STom.Pothier@Sun.COM 	cmi_read_smbios(hdl);
480*10942STom.Pothier@Sun.COM 
4811414Scindi 	mutex_exit(&cmi_load_lock);
4821414Scindi 
4835254Sgavinm 	return (hdl);
4841414Scindi }
4851414Scindi 
4865254Sgavinm /*
4875254Sgavinm  * cmi_fini is not called at the moment.  It is intended to be called
4885254Sgavinm  * on DR deconfigure of a cpu resource.  It should not be called at
4895254Sgavinm  * simple offline of a cpu.
4905254Sgavinm  */
4911414Scindi void
4925254Sgavinm cmi_fini(cmi_hdl_t hdl)
4931414Scindi {
4945254Sgavinm 	cmi_t *cmi = HDL2CMI(hdl);
4955254Sgavinm 
4965254Sgavinm 	if (cms_present(hdl))
4975254Sgavinm 		cms_fini(hdl);
4985254Sgavinm 
4995254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_fini))
5005254Sgavinm 		CMI_OPS(cmi)->cmi_fini(hdl);
5015254Sgavinm 
5025254Sgavinm 	cmi_hdl_rele(hdl);	/* release hold obtained in cmi_hdl_create */
5031414Scindi }
5041414Scindi 
5055254Sgavinm /*
5067532SSean.Ye@Sun.COM  * cmi_post_startup is called from post_startup for the boot cpu only (no
5077532SSean.Ye@Sun.COM  * other cpus are started yet).
5085254Sgavinm  */
5091414Scindi void
5105254Sgavinm cmi_post_startup(void)
5111414Scindi {
5125254Sgavinm 	cmi_hdl_t hdl;
5135254Sgavinm 	cmi_t *cmi;
5145254Sgavinm 
5155254Sgavinm 	if (cmi_no_mca_init != 0 ||
5165254Sgavinm 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
5175254Sgavinm 		return;
5185254Sgavinm 
5195254Sgavinm 	cmi = HDL2CMI(hdl);
5205254Sgavinm 
5215254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_post_startup))
5225254Sgavinm 		CMI_OPS(cmi)->cmi_post_startup(hdl);
5235254Sgavinm 
5245254Sgavinm 	cmi_hdl_rele(hdl);
5251414Scindi }
5261414Scindi 
5272869Sgavinm /*
5282869Sgavinm  * Called just once from start_other_cpus when all processors are started.
5292869Sgavinm  * This will not be called for each cpu, so the registered op must not
5307532SSean.Ye@Sun.COM  * assume it is called as such.  We are not necessarily executing on
5317532SSean.Ye@Sun.COM  * the boot cpu.
5322869Sgavinm  */
5331414Scindi void
5341642Sgavinm cmi_post_mpstartup(void)
5351642Sgavinm {
5365254Sgavinm 	cmi_hdl_t hdl;
5375254Sgavinm 	cmi_t *cmi;
5385254Sgavinm 
5395254Sgavinm 	if (cmi_no_mca_init != 0 ||
5405254Sgavinm 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
5415254Sgavinm 		return;
5425254Sgavinm 
5435254Sgavinm 	cmi = HDL2CMI(hdl);
5445254Sgavinm 
5455254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup))
5465254Sgavinm 		CMI_OPS(cmi)->cmi_post_mpstartup(hdl);
5475254Sgavinm 
5485254Sgavinm 	cmi_hdl_rele(hdl);
5491642Sgavinm }
5501642Sgavinm 
5511642Sgavinm void
5525254Sgavinm cmi_faulted_enter(cmi_hdl_t hdl)
5531414Scindi {
5545254Sgavinm 	cmi_t *cmi = HDL2CMI(hdl);
5555254Sgavinm 
5565254Sgavinm 	if (cmi_no_mca_init != 0)
5575254Sgavinm 		return;
5585254Sgavinm 
5595254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_faulted_enter))
5605254Sgavinm 		CMI_OPS(cmi)->cmi_faulted_enter(hdl);
5615254Sgavinm }
5625254Sgavinm 
5635254Sgavinm void
5645254Sgavinm cmi_faulted_exit(cmi_hdl_t hdl)
5655254Sgavinm {
5665254Sgavinm 	cmi_t *cmi = HDL2CMI(hdl);
5675254Sgavinm 
5685254Sgavinm 	if (cmi_no_mca_init != 0)
5695254Sgavinm 		return;
5705254Sgavinm 
5715254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_faulted_exit))
5725254Sgavinm 		CMI_OPS(cmi)->cmi_faulted_exit(hdl);
5731414Scindi }
5741414Scindi 
5751414Scindi void
5765254Sgavinm cmi_mca_init(cmi_hdl_t hdl)
5771414Scindi {
5785254Sgavinm 	cmi_t *cmi;
5795254Sgavinm 
5805254Sgavinm 	if (cmi_no_mca_init != 0)
5815254Sgavinm 		return;
5825254Sgavinm 
5835254Sgavinm 	cmi = HDL2CMI(hdl);
5845254Sgavinm 
5855254Sgavinm 	if (CMI_OP_PRESENT(cmi, cmi_mca_init))
5865254Sgavinm 		CMI_OPS(cmi)->cmi_mca_init(hdl);
5871414Scindi }
5881414Scindi 
5895254Sgavinm #define	CMI_RESPONSE_PANIC		0x0	/* panic must have value 0 */
5905254Sgavinm #define	CMI_RESPONSE_NONE		0x1
5915254Sgavinm #define	CMI_RESPONSE_CKILL		0x2
5925254Sgavinm #define	CMI_RESPONSE_REBOOT		0x3	/* not implemented */
5935254Sgavinm #define	CMI_RESPONSE_ONTRAP_PROT	0x4
5945254Sgavinm #define	CMI_RESPONSE_LOFAULT_PROT	0x5
5955254Sgavinm 
5965254Sgavinm /*
5975254Sgavinm  * Return 0 if we will panic in response to this machine check, otherwise
5985254Sgavinm  * non-zero.  If the caller is cmi_mca_trap in this file then the nonzero
5995254Sgavinm  * return values are to be interpreted from CMI_RESPONSE_* above.
6005254Sgavinm  *
6015254Sgavinm  * This function must just return what will be done without actually
6025254Sgavinm  * doing anything; this includes not changing the regs.
6035254Sgavinm  */
6041414Scindi int
6055254Sgavinm cmi_mce_response(struct regs *rp, uint64_t disp)
6061414Scindi {
6075254Sgavinm 	int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC :
6085254Sgavinm 	    CMI_RESPONSE_NONE;
6095254Sgavinm 	on_trap_data_t *otp;
6105254Sgavinm 
6115254Sgavinm 	ASSERT(rp != NULL);	/* don't call for polling, only on #MC */
6125254Sgavinm 
6135254Sgavinm 	/*
6145254Sgavinm 	 * If no bits are set in the disposition then there is nothing to
6155254Sgavinm 	 * worry about and we do not need to trampoline to ontrap or
6165254Sgavinm 	 * lofault handlers.
6175254Sgavinm 	 */
6185254Sgavinm 	if (disp == 0)
6195254Sgavinm 		return (CMI_RESPONSE_NONE);
6205254Sgavinm 
6215254Sgavinm 	/*
6225254Sgavinm 	 * Unconstrained errors cannot be forgiven, even by ontrap or
6235254Sgavinm 	 * lofault protection.  The data is not poisoned and may not
6245254Sgavinm 	 * even belong to the trapped context - eg a writeback of
6255254Sgavinm 	 * data that is found to be bad.
6265254Sgavinm 	 */
6275254Sgavinm 	if (disp & CMI_ERRDISP_UC_UNCONSTRAINED)
6285254Sgavinm 		return (panicrsp);
6295254Sgavinm 
6305254Sgavinm 	/*
6315254Sgavinm 	 * ontrap OT_DATA_EC and lofault protection forgive any disposition
6325254Sgavinm 	 * other than unconstrained, even those normally forced fatal.
6335254Sgavinm 	 */
6345254Sgavinm 	if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC)
6355254Sgavinm 		return (CMI_RESPONSE_ONTRAP_PROT);
6365254Sgavinm 	else if (curthread->t_lofault)
6375254Sgavinm 		return (CMI_RESPONSE_LOFAULT_PROT);
6385254Sgavinm 
6395254Sgavinm 	/*
6405254Sgavinm 	 * Forced-fatal errors are terminal even in user mode.
6415254Sgavinm 	 */
6425254Sgavinm 	if (disp & CMI_ERRDISP_FORCEFATAL)
6435254Sgavinm 		return (panicrsp);
6445254Sgavinm 
6455254Sgavinm 	/*
6465254Sgavinm 	 * If the trapped context is corrupt or we have no instruction pointer
6475254Sgavinm 	 * to resume at (and aren't trampolining to a fault handler)
6485254Sgavinm 	 * then in the kernel case we must panic and in usermode we
6495254Sgavinm 	 * kill the affected contract.
6505254Sgavinm 	 */
6515254Sgavinm 	if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID))
6525254Sgavinm 		return (USERMODE(rp->r_cs) ?  CMI_RESPONSE_CKILL : panicrsp);
6535254Sgavinm 
6545254Sgavinm 	/*
6555254Sgavinm 	 * Anything else is harmless
6565254Sgavinm 	 */
6575254Sgavinm 	return (CMI_RESPONSE_NONE);
6581414Scindi }
6591414Scindi 
6605254Sgavinm int cma_mca_trap_panic_suppressed = 0;
6615254Sgavinm 
6625254Sgavinm static void
6635254Sgavinm cmi_mca_panic(void)
6641414Scindi {
6655254Sgavinm 	if (cmi_panic_on_uncorrectable_error) {
6665254Sgavinm 		fm_panic("Unrecoverable Machine-Check Exception");
6675254Sgavinm 	} else {
6685254Sgavinm 		cmn_err(CE_WARN, "suppressing panic from fatal #mc");
6695254Sgavinm 		cma_mca_trap_panic_suppressed++;
6705254Sgavinm 	}
6711414Scindi }
6721414Scindi 
6735254Sgavinm 
6745254Sgavinm int cma_mca_trap_contract_kills = 0;
6755254Sgavinm int cma_mca_trap_ontrap_forgiven = 0;
6765254Sgavinm int cma_mca_trap_lofault_forgiven = 0;
6775254Sgavinm 
6785254Sgavinm /*
6795254Sgavinm  * Native #MC handler - we branch to here from mcetrap
6805254Sgavinm  */
6815254Sgavinm /*ARGSUSED*/
6821414Scindi void
6831414Scindi cmi_mca_trap(struct regs *rp)
6841414Scindi {
6855254Sgavinm #ifndef	__xpv
6865254Sgavinm 	cmi_hdl_t hdl = NULL;
6875254Sgavinm 	uint64_t disp;
6885254Sgavinm 	cmi_t *cmi;
6895254Sgavinm 	int s;
6905254Sgavinm 
6915254Sgavinm 	if (cmi_no_mca_init != 0)
6925254Sgavinm 		return;
6935254Sgavinm 
6945254Sgavinm 	/*
6955254Sgavinm 	 * This function can call cmn_err, and the cpu module cmi_mca_trap
6965254Sgavinm 	 * entry point may also elect to call cmn_err (e.g., if it can't
6975254Sgavinm 	 * log the error onto an errorq, say very early in boot).
6985254Sgavinm 	 * We need to let cprintf know that we must not block.
6995254Sgavinm 	 */
7005254Sgavinm 	s = spl8();
7015254Sgavinm 
7025254Sgavinm 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
7035254Sgavinm 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
7045254Sgavinm 	    (cmi = HDL2CMI(hdl)) == NULL ||
7055254Sgavinm 	    !CMI_OP_PRESENT(cmi, cmi_mca_trap)) {
7065254Sgavinm 
7075254Sgavinm 		cmn_err(CE_WARN, "#MC exception on cpuid %d: %s",
7085254Sgavinm 		    CPU->cpu_id,
7095254Sgavinm 		    hdl ? "handle lookup ok but no #MC handler found" :
7105254Sgavinm 		    "handle lookup failed");
7115254Sgavinm 
7125254Sgavinm 		if (hdl != NULL)
7135254Sgavinm 			cmi_hdl_rele(hdl);
7145254Sgavinm 
7155254Sgavinm 		splx(s);
7165254Sgavinm 		return;
7171414Scindi 	}
7185254Sgavinm 
7195254Sgavinm 	disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp);
7201414Scindi 
7215254Sgavinm 	switch (cmi_mce_response(rp, disp)) {
7225254Sgavinm 	default:
7235254Sgavinm 		cmn_err(CE_WARN, "Invalid response from cmi_mce_response");
7245254Sgavinm 		/*FALLTHRU*/
7255254Sgavinm 
7265254Sgavinm 	case CMI_RESPONSE_PANIC:
7275254Sgavinm 		cmi_mca_panic();
7285254Sgavinm 		break;
7295254Sgavinm 
7305254Sgavinm 	case CMI_RESPONSE_NONE:
7315254Sgavinm 		break;
7325254Sgavinm 
7335254Sgavinm 	case CMI_RESPONSE_CKILL:
7345254Sgavinm 		ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR;
7355254Sgavinm 		aston(curthread);
7365254Sgavinm 		cma_mca_trap_contract_kills++;
7375254Sgavinm 		break;
7381414Scindi 
7395254Sgavinm 	case CMI_RESPONSE_ONTRAP_PROT: {
7405254Sgavinm 		on_trap_data_t *otp = curthread->t_ontrap;
7415254Sgavinm 		otp->ot_trap = OT_DATA_EC;
7425254Sgavinm 		rp->r_pc = otp->ot_trampoline;
7435254Sgavinm 		cma_mca_trap_ontrap_forgiven++;
7445254Sgavinm 		break;
7455254Sgavinm 	}
7461414Scindi 
7475254Sgavinm 	case CMI_RESPONSE_LOFAULT_PROT:
7485254Sgavinm 		rp->r_r0 = EFAULT;
7495254Sgavinm 		rp->r_pc = curthread->t_lofault;
7505254Sgavinm 		cma_mca_trap_lofault_forgiven++;
7515254Sgavinm 		break;
7525254Sgavinm 	}
7535254Sgavinm 
7545254Sgavinm 	cmi_hdl_rele(hdl);
7555254Sgavinm 	splx(s);
7565254Sgavinm #endif	/* __xpv */
7571414Scindi }
7581414Scindi 
7591414Scindi void
7605254Sgavinm cmi_hdl_poke(cmi_hdl_t hdl)
7611414Scindi {
7625254Sgavinm 	cmi_t *cmi = HDL2CMI(hdl);
7635254Sgavinm 
7645254Sgavinm 	if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke))
7655254Sgavinm 		return;
7665254Sgavinm 
7675254Sgavinm 	CMI_OPS(cmi)->cmi_hdl_poke(hdl);
7681414Scindi }
7691414Scindi 
7707532SSean.Ye@Sun.COM #ifndef	__xpv
7711414Scindi void
7727349SAdrian.Frost@Sun.COM cmi_cmci_trap()
7737349SAdrian.Frost@Sun.COM {
7747349SAdrian.Frost@Sun.COM 	cmi_hdl_t hdl = NULL;
7757349SAdrian.Frost@Sun.COM 	cmi_t *cmi;
7767349SAdrian.Frost@Sun.COM 
7777349SAdrian.Frost@Sun.COM 	if (cmi_no_mca_init != 0)
7787349SAdrian.Frost@Sun.COM 		return;
7797349SAdrian.Frost@Sun.COM 
7807349SAdrian.Frost@Sun.COM 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
7817349SAdrian.Frost@Sun.COM 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
7827349SAdrian.Frost@Sun.COM 	    (cmi = HDL2CMI(hdl)) == NULL ||
7837349SAdrian.Frost@Sun.COM 	    !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
7847349SAdrian.Frost@Sun.COM 
7857349SAdrian.Frost@Sun.COM 		cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
7867349SAdrian.Frost@Sun.COM 		    CPU->cpu_id,
7877349SAdrian.Frost@Sun.COM 		    hdl ? "handle lookup ok but no CMCI handler found" :
7887349SAdrian.Frost@Sun.COM 		    "handle lookup failed");
7897349SAdrian.Frost@Sun.COM 
7907349SAdrian.Frost@Sun.COM 		if (hdl != NULL)
7917349SAdrian.Frost@Sun.COM 			cmi_hdl_rele(hdl);
7927349SAdrian.Frost@Sun.COM 
7937349SAdrian.Frost@Sun.COM 		return;
7947349SAdrian.Frost@Sun.COM 	}
7957349SAdrian.Frost@Sun.COM 
7967349SAdrian.Frost@Sun.COM 	CMI_OPS(cmi)->cmi_cmci_trap(hdl);
7977349SAdrian.Frost@Sun.COM 
7987349SAdrian.Frost@Sun.COM 	cmi_hdl_rele(hdl);
7997532SSean.Ye@Sun.COM }
8007349SAdrian.Frost@Sun.COM #endif	/* __xpv */
8017349SAdrian.Frost@Sun.COM 
8027349SAdrian.Frost@Sun.COM void
8035254Sgavinm cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
8041414Scindi {
8055254Sgavinm 	if (!cmi_no_mca_init)
8065254Sgavinm 		cmi_hdl_setmc(hdl, mcops, mcdata);
8071414Scindi }
8081414Scindi 
8097532SSean.Ye@Sun.COM void
8107532SSean.Ye@Sun.COM cmi_mc_sw_memscrub_disable(void)
8117532SSean.Ye@Sun.COM {
8127532SSean.Ye@Sun.COM 	memscrub_disable();
8137532SSean.Ye@Sun.COM }
8147532SSean.Ye@Sun.COM 
8155254Sgavinm cmi_errno_t
8163164Sgavinm cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd,
8173164Sgavinm     int syndtype, mc_unum_t *up)
8181414Scindi {
8191414Scindi 	const struct cmi_mc_ops *mcops;
8205254Sgavinm 	cmi_hdl_t hdl;
8215254Sgavinm 	cmi_errno_t rv;
8225254Sgavinm 
8235254Sgavinm 	if (cmi_no_mca_init ||
8245254Sgavinm 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
8255254Sgavinm 		return (CMIERR_MC_ABSENT);
8261414Scindi 
8275254Sgavinm 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
8285254Sgavinm 	    mcops->cmi_mc_patounum == NULL) {
8295254Sgavinm 		cmi_hdl_rele(hdl);
8305254Sgavinm 		return (CMIERR_MC_NOTSUP);
8315254Sgavinm 	}
8321414Scindi 
8335254Sgavinm 	rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi,
8345254Sgavinm 	    valid_lo, synd, syndtype, up);
8355254Sgavinm 
8365254Sgavinm 	cmi_hdl_rele(hdl);
8375254Sgavinm 
8385254Sgavinm 	return (rv);
8391414Scindi }
8401414Scindi 
8415254Sgavinm cmi_errno_t
8421414Scindi cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
8431414Scindi {
8441414Scindi 	const struct cmi_mc_ops *mcops;
8455254Sgavinm 	cmi_hdl_t hdl;
8465254Sgavinm 	cmi_errno_t rv;
8477532SSean.Ye@Sun.COM 	nvlist_t *hcsp;
8481414Scindi 
8491414Scindi 	if (up != NULL && nvl != NULL)
8505254Sgavinm 		return (CMIERR_API);	/* convert from just one form */
8515254Sgavinm 
8525254Sgavinm 	if (cmi_no_mca_init ||
8535254Sgavinm 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
8545254Sgavinm 		return (CMIERR_MC_ABSENT);
8555254Sgavinm 
8565254Sgavinm 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
8575254Sgavinm 	    mcops->cmi_mc_unumtopa == NULL) {
8585254Sgavinm 		cmi_hdl_rele(hdl);
8595254Sgavinm 
8607532SSean.Ye@Sun.COM 		if (nvl != NULL && nvlist_lookup_nvlist(nvl,
8617532SSean.Ye@Sun.COM 		    FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
8627532SSean.Ye@Sun.COM 		    (nvlist_lookup_uint64(hcsp,
8637532SSean.Ye@Sun.COM 		    "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, pap) == 0 ||
8647532SSean.Ye@Sun.COM 		    nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
8657532SSean.Ye@Sun.COM 		    pap) == 0)) {
8665254Sgavinm 			return (CMIERR_MC_PARTIALUNUMTOPA);
8675254Sgavinm 		} else {
8685254Sgavinm 			return (mcops && mcops->cmi_mc_unumtopa ?
8695254Sgavinm 			    CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT);
8705254Sgavinm 		}
8715254Sgavinm 	}
8725254Sgavinm 
8735254Sgavinm 	rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap);
8745254Sgavinm 
8755254Sgavinm 	cmi_hdl_rele(hdl);
8765254Sgavinm 
8775254Sgavinm 	return (rv);
8785254Sgavinm }
8791414Scindi 
8805254Sgavinm void
8815254Sgavinm cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync)
8825254Sgavinm {
8835254Sgavinm 	const struct cmi_mc_ops *mcops;
8845254Sgavinm 
8855254Sgavinm 	if (cmi_no_mca_init || (mcops = cmi_hdl_getmcops(hdl)) == NULL)
8865254Sgavinm 		return;
8875254Sgavinm 
8885254Sgavinm 	if (mcops->cmi_mc_logout != NULL)
8895254Sgavinm 		mcops->cmi_mc_logout(hdl, ismc, sync);
8905254Sgavinm }
8911414Scindi 
8925254Sgavinm cmi_errno_t
8935254Sgavinm cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs,
8945254Sgavinm     int force)
8955254Sgavinm {
8965254Sgavinm 	cmi_t *cmi = cmi_hdl_getcmi(hdl);
8977532SSean.Ye@Sun.COM 	cmi_errno_t rc;
8985254Sgavinm 
8995254Sgavinm 	if (!CMI_OP_PRESENT(cmi, cmi_msrinject))
9005254Sgavinm 		return (CMIERR_NOTSUP);
9015254Sgavinm 
9027532SSean.Ye@Sun.COM 	cmi_hdl_inj_begin(hdl);
9037532SSean.Ye@Sun.COM 	rc = CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force);
9047532SSean.Ye@Sun.COM 	cmi_hdl_inj_end(hdl);
9057532SSean.Ye@Sun.COM 
9067532SSean.Ye@Sun.COM 	return (rc);
9071414Scindi }
9085254Sgavinm 
9095254Sgavinm boolean_t
9105254Sgavinm cmi_panic_on_ue(void)
9115254Sgavinm {
9125254Sgavinm 	return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE);
9135254Sgavinm }
9147532SSean.Ye@Sun.COM 
9157532SSean.Ye@Sun.COM void
9167532SSean.Ye@Sun.COM cmi_panic_callback(void)
9177532SSean.Ye@Sun.COM {
9187532SSean.Ye@Sun.COM 	cmi_hdl_t hdl;
9197532SSean.Ye@Sun.COM 	cmi_t *cmi;
9207532SSean.Ye@Sun.COM 
9217532SSean.Ye@Sun.COM 	if (cmi_no_mca_init || (hdl = cmi_hdl_any()) == NULL)
9227532SSean.Ye@Sun.COM 		return;
9237532SSean.Ye@Sun.COM 
9247532SSean.Ye@Sun.COM 	cmi = cmi_hdl_getcmi(hdl);
9257532SSean.Ye@Sun.COM 	if (CMI_OP_PRESENT(cmi, cmi_panic_callback))
9267532SSean.Ye@Sun.COM 		CMI_OPS(cmi)->cmi_panic_callback();
9277532SSean.Ye@Sun.COM 
9287532SSean.Ye@Sun.COM 	cmi_hdl_rele(hdl);
9297532SSean.Ye@Sun.COM }
930