diff options
author | stephh <none@none> | 2008-08-02 03:26:27 -0700 |
---|---|---|
committer | stephh <none@none> | 2008-08-02 03:26:27 -0700 |
commit | 25c6ff4b77fcddf4097ce78a8277275ca603b46c (patch) | |
tree | 418fc0cf406815a0bf23f782b349ac0653121a77 /usr/src/lib | |
parent | 5d2225f6bb395dbd38b87e1f0af3ce4afbca42f3 (diff) | |
download | illumos-joyent-25c6ff4b77fcddf4097ce78a8277275ca603b46c.tar.gz |
PSARC/2008/487 Repair Observability changes
6534561 need means of finding existing fault state of a resource
6637804 fmd should distinguish between "repaired" and "acquitted" resources
6637812 fmd_nvl_fmri_has_fault() required to report if a given fault has been diagnosed on a resourtce/fru
6663744 send list.updated events when an individual suspect in a suspect list is repaired
6682295 need fmd_nvl_fmri_replaced() functionality
6686317 extend fmd case state to include final "repair responses complete" state
6712074 need scheme/topo interface to report full service state of a resource
6720169 add location member to the sun-fm-mib
Diffstat (limited to 'usr/src/lib')
19 files changed, 761 insertions, 30 deletions
diff --git a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c index fc4a8a33b5..8089f8d670 100644 --- a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c +++ b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.c @@ -616,7 +616,7 @@ fmd_adm_rsrc_flush(fmd_adm_t *ap, const char *fmri) } int -fmd_adm_rsrc_repair(fmd_adm_t *ap, const char *fmri) +fmd_adm_rsrc_repaired(fmd_adm_t *ap, const char *fmri) { char *str = (char *)fmri; int err; @@ -627,7 +627,50 @@ fmd_adm_rsrc_repair(fmd_adm_t *ap, const char *fmri) return (fmd_adm_set_errno(ap, EINVAL)); do { - cs = fmd_adm_rsrcrepair_1(str, &err, ap->adm_clnt); + cs = fmd_adm_rsrcrepaired_1(str, &err, ap->adm_clnt); + } while (fmd_adm_retry(ap, cs, &retries)); + + if (cs != RPC_SUCCESS) + return (fmd_adm_set_errno(ap, EPROTO)); + + return (fmd_adm_set_svcerr(ap, err)); +} + +int +fmd_adm_rsrc_replaced(fmd_adm_t *ap, const char *fmri) +{ + char *str = (char *)fmri; + int err; + enum clnt_stat cs; + uint_t retries = 0; + + if (fmri == NULL) + return (fmd_adm_set_errno(ap, EINVAL)); + + do { + cs = fmd_adm_rsrcreplaced_1(str, &err, ap->adm_clnt); + } while (fmd_adm_retry(ap, cs, &retries)); + + if (cs != RPC_SUCCESS) + return (fmd_adm_set_errno(ap, EPROTO)); + + return (fmd_adm_set_svcerr(ap, err)); +} + +int +fmd_adm_rsrc_acquit(fmd_adm_t *ap, const char *fmri, const char *uuid) +{ + char *str = (char *)fmri; + char *str2 = (char *)uuid; + int err; + enum clnt_stat cs; + uint_t retries = 0; + + if (fmri == NULL) + return (fmd_adm_set_errno(ap, EINVAL)); + + do { + cs = fmd_adm_rsrcacquit_1(str, str2, &err, ap->adm_clnt); } while (fmd_adm_retry(ap, cs, &retries)); if (cs != RPC_SUCCESS) @@ -657,6 +700,27 @@ fmd_adm_case_repair(fmd_adm_t *ap, const char *uuid) return (fmd_adm_set_svcerr(ap, err)); } +int +fmd_adm_case_acquit(fmd_adm_t *ap, const char *uuid) +{ + char *str = (char *)uuid; + int err; + enum clnt_stat cs; + uint_t retries = 0; + + if (uuid == NULL) + return (fmd_adm_set_errno(ap, EINVAL)); + + do { + cs = fmd_adm_caseacquit_1(str, &err, ap->adm_clnt); + } while (fmd_adm_retry(ap, cs, &retries)); + + if (cs != RPC_SUCCESS) + return (fmd_adm_set_errno(ap, EPROTO)); + + return (fmd_adm_set_svcerr(ap, err)); +} + static int fmd_adm_case_cmp(const void *lp, const void *rp) { diff --git a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.h b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.h index 955b7dcbc7..3dc3fce28f 100644 --- a/usr/src/lib/fm/libfmd_adm/common/fmd_adm.h +++ b/usr/src/lib/fm/libfmd_adm/common/fmd_adm.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -104,8 +104,11 @@ typedef int fmd_adm_case_f(const fmd_adm_caseinfo_t *, void *); extern int fmd_adm_rsrc_count(fmd_adm_t *, int, uint32_t *); extern int fmd_adm_rsrc_iter(fmd_adm_t *, int, fmd_adm_rsrc_f *, void *); extern int fmd_adm_rsrc_flush(fmd_adm_t *, const char *); -extern int fmd_adm_rsrc_repair(fmd_adm_t *, const char *); +extern int fmd_adm_rsrc_repaired(fmd_adm_t *, const char *); +extern int fmd_adm_rsrc_replaced(fmd_adm_t *, const char *); +extern int fmd_adm_rsrc_acquit(fmd_adm_t *, const char *, const char *); extern int fmd_adm_case_repair(fmd_adm_t *, const char *); +extern int fmd_adm_case_acquit(fmd_adm_t *, const char *); extern int fmd_adm_case_iter(fmd_adm_t *, const char *, fmd_adm_case_f *, void *); diff --git a/usr/src/lib/fm/libfmd_adm/common/mapfile-vers b/usr/src/lib/fm/libfmd_adm/common/mapfile-vers index 1760838562..1e736ad74e 100644 --- a/usr/src/lib/fm/libfmd_adm/common/mapfile-vers +++ b/usr/src/lib/fm/libfmd_adm/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -29,6 +29,7 @@ SUNWprivate { global: fmd_adm_case_iter; fmd_adm_case_repair; + fmd_adm_case_acquit; fmd_adm_close; fmd_adm_errmsg; fmd_adm_log_rotate; @@ -42,7 +43,9 @@ SUNWprivate { fmd_adm_rsrc_count; fmd_adm_rsrc_flush; fmd_adm_rsrc_iter; - fmd_adm_rsrc_repair; + fmd_adm_rsrc_repaired; + fmd_adm_rsrc_replaced; + fmd_adm_rsrc_acquit; fmd_adm_serd_iter; fmd_adm_serd_reset; fmd_adm_stats_free; diff --git a/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h b/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h index 049ed6e3c6..5b15f664f3 100644 --- a/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h +++ b/usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -63,9 +63,18 @@ extern "C" { #define SUNFMFAULTEVENT_COL_ASRU 6 #define SUNFMFAULTEVENT_COL_FRU 7 #define SUNFMFAULTEVENT_COL_RESOURCE 8 +#define SUNFMFAULTEVENT_COL_STATUS 9 +#define SUNFMFAULTEVENT_COL_LOCATION 10 #define SUNFMFAULTEVENT_COLMIN SUNFMFAULTEVENT_COL_PROBLEMUUID -#define SUNFMFAULTEVENT_COLMAX SUNFMFAULTEVENT_COL_RESOURCE +#define SUNFMFAULTEVENT_COLMAX SUNFMFAULTEVENT_COL_LOCATION + +#define SUNFMFAULTEVENT_STATE_OTHER 1 +#define SUNFMFAULTEVENT_STATE_FAULTY 2 +#define SUNFMFAULTEVENT_STATE_REMOVED 3 +#define SUNFMFAULTEVENT_STATE_REPLACED 4 +#define SUNFMFAULTEVENT_STATE_REPAIRED 5 +#define SUNFMFAULTEVENT_STATE_ACQUITTED 6 #define SUNFMMODULETABLE_OID SUNFM_OID, 3 diff --git a/usr/src/lib/fm/libfmd_snmp/common/problem.c b/usr/src/lib/fm/libfmd_snmp/common/problem.c index 4a495c5a0a..3410118da9 100644 --- a/usr/src/lib/fm/libfmd_snmp/common/problem.c +++ b/usr/src/lib/fm/libfmd_snmp/common/problem.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -127,6 +127,18 @@ faultevent_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) return (data->d_suspects[index - 1]); } +static sunFmFaultStatus_data_t +faultstatus_lookup_index_exact(sunFmProblem_data_t *data, ulong_t index) +{ + if (index > data->d_nsuspects) + return (NULL); + + if (data->d_statuses == NULL) + return (NULL); + + return (data->d_statuses[index - 1]); +} + /*ARGSUSED*/ static int problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg) @@ -188,6 +200,11 @@ problem_update_one(const fmd_adm_caseinfo_t *acp, void *arg) ASSERT(nelem == data->d_nsuspects); + (void) nvlist_lookup_uint8_array(data->d_aci_event, + FM_SUSPECT_FAULT_STATUS, &data->d_statuses, &nelem); + + ASSERT(nelem == data->d_nsuspects); + uu_avl_node_init(data, &data->d_uuid_avl, problem_uuid_avl_pool); (void) uu_avl_find(problem_uuid_avl, data, NULL, &idx); @@ -636,6 +653,96 @@ sunFmFaultEventTable_nextfe(netsnmp_handler_registration *reginfo, } } +/* + * Returns the ASN.1 lexicographically first fault event after the one + * identified by table_info. Indexes are updated to reflect the OID + * of the data returned. This allows us to implement GETNEXT. + */ +static sunFmFaultStatus_data_t +sunFmFaultStatusTable_nextfe(netsnmp_handler_registration *reginfo, + netsnmp_table_request_info *table_info) +{ + sunFmProblem_data_t *data; + sunFmFaultStatus_data_t rv; + netsnmp_variable_list *var; + ulong_t index; + + for (;;) { + switch (table_info->number_indexes) { + case 2: + default: + DEBUGMSGTL((MODNAME_STR, "nextfe: 2 indices:\n")); + DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); + DEBUGMSG((MODNAME_STR, "\n")); + DEBUGMSGVAR((MODNAME_STR, + table_info->indexes->next_variable)); + DEBUGMSG((MODNAME_STR, "\n")); + index = *(ulong_t *) + table_info->indexes->next_variable->val.integer + 1; + + if ((data = sunFmProblemTable_pr(reginfo, + table_info)) != NULL && + (rv = faultstatus_lookup_index_exact(data, + index)) != NULL) { + snmp_set_var_typed_value( + table_info->indexes->next_variable, + ASN_UNSIGNED, (uchar_t *)&index, + sizeof (index)); + return (rv); + } + + if (sunFmProblemTable_nextpr(reginfo, table_info) == + NULL) + return (NULL); + break; + case 1: + if ((data = sunFmProblemTable_pr(reginfo, + table_info)) != NULL) { + oid tmpoid[MAX_OID_LEN]; + index = 0; + + DEBUGMSGTL((MODNAME_STR, "nextfe: 1 index:\n")); + DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); + DEBUGMSG((MODNAME_STR, "\n")); + var = + SNMP_MALLOC_TYPEDEF(netsnmp_variable_list); + snmp_set_var_typed_value(var, ASN_UNSIGNED, + (uchar_t *)&index, sizeof (index)); + (void) memcpy(tmpoid, reginfo->rootoid, + reginfo->rootoid_len * sizeof (oid)); + tmpoid[reginfo->rootoid_len] = 1; + tmpoid[reginfo->rootoid_len + 1] = + table_info->colnum; + if (build_oid_segment(var) != SNMPERR_SUCCESS) { + snmp_free_varbind(var); + return (NULL); + } + snmp_free_varbind( + table_info->indexes->next_variable); + table_info->indexes->next_variable = var; + table_info->number_indexes = 2; + DEBUGMSGTL((MODNAME_STR, "nextfe: built fake " + "index:\n")); + DEBUGMSGVAR((MODNAME_STR, table_info->indexes)); + DEBUGMSG((MODNAME_STR, "\n")); + DEBUGMSGVAR((MODNAME_STR, + table_info->indexes->next_variable)); + DEBUGMSG((MODNAME_STR, "\n")); + } else { + if (sunFmProblemTable_nextpr(reginfo, + table_info) == NULL) + return (NULL); + } + break; + case 0: + if (sunFmProblemTable_nextpr(reginfo, table_info) == + NULL) + return (NULL); + break; + } + } +} + static sunFmFaultEvent_data_t * sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo, netsnmp_table_request_info *table_info) @@ -651,6 +758,21 @@ sunFmFaultEventTable_fe(netsnmp_handler_registration *reginfo, *(ulong_t *)table_info->indexes->next_variable->val.integer)); } +static sunFmFaultStatus_data_t +sunFmFaultStatusTable_fe(netsnmp_handler_registration *reginfo, + netsnmp_table_request_info *table_info) +{ + sunFmProblem_data_t *data; + + ASSERT(table_info->number_indexes == 2); + + if ((data = sunFmProblemTable_pr(reginfo, table_info)) == NULL) + return (NULL); + + return (faultstatus_lookup_index_exact(data, + *(ulong_t *)table_info->indexes->next_variable->val.integer)); +} + /*ARGSUSED*/ static void sunFmProblemTable_return(unsigned int reg, void *arg) @@ -828,6 +950,7 @@ sunFmFaultEventTable_return(unsigned int reg, void *arg) netsnmp_table_request_info *table_info; sunFmProblem_data_t *pdata; sunFmFaultEvent_data_t *data; + sunFmFaultStatus_data_t status; ASSERT(netsnmp_handler_check_cache(cache) != NULL); @@ -869,30 +992,58 @@ sunFmFaultEventTable_return(unsigned int reg, void *arg) * for GETNEXT requests. */ - switch (reqinfo->mode) { - case MODE_GET: - if ((data = sunFmFaultEventTable_fe(reginfo, table_info)) == - NULL) { + if (table_info->colnum == SUNFMFAULTEVENT_COL_STATUS) { + switch (reqinfo->mode) { + case MODE_GET: + if ((status = sunFmFaultStatusTable_fe(reginfo, + table_info)) == NULL) { + netsnmp_free_delegated_cache(cache); + (void) pthread_mutex_unlock(&update_lock); + return; + } + break; + case MODE_GETNEXT: + case MODE_GETBULK: + if ((status = sunFmFaultStatusTable_nextfe(reginfo, + table_info)) == NULL) { + netsnmp_free_delegated_cache(cache); + (void) pthread_mutex_unlock(&update_lock); + return; + } + break; + default: + snmp_log(LOG_ERR, MODNAME_STR + ": Unsupported request mode %d\n", reqinfo->mode); netsnmp_free_delegated_cache(cache); (void) pthread_mutex_unlock(&update_lock); return; } - break; - case MODE_GETNEXT: - case MODE_GETBULK: - if ((data = sunFmFaultEventTable_nextfe(reginfo, table_info)) == - NULL) { + } else { + switch (reqinfo->mode) { + case MODE_GET: + if ((data = sunFmFaultEventTable_fe(reginfo, + table_info)) == NULL) { + netsnmp_free_delegated_cache(cache); + (void) pthread_mutex_unlock(&update_lock); + return; + } + break; + case MODE_GETNEXT: + case MODE_GETBULK: + if ((data = sunFmFaultEventTable_nextfe(reginfo, + table_info)) == NULL) { + netsnmp_free_delegated_cache(cache); + (void) pthread_mutex_unlock(&update_lock); + return; + } + break; + default: + snmp_log(LOG_ERR, MODNAME_STR + ": Unsupported request mode %d\n", reqinfo->mode); netsnmp_free_delegated_cache(cache); (void) pthread_mutex_unlock(&update_lock); return; } - break; - default: - snmp_log(LOG_ERR, MODNAME_STR ": Unsupported request mode %d\n", - reqinfo->mode); - netsnmp_free_delegated_cache(cache); - (void) pthread_mutex_unlock(&update_lock); - return; } switch (table_info->colnum) { @@ -978,6 +1129,33 @@ sunFmFaultEventTable_return(unsigned int reg, void *arg) free(str); break; } + case SUNFMFAULTEVENT_COL_STATUS: + { + ulong_t pl; + + if (status & FM_SUSPECT_FAULTY) + pl = SUNFMFAULTEVENT_STATE_FAULTY; + else if (status & FM_SUSPECT_NOT_PRESENT) + pl = SUNFMFAULTEVENT_STATE_REMOVED; + else if (status & FM_SUSPECT_REPLACED) + pl = SUNFMFAULTEVENT_STATE_REPLACED; + else if (status & FM_SUSPECT_REPAIRED) + pl = SUNFMFAULTEVENT_STATE_REPAIRED; + else if (status & FM_SUSPECT_ACQUITTED) + pl = SUNFMFAULTEVENT_STATE_ACQUITTED; + netsnmp_table_build_result(reginfo, request, table_info, + ASN_UNSIGNED, (uchar_t *)&pl, sizeof (pl)); + break; + } + case SUNFMFAULTEVENT_COL_LOCATION: + { + char *location = "-"; + + (void) nvlist_lookup_string(data, FM_FAULT_LOCATION, &location); + netsnmp_table_build_result(reginfo, request, table_info, + ASN_OCTET_STR, (uchar_t *)location, strlen(location)); + break; + } default: break; } diff --git a/usr/src/lib/fm/libfmd_snmp/common/problem.h b/usr/src/lib/fm/libfmd_snmp/common/problem.h index fb935e9ed5..d7e280c28a 100644 --- a/usr/src/lib/fm/libfmd_snmp/common/problem.h +++ b/usr/src/lib/fm/libfmd_snmp/common/problem.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,6 +48,7 @@ typedef struct sunFmProblem_data { ulong_t d_nsuspects; nvlist_t **d_suspects; nvlist_t *d_aci_event; + uint8_t *d_statuses; } sunFmProblem_data_t; typedef struct sunFmProblem_update_ctx { @@ -59,6 +60,7 @@ typedef struct sunFmProblem_update_ctx { } sunFmProblem_update_ctx_t; typedef nvlist_t sunFmFaultEvent_data_t; +typedef uint8_t sunFmFaultStatus_data_t; int sunFmProblemTable_init(void); int sunFmFaultEventTable_init(void); diff --git a/usr/src/lib/fm/topo/libtopo/common/dev.c b/usr/src/lib/fm/topo/libtopo/common/dev.c index c671fa5c94..0865b194c0 100644 --- a/usr/src/lib/fm/topo/libtopo/common/dev.c +++ b/usr/src/lib/fm/topo/libtopo/common/dev.c @@ -36,6 +36,7 @@ #include <sys/stat.h> #include <libnvpair.h> #include <fm/topo_mod.h> +#include <fm/fmd_fmri.h> #include <sys/fm/protocol.h> #include <topo_method.h> @@ -53,8 +54,12 @@ static int dev_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int dev_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int dev_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); static int dev_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int dev_fmri_service_state(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); static const topo_method_t dev_methods[] = { { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, @@ -65,9 +70,15 @@ static const topo_method_t dev_methods[] = { TOPO_STABILITY_INTERNAL, dev_fmri_create_meth }, { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, dev_fmri_present }, + { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, + TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, + dev_fmri_replaced }, { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, dev_fmri_unusable }, + { TOPO_METH_SERVICE_STATE, TOPO_METH_SERVICE_STATE_DESC, + TOPO_METH_SERVICE_STATE_VERSION, TOPO_STABILITY_INTERNAL, + dev_fmri_service_state }, { NULL } }; @@ -335,7 +346,7 @@ dev_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, * If the device is present and there is a devid, it must also match. * so di_init that one node. No need for DINFOFORCE. */ - len = strlen(devpath) + strlen("/devices") + 1; + len = strlen(devpath) + strlen("/devices") + 1; path = topo_mod_alloc(mod, len); (void) snprintf(path, len, "/devices%s", devpath); if (devid == NULL) { @@ -383,6 +394,86 @@ dev_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, /*ARGSUSED*/ static int +dev_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + uint8_t fmversion; + char *devpath = NULL; + uint32_t rval; + char *devid = NULL, *path; + ddi_devid_t id; + ddi_devid_t matchid; + di_node_t dnode; + struct stat sb; + int len; + + if (version > TOPO_METH_REPLACED_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || + fmversion > FM_DEV_SCHEME_VERSION || + nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + (void) nvlist_lookup_string(in, FM_FMRI_DEV_ID, &devid); + + if (devpath == NULL || strlen(devpath) == 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + /* + * stat() the device node in devfs. This will tell us if the device is + * present or not. Don't stat the minor, just the whole device. + * If the device is present and there is a devid, it must also match. + * so di_init that one node. No need for DINFOFORCE. + */ + len = strlen(devpath) + strlen("/devices") + 1; + path = topo_mod_alloc(mod, len); + (void) snprintf(path, len, "/devices%s", devpath); + if (devid == NULL) { + if (stat(path, &sb) != -1) + rval = FMD_OBJ_STATE_UNKNOWN; + else if ((dnode = di_init("/", DINFOCACHE)) == DI_NODE_NIL) + rval = FMD_OBJ_STATE_NOT_PRESENT; + else { + if (di_lookup_node(dnode, devpath) == DI_NODE_NIL) + rval = FMD_OBJ_STATE_NOT_PRESENT; + else + rval = FMD_OBJ_STATE_UNKNOWN; + di_fini(dnode); + } + } else { + if (stat(path, &sb) == -1) + rval = FMD_OBJ_STATE_NOT_PRESENT; + else if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) + rval = FMD_OBJ_STATE_NOT_PRESENT; + else { + if ((id = di_devid(dnode)) == NULL || + devid_str_decode(devid, &matchid, NULL) != 0) + rval = FMD_OBJ_STATE_UNKNOWN; + else { + if (devid_compare(id, matchid) != 0) + rval = FMD_OBJ_STATE_REPLACED; + else + rval = FMD_OBJ_STATE_STILL_PRESENT; + devid_free(matchid); + } + di_fini(dnode); + } + } + topo_mod_free(mod, path, len); + + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, rval) != 0) { + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + return (0); +} + +/*ARGSUSED*/ +static int dev_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, nvlist_t *in, nvlist_t **out) { @@ -392,7 +483,7 @@ dev_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, uint32_t unusable; uint_t state; - if (version > TOPO_METH_PRESENT_VERSION) + if (version > TOPO_METH_UNUSABLE_VERSION) return (topo_mod_seterrno(mod, EMOD_VER_NEW)); if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || @@ -428,6 +519,56 @@ dev_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version, return (0); } +/*ARGSUSED*/ +static int +dev_fmri_service_state(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + di_node_t dnode; + uint8_t fmversion; + char *devpath = NULL; + uint32_t service_state; + uint_t state; + + if (version > TOPO_METH_SERVICE_STATE_VERSION) + return (topo_mod_seterrno(mod, EMOD_VER_NEW)); + + if (nvlist_lookup_uint8(in, FM_VERSION, &fmversion) != 0 || + fmversion > FM_DEV_SCHEME_VERSION || + nvlist_lookup_string(in, FM_FMRI_DEV_PATH, &devpath) != 0) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + if (devpath == NULL) + return (topo_mod_seterrno(mod, EMOD_FMRI_MALFORM)); + + if ((dnode = di_init(devpath, DINFOCPYONE)) == DI_NODE_NIL) { + if (errno != ENXIO) + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + service_state = FMD_SERVICE_STATE_UNUSABLE; + } else { + uint_t retired = di_retired(dnode); + state = di_state(dnode); + if (retired || (state & (DI_DEVICE_OFFLINE | DI_DEVICE_DOWN | + DI_BUS_QUIESCED | DI_BUS_DOWN))) + service_state = FMD_SERVICE_STATE_UNUSABLE; + else if (state & DI_DEVICE_DEGRADED) + service_state = FMD_SERVICE_STATE_DEGRADED; + else + service_state = FMD_SERVICE_STATE_OK; + di_fini(dnode); + } + + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + if (nvlist_add_uint32(*out, TOPO_METH_SERVICE_STATE_RET, + service_state) != 0) { + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + return (0); +} + static nvlist_t * dev_fmri_create(topo_mod_t *mp, const char *id, const char *path) { diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c index bb19967c21..8b9c8f08a8 100644 --- a/usr/src/lib/fm/topo/libtopo/common/hc.c +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c @@ -36,6 +36,7 @@ #include <limits.h> #include <fm/topo_mod.h> #include <fm/topo_hc.h> +#include <fm/fmd_fmri.h> #include <sys/param.h> #include <sys/systeminfo.h> #include <sys/fm/protocol.h> @@ -61,6 +62,8 @@ static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int hc_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t, @@ -87,6 +90,9 @@ const topo_method_t hc_methods[] = { TOPO_STABILITY_INTERNAL, hc_compare }, { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, hc_fmri_present }, + { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, + TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, + hc_fmri_replaced }, { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL, hc_fmri_unusable }, @@ -1716,6 +1722,84 @@ hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version, } static int +hc_is_replaced(topo_mod_t *mod, tnode_t *node, void *pdata) +{ + int err; + struct hc_args *hap = (struct hc_args *)pdata; + uint32_t present = 0; + + /* + * check with the enumerator that created this FMRI + * (topo node) + */ + if (topo_method_invoke(node, TOPO_METH_REPLACED, + TOPO_METH_REPLACED_VERSION, hap->ha_fmri, &hap->ha_nvl, + &err) < 0) { + /* + * enumerator didn't provide "replaced" method - so + * try "present" method + */ + if (topo_method_invoke(node, TOPO_METH_PRESENT, + TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl, + &err) < 0) { + /* no present method either - assume present */ + present = 1; + } else { + (void) nvlist_lookup_uint32(hap->ha_nvl, + TOPO_METH_PRESENT_RET, &present); + (void) nvlist_remove(hap->ha_nvl, + TOPO_METH_PRESENT_RET, DATA_TYPE_UINT32); + } + if (topo_mod_nvalloc(mod, &hap->ha_nvl, + NV_UNIQUE_NAME) == 0) + if (nvlist_add_uint32(hap->ha_nvl, + TOPO_METH_REPLACED_RET, + FMD_OBJ_STATE_UNKNOWN) == 0) + return (0); + return (ETOPO_PROP_NVL); + } + + return (0); +} + +static int +hc_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + int err; + struct hc_walk *hwp; + struct hc_args *hap; + + if (version > TOPO_METH_REPLACED_VERSION) + return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW)); + + if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL) + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + + hap->ha_fmri = in; + hap->ha_nvl = NULL; + if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_replaced, + (void *)hap)) != NULL) { + if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) == + TOPO_WALK_ERR) + err = -1; + else + err = 0; + topo_walk_fini(hwp->hcw_wp); + topo_mod_free(mod, hwp, sizeof (struct hc_walk)); + } else { + err = -1; + } + + if (hap->ha_nvl != NULL) + *out = hap->ha_nvl; + + topo_mod_free(mod, hap, sizeof (struct hc_args)); + + return (err); +} + +static int hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata) { int err; diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h index 5164508eaa..4d905b194a 100644 --- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h +++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h @@ -90,9 +90,11 @@ extern void topo_walk_fini(topo_walk_t *); * FMRI helper routines */ extern int topo_fmri_present(topo_hdl_t *, nvlist_t *, int *); +extern int topo_fmri_replaced(topo_hdl_t *, nvlist_t *, int *); extern int topo_fmri_contains(topo_hdl_t *, nvlist_t *, nvlist_t *, int *); extern int topo_fmri_expand(topo_hdl_t *, nvlist_t *, int *); extern int topo_fmri_unusable(topo_hdl_t *, nvlist_t *, int *); +extern int topo_fmri_service_state(topo_hdl_t *, nvlist_t *, int *); extern int topo_fmri_nvl2str(topo_hdl_t *, nvlist_t *, char **, int *); extern int topo_fmri_str2nvl(topo_hdl_t *, const char *, nvlist_t **, int *); extern int topo_fmri_asru(topo_hdl_t *, nvlist_t *, nvlist_t **, int *); diff --git a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers index 95ac3e2bcd..c24261fd3b 100644 --- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers +++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers @@ -41,7 +41,9 @@ SUNWprivate { topo_fmri_label; topo_fmri_nvl2str; topo_fmri_present; + topo_fmri_replaced; topo_fmri_serial; + topo_fmri_service_state; topo_fmri_setprop; topo_fmri_str2nvl; topo_fmri_strcmp; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c index da82e8bc57..c91d01c4b5 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c +++ b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c @@ -30,6 +30,7 @@ #include <string.h> #include <limits.h> #include <fm/topo_mod.h> +#include <fm/fmd_fmri.h> #include <sys/fm/protocol.h> #include <topo_alloc.h> #include <topo_error.h> @@ -50,8 +51,10 @@ * * - expand * - present + * - replaced * - contains * - unusable + * - service_state * - nvl2str * * In addition, the following operations are supported per-FMRI: @@ -199,6 +202,34 @@ topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err) } int +topo_fmri_replaced(topo_hdl_t *thp, nvlist_t *fmri, int *err) +{ + uint32_t replaced = FMD_OBJ_STATE_NOT_PRESENT; + char *scheme; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_REPLACED, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_REPLACED, out)); + + if (topo_method_invoke(rnode, TOPO_METH_REPLACED, + TOPO_METH_REPLACED_VERSION, fmri, &out, err) < 0) { + (void) set_error(thp, *err, err, TOPO_METH_REPLACED, out); + return (FMD_OBJ_STATE_UNKNOWN); + } + + (void) nvlist_lookup_uint32(out, TOPO_METH_REPLACED_RET, &replaced); + nvlist_free(out); + + return (replaced); +} + +int topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err) { uint32_t contains; @@ -267,6 +298,34 @@ topo_fmri_unusable(topo_hdl_t *thp, nvlist_t *fmri, int *err) } int +topo_fmri_service_state(topo_hdl_t *thp, nvlist_t *fmri, int *err) +{ + char *scheme; + uint32_t service_state = FMD_SERVICE_STATE_UNKNOWN; + nvlist_t *out = NULL; + tnode_t *rnode; + + if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0) + return (set_error(thp, ETOPO_FMRI_MALFORM, err, + TOPO_METH_SERVICE_STATE, out)); + + if ((rnode = topo_hdl_root(thp, scheme)) == NULL) + return (set_error(thp, ETOPO_METHOD_NOTSUP, err, + TOPO_METH_SERVICE_STATE, out)); + + if (topo_method_invoke(rnode, TOPO_METH_SERVICE_STATE, + TOPO_METH_SERVICE_STATE_VERSION, fmri, &out, err) < 0) + return (set_error(thp, *err, err, TOPO_METH_SERVICE_STATE, + out)); + + (void) nvlist_lookup_uint32(out, TOPO_METH_SERVICE_STATE_RET, + &service_state); + nvlist_free(out); + + return (service_state); +} + +int topo_fmri_expand(topo_hdl_t *thp, nvlist_t *fmri, int *err) { char *scheme; diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h index 4c404ca450..398b704287 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h @@ -137,12 +137,24 @@ extern nvlist_t *topo_mod_auth(topo_mod_t *, tnode_t *); #define TOPO_METH_PRESENT_VERSION TOPO_METH_PRESENT_VERSION0 #define TOPO_METH_PRESENT_RET "present-ret" +#define TOPO_METH_REPLACED "topo_replaced" +#define TOPO_METH_REPLACED_DESC "replaced indicator" +#define TOPO_METH_REPLACED_VERSION0 0 +#define TOPO_METH_REPLACED_VERSION TOPO_METH_REPLACED_VERSION0 +#define TOPO_METH_REPLACED_RET "replaced-ret" + #define TOPO_METH_UNUSABLE "topo_unusable" #define TOPO_METH_UNUSABLE_DESC "unusable indicator" #define TOPO_METH_UNUSABLE_VERSION0 0 #define TOPO_METH_UNUSABLE_VERSION TOPO_METH_UNUSABLE_VERSION0 #define TOPO_METH_UNUSABLE_RET "unusable-ret" +#define TOPO_METH_SERVICE_STATE "topo_service_state" +#define TOPO_METH_SERVICE_STATE_DESC "service_state indicator" +#define TOPO_METH_SERVICE_STATE_VERSION0 0 +#define TOPO_METH_SERVICE_STATE_VERSION TOPO_METH_SERVICE_STATE_VERSION0 +#define TOPO_METH_SERVICE_STATE_RET "service_state-ret" + #define TOPO_METH_EXPAND "topo_expand" #define TOPO_METH_EXPAND_DESC "expand FMRI" #define TOPO_METH_EXPAND_VERSION0 0 diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h index caedcb2519..637b90ac4b 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h @@ -138,6 +138,8 @@ extern int mem_asru_compute(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); extern int rank_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +extern int rank_fmri_replaced(topo_mod_t *, tnode_t *, topo_version_t, + nvlist_t *, nvlist_t **); extern int mem_asru_create(topo_mod_t *, nvlist_t *, nvlist_t **); /* diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c index 69a8804082..937a9cd97d 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c @@ -81,6 +81,9 @@ static const topo_method_t rank_methods[] = { { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, rank_fmri_present }, + { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, + TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, + rank_fmri_replaced }, { NULL } }; diff --git a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c index 04ea6be512..2de05e94da 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c +++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c @@ -33,6 +33,7 @@ #include <sys/types.h> #include <stdarg.h> #include <strings.h> +#include <fm/fmd_fmri.h> #include <sys/fm/protocol.h> #include "chip.h" @@ -454,3 +455,69 @@ done: return (0); } + +/* + * If we're getting called then the question of whether this dimm is plugged + * in has already been answered. What we don't know for sure is whether it's + * the same dimm or a different one plugged in the same slot. To check, we + * try and compare the serial numbers on the dimm in the current topology with + * the serial num from the unum fmri that got passed into this function as the + * argument. + * + * In the event we encounter problems comparing serials or if a comparison isn't + * possible, we err on the side of caution and set is_present to TRUE. + */ +/* ARGSUSED */ +int +rank_fmri_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t version, + nvlist_t *in, nvlist_t **out) +{ + tnode_t *dimmnode; + int err, rval = FMD_OBJ_STATE_UNKNOWN; + nvlist_t *unum; + char *curr_serial, *old_serial = NULL; + + /* + * If a serial number for the dimm was available at the time of the + * fault, it will have been added as a string to the unum nvlist + */ + unum = in; + if (nvlist_lookup_string(unum, FM_FMRI_HC_SERIAL_ID, &old_serial) != 0) + goto done; + + /* + * If the current serial number is available for the DIMM that this rank + * belongs to, it will be accessible as a property on the parent (dimm) + * node. + */ + dimmnode = topo_node_parent(node); + if (topo_prop_get_string(dimmnode, TOPO_PGROUP_PROTOCOL, + FM_FMRI_HC_SERIAL_ID, &curr_serial, &err) != 0) { + if (err != ETOPO_PROP_NOENT) { + whinge(mod, &err, "rank_fmri_present: Unexpected error " + "retrieving serial from node"); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } else + goto done; + } + + if (strcmp(old_serial, curr_serial) != 0) + rval = FMD_OBJ_STATE_REPLACED; + else + rval = FMD_OBJ_STATE_STILL_PRESENT; + + topo_mod_strfree(mod, curr_serial); +done: + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) { + whinge(mod, &err, + "rank_fmri_present: failed to allocate nvlist!"); + return (topo_mod_seterrno(mod, EMOD_NOMEM)); + } + + if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, rval) != 0) { + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + return (0); +} diff --git a/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c b/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c index bda8d6e787..5f028e1841 100644 --- a/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c +++ b/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c @@ -29,6 +29,7 @@ #include <strings.h> #include <umem.h> #include <fm/topo_mod.h> +#include <fm/fmd_fmri.h> #include <sys/fm/ldom.h> #include <sys/fm/protocol.h> @@ -37,7 +38,7 @@ /* * This enumerator creates cpu-schemed nodes for each strand found in the * sun4v Physical Rource Inventory (PRI). - * Each node export three methods present(), expand() and unusable(). + * Each node export four methods present(), expand() replaced() and unusable(). * */ @@ -52,6 +53,8 @@ static int cpu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, static void cpu_release(topo_mod_t *, tnode_t *); static int cpu_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int cpu_replaced(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); static int cpu_expand(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int cpu_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, @@ -66,6 +69,8 @@ static const topo_modinfo_t cpu_info = static const topo_method_t cpu_methods[] = { { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, cpu_present }, + { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, + TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, cpu_replaced }, { TOPO_METH_EXPAND, TOPO_METH_EXPAND_DESC, TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL, cpu_expand }, { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, @@ -182,6 +187,54 @@ cpu_present(topo_mod_t *mod, tnode_t *node, topo_version_t vers, /*ARGSUSED*/ static int +cpu_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t vers, + nvlist_t *in, nvlist_t **out) +{ + uint8_t version; + uint32_t cpuid; + uint64_t nvlserid; + uint32_t rval = FMD_OBJ_STATE_NOT_PRESENT; + md_cpumap_t *mcmp; + md_info_t *chip = (md_info_t *)topo_mod_getspecific(mod); + + /* + * Get the physical cpuid + */ + if (nvlist_lookup_uint8(in, FM_VERSION, &version) != 0 || + version > FM_CPU_SCHEME_VERSION || + nvlist_lookup_uint32(in, FM_FMRI_CPU_ID, &cpuid) != 0) { + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + /* + * Find the cpuid entry + * If the input nvl contains a serial number, the cpu is identified + * by a tuple <cpuid, cpuserial> + * Otherwise, the cpu is identified by the <cpuid>. + */ + if ((mcmp = cpu_find_cpumap(chip, cpuid)) != NULL) { + if (nvlist_lookup_uint64(in, FM_FMRI_CPU_SERIAL_ID, &nvlserid) + == 0) + rval = (nvlserid == mcmp->cpumap_serialno) ? + FMD_OBJ_STATE_STILL_PRESENT : + FMD_OBJ_STATE_REPLACED; + else + rval = FMD_OBJ_STATE_UNKNOWN; + } + + /* return the replaced status */ + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, rval) != 0) { + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + return (0); +} + +/*ARGSUSED*/ +static int cpu_expand(topo_mod_t *mod, tnode_t *node, topo_version_t vers, nvlist_t *in, nvlist_t **out) { diff --git a/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem.c b/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem.c index 805ec3ab03..600e21873b 100644 --- a/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem.c +++ b/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem.c @@ -29,6 +29,7 @@ #include <strings.h> #include <umem.h> #include <fm/topo_mod.h> +#include <fm/fmd_fmri.h> #include <sys/fm/protocol.h> #include <sys/mem.h> @@ -37,7 +38,7 @@ /* * This enumerator creates mem-schemed nodes for each dimm found in the * sun4v Physical Resource Inventory (PRI). - * Each node exports four methods: present(), expand(), unusable(), + * Each node exports five methods: present(), expand(), unusable(), replaced(), * and contains(). * */ @@ -53,6 +54,8 @@ static int mem_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, static void mem_release(topo_mod_t *, tnode_t *); static int mem_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); +static int mem_replaced(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, + nvlist_t **); static int mem_expand(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, nvlist_t **); static int mem_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, @@ -69,6 +72,8 @@ static const topo_modinfo_t mem_info = static const topo_method_t mem_methods[] = { { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION, TOPO_STABILITY_INTERNAL, mem_present }, + { TOPO_METH_REPLACED, TOPO_METH_REPLACED_DESC, + TOPO_METH_REPLACED_VERSION, TOPO_STABILITY_INTERNAL, mem_replaced }, { TOPO_METH_EXPAND, TOPO_METH_EXPAND_DESC, TOPO_METH_EXPAND_VERSION, TOPO_STABILITY_INTERNAL, mem_expand }, { TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC, @@ -166,6 +171,45 @@ mem_present(topo_mod_t *mod, tnode_t *node, topo_version_t vers, return (0); } +/*ARGSUSED*/ +static int +mem_replaced(topo_mod_t *mod, tnode_t *node, topo_version_t vers, + nvlist_t *in, nvlist_t **out) +{ + uint8_t version; + char **nvlserids; + size_t n, nserids; + uint32_t rval = FMD_OBJ_STATE_NOT_PRESENT; + md_mem_info_t *mem = (md_mem_info_t *)topo_mod_getspecific(mod); + + /* sun4v platforms all support dimm serial numbers */ + + if (nvlist_lookup_uint8(in, FM_VERSION, &version) != 0 || + version > FM_MEM_SCHEME_VERSION || + nvlist_lookup_string_array(in, FM_FMRI_MEM_SERIAL_ID, + &nvlserids, &nserids) != 0) { + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + /* Find the dimm entry */ + for (n = 0; n < nserids; n++) { + if (mem_get_dimm_by_sn(nvlserids[n], mem) != NULL) { + rval = FMD_OBJ_STATE_STILL_PRESENT; + break; + } + } + + /* return the replaced status */ + if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + if (nvlist_add_uint32(*out, TOPO_METH_REPLACED_RET, rval) != 0) { + nvlist_free(*out); + return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); + } + + return (0); +} + void mem_strarray_free(topo_mod_t *mod, char **arr, size_t dim) { diff --git a/usr/src/lib/libdevinfo/devinfo.c b/usr/src/lib/libdevinfo/devinfo.c index 582aad2156..db6a62cab1 100644 --- a/usr/src/lib/libdevinfo/devinfo.c +++ b/usr/src/lib/libdevinfo/devinfo.c @@ -978,6 +978,8 @@ di_state(di_node_t node) result |= DI_DEVICE_OFFLINE; if (DI_NODE(node)->state & DEVI_DEVICE_DOWN) result |= DI_DEVICE_OFFLINE; + if (DI_NODE(node)->state & DEVI_DEVICE_DEGRADED) + result |= DI_DEVICE_DEGRADED; if (DI_NODE(node)->state & DEVI_BUS_QUIESCED) result |= DI_BUS_QUIESCED; if (DI_NODE(node)->state & DEVI_BUS_DOWN) diff --git a/usr/src/lib/libdevinfo/libdevinfo.h b/usr/src/lib/libdevinfo/libdevinfo.h index ca745b3b31..0bea41674c 100644 --- a/usr/src/lib/libdevinfo/libdevinfo.h +++ b/usr/src/lib/libdevinfo/libdevinfo.h @@ -82,6 +82,7 @@ extern "C" { #define DI_DRIVER_DETACHED 0x8000 #define DI_DEVICE_OFFLINE 0x1 #define DI_DEVICE_DOWN 0x2 +#define DI_DEVICE_DEGRADED 0x4 #define DI_BUS_QUIESCED 0x100 #define DI_BUS_DOWN 0x200 |