/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #ifdef sun4v #include static fmd_hdl_t *init_hdl; ldom_hdl_t *cma_lhp; #endif #ifdef i386 boolean_t cma_is_native; #endif extern const char *fmd_fmri_get_platform(); cma_t cma; cma_stats_t cma_stats = { { "cpu_flts", FMD_TYPE_UINT64, "cpu faults resolved" }, { "cpu_repairs", FMD_TYPE_UINT64, "cpu faults repaired" }, { "cpu_fails", FMD_TYPE_UINT64, "cpu faults unresolveable" }, { "cpu_blfails", FMD_TYPE_UINT64, "failed cpu blacklists" }, { "cpu_supp", FMD_TYPE_UINT64, "cpu offlines suppressed" }, { "cpu_blsupp", FMD_TYPE_UINT64, "cpu blacklists suppressed" }, { "page_flts", FMD_TYPE_UINT64, "page faults resolved" }, { "page_repairs", FMD_TYPE_UINT64, "page faults repaired" }, { "page_fails", FMD_TYPE_UINT64, "page faults unresolveable" }, { "page_supp", FMD_TYPE_UINT64, "page retires suppressed" }, { "page_nonent", FMD_TYPE_UINT64, "retires for non-existent fmris" }, { "bad_flts", FMD_TYPE_UINT64, "invalid fault events received" }, { "nop_flts", FMD_TYPE_UINT64, "inapplicable fault events received" }, { "auto_flts", FMD_TYPE_UINT64, "auto-close faults received" } }; typedef struct cma_subscriber { const char *subr_class; const char *subr_sname; uint_t subr_svers; int (*subr_func)(fmd_hdl_t *, nvlist_t *, nvlist_t *, const char *, boolean_t); } cma_subscriber_t; static const cma_subscriber_t cma_subrs[] = { #if defined(i386) /* * On x86, the ASRUs are expected to be in hc scheme. When * cpumem-retire wants to retire a cpu or mem page, it calls the * methods registered in the topo node to do that. The topo * enumerator, which necessarily knows all the config info that * we'd ever need in deciding what/how to retire etc. This takes * away much of that complexity from the agent into the entity * that knows all config/topo information. */ { "fault.memory.page", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_sb", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_ck", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.generic-x86.page_ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.generic-x86.page_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.intel.page_ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.intel.page_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.memory.dimm", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm_sb", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ck", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.generic-x86.dimm_ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.generic-x86.dimm_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.intel.dimm_ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.intel.dimm_ue", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.intel.fbd.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm_testfail", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.bank", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.quickpath.mem_scrubbing", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_page_retire }, { "fault.cpu.intel.quickpath.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.mc", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.dma", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.dma", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, /* * The ASRU for cpu faults are in cpu scheme on native and in hc * scheme on xpv. So each cpu fault class needs to be listed twice. */ /* * The following faults do NOT retire a cpu thread, * and therefore must be intercepted before * the default "fault.cpu.*" dispatch to cma_cpu_hc_retire. */ { "fault.cpu.amd.dramchannel", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.amd.dramchannel", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect_memory", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect_memory", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect_io", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect_io", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.generic-x86.bus_interconnect", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect_memory", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect_memory", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect_io", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect_io", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.bus_interconnect", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.intel.nb.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.nb.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.intel.dma", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.intel.dma", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.cpu.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cpu_hc_retire }, #elif defined(sun4v) /* * The following are PI sun4v faults */ { "fault.memory.memlink", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.memlink-uc", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.memlink-failover", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm-ue-imminent", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dram-ue-imminent", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.dimm-page-retires-excessive", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-page-retires-excessive", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dram-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.link-c", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.link-u", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.link-f", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.link-c", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.link-u", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.link-f", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, /* * The following ultraSPARC-T1/T2 faults do NOT retire a cpu thread, * and therefore must be intercepted before * the default "fault.cpu.*" dispatch to cma_cpu_hc_retire. */ { "fault.cpu.*.l2cachedata", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.l2cachetag", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.l2cachectl", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.l2data-c", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.l2data-u", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.mau", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.lfu-u", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.lfu-f", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.*.lfu-p", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T1.freg", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T1.l2cachedata", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T1.l2cachetag", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T1.l2cachectl", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T1.mau", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, { "fault.cpu.ultraSPARC-T2plus.chip", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.cpu.*", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.cpu.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cpu_hc_retire }, #elif defined(opl) { "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-page-retires-excessive", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dram-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.cpu.SPARC64-VI.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cpu_cpu_retire }, { "fault.cpu.SPARC64-VII.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cpu_cpu_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.se", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.se-offlinereq", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VI.core.ce-offlinereq", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.se", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.se-offlinereq", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.ce", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, { "fault.chassis.SPARC-Enterprise.cpu.SPARC64-VII.core.ce-offlinereq", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, cma_cpu_hc_retire }, #else /* * For platforms excluding i386, sun4v and opl. */ { "fault.memory.page", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.page_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, cma_page_retire }, { "fault.memory.dimm", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_sb", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ck", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_ue", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-page-retires-excessive", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dram-ue-imminent", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.dimm_testfail", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.bank", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_MEM, FM_MEM_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_HC, FM_HC_SCHEME_VERSION, NULL }, { "fault.memory.datapath", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, NULL }, /* * The following faults do NOT retire a cpu thread, * and therefore must be intercepted before * the default "fault.cpu.*" dispatch to cma_cpu_cpu_retire. */ { "fault.cpu.ultraSPARC-IVplus.l2cachedata-line", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cache_way_retire }, { "fault.cpu.ultraSPARC-IVplus.l3cachedata-line", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cache_way_retire }, { "fault.cpu.ultraSPARC-IVplus.l2cachetag-line", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cache_way_retire }, { "fault.cpu.ultraSPARC-IVplus.l3cachetag-line", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cache_way_retire }, /* * Default "fault.cpu.*" for "cpu" scheme ASRU dispatch. */ { "fault.cpu.*", FM_FMRI_SCHEME_CPU, FM_CPU_SCHEME_VERSION, cma_cpu_cpu_retire }, #endif { NULL, NULL, 0, NULL } }; static const cma_subscriber_t * nvl2subr(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t **asrup) { const cma_subscriber_t *sp; nvlist_t *asru; char *scheme; uint8_t version; boolean_t retire; if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_RETIRE, &retire) == 0 && retire == 0) { fmd_hdl_debug(hdl, "cma_recv: retire suppressed"); return (NULL); } if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru) != 0 || nvlist_lookup_string(asru, FM_FMRI_SCHEME, &scheme) != 0 || nvlist_lookup_uint8(asru, FM_VERSION, &version) != 0) { cma_stats.bad_flts.fmds_value.ui64++; return (NULL); } for (sp = cma_subrs; sp->subr_class != NULL; sp++) { if (fmd_nvl_class_match(hdl, nvl, sp->subr_class) && strcmp(scheme, sp->subr_sname) == 0 && version <= sp->subr_svers) { *asrup = asru; return (sp); } } cma_stats.nop_flts.fmds_value.ui64++; return (NULL); } static void cma_recv_list(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class) { char *uuid = NULL; nvlist_t **nva, **save_nva; uint_t nvc = 0, save_nvc; uint_t keepopen; int err = 0; nvlist_t *asru = NULL; uint32_t index; err |= nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid); err |= nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nva, &nvc); if (err != 0) { cma_stats.bad_flts.fmds_value.ui64++; return; } save_nvc = keepopen = nvc; save_nva = nva; while (nvc-- != 0 && (strcmp(class, FM_LIST_SUSPECT_CLASS) != 0 || !fmd_case_uuclosed(hdl, uuid))) { nvlist_t *nvl = *nva++; const cma_subscriber_t *subr; int has_fault; if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL) continue; /* * A handler returns CMA_RA_SUCCESS to indicate that * from this suspects point-of-view the case may be * closed, CMA_RA_FAILURE otherwise. * A handler must not close the case itself. */ if (subr->subr_func != NULL) { has_fault = fmd_nvl_fmri_has_fault(hdl, asru, FMD_HAS_FAULT_ASRU, NULL); if (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0) { if (has_fault == 1) err = subr->subr_func(hdl, nvl, asru, uuid, 0); } else { if (has_fault == 0) err = subr->subr_func(hdl, nvl, asru, uuid, 1); } if (err == CMA_RA_SUCCESS) keepopen--; } } /* * Run though again to catch any new faults in list.updated. */ while (save_nvc-- != 0 && (strcmp(class, FM_LIST_UPDATED_CLASS) == 0)) { nvlist_t *nvl = *save_nva++; const cma_subscriber_t *subr; int has_fault; if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL) continue; if (subr->subr_func != NULL) { has_fault = fmd_nvl_fmri_has_fault(hdl, asru, FMD_HAS_FAULT_ASRU, NULL); if (has_fault == 1) err = subr->subr_func(hdl, nvl, asru, uuid, 0); } } /* * Do not close the case if we are handling cache faults. */ if (asru != NULL) { if (nvlist_lookup_uint32(asru, FM_FMRI_CPU_CACHE_INDEX, &index) != 0) { if (!keepopen && strcmp(class, FM_LIST_SUSPECT_CLASS) == 0) { fmd_case_uuclose(hdl, uuid); } } } if (!keepopen && strcmp(class, FM_LIST_REPAIRED_CLASS) == 0) fmd_case_uuresolved(hdl, uuid); } static void cma_recv_one(fmd_hdl_t *hdl, nvlist_t *nvl) { const cma_subscriber_t *subr; nvlist_t *asru; if ((subr = nvl2subr(hdl, nvl, &asru)) == NULL) return; if (subr->subr_func != NULL) { if (fmd_nvl_fmri_has_fault(hdl, asru, FMD_HAS_FAULT_ASRU, NULL) == 1) (void) subr->subr_func(hdl, nvl, asru, NULL, 0); } } /*ARGSUSED*/ static void cma_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class) { fmd_hdl_debug(hdl, "received %s\n", class); if (strcmp(class, FM_LIST_RESOLVED_CLASS) == 0) return; if (strcmp(class, FM_LIST_SUSPECT_CLASS) == 0 || strcmp(class, FM_LIST_REPAIRED_CLASS) == 0 || strcmp(class, FM_LIST_UPDATED_CLASS) == 0) cma_recv_list(hdl, nvl, class); else cma_recv_one(hdl, nvl); } /*ARGSUSED*/ static void cma_timeout(fmd_hdl_t *hdl, id_t id, void *arg) { if (id == cma.cma_page_timerid) cma_page_retry(hdl); #ifdef sun4v /* * cpu offline/online needs to be retried on sun4v because * ldom request can be asynchronous. */ else if (id == cma.cma_cpu_timerid) cma_cpu_retry(hdl); #endif } #ifdef sun4v static void * cma_init_alloc(size_t size) { return (fmd_hdl_alloc(init_hdl, size, FMD_SLEEP)); } static void cma_init_free(void *addr, size_t size) { fmd_hdl_free(init_hdl, addr, size); } #endif static const fmd_hdl_ops_t fmd_ops = { cma_recv, /* fmdo_recv */ cma_timeout, /* fmdo_timeout */ NULL, /* fmdo_close */ NULL, /* fmdo_stats */ NULL, /* fmdo_gc */ }; static const fmd_prop_t fmd_props[] = { { "cpu_tries", FMD_TYPE_UINT32, "10" }, { "cpu_delay", FMD_TYPE_TIME, "1sec" }, #ifdef sun4v { "cpu_ret_mindelay", FMD_TYPE_TIME, "5sec" }, { "cpu_ret_maxdelay", FMD_TYPE_TIME, "5min" }, #endif /* sun4v */ { "cpu_offline_enable", FMD_TYPE_BOOL, "true" }, { "cpu_online_enable", FMD_TYPE_BOOL, "true" }, { "cpu_forced_offline", FMD_TYPE_BOOL, "true" }, #ifdef opl { "cpu_blacklist_enable", FMD_TYPE_BOOL, "false" }, { "cpu_unblacklist_enable", FMD_TYPE_BOOL, "false" }, #else { "cpu_blacklist_enable", FMD_TYPE_BOOL, "true" }, { "cpu_unblacklist_enable", FMD_TYPE_BOOL, "true" }, #endif /* opl */ { "page_ret_mindelay", FMD_TYPE_TIME, "1sec" }, { "page_ret_maxdelay", FMD_TYPE_TIME, "5min" }, { "page_retire_enable", FMD_TYPE_BOOL, "true" }, { "page_unretire_enable", FMD_TYPE_BOOL, "true" }, { NULL, 0, NULL } }; static const fmd_hdl_info_t fmd_info = { "CPU/Memory Retire Agent", CMA_VERSION, &fmd_ops, fmd_props }; void _fmd_init(fmd_hdl_t *hdl) { hrtime_t nsec; #ifdef i386 char buf[BUFSIZ]; const char *dom0 = "control_d"; /* * Abort the cpumem-retire module if Solaris is running under DomU. */ if (sysinfo(SI_PLATFORM, buf, sizeof (buf)) == -1) return; if (strncmp(buf, "i86pc", sizeof (buf)) == 0) { cma_is_native = B_TRUE; } else if (strncmp(buf, "i86xpv", sizeof (buf)) != 0) { return; } else { int fd = open("/dev/xen/domcaps", O_RDONLY); if (fd != -1) { if (read(fd, buf, sizeof (buf)) <= 0 || strncmp(buf, dom0, strlen(dom0)) != 0) { (void) close(fd); return; } (void) close(fd); } cma_is_native = B_FALSE; } #endif /* i386 */ if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) return; /* invalid data in configuration file */ fmd_hdl_subscribe(hdl, "fault.cpu.*"); fmd_hdl_subscribe(hdl, "fault.memory.*"); #ifdef opl fmd_hdl_subscribe(hdl, "fault.chassis.SPARC-Enterprise.cpu.*"); #endif (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, sizeof (cma_stats) / sizeof (fmd_stat_t), (fmd_stat_t *)&cma_stats); cma.cma_cpu_tries = fmd_prop_get_int32(hdl, "cpu_tries"); nsec = fmd_prop_get_int64(hdl, "cpu_delay"); cma.cma_cpu_delay.tv_sec = nsec / NANOSEC; cma.cma_cpu_delay.tv_nsec = nsec % NANOSEC; cma.cma_page_mindelay = fmd_prop_get_int64(hdl, "page_ret_mindelay"); cma.cma_page_maxdelay = fmd_prop_get_int64(hdl, "page_ret_maxdelay"); #ifdef sun4v cma.cma_cpu_mindelay = fmd_prop_get_int64(hdl, "cpu_ret_mindelay"); cma.cma_cpu_maxdelay = fmd_prop_get_int64(hdl, "cpu_ret_maxdelay"); #endif cma.cma_cpu_dooffline = fmd_prop_get_int32(hdl, "cpu_offline_enable"); cma.cma_cpu_forcedoffline = fmd_prop_get_int32(hdl, "cpu_forced_offline"); cma.cma_cpu_doonline = fmd_prop_get_int32(hdl, "cpu_online_enable"); cma.cma_cpu_doblacklist = fmd_prop_get_int32(hdl, "cpu_blacklist_enable"); cma.cma_cpu_dounblacklist = fmd_prop_get_int32(hdl, "cpu_unblacklist_enable"); cma.cma_page_doretire = fmd_prop_get_int32(hdl, "page_retire_enable"); cma.cma_page_dounretire = fmd_prop_get_int32(hdl, "page_unretire_enable"); if (cma.cma_page_maxdelay < cma.cma_page_mindelay) fmd_hdl_abort(hdl, "page retirement delays conflict\n"); #ifdef sun4v init_hdl = hdl; cma_lhp = ldom_init(cma_init_alloc, cma_init_free); #endif } void _fmd_fini(fmd_hdl_t *hdl) { #ifdef sun4v ldom_fini(cma_lhp); cma_cpu_fini(hdl); #endif cma_page_fini(hdl); }