summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorstephh <none@none>2008-08-02 03:26:27 -0700
committerstephh <none@none>2008-08-02 03:26:27 -0700
commit25c6ff4b77fcddf4097ce78a8277275ca603b46c (patch)
tree418fc0cf406815a0bf23f782b349ac0653121a77 /usr/src/lib
parent5d2225f6bb395dbd38b87e1f0af3ce4afbca42f3 (diff)
downloadillumos-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')
-rw-r--r--usr/src/lib/fm/libfmd_adm/common/fmd_adm.c68
-rw-r--r--usr/src/lib/fm/libfmd_adm/common/fmd_adm.h7
-rw-r--r--usr/src/lib/fm/libfmd_adm/common/mapfile-vers7
-rw-r--r--usr/src/lib/fm/libfmd_snmp/common/fmd_snmp.h13
-rw-r--r--usr/src/lib/fm/libfmd_snmp/common/problem.c212
-rw-r--r--usr/src/lib/fm/libfmd_snmp/common/problem.h4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/dev.c145
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c84
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/libtopo.h2
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mapfile-vers2
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_fmri.c59
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h12
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip.h2
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip_amd.c3
-rw-r--r--usr/src/lib/fm/topo/modules/i86pc/chip/chip_subr.c67
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c55
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem.c46
-rw-r--r--usr/src/lib/libdevinfo/devinfo.c2
-rw-r--r--usr/src/lib/libdevinfo/libdevinfo.h1
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