summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd.c4
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.c39
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.h2
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_api.map2
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_xprt.c41
-rw-r--r--usr/src/cmd/fm/fmd/common/fmd_xprt.h10
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/Makefile13
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm.c2198
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.c681
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.h108
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_filter.c366
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_filter.h69
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_impl.h3
-rw-r--r--usr/src/cmd/fm/modules/sun4v/etm/etm_iosvc.h155
-rw-r--r--usr/src/lib/fm/libldom/Makefile16
-rw-r--r--usr/src/lib/fm/libldom/Makefile.com7
-rw-r--r--usr/src/lib/fm/libldom/sparc/Makefile19
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c117
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.h34
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom.c342
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom.h57
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom_alloc.c38
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom_alloc.h43
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c790
-rw-r--r--usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.h114
-rw-r--r--usr/src/lib/fm/libldom/sparc/mapfile-vers9
-rw-r--r--usr/src/lib/fm/libldom/sparcv9/Makefile6
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard.c17
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_hostbridge.c31
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_topo.h7
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_mdesc.c12
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c17
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu.c6
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c14
-rw-r--r--usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c11
35 files changed, 5022 insertions, 376 deletions
diff --git a/usr/src/cmd/fm/fmd/common/fmd.c b/usr/src/cmd/fm/fmd/common/fmd.c
index 96b3d7d933..903ad1d9b5 100644
--- a/usr/src/cmd/fm/fmd/common/fmd.c
+++ b/usr/src/cmd/fm/fmd/common/fmd.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/param.h>
@@ -241,7 +239,7 @@ static const fmd_conf_formal_t _fmd_conf[] = {
{ "client.error", &fmd_cerror_ops, "unload" }, /* client error policy */
{ "client.memlim", &fmd_conf_size, "10m" }, /* client allocation limit */
{ "client.evqlim", &fmd_conf_uint32, "256" }, /* client event queue limit */
-{ "client.thrlim", &fmd_conf_uint32, "8" }, /* client aux thread limit */
+{ "client.thrlim", &fmd_conf_uint32, "20" }, /* client aux thread limit */
{ "client.thrsig", &fmd_conf_signal, "SIGUSR1" }, /* fmd_thr_signal() value */
{ "client.tmrlim", &fmd_conf_uint32, "1024" }, /* client pending timer limit */
{ "client.xprtlim", &fmd_conf_uint32, "256" }, /* client transport limit */
diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.c b/usr/src/cmd/fm/fmd/common/fmd_api.c
index 1a2ab860ec..dfea6c9a02 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_api.c
+++ b/usr/src/cmd/fm/fmd/common/fmd_api.c
@@ -1731,6 +1731,23 @@ fmd_thr_signal(fmd_hdl_t *hdl, pthread_t tid)
fmd_module_unlock(mp);
}
+void
+fmd_thr_checkpoint(fmd_hdl_t *hdl)
+{
+ fmd_module_t *mp = fmd_api_module_lock(hdl);
+ pthread_t tid = pthread_self();
+
+ if (tid == mp->mod_thread->thr_tid ||
+ fmd_idspace_getspecific(mp->mod_threads, tid) == NULL) {
+ fmd_api_error(mp, EFMD_THR_INVAL, "tid %u is not a valid "
+ "auxiliary thread id for module %s\n", tid, mp->mod_name);
+ }
+
+ fmd_ckpt_save(mp);
+
+ fmd_module_unlock(mp);
+}
+
id_t
fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
{
@@ -2257,7 +2274,27 @@ fmd_xprt_post(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
"fmd_xprt_post() cannot be called from _fmd_init()\n");
}
- fmd_xprt_recv(xp, nvl, hrt);
+ fmd_xprt_recv(xp, nvl, hrt, FMD_B_FALSE);
+}
+
+void
+fmd_xprt_log(fmd_hdl_t *hdl, fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
+{
+ fmd_xprt_impl_t *xip = fmd_api_transport_impl(hdl, xp);
+
+ /*
+ * fmd_xprt_recv() must block during startup waiting for fmd to globally
+ * clear FMD_XPRT_DSUSPENDED. As such, we can't allow it to be called
+ * from a module's _fmd_init() routine, because that would block
+ * fmd from completing initial module loading, resulting in a deadlock.
+ */
+ if ((xip->xi_flags & FMD_XPRT_ISUSPENDED) &&
+ (pthread_self() == xip->xi_queue->eq_mod->mod_thread->thr_tid)) {
+ fmd_api_error(fmd_api_module_lock(hdl), EFMD_XPRT_INVAL,
+ "fmd_xprt_log() cannot be called from _fmd_init()\n");
+ }
+
+ fmd_xprt_recv(xp, nvl, hrt, FMD_B_TRUE);
}
void
diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.h b/usr/src/cmd/fm/fmd/common/fmd_api.h
index 897405a24a..2dd2c7e3a6 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_api.h
+++ b/usr/src/cmd/fm/fmd/common/fmd_api.h
@@ -213,6 +213,7 @@ extern int fmd_serd_empty(fmd_hdl_t *, const char *);
extern pthread_t fmd_thr_create(fmd_hdl_t *, void (*)(void *), void *);
extern void fmd_thr_destroy(fmd_hdl_t *, pthread_t);
extern void fmd_thr_signal(fmd_hdl_t *, pthread_t);
+extern void fmd_thr_checkpoint(fmd_hdl_t *);
extern id_t fmd_timer_install(fmd_hdl_t *, void *, fmd_event_t *, hrtime_t);
extern void fmd_timer_remove(fmd_hdl_t *, id_t);
@@ -252,6 +253,7 @@ extern uint64_t fmd_event_ena_create(fmd_hdl_t *);
extern fmd_xprt_t *fmd_xprt_open(fmd_hdl_t *, uint_t, nvlist_t *, void *);
extern void fmd_xprt_close(fmd_hdl_t *, fmd_xprt_t *);
extern void fmd_xprt_post(fmd_hdl_t *, fmd_xprt_t *, nvlist_t *, hrtime_t);
+extern void fmd_xprt_log(fmd_hdl_t *, fmd_xprt_t *, nvlist_t *, hrtime_t);
extern void fmd_xprt_suspend(fmd_hdl_t *, fmd_xprt_t *);
extern void fmd_xprt_resume(fmd_hdl_t *, fmd_xprt_t *);
extern int fmd_xprt_error(fmd_hdl_t *, fmd_xprt_t *);
diff --git a/usr/src/cmd/fm/fmd/common/fmd_api.map b/usr/src/cmd/fm/fmd/common/fmd_api.map
index 2c1eac554e..268c26dbb0 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_api.map
+++ b/usr/src/cmd/fm/fmd/common/fmd_api.map
@@ -109,6 +109,7 @@
fmd_thr_create = FUNCTION extern;
fmd_thr_destroy = FUNCTION extern;
fmd_thr_signal = FUNCTION extern;
+ fmd_thr_checkpoint = FUNCTION extern;
fmd_timer_install = FUNCTION extern;
fmd_timer_remove = FUNCTION extern;
@@ -116,6 +117,7 @@
fmd_xprt_close = FUNCTION extern;
fmd_xprt_error = FUNCTION extern;
fmd_xprt_getspecific = FUNCTION extern;
+ fmd_xprt_log = FUNCTION extern;
fmd_xprt_open = FUNCTION extern;
fmd_xprt_post = FUNCTION extern;
fmd_xprt_resume = FUNCTION extern;
diff --git a/usr/src/cmd/fm/fmd/common/fmd_xprt.c b/usr/src/cmd/fm/fmd/common/fmd_xprt.c
index ff58021f29..18e25f7efe 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_xprt.c
+++ b/usr/src/cmd/fm/fmd/common/fmd_xprt.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* FMD Transport Subsystem
*
@@ -999,7 +997,7 @@ fmd_xprt_send(fmd_xprt_t *xp)
}
void
-fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
+fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt, boolean_t logonly)
{
fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp;
const fmd_xprt_rule_t *xrp;
@@ -1007,7 +1005,7 @@ fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
fmd_event_t *e;
char *class, *uuid, *code;
- int isproto;
+ boolean_t isproto, isereport;
uint64_t *tod;
uint8_t ttl;
@@ -1051,7 +1049,27 @@ fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
goto done;
}
- fmd_dprintf(FMD_DBG_XPRT, "xprt %u posting %s\n", xip->xi_id, class);
+ fmd_dprintf(FMD_DBG_XPRT, "xprt %u %s %s\n", xip->xi_id,
+ ((logonly == FMD_B_TRUE) ? "logging" : "posting"), class);
+
+ isereport = (strncmp(class, FM_EREPORT_CLASS,
+ sizeof (FM_EREPORT_CLASS - 1)) == 0) ? FMD_B_TRUE : FMD_B_FALSE;
+
+ /*
+ * The logonly flag should only be set for ereports.
+ */
+ if ((logonly == FMD_B_TRUE) && (isereport == FMD_B_FALSE)) {
+ fmd_error(EFMD_XPRT_INVAL, "discarding nvlist %p: "
+ "logonly flag is not valid for class %s",
+ (void *)nvl, class);
+
+ (void) pthread_mutex_lock(&xip->xi_stats_lock);
+ xip->xi_stats->xs_discarded.fmds_value.ui64++;
+ (void) pthread_mutex_unlock(&xip->xi_stats_lock);
+
+ nvlist_free(nvl);
+ goto done;
+ }
/*
* If a time-to-live value is present in the event and is zero, drop
@@ -1088,7 +1106,9 @@ fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
* control event. If a FMD_EVN_TOD member is found, create a protocol
* event using this time. Otherwise create a protocol event using hrt.
*/
- if ((isproto = strncmp(class, FMD_CTL_CLASS, FMD_CTL_CLASS_LEN)) == 0)
+ isproto = (strncmp(class, FMD_CTL_CLASS, FMD_CTL_CLASS_LEN) == 0) ?
+ FMD_B_FALSE : FMD_B_TRUE;
+ if (isproto == FMD_B_FALSE)
e = fmd_event_create(FMD_EVT_CTL, hrt, nvl, fmd_ctl_init(nvl));
else if (nvlist_lookup_uint64_array(nvl, FMD_EVN_TOD, &tod, &n) != 0)
e = fmd_event_create(FMD_EVT_PROTOCOL, hrt, nvl, class);
@@ -1135,7 +1155,7 @@ fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
* Record the event in the errlog if it is an ereport. This code will
* be replaced later with a per-transport intent log instead.
*/
- if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_EREPORT_CLASS ".*")) {
+ if (isereport == FMD_B_TRUE) {
(void) pthread_rwlock_rdlock(&dp->d_log_lock);
fmd_log_append(dp->d_errlog, e, NULL);
(void) pthread_rwlock_unlock(&dp->d_log_lock);
@@ -1156,7 +1176,10 @@ fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt)
fmd_module_unlock(xip->xi_queue->eq_mod);
}
- if (isproto)
+ if (logonly == FMD_B_TRUE) {
+ fmd_event_hold(e);
+ fmd_event_rele(e);
+ } else if (isproto == FMD_B_TRUE)
fmd_dispq_dispatch(dp->d_disp, e, class);
else
fmd_modhash_dispatch(dp->d_mod_hash, e);
diff --git a/usr/src/cmd/fm/fmd/common/fmd_xprt.h b/usr/src/cmd/fm/fmd/common/fmd_xprt.h
index 777e61daab..41054fdc35 100644
--- a/usr/src/cmd/fm/fmd/common/fmd_xprt.h
+++ b/usr/src/cmd/fm/fmd/common/fmd_xprt.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -21,14 +20,13 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _FMD_XPRT_H
#define _FMD_XPRT_H
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <pthread.h>
#include <libnvpair.h>
@@ -138,7 +136,7 @@ extern void fmd_xprt_destroy(fmd_xprt_t *);
extern void fmd_xprt_xsuspend(fmd_xprt_t *, uint_t);
extern void fmd_xprt_xresume(fmd_xprt_t *, uint_t);
extern void fmd_xprt_send(fmd_xprt_t *);
-extern void fmd_xprt_recv(fmd_xprt_t *, nvlist_t *, hrtime_t);
+extern void fmd_xprt_recv(fmd_xprt_t *, nvlist_t *, hrtime_t, boolean_t);
extern void fmd_xprt_uuclose(fmd_xprt_t *, const char *);
extern void fmd_xprt_subscribe(fmd_xprt_t *, const char *);
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/Makefile b/usr/src/cmd/fm/modules/sun4v/etm/Makefile
index 35a58794ce..d4d21abf5e 100644
--- a/usr/src/cmd/fm/modules/sun4v/etm/Makefile
+++ b/usr/src/cmd/fm/modules/sun4v/etm/Makefile
@@ -19,19 +19,22 @@
# 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"
MODULE = etm
CLASS = arch
ARCH = sun4v
-SRCS = etm.c etm_xport_api_dd.c
+SRCS = etm.c etm_xport_api_dd.c etm_filter.c etm_ckpt.c
include ../../Makefile.plugin
-CPPFLAGS += -I$(SRC)/uts/sun4v -I$(ROOT)/usr/platform/sun4v/include
-LDLIBS += -L$(ROOT)/usr/lib/fm -lldom
+CPPFLAGS += -I$(SRC)/uts/sun4v \
+ -I$(SRC)/uts/common \
+ -I$(ROOT)/usr/platform/sun4v/include
+LDLIBS += -L$(ROOT)/usr/lib/fm -lldom -ltopo
LDFLAGS += -R/usr/lib/fm
+
+DYNFLAGS += -R/usr/lib
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm.c b/usr/src/cmd/fm/modules/sun4v/etm/etm.c
index 6362b09225..95458b3adf 100644
--- a/usr/src/cmd/fm/modules/sun4v/etm/etm.c
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm.c
@@ -31,8 +31,6 @@
* plugin for sending/receiving FMA events to/from service processor
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* --------------------------------- includes --------------------------------
*/
@@ -42,12 +40,16 @@
#include <sys/fm/ldom.h>
#include <sys/strlog.h>
#include <sys/syslog.h>
+#include <sys/libds.h>
#include <netinet/in.h>
#include <fm/fmd_api.h>
#include "etm_xport_api.h"
#include "etm_etm_proto.h"
#include "etm_impl.h"
+#include "etm_iosvc.h"
+#include "etm_filter.h"
+#include "etm_ckpt.h"
#include <pthread.h>
#include <signal.h>
@@ -60,6 +62,8 @@
#include <values.h>
#include <alloca.h>
#include <errno.h>
+#include <dlfcn.h>
+#include <link.h>
#include <fcntl.h>
#include <time.h>
@@ -70,34 +74,44 @@
static void
etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class);
+static int
+etm_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *event, nvlist_t *nvl);
+
+static void
+etm_send_to_remote_root(void *arg);
+
+static void
+etm_recv_from_remote_root(void *arg);
+
/*
* ------------------------- data structs for FMD ----------------------------
*/
-static const fmd_hdl_ops_t fmd_ops = {
+static fmd_hdl_ops_t fmd_ops = {
etm_recv, /* fmdo_recv */
NULL, /* fmdo_timeout */
NULL, /* fmdo_close */
NULL, /* fmdo_stats */
NULL, /* fmdo_gc */
- NULL, /* fmdo_send */
+ etm_send, /* fmdo_send */
};
static const fmd_prop_t fmd_props[] = {
- { ETM_PROP_NM_XPORT_ADDRS, FMD_TYPE_STRING, "" },
- { ETM_PROP_NM_DEBUG_LVL, FMD_TYPE_INT32, "0" },
- { ETM_PROP_NM_DEBUG_MAX_EV_CNT, FMD_TYPE_INT32, "-1" },
- { ETM_PROP_NM_CONSOLE, FMD_TYPE_BOOL, "false" },
- { ETM_PROP_NM_SYSLOGD, FMD_TYPE_BOOL, "true" },
- { ETM_PROP_NM_FACILITY, FMD_TYPE_STRING, "LOG_DAEMON" },
- { ETM_PROP_NM_MAX_RESP_Q_LEN, FMD_TYPE_UINT32, "512" },
- { ETM_PROP_NM_BAD_ACC_TO_SEC, FMD_TYPE_UINT32, "1" },
+ { ETM_PROP_NM_XPORT_ADDRS, FMD_TYPE_STRING, "" },
+ { ETM_PROP_NM_DEBUG_LVL, FMD_TYPE_INT32, "0" },
+ { ETM_PROP_NM_DEBUG_MAX_EV_CNT, FMD_TYPE_INT32, "-1" },
+ { ETM_PROP_NM_CONSOLE, FMD_TYPE_BOOL, "false" },
+ { ETM_PROP_NM_SYSLOGD, FMD_TYPE_BOOL, "true" },
+ { ETM_PROP_NM_FACILITY, FMD_TYPE_STRING, "LOG_DAEMON" },
+ { ETM_PROP_NM_MAX_RESP_Q_LEN, FMD_TYPE_UINT32, "512" },
+ { ETM_PROP_NM_BAD_ACC_TO_SEC, FMD_TYPE_UINT32, "1" },
+ { ETM_PROP_NM_FMA_RESP_WAIT_TIME, FMD_TYPE_INT32, "240" },
{ NULL, 0, NULL }
};
static const fmd_hdl_info_t fmd_info = {
- "FMA Event Transport Module", "1.1", &fmd_ops, fmd_props
+ "FMA Event Transport Module", "1.2", &fmd_ops, fmd_props
};
/*
@@ -108,6 +122,9 @@ static const fmd_hdl_info_t fmd_info = {
#define ETM_MISC_BUF_SZ (4 * 1024)
+static uint32_t
+etm_ldom_type = LDOM_TYPE_LEGACY;
+
/* try limit for IO operations w/ capped exp backoff sleep on retry */
/*
@@ -129,7 +146,7 @@ static const fmd_hdl_info_t fmd_info = {
/* amount to increment protocol transaction id on each new send */
-#define ETM_XID_INC (2)
+#define ETM_XID_INC (2)
typedef struct etm_resp_q_ele {
@@ -147,7 +164,7 @@ typedef struct etm_resp_q_ele {
*/
static fmd_hdl_t
-*init_hdl = NULL; /* used in mem allocator at init time */
+*init_hdl = NULL; /* used in mem allocator and several other places */
static int
etm_debug_lvl = 0; /* debug level: 0 is off, 1 is on, 2 is more, etc */
@@ -198,7 +215,8 @@ static uint32_t
etm_xid_ver_negot = 0; /* xid of last CONTROL msg sent requesting ver negot */
static uint32_t
-etm_xid_posted_ev = 0; /* xid of last FMA_EVENT msg/event posted OK to FMD */
+etm_xid_posted_logged_ev = 0;
+ /* xid of last FMA_EVENT msg/event posted OK to FMD */
static uint32_t
etm_xid_posted_sa = 0; /* xid of last ALERT msg/event posted OK to syslog */
@@ -206,6 +224,9 @@ etm_xid_posted_sa = 0; /* xid of last ALERT msg/event posted OK to syslog */
static uint8_t
etm_resp_ver = ETM_PROTO_V1; /* proto ver [negotiated] for msg sends */
+static uint32_t
+etm_fma_resp_wait_time = 30; /* time (sec) wait for fma event resp */
+
static pthread_mutex_t
etm_write_lock = PTHREAD_MUTEX_INITIALIZER; /* for write operations */
@@ -324,7 +345,6 @@ static struct stats {
/* FMD entry point bad arguments */
- fmd_stat_t etm_fmd_recv_badargs;
fmd_stat_t etm_fmd_init_badargs;
fmd_stat_t etm_fmd_fini_badargs;
@@ -486,12 +506,10 @@ static struct stats {
/* FMD entry point bad arguments */
- { "etm_fmd_recv_badargs", FMD_TYPE_UINT64,
- "bad arguments from fmd_recv entry point" },
{ "etm_fmd_init_badargs", FMD_TYPE_UINT64,
- "bad arguments from fmd_init entry point" },
+ "bad arguments from fmd_init entry point" },
{ "etm_fmd_fini_badargs", FMD_TYPE_UINT64,
- "bad arguments from fmd_fini entry point" },
+ "bad arguments from fmd_fini entry point" },
/* Alert logging errors */
@@ -506,6 +524,132 @@ static struct stats {
"xport resets after xport API failure" }
};
+
+/*
+ * -------------------- global data for Root ldom-------------------------
+ */
+
+ldom_hdl_t
+*etm_lhp = NULL; /* ldom pointer */
+
+static void *etm_dl_hdl = (void *)NULL;
+static const char *etm_dl_path = "libds.so.1";
+static int etm_dl_mode = (RTLD_NOW | RTLD_LOCAL);
+
+static int(*etm_ds_svc_reg)(ds_capability_t *cap, ds_ops_t *ops) =
+ (int (*)(ds_capability_t *cap, ds_ops_t *ops))NULL;
+static int(*etm_ds_clnt_reg)(ds_capability_t *cap, ds_ops_t *ops) =
+ (int (*)(ds_capability_t *cap, ds_ops_t *ops))NULL;
+static int(*etm_ds_send_msg)(ds_hdl_t hdl, void *buf, size_t buflen) =
+ (int (*)(ds_hdl_t hdl, void *buf, size_t buflen))NULL;
+static int(*etm_ds_recv_msg)(ds_hdl_t hdl, void *buf, size_t buflen,
+ size_t *msglen) =
+ (int (*)(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen))NULL;
+static int (*etm_ds_fini)(void) = (int (*)(void))NULL;
+
+static pthread_mutex_t
+iosvc_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_t
+etm_async_e_tid = NULL; /* thread id of io svc async event handler */
+
+static etm_proto_v1_ev_hdr_t iosvc_hdr = {
+ ETM_PROTO_MAGIC_NUM, /* magic number */
+ ETM_PROTO_V1, /* default to V1, not checked */
+ ETM_MSG_TYPE_FMA_EVENT, /* Root Domain inteoduces only FMA events */
+ 0, /* sub-type */
+ 0, /* pad */
+ 0, /* add the xid at the Q send time */
+ ETM_PROTO_V1_TIMEOUT_NONE,
+ 0 /* ev_lens, 0-termed, after 1 FMA event */
+};
+
+/*
+ * static iosvc_list
+ */
+static etm_iosvc_t iosvc_list[NUM_OF_ROOT_DOMAINS] = {
+ {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0},
+ {"", 0}, {"", 0}
+};
+
+static etm_iosvc_t io_svc = {
+ "\0", /* ldom_name */
+ PTHREAD_COND_INITIALIZER, /* nudges */
+ PTHREAD_MUTEX_INITIALIZER, /* protects the iosvc msg Q */
+ NULL, /* iosvc msg Q head */
+ NULL, /* iosvc msg Q tail */
+ 0, /* msg Q current length */
+ 100, /* msg Q max length */
+ 0, /* current transaction id */
+ 0, /* xid of last event posted to FMD */
+ DS_INVALID_HDL, /* DS handle */
+ NULL, /* fmd xprt handle */
+ NULL, /* tid 4 send to remote RootDomain */
+ NULL, /* tid 4 recv from remote RootDomain */
+ PTHREAD_COND_INITIALIZER, /* nudges etm_send_to_remote_root */
+ PTHREAD_MUTEX_INITIALIZER, /* protects msg_ack_cv */
+ 0, /* send/recv threads are not dying */
+ 0, /* flag for start sending msg Q */
+ 0 /* indicate if the ACK has come */
+};
+etm_iosvc_t *io_svc_p = &io_svc;
+
+
+static uint32_t
+flags; /* flags for fmd_xprt_open */
+
+static etm_async_event_ele_t
+async_event_q[ASYNC_EVENT_Q_SIZE]; /* holds the async events */
+
+static uint32_t
+etm_async_q_head = 0; /* ptr to cur head of async event queue */
+
+static uint32_t
+etm_async_q_tail = 0; /* ptr to cur tail of async event queue */
+
+static uint32_t
+etm_async_q_cur_len = 0; /* cur length (ele cnt) of async event queue */
+
+static uint32_t
+etm_async_q_max_len = ASYNC_EVENT_Q_SIZE;
+ /* max length (ele cnt) of async event queue */
+
+static pthread_cond_t
+etm_async_event_q_cv = PTHREAD_COND_INITIALIZER;
+ /* nudges async event handler */
+
+static pthread_mutex_t
+etm_async_event_q_lock = PTHREAD_MUTEX_INITIALIZER;
+ /* protects async event q */
+
+static ds_ver_t
+etm_iosvc_vers[] = { { 1, 0} };
+
+#define ETM_NVERS (sizeof (etm_iosvc_vers) / sizeof (ds_ver_t))
+
+static ds_capability_t
+iosvc_caps = {
+ "ETM", /* svc_id */
+ etm_iosvc_vers, /* vers */
+ ETM_NVERS /* number of vers */
+};
+
+static void
+etm_iosvc_reg_handler(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
+ ds_domain_hdl_t did);
+
+static void
+etm_iosvc_unreg_handler(ds_hdl_t hdl, ds_cb_arg_t arg);
+
+static ds_ops_t
+iosvc_ops = {
+ etm_iosvc_reg_handler, /* ds_reg_cb */
+ etm_iosvc_unreg_handler, /* ds_unreg_cb */
+ NULL, /* ds_data_cb */
+ NULL /* cb_arg */
+};
+
+
/*
* -------------------------- support functions ------------------------------
*/
@@ -519,6 +663,7 @@ static struct stats {
* the outputted hex digits, while Linux and VxWorks do.
*/
+
/*
* etm_show_time - display the current time of day (for debugging) using
* the given FMD module handle and annotation string
@@ -681,18 +826,18 @@ etm_io_op(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn,
return (-EINVAL);
}
switch (io_op) {
- case ETM_IO_OP_RD:
- io_func_ptr = etm_xport_read;
- io_retry_stat = etm_stats.etm_xport_rd_retry;
- io_fail_stat = etm_stats.etm_xport_rd_fail;
- break;
- case ETM_IO_OP_WR:
- io_func_ptr = etm_xport_write;
- io_retry_stat = etm_stats.etm_xport_wr_retry;
- io_fail_stat = etm_stats.etm_xport_wr_fail;
- break;
- default:
- return (-EINVAL);
+ case ETM_IO_OP_RD:
+ io_func_ptr = etm_xport_read;
+ io_retry_stat = etm_stats.etm_xport_rd_retry;
+ io_fail_stat = etm_stats.etm_xport_rd_fail;
+ break;
+ case ETM_IO_OP_WR:
+ io_func_ptr = etm_xport_write;
+ io_retry_stat = etm_stats.etm_xport_wr_retry;
+ io_fail_stat = etm_stats.etm_xport_wr_fail;
+ break;
+ default:
+ return (-EINVAL);
}
if (byte_cnt == 0) {
return (byte_cnt); /* nop */
@@ -1166,7 +1311,7 @@ etm_hdr_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, nvlist_t *evp,
*/
static int
-etm_post_to_fmd(fmd_hdl_t *hdl, nvlist_t *evp)
+etm_post_to_fmd(fmd_hdl_t *hdl, fmd_xprt_t *fmd_xprt, nvlist_t *evp)
{
ssize_t ev_sz; /* sizeof *evp */
@@ -1175,7 +1320,7 @@ etm_post_to_fmd(fmd_hdl_t *hdl, nvlist_t *evp)
if (etm_debug_lvl >= 2) {
etm_show_time(hdl, "ante ev post");
}
- fmd_xprt_post(hdl, etm_fmd_xprt, evp, 0);
+ fmd_xprt_post(hdl, fmd_xprt, evp, 0);
etm_stats.etm_wr_fmd_fmaevent.fmds_value.ui64++;
etm_stats.etm_wr_fmd_bytes.fmds_value.ui64 += ev_sz;
if (etm_debug_lvl >= 1) {
@@ -1341,6 +1486,483 @@ func_ret:
} /* etm_req_ver_negot() */
+
+
+/*
+ * etm_iosvc_msg_enq - add element to tail of ETM iosvc msg queue
+ * etm_iosvc_msg_deq - del element from head of ETM iosvc msg queue
+ * need to grab the mutex lock before calling this routine
+ * return >0 for success, or -errno value
+ */
+static int
+etm_iosvc_msg_enq(fmd_hdl_t *hdl, etm_iosvc_t *iosvc, etm_iosvc_q_ele_t *msgp)
+{
+ etm_iosvc_q_ele_t *newp; /* ptr to new msg q ele */
+
+ if (iosvc->msg_q_cur_len >= iosvc->msg_q_max_len) {
+ fmd_hdl_debug(hdl, "warning: enq to full msg queue\n");
+ return (-E2BIG);
+ }
+
+ newp = fmd_hdl_zalloc(hdl, sizeof (*newp), FMD_SLEEP);
+ (void) memcpy(newp, msgp, sizeof (*newp));
+ newp->msg_nextp = NULL;
+
+ if (iosvc->msg_q_cur_len == 0) {
+ iosvc->msg_q_head = newp;
+ } else {
+ iosvc->msg_q_tail->msg_nextp = newp;
+ }
+
+ iosvc->msg_q_tail = newp;
+ iosvc->msg_q_cur_len++;
+ fmd_hdl_debug(hdl, "info: current msg queue length %d\n",
+ iosvc->msg_q_cur_len);
+
+ return (1);
+
+} /* etm_iosvc_msg_enq() */
+
+static int
+etm_iosvc_msg_deq(fmd_hdl_t *hdl, etm_iosvc_t *iosvc, etm_iosvc_q_ele_t *msgp)
+{
+ etm_iosvc_q_ele_t *oldp; /* ptr to old msg q ele */
+
+ if (iosvc->msg_q_cur_len == 0) {
+ fmd_hdl_debug(hdl, "warning: deq from empty responder queue\n");
+ return (-ENOENT);
+ }
+
+ (void) memcpy(msgp, iosvc->msg_q_head, sizeof (*msgp));
+ msgp->msg_nextp = NULL;
+
+ oldp = iosvc->msg_q_head;
+ iosvc->msg_q_head = iosvc->msg_q_head->msg_nextp;
+
+ /*
+ * free the mem alloc-ed in etm_iosvc_msg_enq()
+ */
+ fmd_hdl_free(hdl, oldp, sizeof (*oldp));
+
+ iosvc->msg_q_cur_len--;
+ if (iosvc->msg_q_cur_len == 0) {
+ iosvc->msg_q_tail = NULL;
+ }
+
+ return (1);
+
+} /* etm_iosvc_msg_deq() */
+
+
+/*
+ * etm_msg_enq_head():
+ * enq the msg to the head of the Q.
+ * If the Q is full, drop the msg at the tail then enq the msg at head.
+ * need to grab mutex lock iosvc->msg_q_lock before calling this routine.
+ */
+static void
+etm_msg_enq_head(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
+ etm_iosvc_q_ele_t *msg_ele)
+{
+
+ etm_iosvc_q_ele_t *newp; /* iosvc msg ele ptr */
+
+ if (iosvc->msg_q_cur_len >= iosvc->msg_q_max_len) {
+ fmd_hdl_debug(fmd_hdl,
+ "warning: add to head of a full msg queue."
+ " Drop the msg at the tail\n");
+ /*
+ * drop the msg at the tail
+ */
+ newp = iosvc->msg_q_head;
+ while (newp->msg_nextp != iosvc->msg_q_tail) {
+ newp = newp->msg_nextp;
+ }
+
+ /*
+ * free the msg in iosvc->msg_q_tail->msg
+ * free the mem pointed to by iosvc->msg_q_tail
+ */
+ fmd_hdl_free(fmd_hdl, iosvc->msg_q_tail->msg,
+ iosvc->msg_q_tail->msg_size);
+ fmd_hdl_free(fmd_hdl, iosvc->msg_q_tail, sizeof (*newp));
+ iosvc->msg_q_tail = newp;
+ iosvc->msg_q_tail->msg_nextp = NULL;
+ iosvc->msg_q_cur_len--;
+ }
+
+ /*
+ * enq the msg to the head
+ */
+ newp = fmd_hdl_zalloc(fmd_hdl, sizeof (*newp), FMD_SLEEP);
+ (void) memcpy(newp, msg_ele, sizeof (*newp));
+ if (iosvc->msg_q_cur_len == 0) {
+ newp->msg_nextp = NULL;
+ iosvc->msg_q_tail = newp;
+ } else {
+ newp->msg_nextp = iosvc->msg_q_head;
+ }
+ iosvc->msg_q_head = newp;
+ iosvc->msg_q_cur_len++;
+} /* etm_msg_enq_head() */
+
+/*
+ * etm_isovc_cleanup():
+ * clean up what's in the passed-in iosvc struct, including the msg Q.
+ */
+static void
+etm_iosvc_cleanup(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc)
+{
+
+ etm_iosvc_q_ele_t msg_ele; /* io svc msg Q ele */
+
+ iosvc->thr_is_dying = 1;
+
+ if (iosvc->send_tid != NULL) {
+ fmd_thr_signal(fmd_hdl, iosvc->send_tid);
+ fmd_thr_destroy(fmd_hdl, iosvc->send_tid);
+ iosvc->send_tid = NULL;
+ } /* if io svc send thread was created ok */
+
+ if (iosvc->recv_tid != NULL) {
+ fmd_thr_signal(fmd_hdl, iosvc->recv_tid);
+ fmd_thr_destroy(fmd_hdl, iosvc->recv_tid);
+ iosvc->recv_tid = NULL;
+ } /* if root domain recv thread was created */
+
+ iosvc->ldom_name[0] = '\0';
+
+ iosvc->ds_hdl = DS_INVALID_HDL;
+
+ if (iosvc->fmd_xprt != NULL) {
+ fmd_xprt_close(fmd_hdl, iosvc->fmd_xprt);
+ iosvc->fmd_xprt = NULL;
+ } /* if fmd-xprt has been opened */
+
+ (void) pthread_mutex_lock(&iosvc->msg_q_lock);
+ while (iosvc->msg_q_cur_len > 0) {
+ (void) etm_iosvc_msg_deq(fmd_hdl, iosvc, &msg_ele);
+ fmd_hdl_free(fmd_hdl, msg_ele.msg, msg_ele.msg_size);
+ }
+ (void) pthread_mutex_unlock(&iosvc->msg_q_lock);
+
+ return;
+
+} /* etm_iosvc_cleanup() */
+
+/*
+ * etm_iosvc_lookup(using ldom_name or ds_hdl when ldom_name is empty)
+ * not found, create one, add to iosvc_list
+ */
+etm_iosvc_t *
+etm_iosvc_lookup(fmd_hdl_t *fmd_hdl, char *ldom_name, ds_hdl_t ds_hdl,
+ boolean_t iosvc_create)
+{
+ uint32_t i; /* for loop var */
+ int32_t first_empty_slot = -1; /* remember that */
+
+ for (i = 0; i < NUM_OF_ROOT_DOMAINS; i++) {
+ if (ldom_name[0] == '\0') {
+ /*
+ * search by hdl passed in
+ * the only time this is used is at ds_unreg_cb time.
+ * there is no ldom name, only the valid ds_hdl.
+ * find an iosvc with the matching ds_hdl.
+ * ignore the iosvc_create flag, should never need to
+ * create an iosvc for ds_unreg_cb
+ */
+ if (ds_hdl == iosvc_list[i].ds_hdl) {
+ if (etm_debug_lvl >= 2) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: found an iosvc at slot %d w/ ds_hdl %d \n",
+ i, iosvc_list[i].ds_hdl);
+ }
+ if (iosvc_list[i].ldom_name[0] != '\0')
+ if (etm_debug_lvl >= 2) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: found an iosvc w/ ldom_name %s \n",
+ iosvc_list[i].ldom_name);
+ }
+ return (&iosvc_list[i]);
+ } else {
+ continue;
+ }
+ } else if (iosvc_list[i].ldom_name[0] != '\0') {
+ /*
+ * this is an non-empty iosvc structure slot
+ */
+ if (strcmp(ldom_name, iosvc_list[i].ldom_name) == 0) {
+ /*
+ * found an iosvc structure that matches the
+ * passed in ldom_name, return the ptr
+ */
+ if (etm_debug_lvl >= 2) {
+ fmd_hdl_debug(fmd_hdl, "info: found an "
+ "iosvc at slot %d w/ ds_hdl %d \n",
+ i, iosvc_list[i].ds_hdl);
+ fmd_hdl_debug(fmd_hdl, "info: found an "
+ "iosvc w/ ldom_name %s \n",
+ iosvc_list[i].ldom_name);
+ }
+ return (&iosvc_list[i]);
+ } else {
+ /*
+ * non-empty slot with no-matching name,
+ * move on to next slot.
+ */
+ continue;
+ }
+ } else {
+ /*
+ * found the 1st slot with ldom name being empty
+ * remember the slot #, will be used for creating one
+ */
+ if (first_empty_slot == -1) {
+ first_empty_slot = i;
+ }
+ }
+ }
+ if (iosvc_create == B_TRUE && first_empty_slot >= 0) {
+ /*
+ * this is the case we need to add an iosvc at first_empty_slot
+ * for the ldom_name at iosvc_list[first_empty_slot]
+ */
+ fmd_hdl_debug(fmd_hdl,
+ "info: create an iosvc with ldom name %s\n",
+ ldom_name);
+ i = first_empty_slot;
+ (void) memcpy(&iosvc_list[i], &io_svc, sizeof (etm_iosvc_t));
+ (void) strcpy(iosvc_list[i].ldom_name, ldom_name);
+ fmd_hdl_debug(fmd_hdl, "info: iosvc #%d has ldom name %s\n",
+ i, iosvc_list[i].ldom_name);
+ return (&iosvc_list[i]);
+ } else {
+ return (NULL);
+ }
+
+} /* etm_iosvc_lookup() */
+
+
+/*
+ * etm_ckpt_remove:
+ * remove the ckpt for the iosvc element
+ */
+static void
+etm_ckpt_remove(fmd_hdl_t *hdl, etm_iosvc_q_ele_t *ele) {
+ int err; /* temp error */
+ nvlist_t *evp = NULL; /* event pointer */
+ etm_proto_v1_ev_hdr_t *hdrp; /* hdr for FMA_EVENT */
+ char *buf; /* packed event pointer */
+
+ if ((ele->ckpt_flag == ETM_CKPT_NOOP) ||
+ (etm_ldom_type != LDOM_TYPE_CONTROL)) {
+ return;
+ }
+
+ /* the pointer to the packed event in the etm message */
+ hdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)ele->msg);
+ buf = (char *)((ptrdiff_t)hdrp + sizeof (*hdrp)
+ + (1 * sizeof (hdrp->ev_lens[0])));
+
+ /* unpack it, then uncheckpoited it */
+ if ((err = nvlist_unpack(buf, hdrp->ev_lens[0], &evp, 0)) != 0) {
+ fmd_hdl_debug(hdl, "failed to unpack event(rc=%d)\n", err);
+ return;
+ }
+ (void) etm_ckpt_delete(hdl, evp);
+ nvlist_free(evp);
+}
+
+/*
+ * etm_send_ds_msg()
+ * call ds_send_msg() to send the msg passed in.
+ * timedcond_wait for the ACK to come back.
+ * if the ACK doesn't come in the specified time, retrun -EAGAIN.
+ * other wise, return 1.
+ */
+int
+etm_send_ds_msg(fmd_hdl_t *fmd_hdl, boolean_t ckpt_remove, etm_iosvc_t *iosvc,
+ etm_iosvc_q_ele_t *msg_ele, etm_proto_v1_ev_hdr_t *evhdrp)
+{
+ uint32_t rc; /* for return code */
+
+ struct timeval tv;
+ struct timespec timeout;
+
+
+ /*
+ * call ds_send_msg(). Return (-EAGAIN) if not successful
+ */
+ if ((rc = (*etm_ds_send_msg)(iosvc->ds_hdl, msg_ele->msg,
+ msg_ele->msg_size)) != 0) {
+ fmd_hdl_debug(fmd_hdl, "info: ds_send_msg rc %d xid %d\n",
+ rc, evhdrp->ev_pp.pp_xid);
+ return (-EAGAIN);
+ }
+
+ /*
+ * wait on the cv for resp msg for cur_send_xid
+ */
+ (void *) pthread_mutex_lock(&iosvc->msg_ack_lock);
+
+ (void) gettimeofday(&tv, 0);
+ timeout.tv_sec = tv.tv_sec + etm_fma_resp_wait_time;
+ timeout.tv_nsec = 0;
+
+ fmd_hdl_debug(fmd_hdl, "info: waiting on msg_ack_cv for ldom %s\n",
+ iosvc->ldom_name);
+ rc = pthread_cond_timedwait(&iosvc->msg_ack_cv, &iosvc->msg_ack_lock,
+ &timeout);
+ (void *) pthread_mutex_unlock(&iosvc->msg_ack_lock);
+ fmd_hdl_debug(fmd_hdl, "info: msg_ack_cv returns with rc %d\n", rc);
+
+ /*
+ * check to see if ack_ok is non-zero
+ * if non-zero, resp msg has been received
+ */
+ if (iosvc->ack_ok != 0) {
+ /*
+ * ACK came ok, this send is successful,
+ * tell the caller ready to send next.
+ * free mem alloc-ed in
+ * etm_pack_ds_msg
+ */
+ if (ckpt_remove == B_TRUE &&
+ etm_ldom_type == LDOM_TYPE_CONTROL) {
+ etm_ckpt_remove(fmd_hdl, msg_ele);
+ }
+ fmd_hdl_free(fmd_hdl, msg_ele->msg, msg_ele->msg_size);
+ iosvc->cur_send_xid++;
+ return (1);
+ } else {
+ /*
+ * the ACK did not come on time
+ * tell the caller to resend cur_send_xid
+ */
+ return (-EAGAIN);
+ } /* iosvc->ack_ok != 0 */
+} /* etm_send_ds_msg() */
+
+/*
+ * both events from fmdo_send entry point and from SP are using the
+ * etm_proto_v1_ev_hdr_t as its header and it will be the same header for all
+ * ds send/recv msgs.
+ * Idealy, we should use the hdr coming with the SP FMA event. Since fmdo_send
+ * entry point can be called before FMA events from SP, we can't rely on
+ * the SP FMA event hdr. Use the static hdr for packing ds msgs for fmdo_send
+ * events.
+ * return >0 for success, or -errno value
+ * Design assumption: there is one FMA event per ds msg
+ */
+int
+etm_pack_ds_msg(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
+ etm_proto_v1_ev_hdr_t *ev_hdrp, size_t hdr_sz, nvlist_t *evp,
+ etm_pack_msg_type_t msg_type, uint_t ckpt_opt)
+{
+ etm_proto_v1_ev_hdr_t *hdrp; /* for FMA_EVENT msg */
+ uint32_t *lenp; /* ptr to FMA event length */
+ size_t evsz; /* packed FMA event size */
+ char *buf;
+ uint32_t rc; /* for return code */
+ char *msg; /* body of msg to be Qed */
+
+ etm_iosvc_q_ele_t msg_ele; /* io svc msg Q ele */
+ etm_proto_v1_ev_hdr_t *evhdrp;
+
+
+ if (ev_hdrp == NULL) {
+ hdrp = &iosvc_hdr;
+ } else {
+ hdrp = ev_hdrp;
+ }
+
+ /*
+ * determine hdr_sz if 0, otherwise use the one passed in hdr_sz
+ */
+
+ if (hdr_sz == 0) {
+ hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0]));
+ }
+
+ /*
+ * determine evp size
+ */
+ (void) nvlist_size(evp, &evsz, NV_ENCODE_XDR);
+
+ /* indicate 1 FMA event, no network encoding, and 0-terminate */
+ lenp = &hdrp->ev_lens[0];
+ *lenp = evsz;
+
+ /*
+ * now the total of mem needs to be alloc-ed/ds msg size is
+ * hdr_sz + evsz
+ * msg will be freed in etm_send_to_remote_root() after ds_send_msg()
+ */
+ msg = fmd_hdl_zalloc(fmd_hdl, hdr_sz + evsz, FMD_SLEEP);
+
+
+ /*
+ * copy hdr, 0 terminate the length vector, and then evp
+ */
+ (void) memcpy(msg, hdrp, sizeof (*hdrp));
+ hdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)msg);
+ lenp = &hdrp->ev_lens[0];
+ lenp++;
+ *lenp = 0;
+
+ buf = fmd_hdl_zalloc(fmd_hdl, evsz, FMD_SLEEP);
+ (void) nvlist_pack(evp, (char **)&buf, &evsz, NV_ENCODE_XDR, 0);
+ (void) memcpy(msg + hdr_sz, buf, evsz);
+ fmd_hdl_free(fmd_hdl, buf, evsz);
+
+ fmd_hdl_debug(fmd_hdl, "info: hdr_sz= %d evsz= %d in etm_pack_ds_msg"
+ "for ldom %s\n", hdr_sz, evsz, iosvc->ldom_name);
+ msg_ele.msg = msg;
+ msg_ele.msg_size = hdr_sz + evsz;
+ msg_ele.ckpt_flag = ckpt_opt;
+
+ /*
+ * decide what to do with the msg:
+ * if SP ereports (msg_type == SP_MSG), always enq the msg
+ * if not SP ereports, ie, fmd xprt control msgs, enq it _only_ after
+ * resource.fm.xprt.run has been sent (which sets start_sending_Q to 1)
+ */
+ if ((msg_type == SP_MSG) ||
+ (msg_type != SP_MSG) && (iosvc->start_sending_Q == 1)) {
+ /*
+ * this is the case when the msg needs to be enq-ed
+ */
+ (void) pthread_mutex_lock(&iosvc->msg_q_lock);
+ rc = etm_iosvc_msg_enq(fmd_hdl, iosvc, &msg_ele);
+ if ((rc > 0) && (ckpt_opt & ETM_CKPT_SAVE) &&
+ (etm_ldom_type == LDOM_TYPE_CONTROL)) {
+ (void) etm_ckpt_add(fmd_hdl, evp);
+ }
+ if (iosvc->msg_q_cur_len == 1)
+ (void) pthread_cond_signal(&iosvc->msg_q_cv);
+ (void) pthread_mutex_unlock(&iosvc->msg_q_lock);
+ } else {
+ /*
+ * fmd RDWR xprt procotol startup msgs, send it now!
+ */
+ iosvc->ack_ok = 0;
+ evhdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)msg_ele.msg);
+ evhdrp->ev_pp.pp_xid = iosvc->cur_send_xid + 1;
+ while (!iosvc->ack_ok && iosvc->ds_hdl != DS_INVALID_HDL &&
+ !etm_is_dying) {
+ if (etm_send_ds_msg(fmd_hdl, B_FALSE, iosvc, &msg_ele,
+ evhdrp) < 0) {
+ continue;
+ }
+ }
+ if (msg_type == FMD_XPRT_RUN_MSG)
+ iosvc->start_sending_Q = 1;
+ }
+
+ return (rc);
+
+} /* etm_pack_ds_msg() */
+
/*
* Design_Note: For all etm_resp_q_*() functions and etm_resp_q_* globals,
* the mutex etm_resp_q_lock must be held by the caller.
@@ -1601,9 +2223,11 @@ etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
etm_proto_v1_ctl_hdr_t *ctl_hdrp; /* for CONTROL msg */
etm_proto_v1_resp_hdr_t *resp_hdrp; /* for RESPONSE msg */
etm_proto_v3_sa_hdr_t *sa_hdrp; /* for ALERT msg */
+ etm_iosvc_t *iosvc; /* iosvc data structure */
int32_t resp_code; /* response code */
ssize_t enq_rv; /* resp_q enqueue status */
size_t hdr_sz; /* sizeof header */
+ size_t evsz; /* FMA event size */
uint8_t *body_buf; /* msg body buffer */
uint32_t body_sz; /* sizeof body_buf */
uint32_t ev_cnt; /* count of FMA events */
@@ -1612,6 +2236,10 @@ etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
char *class; /* FMA event class */
ssize_t i, n; /* gen use */
int should_reset_xport; /* bool to reset xport */
+ char ldom_name[MAX_LDOM_NAME]; /* ldom name */
+ int rc; /* return code */
+ uint64_t did; /* domain id */
+
if (etm_debug_lvl >= 2) {
etm_show_time(hdl, "ante conn handle");
@@ -1686,11 +2314,11 @@ etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
* if a dup then resend response but skip repost to FMD
*/
- if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_ev) {
+ if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_logged_ev) {
enq_rv = etm_maybe_enq_response(hdl, conn,
ev_hdrp, hdr_sz, 0);
fmd_hdl_debug(hdl, "info: skipping dup FMA event post "
- "xid 0x%x\n", etm_xid_posted_ev);
+ "xid 0x%x\n", etm_xid_posted_logged_ev);
etm_stats.etm_rd_dup_fmaevent.fmds_value.ui64++;
goto func_ret;
}
@@ -1720,6 +2348,7 @@ etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
bp += ev_hdrp->ev_lens[i];
continue;
}
+
if (etm_debug_lvl >= 1) {
(void) nvlist_lookup_string(evp, FM_CLASS,
&class);
@@ -1729,10 +2358,61 @@ etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
fmd_hdl_debug(hdl, "info: FMA event %p "
"class %s\n", evp, class);
}
- resp_code = etm_post_to_fmd(hdl, evp);
- if (resp_code >= 0) {
- etm_xid_posted_ev = ev_hdrp->ev_pp.pp_xid;
+
+ rc = nvlist_size(evp, &evsz, NV_ENCODE_XDR);
+ fmd_hdl_debug(hdl,
+ "info: evp size before pack ds msg %d\n", evsz);
+ ldom_name[0] = '\0';
+ rc = etm_filter_find_ldom_id(hdl, evp, ldom_name,
+ MAX_LDOM_NAME, &did);
+
+ /*
+ * if rc is zero and the ldom_name is not "primary",
+ * the evp belongs to a root domain, put the evp in an
+ * outgoing etm queue,
+ * in all other cases, whether ldom_name is primary or
+ * can't find a ldom name, call etm_post_to_fmd
+ */
+ if ((rc == 0) && strcmp(ldom_name, "primary") &&
+ strcmp(ldom_name, "")) {
+ /*
+ * use the ldom_name, guaranteered at this point
+ * to be a valid ldom name/non-NULL, to find the
+ * iosvc data.
+ * add an iosvc struct if can not find one
+ */
+ (void) pthread_mutex_unlock(&iosvc_list_lock);
+ iosvc = etm_iosvc_lookup(hdl, ldom_name,
+ DS_INVALID_HDL, B_TRUE);
+ (void) pthread_mutex_unlock(&iosvc_list_lock);
+ if (iosvc == NULL) {
+ fmd_hdl_debug(hdl,
+ "error: can't find iosvc for ldom "
+ "name %s\n", ldom_name);
+ } else {
+ resp_code = 0;
+ (void) etm_pack_ds_msg(hdl, iosvc,
+ ev_hdrp, hdr_sz, evp,
+ SP_MSG, ETM_CKPT_SAVE);
+ /*
+ * call the new fmd_xprt_log()
+ */
+ fmd_xprt_log(hdl, etm_fmd_xprt, evp, 0);
+ etm_xid_posted_logged_ev =
+ ev_hdrp->ev_pp.pp_xid;
+ }
+ } else {
+ /*
+ * post the fma event to the control fmd
+ */
+ resp_code = etm_post_to_fmd(hdl, etm_fmd_xprt,
+ evp);
+ if (resp_code >= 0) {
+ etm_xid_posted_logged_ev =
+ ev_hdrp->ev_pp.pp_xid;
+ }
}
+
evp = NULL;
enq_rv = etm_maybe_enq_response(hdl, conn,
ev_hdrp, hdr_sz, resp_code);
@@ -1943,6 +2623,12 @@ etm_server(void *arg)
fmd_hdl_debug(hdl, "info: connection server starting\n");
+ /*
+ * Restore the checkpointed events and dispatch them before starting to
+ * receive more events from the sp.
+ */
+ etm_ckpt_recover(hdl);
+
while (!etm_is_dying) {
if ((conn = etm_xport_accept(hdl, NULL)) == NULL) {
@@ -2080,6 +2766,945 @@ etm_init_free(void *addr, size_t size)
}
/*
+ * ---------------------root ldom support functions -----------------------
+ */
+
+/*
+ * use a static array async_event_q instead of dynamicaly allocated mem queue
+ * for etm_async_q_enq and etm_async_q_deq.
+ * This is not running in an fmd aux thread, can't use the fmd_hdl_* funcs.
+ * caller needs to grab the mutex lock before calling this func.
+ * return >0 for success, or -errno value
+ */
+static int
+etm_async_q_enq(etm_async_event_ele_t *async_e)
+{
+
+ if (etm_async_q_cur_len >= etm_async_q_max_len) {
+ /* etm_stats.etm_enq_drop_async_q.fmds_value.ui64++; */
+ return (-E2BIG);
+ }
+
+ (void) memcpy(&async_event_q[etm_async_q_tail], async_e,
+ sizeof (*async_e));
+
+ etm_async_q_tail++;
+ if (etm_async_q_tail == etm_async_q_max_len) {
+ etm_async_q_tail = 0;
+ }
+ etm_async_q_cur_len++;
+
+/* etm_stats.etm_async_q_cur_len.fmds_value.ui64 = etm_async_q_cur_len; */
+
+ return (1);
+
+} /* etm_async_q_enq() */
+
+
+static int
+etm_async_q_deq(etm_async_event_ele_t *async_e)
+{
+
+ if (etm_async_q_cur_len == 0) {
+ /* etm_stats.etm_deq_drop_async_q.fmds_value.ui64++; */
+ return (-ENOENT);
+ }
+
+ (void) memcpy(async_e, &async_event_q[etm_async_q_head],
+ sizeof (*async_e));
+
+ etm_async_q_head++;
+ if (etm_async_q_head == etm_async_q_max_len) {
+ etm_async_q_head = 0;
+ }
+ etm_async_q_cur_len--;
+/* etm_stats.etm_async__q_cur_len.fmds_value.ui64 = etm_async_q_cur_len; */
+
+ return (1);
+} /* etm_async_q_deq */
+
+
+/*
+ * ds userland interface ds_reg_cb callback func
+ */
+
+/* ARGSUSED */
+static void
+etm_iosvc_reg_handler(ds_hdl_t ds_hdl, ds_cb_arg_t arg, ds_ver_t *ver,
+ ds_domain_hdl_t dhdl)
+{
+ etm_async_event_ele_t async_ele;
+
+
+ /*
+ * do version check here.
+ * checked the ver received here against etm_iosvc_vers here
+ */
+ if (etm_iosvc_vers[0].major != ver->major ||
+ etm_iosvc_vers[0].minor != ver->minor) {
+ /*
+ * can't log an fmd debug msg,
+ * not running in an fmd aux thread
+ */
+ return;
+ }
+
+ /*
+ * the callback should have a valid ldom_name
+ * can't log fmd debugging msg here since this is not in an fmd aux
+ * thread. log fmd debug msg in etm_async_event_handle()
+ */
+ async_ele.ds_hdl = ds_hdl;
+ async_ele.dhdl = dhdl;
+ async_ele.ldom_name[0] = '\0';
+ async_ele.event_type = ETM_ASYNC_EVENT_DS_REG_CB;
+ (void) pthread_mutex_lock(&etm_async_event_q_lock);
+ (void) etm_async_q_enq(&async_ele);
+ if (etm_async_q_cur_len == 1)
+ (void) pthread_cond_signal(&etm_async_event_q_cv);
+ (void) pthread_mutex_unlock(&etm_async_event_q_lock);
+
+} /* etm_iosvc_reg_handler */
+
+
+/*
+ * ds userland interface ds_unreg_cb callback func
+ */
+
+/*ARGSUSED*/
+static void
+etm_iosvc_unreg_handler(ds_hdl_t hdl, ds_cb_arg_t arg)
+{
+ etm_async_event_ele_t async_ele;
+
+ /*
+ * fill in async_ele and enqueue async_ele
+ */
+ async_ele.ldom_name[0] = '\0';
+ async_ele.ds_hdl = hdl;
+ async_ele.event_type = ETM_ASYNC_EVENT_DS_UNREG_CB;
+ (void) pthread_mutex_lock(&etm_async_event_q_lock);
+ (void) etm_async_q_enq(&async_ele);
+ if (etm_async_q_cur_len == 1)
+ (void) pthread_cond_signal(&etm_async_event_q_cv);
+ (void) pthread_mutex_unlock(&etm_async_event_q_lock);
+} /* etm_iosvc_unreg_handler */
+
+/*
+ * ldom event registration callback func
+ */
+
+/* ARGSUSED */
+static void
+ldom_event_handler(char *ldom_name, ldom_event_t event, ldom_cb_arg_t data)
+{
+ etm_async_event_ele_t async_ele;
+
+ /*
+ * the callback will have a valid ldom_name
+ */
+ async_ele.ldom_name[0] = '\0';
+ if (ldom_name)
+ (void) strcpy(async_ele.ldom_name, ldom_name);
+ async_ele.ds_hdl = DS_INVALID_HDL;
+
+ /*
+ * fill in async_ele and enq async_ele
+ */
+ switch (event) {
+ case LDOM_EVENT_BIND:
+ async_ele.event_type = ETM_ASYNC_EVENT_LDOM_BIND;
+ break;
+ case LDOM_EVENT_UNBIND:
+ async_ele.event_type = ETM_ASYNC_EVENT_LDOM_UNBIND;
+ break;
+ case LDOM_EVENT_ADD:
+ async_ele.event_type = ETM_ASYNC_EVENT_LDOM_ADD;
+ break;
+ case LDOM_EVENT_REMOVE:
+ async_ele.event_type = ETM_ASYNC_EVENT_LDOM_REMOVE;
+ break;
+ default:
+ /*
+ * for all other ldom events, do nothing
+ */
+ return;
+ } /* switch (event) */
+
+ (void) pthread_mutex_lock(&etm_async_event_q_lock);
+ (void) etm_async_q_enq(&async_ele);
+ if (etm_async_q_cur_len == 1)
+ (void) pthread_cond_signal(&etm_async_event_q_cv);
+ (void) pthread_mutex_unlock(&etm_async_event_q_lock);
+
+} /* ldom_event_handler */
+
+
+/*
+ * This is running as an fmd aux thread.
+ * This is the func that actually handle the events, which include:
+ * 1. ldom events. ldom events are on Control Domain only
+ * 2. any DS userland callback funcs
+ * these events are already Q-ed in the async_event_ele_q
+ * deQ and process the events accordingly
+ */
+static void
+etm_async_event_handler(void *arg)
+{
+
+ fmd_hdl_t *fmd_hdl = (fmd_hdl_t *)arg;
+ etm_iosvc_t *iosvc; /* ptr 2 iosvc struct */
+ etm_async_event_ele_t async_e;
+
+ fmd_hdl_debug(fmd_hdl, "info: etm_async_event_handler starting\n");
+ /*
+ * handle etm is not dying and Q len > 0
+ */
+ while (!etm_is_dying) {
+ /*
+ * grab the lock to check the Q len
+ */
+ (void) pthread_mutex_lock(&etm_async_event_q_lock);
+ fmd_hdl_debug(fmd_hdl, "info: etm_async_q_cur_len %d\n",
+ etm_async_q_cur_len);
+
+ while (etm_async_q_cur_len > 0) {
+ (void) etm_async_q_deq(&async_e);
+ (void) pthread_mutex_unlock(&etm_async_event_q_lock);
+ fmd_hdl_debug(fmd_hdl,
+ "info: processing an async event type %d ds_hdl"
+ " %d\n", async_e.event_type, async_e.ds_hdl);
+ if (async_e.ldom_name[0] != '\0') {
+ fmd_hdl_debug(fmd_hdl,
+ "info: procssing async evt ldom_name %s\n",
+ async_e.ldom_name);
+ }
+
+ /*
+ * at this point, if async_e.ldom_name is not NULL,
+ * we have a valid iosvc strcut ptr.
+ * the only time async_e.ldom_name is NULL is at
+ * ds_unreg_cb()
+ */
+ switch (async_e.event_type) {
+ case ETM_ASYNC_EVENT_LDOM_UNBIND:
+ case ETM_ASYNC_EVENT_LDOM_REMOVE:
+ /*
+ * we have a valid ldom_name,
+ * etm_lookup_struct(ldom_name)
+ * do nothing if can't find an iosvc
+ * no iosvc clean up to do
+ */
+ (void) pthread_mutex_lock(
+ &iosvc_list_lock);
+ iosvc = etm_iosvc_lookup(fmd_hdl,
+ async_e.ldom_name,
+ async_e.ds_hdl, B_FALSE);
+ if (iosvc == NULL) {
+ fmd_hdl_debug(fmd_hdl,
+ "error: can't find iosvc for ldom "
+ "name %s\n",
+ async_e.ldom_name);
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+ }
+ etm_iosvc_cleanup(fmd_hdl, iosvc);
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+
+ case ETM_ASYNC_EVENT_LDOM_BIND:
+
+ /*
+ * create iosvc if it has not been
+ * created
+ * async_e.ds_hdl is invalid
+ * async_e.ldom_name is valid ldom_name
+ */
+ (void) pthread_mutex_lock(
+ &iosvc_list_lock);
+ iosvc = etm_iosvc_lookup(fmd_hdl,
+ async_e.ldom_name,
+ async_e.ds_hdl, B_TRUE);
+ if (iosvc == NULL) {
+ fmd_hdl_debug(fmd_hdl,
+ "error: can't create iosvc for "
+ "async evnt %d\n",
+ async_e.event_type);
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+ }
+ (void) strcpy(iosvc->ldom_name,
+ async_e.ldom_name);
+ iosvc->ds_hdl = async_e.ds_hdl;
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+
+ case ETM_ASYNC_EVENT_DS_REG_CB:
+ if (etm_ldom_type == LDOM_TYPE_CONTROL) {
+ /*
+ * find the root ldom name from
+ * ldom domain hdl/id
+ */
+ if (etm_filter_find_ldom_name(
+ fmd_hdl, async_e.dhdl,
+ async_e.ldom_name,
+ MAX_LDOM_NAME) != 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "error: can't find root "
+ "domain name from did %d\n",
+ async_e.dhdl);
+ break;
+ } else {
+ fmd_hdl_debug(fmd_hdl,
+ "info: etm_filter_find_"
+ "ldom_name returned %s\n",
+ async_e.ldom_name);
+ }
+ /*
+ * now we should have a valid
+ * root domain name.
+ * lookup the iosvc struct
+ * associated with the ldom_name
+ * and init the iosvc struct
+ */
+ (void) pthread_mutex_lock(
+ &iosvc_list_lock);
+ iosvc = etm_iosvc_lookup(
+ fmd_hdl, async_e.ldom_name,
+ async_e.ds_hdl, B_TRUE);
+ if (iosvc == NULL) {
+ fmd_hdl_debug(fmd_hdl,
+ "error: can't create iosvc "
+ "for async evnt %d\n",
+ async_e.event_type);
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+ }
+ iosvc->ds_hdl = async_e.ds_hdl;
+ iosvc->cur_send_xid = 0;
+
+ /*
+ * open the fmd xprt if it
+ * hasn't been previously opened
+ */
+ iosvc->start_sending_Q = 0;
+ fmd_hdl_debug(fmd_hdl,
+ "info: before fmd_xprt_open"
+ "ldom_name is %s\n",
+ async_e.ldom_name);
+ if (iosvc->fmd_xprt == NULL) {
+ iosvc->fmd_xprt =
+ fmd_xprt_open(
+ fmd_hdl,
+ flags, NULL,
+ iosvc);
+ }
+
+ iosvc->thr_is_dying = 0;
+ if (iosvc->recv_tid == NULL) {
+ iosvc->recv_tid =
+ fmd_thr_create(
+ fmd_hdl,
+ etm_recv_from_remote_root,
+ iosvc);
+ }
+ if (iosvc->send_tid == NULL) {
+ iosvc->send_tid =
+ fmd_thr_create(
+ fmd_hdl,
+ etm_send_to_remote_root,
+ iosvc);
+ }
+
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ } else {
+ iosvc = &io_svc;
+ (void) strcpy(iosvc->ldom_name,
+ async_e.ldom_name);
+ iosvc->ds_hdl = async_e.ds_hdl;
+ iosvc->cur_send_xid = 0;
+ iosvc->start_sending_Q = 0;
+
+ /*
+ * open the fmd xprt if it
+ * hasn't been previously opened
+ */
+ if (iosvc->fmd_xprt == NULL) {
+ iosvc->fmd_xprt =
+ fmd_xprt_open(
+ fmd_hdl,
+ flags, NULL,
+ iosvc);
+ }
+
+ iosvc->thr_is_dying = 0;
+ if (iosvc->recv_tid == NULL) {
+ iosvc->recv_tid =
+ fmd_thr_create(
+ fmd_hdl,
+ etm_recv_from_remote_root,
+ iosvc);
+ }
+ if (iosvc->send_tid == NULL) {
+ iosvc->send_tid =
+ fmd_thr_create(
+ fmd_hdl,
+ etm_send_to_remote_root,
+ iosvc);
+ }
+ }
+ break;
+
+ case ETM_ASYNC_EVENT_DS_UNREG_CB:
+ /*
+ * decide which iosvc struct to perform
+ * this UNREG callback on.
+ */
+ if (etm_ldom_type == LDOM_TYPE_CONTROL) {
+ (void) pthread_mutex_lock(
+ &iosvc_list_lock);
+ /*
+ * lookup the iosvc struct w/
+ * ds_hdl
+ */
+ iosvc = etm_iosvc_lookup(
+ fmd_hdl, async_e.ldom_name,
+ async_e.ds_hdl, B_FALSE);
+ if (iosvc == NULL) {
+ fmd_hdl_debug(fmd_hdl,
+ "error: can't find iosvc "
+ "for async evnt %d\n",
+ async_e.event_type);
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ break;
+ }
+
+ /*
+ * ds_hdl and fmd_xprt_open
+ * go hand to hand together
+ * after unreg_cb,
+ * ds_hdl is INVALID and
+ * fmd_xprt is closed.
+ * the ldom name and the msg Q
+ * remains in iosvc_list
+ */
+ iosvc->ds_hdl = DS_INVALID_HDL;
+ if (iosvc->fmd_xprt != NULL)
+ fmd_xprt_close(fmd_hdl,
+ iosvc->fmd_xprt);
+ iosvc->fmd_xprt = NULL;
+
+ if (iosvc->ldom_name != '\0')
+ fmd_hdl_debug(fmd_hdl,
+ "info: iosvc w/ ldom_name "
+ "%s \n", iosvc->ldom_name);
+
+ /*
+ * destroy send/recv threads
+ * on Control side.
+ */
+ iosvc->thr_is_dying = 1;
+ if (iosvc->send_tid != NULL) {
+ fmd_thr_signal(fmd_hdl,
+ iosvc->send_tid);
+ fmd_thr_destroy(fmd_hdl,
+ iosvc->send_tid);
+ iosvc->send_tid = NULL;
+ } /* if send tid was created */
+
+ if (iosvc->recv_tid != NULL) {
+ fmd_thr_signal(fmd_hdl,
+ iosvc->recv_tid);
+ fmd_thr_destroy(fmd_hdl,
+ iosvc->recv_tid);
+ iosvc->recv_tid = NULL;
+ } /* if recv tid was created */
+
+ (void) pthread_mutex_unlock(
+ &iosvc_list_lock);
+ } else {
+ iosvc = &io_svc;
+ /*
+ * destroy send/recv threads
+ * on Root side.
+ */
+ iosvc->thr_is_dying = 1;
+ if (iosvc->send_tid != NULL) {
+ fmd_thr_signal(fmd_hdl,
+ iosvc->send_tid);
+ fmd_thr_destroy(fmd_hdl,
+ iosvc->send_tid);
+ iosvc->send_tid = NULL;
+ } /* if send tid was created */
+
+ if (iosvc->recv_tid != NULL) {
+ fmd_thr_signal(fmd_hdl,
+ iosvc->recv_tid);
+ fmd_thr_destroy(fmd_hdl,
+ iosvc->recv_tid);
+ iosvc->recv_tid = NULL;
+ } /* if recv tid was created */
+
+ iosvc->ds_hdl = DS_INVALID_HDL;
+ if (iosvc->fmd_xprt != NULL)
+ fmd_xprt_close(fmd_hdl,
+ iosvc->fmd_xprt);
+ iosvc->fmd_xprt = NULL;
+ }
+ break;
+
+ default:
+ /*
+ * for all other events, etm doesn't care.
+ * already logged an fmd info msg w/
+ * the event type. Do nothing here.
+ */
+ break;
+ } /* switch (async_e.event_type) */
+
+ if (etm_ldom_type == LDOM_TYPE_CONTROL) {
+ etm_filter_handle_ldom_event(fmd_hdl,
+ async_e.event_type, async_e.ldom_name);
+ }
+
+ /*
+ * grab the lock to check the q length again
+ */
+ (void) pthread_mutex_lock(&etm_async_event_q_lock);
+
+ if (etm_is_dying) {
+ break;
+ }
+ } /* etm_async_q_cur_len */
+
+ /*
+ * we have the mutex lock at this point, whether
+ * . etm_is_dying and/or
+ * . q_len == 0
+ */
+ if (!etm_is_dying && etm_async_q_cur_len == 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: cond wait on async_event_q_cv\n");
+ (void) pthread_cond_wait(&etm_async_event_q_cv,
+ &etm_async_event_q_lock);
+ fmd_hdl_debug(fmd_hdl,
+ "info: cond wait on async_event_q_cv rtns\n");
+ }
+ (void) pthread_mutex_unlock(&etm_async_event_q_lock);
+ } /* etm_is_dying */
+
+ fmd_hdl_debug(fmd_hdl,
+ "info: etm async event handler thread exiting\n");
+
+} /* etm_async_event_handler */
+
+/*
+ * deQ what's in iosvc msg Q
+ * send iosvc_msgp to the remote io svc ldom by calling ds_send_msg()
+ * the iosvc_msgp already has the packed msg, which is hdr + 1 fma event
+ */
+static void
+etm_send_to_remote_root(void *arg)
+{
+
+ etm_iosvc_t *iosvc = (etm_iosvc_t *)arg; /* iosvc ptr */
+ etm_iosvc_q_ele_t msg_ele; /* iosvc msg ele */
+ etm_proto_v1_ev_hdr_t *ev_hdrp; /* hdr for FMA_EVENT */
+ fmd_hdl_t *fmd_hdl = init_hdl; /* fmd handle */
+
+
+ fmd_hdl_debug(fmd_hdl,
+ "info: send to remote iosvc starting w/ ldom_name %s\n",
+ iosvc->ldom_name);
+
+ /*
+ * loop forever until etm_is_dying or thr_is_dying
+ */
+ while (!etm_is_dying && !iosvc->thr_is_dying) {
+ if (iosvc->ds_hdl != DS_INVALID_HDL &&
+ iosvc->start_sending_Q > 0) {
+ (void) pthread_mutex_lock(&iosvc->msg_q_lock);
+ while (iosvc->msg_q_cur_len > 0 &&
+ iosvc->ds_hdl != DS_INVALID_HDL) {
+ (void) etm_iosvc_msg_deq(fmd_hdl, iosvc,
+ &msg_ele);
+ if (etm_debug_lvl >= 3) {
+ fmd_hdl_debug(fmd_hdl, "info: valid "
+ "ds_hdl before ds_send_msg \n");
+ }
+ (void) pthread_mutex_unlock(&iosvc->msg_q_lock);
+
+ iosvc->ack_ok = 0;
+ ev_hdrp = (etm_proto_v1_ev_hdr_t *)
+ ((ptrdiff_t)msg_ele.msg);
+ ev_hdrp->ev_pp.pp_xid = iosvc->cur_send_xid + 1;
+ while (!iosvc->ack_ok &&
+ iosvc->ds_hdl != DS_INVALID_HDL &&
+ !etm_is_dying) {
+ /*
+ * call ds_send_msg() to send the msg,
+ * wait for the recv end to send the
+ * resp msg back.
+ * If resp msg is recv-ed, ack_ok
+ * will be set to 1.
+ * otherwise, retry.
+ */
+ if (etm_send_ds_msg(fmd_hdl, B_TRUE,
+ iosvc, &msg_ele, ev_hdrp) < 0) {
+ continue;
+ }
+
+ if (etm_is_dying || iosvc->thr_is_dying)
+ break;
+ }
+
+ /*
+ * if out of the while loop but !ack_ok, ie,
+ * ds_hdl becomes invalid at some point
+ * while waiting the resp msg, we need to put
+ * the msg back to the head of the Q.
+ */
+ if (!iosvc->ack_ok) {
+ (void) pthread_mutex_lock(
+ &iosvc->msg_q_lock);
+ /*
+ * put the msg back to the head of Q.
+ * If the Q is full at this point,
+ * drop the msg at the tail, enq this
+ * msg to the head.
+ */
+ etm_msg_enq_head(fmd_hdl, iosvc,
+ &msg_ele);
+ (void) pthread_mutex_unlock(
+ &iosvc->msg_q_lock);
+ }
+
+ /*
+ *
+ * grab the lock to check the Q len again
+ */
+ (void) pthread_mutex_lock(&iosvc->msg_q_lock);
+ if (etm_is_dying || iosvc->thr_is_dying) {
+ break;
+ }
+ } /* while dequeing iosvc msgs to send */
+
+ /*
+ * we have the mutex lock for msg_q_lock at this point
+ * we are here because
+ * 1) q_len == 0: then wait on the cv for Q to be filled
+ * 2) etm_is_dying
+ */
+ if (!etm_is_dying && !iosvc->thr_is_dying &&
+ iosvc->msg_q_cur_len == 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: waiting on msg_q_cv\n");
+ (void) pthread_cond_wait(&iosvc->msg_q_cv,
+ &iosvc->msg_q_lock);
+ }
+ (void) pthread_mutex_unlock(&iosvc->msg_q_lock);
+ if (etm_is_dying || iosvc->thr_is_dying) {
+ break;
+ }
+ } else {
+ (void) etm_sleep(1);
+ } /* wait for the start_sendingQ > 0 */
+ } /* etm_is_dying or thr_is_dying */
+ fmd_hdl_debug(fmd_hdl, "info; etm send thread exiting \n");
+} /* etm_send_to_remote_root */
+
+
+/*
+ * receive etm msgs from the remote root ldom by calling ds_recv_msg()
+ * if FMA events/ereports, call fmd_xprt_post() to post to fmd
+ * send ACK back by calling ds_send_msg()
+ */
+static void
+etm_recv_from_remote_root(void *arg)
+{
+ etm_iosvc_t *iosvc = (etm_iosvc_t *)arg; /* iosvc ptr */
+ etm_proto_v1_pp_t *pp; /* protocol preamble */
+ etm_proto_v1_ev_hdr_t *ev_hdrp; /* for FMA_EVENT msg */
+ etm_proto_v1_resp_hdr_t *resp_hdrp; /* for RESPONSE msg */
+ int32_t resp_code = 0; /* default is success */
+ int32_t rc; /* return value */
+ size_t maxlen = MAXLEN;
+ /* max msg len */
+ char msgbuf[MAXLEN]; /* recv msg buf */
+ size_t msg_size; /* recv msg size */
+ size_t hdr_sz; /* sizeof *hdrp */
+ size_t evsz; /* sizeof *evp */
+ size_t fma_event_size; /* sizeof FMA event */
+ nvlist_t *evp; /* ptr to the nvlist */
+ char *buf; /* ptr to the nvlist */
+ static uint32_t mem_alloc = 0; /* indicate if alloc mem */
+ char *msg; /* ptr to alloc mem */
+ fmd_hdl_t *fmd_hdl = init_hdl;
+
+
+
+ fmd_hdl_debug(fmd_hdl,
+ "info: recv from remote iosvc starting with ldom name %s \n",
+ iosvc->ldom_name);
+
+ /*
+ * loop forever until etm_is_dying or the thread is dying
+ */
+
+ msg = msgbuf;
+ while (!etm_is_dying && !iosvc->thr_is_dying) {
+ if (iosvc->ds_hdl == DS_INVALID_HDL) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds_hdl is invalid in recv thr\n");
+ (void) etm_sleep(1);
+ continue;
+ }
+
+ /*
+ * for now, there are FMA_EVENT and ACK msg type.
+ * use FMA_EVENT buf as the maxlen, hdr+1 fma event.
+ * FMA_EVENT is big enough to hold an ACK msg.
+ * the actual msg size received is in msg_size.
+ */
+ rc = (*etm_ds_recv_msg)(iosvc->ds_hdl, msg, maxlen, &msg_size);
+ if (rc == EFBIG) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds_recv_msg needs mem the size of %d\n",
+ msg_size);
+ msg = fmd_hdl_zalloc(fmd_hdl, msg_size, FMD_SLEEP);
+ mem_alloc = 1;
+ } else if (rc == 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds_recv_msg received a msg ok\n");
+ /*
+ * check the magic # in msg.hdr
+ */
+ pp = (etm_proto_v1_pp_t *)((ptrdiff_t)msg);
+ if (pp->pp_magic_num != ETM_PROTO_MAGIC_NUM) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: bad ds recv on magic\n");
+ continue;
+ }
+
+ /*
+ * check the msg type against msg_size to be sure
+ * that received msg is not a truncated msg
+ */
+ if (pp->pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
+
+ ev_hdrp = (etm_proto_v1_ev_hdr_t *)
+ ((ptrdiff_t)msg);
+ fmd_hdl_debug(fmd_hdl, "info: ds received "
+ "FMA EVENT xid=%d msg_size=%d\n",
+ ev_hdrp->ev_pp.pp_xid, msg_size);
+ hdr_sz = sizeof (*ev_hdrp) +
+ 1*(sizeof (ev_hdrp->ev_lens[0]));
+ fma_event_size = hdr_sz + ev_hdrp->ev_lens[0];
+ if (fma_event_size != msg_size) {
+ fmd_hdl_debug(fmd_hdl, "info: wrong "
+ "ev msg size received\n");
+ continue;
+ /*
+ * Simply do nothing. The send side
+ * will timedcond_wait waiting on the
+ * resp msg will timeout and
+ * re-send the same msg.
+ */
+ }
+ if (etm_debug_lvl >= 3) {
+ fmd_hdl_debug(fmd_hdl, "info: recv msg"
+ " size %d hdrsz %d evp size %d\n",
+ msg_size, hdr_sz,
+ ev_hdrp->ev_lens[0]);
+ }
+
+ if (ev_hdrp->ev_pp.pp_xid !=
+ iosvc->xid_posted_ev) {
+ /*
+ * different from last xid posted to
+ * fmd, post to fmd now.
+ */
+ buf = msg + hdr_sz;
+ rc = nvlist_unpack(buf,
+ ev_hdrp->ev_lens[0], &evp, 0);
+ rc = nvlist_size(evp, &evsz,
+ NV_ENCODE_XDR);
+ fmd_hdl_debug(fmd_hdl,
+ "info: evp size %d before fmd"
+ "post\n", evsz);
+
+ if ((rc = etm_post_to_fmd(fmd_hdl,
+ iosvc->fmd_xprt, evp)) >= 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: xid posted to fmd %d"
+ "\n",
+ ev_hdrp->ev_pp.pp_xid);
+ iosvc->xid_posted_ev =
+ ev_hdrp->ev_pp.pp_xid;
+ }
+ }
+
+ /*
+ * ready to send the RESPONSE msg back
+ * reuse the msg buffer as the response buffer
+ */
+ resp_hdrp = (etm_proto_v1_resp_hdr_t *)
+ ((ptrdiff_t)msg);
+ resp_hdrp->resp_pp.pp_msg_type =
+ ETM_MSG_TYPE_RESPONSE;
+
+ resp_hdrp->resp_code = resp_code;
+ resp_hdrp->resp_len = sizeof (*resp_hdrp);
+
+ /*
+ * send the whole response msg in one send
+ */
+ if ((*etm_ds_send_msg)(iosvc->ds_hdl, msg,
+ sizeof (*resp_hdrp)) != 0) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: send response msg failed\n");
+ } else {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds send resp msg ok"
+ "size %d\n", sizeof (*resp_hdrp));
+ }
+ } else if (pp->pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds received respond msg xid=%d"
+ "msg_size=%d for ldom %s\n", pp->pp_xid,
+ msg_size, iosvc->ldom_name);
+ if (sizeof (*resp_hdrp) != msg_size) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: wrong resp msg size"
+ "received\n");
+ fmd_hdl_debug(fmd_hdl,
+ "info: resp msg size %d recv resp"
+ "msg size %d\n",
+ sizeof (*resp_hdrp), msg_size);
+ continue;
+ }
+ /*
+ * is the pp.pp_xid == iosvc->cur_send_xid+1,
+ * if so, nudge the send routine to send next
+ */
+ if (pp->pp_xid != iosvc->cur_send_xid+1) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds received resp msg xid=%d "
+ "doesn't match cur_send_id=%d\n",
+ pp->pp_xid, iosvc->cur_send_xid+1);
+ continue;
+ }
+ (void) pthread_mutex_lock(&iosvc->msg_ack_lock);
+ iosvc->ack_ok = 1;
+ (void) pthread_cond_signal(&iosvc->msg_ack_cv);
+ (void) pthread_mutex_unlock(
+ &iosvc->msg_ack_lock);
+ fmd_hdl_debug(fmd_hdl,
+ "info: signaling msg_ack_cv\n");
+ } else {
+ /*
+ * place holder for future msg types
+ */
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds received unrecognized msg\n");
+ }
+ if (mem_alloc) {
+ fmd_hdl_free(fmd_hdl, msg, msg_size);
+ mem_alloc = 0;
+ msg = msgbuf;
+ }
+ } else {
+ if (etm_debug_lvl >= 3) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ds_recv_msg() failed\n");
+ }
+ } /* ds_recv_msg() returns */
+ } /* etm_is_dying */
+
+ /*
+ * need to free the mem allocated in msg upon exiting the thread
+ */
+ if (mem_alloc) {
+ fmd_hdl_free(fmd_hdl, msg, msg_size);
+ mem_alloc = 0;
+ msg = msgbuf;
+ }
+ fmd_hdl_debug(fmd_hdl, "info; etm recv thread exiting \n");
+} /* etm_recv_from_remote_root */
+
+
+
+/*
+ * etm_ds_init
+ * initialize DS services function pointers by calling
+ * dlopen() followed by dlsym() for each ds func.
+ * if any dlopen() or dlsym() call fails, return -ENOENT
+ * return >0 for successs, -ENOENT for failure
+ */
+static int
+etm_ds_init(fmd_hdl_t *hdl)
+{
+ int rc = 0;
+
+ if ((etm_dl_hdl = dlopen(etm_dl_path, etm_dl_mode)) == NULL) {
+ fmd_hdl_debug(hdl, "error: failed to dlopen %s\n", etm_dl_path);
+ return (-ENOENT);
+ }
+
+ etm_ds_svc_reg = (int (*)(ds_capability_t *cap, ds_ops_t *ops))
+ dlsym(etm_dl_hdl, "ds_svc_reg");
+ if (etm_ds_svc_reg == NULL) {
+ fmd_hdl_debug(hdl,
+ "error: failed to dlsym ds_svc_reg() w/ error %s\n",
+ dlerror());
+ rc = -ENOENT;
+ }
+
+
+ etm_ds_clnt_reg = (int (*)(ds_capability_t *cap, ds_ops_t *ops))
+ dlsym(etm_dl_hdl, "ds_clnt_reg");
+ if (etm_ds_clnt_reg == NULL) {
+ fmd_hdl_debug(hdl,
+ "error: dlsym(ds_clnt_reg) failed w/ errno %d\n", errno);
+ rc = -ENOENT;
+ }
+
+ etm_ds_send_msg = (int (*)(ds_hdl_t hdl, void *buf, size_t buflen))
+ dlsym(etm_dl_hdl, "ds_send_msg");
+ if (etm_ds_send_msg == NULL) {
+ fmd_hdl_debug(hdl, "error: dlsym(ds_send_msg) failed\n");
+ rc = -ENOENT;
+ }
+
+ etm_ds_recv_msg = (int (*)(ds_hdl_t hdl, void *buf, size_t buflen,
+ size_t *msglen))dlsym(etm_dl_hdl, "ds_recv_msg");
+ if (etm_ds_recv_msg == NULL) {
+ fmd_hdl_debug(hdl, "error: dlsym(ds_recv_msg) failed\n");
+ rc = -ENOENT;
+ }
+
+ etm_ds_fini = (int (*)(void))dlsym(etm_dl_hdl, "ds_fini");
+ if (etm_ds_fini == NULL) {
+ fmd_hdl_debug(hdl, "error: dlsym(ds_fini) failed\n");
+ rc = -ENOENT;
+ }
+
+ if (rc == -ENOENT) {
+ (void) dlclose(etm_dl_hdl);
+ }
+ return (rc);
+
+} /* etm_ds_init() */
+
+
+/*
* -------------------------- FMD entry points -------------------------------
*/
@@ -2095,9 +3720,11 @@ _fmd_init(fmd_hdl_t *hdl)
{
struct timeval tmv; /* timeval */
ssize_t n; /* gen use */
- ldom_hdl_t *lhp; /* ldom pointer */
const struct facility *fp; /* syslog facility matching */
char *facname; /* syslog facility property */
+ uint32_t type_mask; /* type of the local host */
+ int rc; /* funcs return code */
+
if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
return; /* invalid data in configuration file */
@@ -2106,109 +3733,232 @@ _fmd_init(fmd_hdl_t *hdl)
fmd_hdl_debug(hdl, "info: module initializing\n");
init_hdl = hdl;
- lhp = ldom_init(etm_init_alloc, etm_init_free);
+ etm_lhp = ldom_init(etm_init_alloc, etm_init_free);
/*
- * Do not load this module if it is runing on a guest ldom.
+ * decide the ldom type, do initialization accordingly
*/
- if (ldom_major_version(lhp) == 1 && ldom_on_service(lhp) == 0) {
+ if ((rc = ldom_get_type(etm_lhp, &type_mask)) != 0) {
+ fmd_hdl_debug(hdl, "error: can't decide ldom type\n");
fmd_hdl_debug(hdl, "info: module unregistering\n");
- ldom_fini(lhp);
+ ldom_fini(etm_lhp);
fmd_hdl_unregister(hdl);
return;
- } else {
- ldom_fini(lhp);
}
- /* setup statistics and properties from FMD */
+ if ((type_mask & LDOM_TYPE_LEGACY) || (type_mask & LDOM_TYPE_CONTROL)) {
+ if (type_mask & LDOM_TYPE_LEGACY) {
+ /*
+ * running on a legacy sun4v domain,
+ * act as the the old sun4v
+ */
+ etm_ldom_type = LDOM_TYPE_LEGACY;
+ fmd_hdl_debug(hdl, "info: running as the old sun4v\n");
+ ldom_fini(etm_lhp);
+ } else if (type_mask & LDOM_TYPE_CONTROL) {
+ etm_ldom_type = LDOM_TYPE_CONTROL;
+ fmd_hdl_debug(hdl, "info: running as control domain\n");
+
+ /*
+ * looking for libds.so.1.
+ * If not found, don't do DS registration. As a result,
+ * there will be no DS callbacks or other DS services.
+ */
+ if (etm_ds_init(hdl) >= 0) {
+ etm_filter_init(hdl);
+ etm_ckpt_init(hdl);
+
+ flags = FMD_XPRT_RDWR | FMD_XPRT_ACCEPT;
+
+ /*
+ * ds client registration
+ */
+ if ((rc = (*etm_ds_clnt_reg)(&iosvc_caps,
+ &iosvc_ops))) {
+ fmd_hdl_debug(hdl,
+ "error: ds_clnt_reg(): errno %d\n", rc);
+ }
+ } else {
+ fmd_hdl_debug(hdl, "error: dlopen() libds "
+ "failed, continue without the DS services");
+ }
- (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
- sizeof (etm_stats) / sizeof (fmd_stat_t), (fmd_stat_t *)&etm_stats);
+ /*
+ * register for ldom status events
+ */
+ if ((rc = ldom_register_event(etm_lhp,
+ ldom_event_handler, hdl))) {
+ fmd_hdl_debug(hdl,
+ "error: ldom_register_event():"
+ " errno %d\n", rc);
+ }
- etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
- etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl,
- ETM_PROP_NM_DEBUG_MAX_EV_CNT);
- fmd_hdl_debug(hdl, "info: etm_debug_lvl %d "
- "etm_debug_max_ev_cnt %d\n", etm_debug_lvl, etm_debug_max_ev_cnt);
+ /*
+ * create the thread for handling both the ldom status
+ * change and service events
+ */
+ etm_async_e_tid = fmd_thr_create(hdl,
+ etm_async_event_handler, hdl);
+ }
- etm_resp_q_max_len = fmd_prop_get_int32(hdl,
- ETM_PROP_NM_MAX_RESP_Q_LEN);
- etm_stats.etm_resp_q_max_len.fmds_value.ui64 = etm_resp_q_max_len;
- etm_bad_acc_to_sec = fmd_prop_get_int32(hdl,
- ETM_PROP_NM_BAD_ACC_TO_SEC);
+ /* setup statistics and properties from FMD */
- /* obtain an FMD transport handle so we can post FMA events later */
+ (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
+ sizeof (etm_stats) / sizeof (fmd_stat_t),
+ (fmd_stat_t *)&etm_stats);
- etm_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
+ etm_fma_resp_wait_time = fmd_prop_get_int32(hdl,
+ ETM_PROP_NM_FMA_RESP_WAIT_TIME);
+ etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
+ etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl,
+ ETM_PROP_NM_DEBUG_MAX_EV_CNT);
+ fmd_hdl_debug(hdl, "info: etm_debug_lvl %d "
+ "etm_debug_max_ev_cnt %d\n", etm_debug_lvl,
+ etm_debug_max_ev_cnt);
- /* encourage protocol transaction id to be unique per module load */
+ etm_resp_q_max_len = fmd_prop_get_int32(hdl,
+ ETM_PROP_NM_MAX_RESP_Q_LEN);
+ etm_stats.etm_resp_q_max_len.fmds_value.ui64 =
+ etm_resp_q_max_len;
+ etm_bad_acc_to_sec = fmd_prop_get_int32(hdl,
+ ETM_PROP_NM_BAD_ACC_TO_SEC);
- (void) gettimeofday(&tmv, NULL);
- etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) |
- ((unsigned long)tmv.tv_usec >> 10));
+ /*
+ * obtain an FMD transport handle so we can post
+ * FMA events later
+ */
- /* init the ETM transport */
+ etm_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
- if ((n = etm_xport_init(hdl)) != 0) {
- fmd_hdl_error(hdl, "error: bad xport init errno %d\n", (-n));
- fmd_hdl_unregister(hdl);
- return;
- }
+ /*
+ * encourage protocol transaction id to be unique per module
+ * load
+ */
- /*
- * Cache any properties we use every time we receive an alert.
- */
- syslog_file = fmd_prop_get_int32(hdl, ETM_PROP_NM_SYSLOGD);
- syslog_cons = fmd_prop_get_int32(hdl, ETM_PROP_NM_CONSOLE);
+ (void) gettimeofday(&tmv, NULL);
+ etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) |
+ ((unsigned long)tmv.tv_usec >> 10));
- if (syslog_file && (syslog_logfd = open("/dev/conslog",
- O_WRONLY | O_NOCTTY)) == -1) {
- fmd_hdl_error(hdl, "error: failed to open /dev/conslog");
- syslog_file = 0;
- }
+ /* init the ETM transport */
- if (syslog_cons && (syslog_msgfd = open("/dev/sysmsg",
- O_WRONLY | O_NOCTTY)) == -1) {
- fmd_hdl_error(hdl, "error: failed to open /dev/sysmsg");
- syslog_cons = 0;
- }
+ if ((n = etm_xport_init(hdl)) != 0) {
+ fmd_hdl_error(hdl, "error: bad xport init errno %d\n",
+ (-n));
+ fmd_hdl_unregister(hdl);
+ return;
+ }
- if (syslog_file) {
/*
- * Look up the value of the "facility" property and use it to
- * determine * what syslog LOG_* facility value we use to
- * fill in our log_ctl_t.
+ * Cache any properties we use every time we receive an alert.
*/
- facname = fmd_prop_get_string(hdl, ETM_PROP_NM_FACILITY);
+ syslog_file = fmd_prop_get_int32(hdl, ETM_PROP_NM_SYSLOGD);
+ syslog_cons = fmd_prop_get_int32(hdl, ETM_PROP_NM_CONSOLE);
- for (fp = syslog_facs; fp->fac_name != NULL; fp++) {
- if (strcmp(fp->fac_name, facname) == 0)
- break;
+ if (syslog_file && (syslog_logfd = open("/dev/conslog",
+ O_WRONLY | O_NOCTTY)) == -1) {
+ fmd_hdl_error(hdl,
+ "error: failed to open /dev/conslog");
+ syslog_file = 0;
}
- if (fp->fac_name == NULL) {
- fmd_hdl_error(hdl, "error: invalid 'facility'"
- " setting: %s\n", facname);
- syslog_file = 0;
- } else {
- syslog_facility = fp->fac_value;
- syslog_ctl.flags = SL_CONSOLE | SL_LOGONLY;
+ if (syslog_cons && (syslog_msgfd = open("/dev/sysmsg",
+ O_WRONLY | O_NOCTTY)) == -1) {
+ fmd_hdl_error(hdl, "error: failed to open /dev/sysmsg");
+ syslog_cons = 0;
}
- fmd_prop_free_string(hdl, facname);
- }
+ if (syslog_file) {
+ /*
+ * Look up the value of the "facility" property and
+ * use it to determine * what syslog LOG_* facility
+ * value we use to fill in our log_ctl_t.
+ */
+ facname = fmd_prop_get_string(hdl,
+ ETM_PROP_NM_FACILITY);
+
+ for (fp = syslog_facs; fp->fac_name != NULL; fp++) {
+ if (strcmp(fp->fac_name, facname) == 0)
+ break;
+ }
- /*
- * start the message responder and the connection acceptance server;
- * request protocol version be negotiated after waiting a second
- * for the receiver to be ready to start handshaking
- */
+ if (fp->fac_name == NULL) {
+ fmd_hdl_error(hdl, "error: invalid 'facility'"
+ " setting: %s\n", facname);
+ syslog_file = 0;
+ } else {
+ syslog_facility = fp->fac_value;
+ syslog_ctl.flags = SL_CONSOLE | SL_LOGONLY;
+ }
+
+ fmd_prop_free_string(hdl, facname);
+ }
+
+ /*
+ * start the message responder and the connection acceptance
+ * server; request protocol version be negotiated after waiting
+ * a second for the receiver to be ready to start handshaking
+ */
+
+ etm_resp_tid = fmd_thr_create(hdl, etm_responder, hdl);
+ etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl);
- etm_resp_tid = fmd_thr_create(hdl, etm_responder, hdl);
- etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl);
+ (void) etm_sleep(ETM_SLEEP_QUIK);
+ etm_req_ver_negot(hdl);
- (void) etm_sleep(ETM_SLEEP_QUIK);
- etm_req_ver_negot(hdl);
+ } else if (type_mask & LDOM_TYPE_ROOT) {
+ etm_ldom_type = LDOM_TYPE_ROOT;
+ fmd_hdl_debug(hdl, "info: running as root domain\n");
+
+ /*
+ * looking for libds.so.1.
+ * If not found, don't do DS registration. As a result,
+ * there will be no DS callbacks or other DS services.
+ */
+ if (etm_ds_init(hdl) < 0) {
+ fmd_hdl_debug(hdl,
+ "error: dlopen() libds failed, "
+ "module unregistering\n");
+ ldom_fini(etm_lhp);
+ fmd_hdl_unregister(hdl);
+ return;
+ }
+
+ /*
+ * DS service registration
+ */
+ if ((rc = (*etm_ds_svc_reg)(&iosvc_caps, &iosvc_ops))) {
+ fmd_hdl_debug(hdl, "error: ds_svc_reg(): errno %d\n",
+ rc);
+ }
+
+ /*
+ * this thread is created for ds_reg_cb/ds_unreg_cb
+ */
+ etm_async_e_tid = fmd_thr_create(hdl,
+ etm_async_event_handler, hdl);
+
+ flags = FMD_XPRT_RDWR;
+ } else if ((type_mask & LDOM_TYPE_IO) || (type_mask == 0)) {
+ /*
+ * Do not load this module if it is
+ * . runing on a non-root ldom
+ * . the domain owns no io devices
+ */
+ fmd_hdl_debug(hdl,
+ "info: non-root ldom, module unregistering\n");
+ ldom_fini(etm_lhp);
+ fmd_hdl_unregister(hdl);
+ return;
+ } else {
+ /*
+ * place holder, all other cases. unload etm for now
+ */
+ fmd_hdl_debug(hdl,
+ "info: other ldom type, module unregistering\n");
+ ldom_fini(etm_lhp);
+ fmd_hdl_unregister(hdl);
+ return;
+ }
fmd_hdl_debug(hdl, "info: module initialized ok\n");
@@ -2231,6 +3981,13 @@ etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
size_t buflen; /* size of packed FMA event */
uint8_t *buf; /* tmp buffer for packed FMA event */
+ /*
+ * if this is running on a Root Domain, ignore the events,
+ * return right away
+ */
+ if (etm_ldom_type == LDOM_TYPE_ROOT)
+ return;
+
buflen = 0;
if ((n = nvlist_size(evp, &buflen, NV_ENCODE_XDR)) != 0) {
fmd_hdl_error(hdl, "error: FMA event dropped: "
@@ -2267,6 +4024,20 @@ etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
buf = fmd_hdl_zalloc(hdl, buflen, FMD_SLEEP);
+ /*
+ * increment the ttl value if the event is from remote (a root domain)
+ * uncomment this when enabling fault forwarding from Root domains
+ * to Control domain.
+ *
+ * uint8_t ttl;
+ * if (fmd_event_local(hdl, evp) != FMD_EVF_LOCAL) {
+ * if (nvlist_lookup_uint8(evp, FMD_EVN_TTL, &ttl) == 0) {
+ * (void) nvlist_remove(evp, FMD_EVN_TTL, DATA_TYPE_UINT8);
+ * (void) nvlist_add_uint8(evp, FMD_EVN_TTL, ttl + 1);
+ * }
+ * }
+ */
+
if ((n = nvlist_pack(evp, (char **)&buf, &buflen,
NV_ENCODE_XDR, 0)) != 0) {
fmd_hdl_error(hdl, "error: FMA event dropped: "
@@ -2348,6 +4119,106 @@ etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
} /* etm_recv() */
+
+/*
+ * etm_send - receive an FMA event from FMD and enQ it in the iosvc.Q.
+ * etm_send_to_remote_root() deQ and xprt the FMA events to a
+ * remote root domain
+ * return FMD_SEND_SUCCESS for success,
+ * FMD_SEND_FAILED for error
+ */
+
+/*ARGSUSED*/
+int
+etm_send(fmd_hdl_t *fmd_hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl)
+{
+ uint32_t pack_it; /* whether to pack/enq the event */
+ etm_pack_msg_type_t msg_type;
+ /* tell etm_pack_ds_msg() what to do */
+ etm_iosvc_t *iosvc; /* ptr to cur iosvc struct */
+ char *class; /* nvlist class name */
+
+ pack_it = 1;
+ msg_type = FMD_XPRT_OTHER_MSG;
+
+ (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
+ if (class == NULL) {
+ pack_it = 0;
+ } else {
+ if (etm_debug_lvl >= 1) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: evp class= %s in etm_send\n", class);
+ }
+
+ if (etm_ldom_type == LDOM_TYPE_CONTROL) {
+ iosvc =
+ (etm_iosvc_t *)fmd_xprt_getspecific(fmd_hdl, xp);
+
+ /*
+ * check the flag FORWARDING_FAULTS_TO_CONTROL to
+ * decide if or not to drop fault subscription
+ * control msgs
+ */
+ if (strcmp(class, "resource.fm.xprt.subscribe") == 0) {
+ pack_it = 0;
+ /*
+ * if (FORWARDING_FAULTS_TO_CONTROL == 1) {
+ * (void) nvlist_lookup_string(nvl,
+ * FM_RSRC_XPRT_SUBCLASS, &subclass);
+ * if (strcmp(subclass, "list.suspect")
+ * == 0) {
+ * pack_it = 1;
+ * msg_action = FMD_XPRT_OTHER_MSG;
+ * }
+ * if (strcmp(subclass, "list.repaired")
+ * == 0) {
+ * pack_it = 1;
+ * msg_action = FMD_XPRT_OTHER_MSG;
+ * }
+ * }
+ */
+ }
+ if (strcmp(class, "resource.fm.xprt.run") == 0) {
+ pack_it = 1;
+ msg_type = FMD_XPRT_RUN_MSG;
+ }
+ } else { /* has to be the root domain ldom */
+ iosvc = &io_svc;
+ /*
+ * drop all ereport and fault subscriptions
+ * are we dropping too much here, more than just ereport
+ * and fault subscriptions? need to check
+ */
+ if (strcmp(class, "resource.fm.xprt.subscribe") == 0)
+ pack_it = 0;
+ if (strcmp(class, "resource.fm.xprt.run") == 0) {
+ pack_it = 1;
+ msg_type = FMD_XPRT_RUN_MSG;
+ }
+ }
+ }
+
+ if (pack_it) {
+ if (etm_debug_lvl >= 1) {
+ fmd_hdl_debug(fmd_hdl,
+ "info: ldom name returned from xprt get specific="
+ "%s xprt=%lld\n", iosvc->ldom_name, xp);
+ }
+ /*
+ * pack the etm msg for the DS library and enq in io_svc->Q
+ * when the hdrp is NULL, the packing func will use the static
+ * iosvc_hdr
+ */
+ (void) etm_pack_ds_msg(fmd_hdl, iosvc, NULL, 0, nvl, msg_type,
+ ETM_CKPT_NOOP);
+ }
+
+ return (FMD_SEND_SUCCESS);
+
+} /* etm_send() */
+
+
+
/*
* _fmd_fini - stop the server daemon and teardown the transport
*/
@@ -2355,7 +4226,10 @@ etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
void
_fmd_fini(fmd_hdl_t *hdl)
{
- ssize_t n; /* gen use */
+ ssize_t n; /* gen use */
+ etm_iosvc_t *iosvc; /* ptr to insvc struct */
+ etm_iosvc_q_ele_t msg_ele; /* iosvc msg ele */
+ uint32_t i; /* for loop var */
fmd_hdl_debug(hdl, "info: module finalizing\n");
@@ -2375,20 +4249,96 @@ _fmd_fini(fmd_hdl_t *hdl)
etm_resp_tid = NULL;
} /* if responder thread was successfully created */
- /* teardown the transport and cleanup syslogging */
+ if (etm_async_e_tid != NULL) {
+ fmd_thr_signal(hdl, etm_async_e_tid);
+ fmd_thr_destroy(hdl, etm_async_e_tid);
+ etm_async_e_tid = NULL;
+ } /* if async event handler thread was successfully created */
- if ((n = etm_xport_fini(hdl)) != 0) {
- fmd_hdl_error(hdl, "warning: xport fini errno %d\n", (-n));
- }
- if (etm_fmd_xprt != NULL) {
- fmd_xprt_close(hdl, etm_fmd_xprt);
+
+ if ((etm_ldom_type == LDOM_TYPE_LEGACY) ||
+ (etm_ldom_type == LDOM_TYPE_CONTROL)) {
+
+ /* teardown the transport and cleanup syslogging */
+ if ((n = etm_xport_fini(hdl)) != 0) {
+ fmd_hdl_error(hdl, "warning: xport fini errno %d\n",
+ (-n));
+ }
+ if (etm_fmd_xprt != NULL) {
+ fmd_xprt_close(hdl, etm_fmd_xprt);
+ }
+
+ if (syslog_logfd != -1) {
+ (void) close(syslog_logfd);
+ }
+ if (syslog_msgfd != -1) {
+ (void) close(syslog_msgfd);
+ }
}
- if (syslog_logfd != -1) {
- (void) close(syslog_logfd);
+ if (etm_ldom_type == LDOM_TYPE_CONTROL) {
+ if (ldom_unregister_event(etm_lhp))
+ fmd_hdl_debug(hdl, "ldom_unregister_event() failed\n");
+
+ /*
+ * on control side, need to go thru every iosvc struct to
+ * 1) process remaining events in the iosvc Q:
+ * for plan A:
+ * discard remaining events in the Q/free the memory,
+ * since fmd_xprt_log() already logged in Control D's FMD
+ * 2) unregister the ds_hdl if valid
+ * 3) close the fmd_xprt if it has not been closed
+ */
+ for (i = 0; i < NUM_OF_ROOT_DOMAINS; i++) {
+ if (iosvc_list[i].ldom_name[0] != '\0') {
+ /*
+ * found an iosvc struct for a root domain
+ */
+ iosvc = &iosvc_list[i];
+ (void) pthread_mutex_lock(&iosvc_list_lock);
+ etm_iosvc_cleanup(hdl, iosvc);
+ (void) pthread_mutex_unlock(&iosvc_list_lock);
+
+ } else {
+ /*
+ * reach the end of existing iosvc structures
+ */
+ continue;
+ }
+ } /* for i<NUM_OF_ROOT_DOMAINS */
+ etm_ckpt_fini(hdl);
+ etm_filter_fini(hdl);
+
+ ldom_fini(etm_lhp);
+
+ } else if (etm_ldom_type == LDOM_TYPE_ROOT) {
+ iosvc = &io_svc;
+ if (iosvc->send_tid != NULL) {
+ fmd_thr_signal(hdl, iosvc->send_tid);
+ fmd_thr_destroy(hdl, iosvc->send_tid);
+ iosvc->send_tid = NULL;
+ } /* if io svc send thread was successfully created */
+
+ if (iosvc->recv_tid != NULL) {
+ fmd_thr_signal(hdl, iosvc->recv_tid);
+ fmd_thr_destroy(hdl, iosvc->recv_tid);
+ iosvc->recv_tid = NULL;
+ } /* if io svc receive thread was successfully created */
+
+ (void) pthread_mutex_lock(&iosvc->msg_q_lock);
+ while (iosvc->msg_q_cur_len > 0) {
+ (void) etm_iosvc_msg_deq(hdl, iosvc, &msg_ele);
+ fmd_hdl_free(hdl, msg_ele.msg, msg_ele.msg_size);
+ }
+ (void) pthread_mutex_unlock(&iosvc->msg_q_lock);
+
+ if (iosvc->fmd_xprt != NULL)
+ fmd_xprt_close(hdl, iosvc->fmd_xprt);
+ ldom_fini(etm_lhp);
}
- if (syslog_msgfd != -1) {
- (void) close(syslog_msgfd);
+ if (etm_ds_fini) {
+ (*etm_ds_fini)();
+ (void) dlclose(etm_dl_hdl);
}
fmd_hdl_debug(hdl, "info: module finalized ok\n");
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.c b/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.c
new file mode 100644
index 0000000000..36edbd8332
--- /dev/null
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.c
@@ -0,0 +1,681 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * etm_ckpt.c
+ * Description:
+ * Checkpoint the ereport events for persitence across fmd restart.
+ *
+ * Each ereport is stored in a named buffer. Each ereport is uniquely
+ * indentified by a id which is consists of a number of ereport fields. The
+ * name of the buffer is derived from the id.
+ *
+ * All ereport ids are stored in the circular list which is saved in a
+ * separate buffer.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fm/ldom.h>
+#include <sys/fm/protocol.h>
+#include <fm/fmd_api.h>
+#include <fm/libtopo.h>
+#include <fm/topo_hc.h>
+
+#include "etm_etm_proto.h"
+#include "etm_iosvc.h"
+#include "etm_ckpt.h"
+#include "etm_filter.h"
+
+#define ETM_ATTR_PRIMARY "primary"
+#define ETM_ATTR_TOD "__tod"
+#define ETM_LDOM_PRIMARY "primary"
+
+/*
+ * -------------------------- private variables ------------------------------
+ */
+
+static etm_ckpt_id_list_t *etm_id_lst = NULL; /* list of ereports ids */
+
+static pthread_mutex_t etm_id_lst_lock; /* list lock */
+
+/*
+ * -------------------------- functions --------------------------------------
+ */
+
+/*
+ * etm_ckpt_str_hash()
+ * Description:
+ * Hash a class name to a number
+ */
+static uint_t
+etm_ckpt_str_hash(char *str)
+{
+ uint_t hash = 0; /* hash value */
+
+ if (str == NULL)
+ return (0);
+
+ while (*str != '\0')
+ hash += *str++;
+
+ return (hash);
+}
+
+/*
+ * etm_ckpt_id2str()
+ * Description:
+ * Get the string of an ereport id. It is used as the named buffer that
+ * store the ereport.
+ */
+static void
+etm_ckpt_id2str(etm_ckpt_erpt_id_t *id, char *str, size_t size) {
+ (void) snprintf(str, size, "%s_%llx_%d_%x_%d", ETM_CKPT_ERPT_PREFIX,
+ id->ei_ena, id->ei_hash, id->ei_tod1, id->ei_pri);
+}
+
+/*
+ * etm_ckpt_erpt2id()
+ * Description:
+ * Get the buffer name and ereport id of a given ereport
+ */
+static int
+etm_ckpt_erpt2id(fmd_hdl_t *hdl, nvlist_t *erpt, etm_ckpt_erpt_id_t *id,
+ char *str, int size) {
+ char *class = NULL;
+ uint64_t *tod;
+ uint_t sz;
+ boolean_t pri = B_FALSE;
+
+ bzero(id, sizeof (etm_ckpt_erpt_id_t));
+
+ /* ena */
+ if (nvlist_lookup_uint64(erpt, FM_EREPORT_ENA, &id->ei_ena) != 0) {
+ fmd_hdl_debug(hdl, "Ena not found\n");
+ return (-1);
+ }
+
+ /* class name */
+ (void) nvlist_lookup_string(erpt, FM_CLASS, &class);
+ if (class == NULL) {
+ fmd_hdl_debug(hdl, "%s not found\n", FM_CLASS);
+ return (-1);
+ }
+ if (strncmp(class, FM_EREPORT_CLASS, strlen(FM_EREPORT_CLASS)) != 0) {
+ fmd_hdl_debug(hdl, "Only support checkpointing %s\n",
+ FM_EREPORT_CLASS);
+ return (-1);
+ }
+ id->ei_hash = etm_ckpt_str_hash(class);
+
+ /* tod[1]: fractional of a second */
+ if (nvlist_lookup_uint64_array(erpt, ETM_ATTR_TOD, &tod, &sz) == 0) {
+ if (sz >= 2) {
+ id->ei_tod1 = (uint32_t)tod[1];
+ }
+ }
+
+ /* primary flag */
+ if (nvlist_lookup_boolean_value(erpt, ETM_ATTR_PRIMARY, &pri) == 0) {
+ id->ei_pri = pri ? 1 : 0;
+ }
+
+ etm_ckpt_id2str(id, str, size);
+
+ return (0);
+}
+
+/*
+ * etm_ckpt_il_equal()
+ * Description:
+ * Test if two ereport ids are equal.
+ */
+static boolean_t
+etm_ckpt_il_equal(etm_ckpt_erpt_id_t *i1, etm_ckpt_erpt_id_t *i2)
+{
+ return ((i1->ei_ena == i2->ei_ena) && (i1->ei_tod1 == i2->ei_tod1) &&
+ (i1->ei_pri == i2->ei_pri) && (i1->ei_hash == i2->ei_hash));
+}
+
+/*
+ * etm_ckpt_il_resize()
+ * Description:
+ * Increase the size of the circular list and pack its entries.
+ */
+static void
+etm_ckpt_il_resize(fmd_hdl_t *hdl, uint_t factor)
+{
+ etm_ckpt_id_list_t *il1, *il2; /* temp lists */
+ size_t sz1, sz2; /* sizes of lists */
+ int i, next; /* temp counters */
+ etm_ckpt_erpt_id_t *p1, *p2, *s1, *s2; /* temp id pointers */
+ etm_ckpt_erpt_id_t blank; /* blank ereport id */
+
+ if (factor == 0)
+ return;
+
+ /* the present queue */
+ il1 = etm_id_lst;
+ sz1 = sizeof (etm_ckpt_id_list_t) + il1->il_ids_sz;
+
+ /* Create an empty queue with a new size */
+ sz2 = sizeof (etm_ckpt_id_list_t) + (factor * il1->il_ids_sz);
+ il2 = fmd_hdl_zalloc(hdl, sz2, FMD_SLEEP);
+ il2->il_ver = ETM_CKPT_VERSION;
+ il2->il_max = factor * etm_id_lst->il_max;
+ il2->il_ids_sz = factor * il1->il_ids_sz;
+
+ /* pointers to the two arrays of entries */
+ bzero(&blank, sizeof (blank));
+ s1 = (etm_ckpt_erpt_id_t *)
+ ((ptrdiff_t)il1 + sizeof (etm_ckpt_id_list_t));
+ s2 = (etm_ckpt_erpt_id_t *)
+ ((ptrdiff_t)il2 + sizeof (etm_ckpt_id_list_t));
+
+ /* copy non-empty ereport ids from list il1 to il2. Toss the blank. */
+ if (il1->il_head != il1->il_tail) {
+ for (i = il1->il_head; i != il1->il_tail; i = next) {
+ next = (i + 1) % il1->il_max;
+ p1 = s1 + next;
+ if (!etm_ckpt_il_equal(p1, &blank)) {
+ /* copy non-empty entries */
+ il2->il_tail = (il2->il_tail + 1) % il2->il_max;
+ fmd_hdl_debug(hdl, "Copying entry %d to %d\n",
+ next, il2->il_tail);
+ p2 = s2 + il2->il_tail;
+ *p2 = *p1;
+ il2->il_cnt++;
+ }
+ }
+ }
+
+ if (factor == 1) {
+ /* both lists have the same size, update the present list */
+ bcopy(il2, il1, sz1);
+ fmd_hdl_free(hdl, il2, sz2);
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il1, sz1);
+ } else {
+ /* replace the present list */
+ etm_id_lst = il2;
+ fmd_hdl_free(hdl, il1, sz1);
+ /* write to new buffer */
+ fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
+ fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, sz2);
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) il2, sz2);
+ }
+}
+
+/*
+ * etm_ckpt_il_find()
+ * Description:
+ * Find the ereport id in the list.
+ */
+/* ARGSUSED */
+static int
+etm_ckpt_il_find(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id)
+{
+ int i, next; /* temp counter */
+ etm_ckpt_erpt_id_t *p, *s; /* temp erpt id */
+
+ fmd_hdl_debug(hdl, "etm_ckpt_il_find()\n");
+
+ /* empty list */
+ if (etm_id_lst->il_head == etm_id_lst->il_tail) {
+ fmd_hdl_debug(hdl, "find an empty list\n");
+ return (-1);
+ }
+ s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
+ sizeof (etm_ckpt_id_list_t));
+ for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
+ next = (i + 1) % etm_id_lst->il_max;
+ p = s + next;
+ if (etm_ckpt_il_equal(p, id))
+ return (i);
+ }
+
+ return (-1);
+}
+
+/*
+ * etm_ckpt_il_add()
+ * Description:
+ * Add an ereport id in the list.
+ */
+static int
+etm_ckpt_il_add(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
+ int next;
+ etm_ckpt_erpt_id_t *p, *s; /* temp id */
+
+ /*
+ * resize the q if it is full.
+ * If the capacity is less 80%, purge the emtpy entries to make more
+ * room for new entries. Otherwise, double the queue size.
+ */
+ next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
+ if (next == etm_id_lst->il_head) {
+ if ((etm_id_lst->il_cnt * 1.0 / etm_id_lst->il_max) < 0.8) {
+ etm_ckpt_il_resize(hdl, 1);
+ } else {
+ etm_ckpt_il_resize(hdl, 2);
+ }
+
+ /* test if the list again */
+ next = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
+ if (next == etm_id_lst->il_head) {
+ fmd_hdl_error(hdl, "List is full %d %d\n",
+ etm_id_lst->il_head, etm_id_lst->il_tail);
+ }
+ }
+
+ /* Add the id entry at the head */
+ s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
+ sizeof (etm_ckpt_id_list_t));
+ etm_id_lst->il_tail = (etm_id_lst->il_tail + 1) % etm_id_lst->il_max;
+ p = s + etm_id_lst->il_tail;
+ *p = *id;
+ etm_id_lst->il_cnt++;
+
+ return (etm_id_lst->il_tail);
+}
+
+/*
+ * etm_ckpt_il_delete()
+ * Description:
+ * Delete an ereport id from the list.
+ */
+int
+etm_ckpt_il_delete(fmd_hdl_t *hdl, etm_ckpt_erpt_id_t *id) {
+
+ int i, next; /* temp counter */
+ etm_ckpt_erpt_id_t *p, *s; /* temp id pointers */
+ etm_ckpt_erpt_id_t blank; /* blank id */
+
+ /* empty list */
+ if (etm_id_lst->il_tail == etm_id_lst->il_head) {
+ fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
+ return (-1);
+ }
+
+ bzero(&blank, sizeof (blank));
+ s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
+ sizeof (etm_ckpt_id_list_t));
+
+ /* delete leading empty entries */
+ for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
+ next = (i + 1) % etm_id_lst->il_max;
+ p = s + next;
+ if (!etm_ckpt_il_equal(p, &blank)) {
+ break;
+ }
+ etm_id_lst->il_cnt--;
+ etm_id_lst->il_head = next;
+ }
+
+ /* empty queue */
+ if (etm_id_lst->il_head == etm_id_lst->il_tail) {
+ fmd_hdl_debug(hdl, "Empty queue(%d)\n", etm_id_lst->il_head);
+ return (-1);
+ }
+
+ /* find the entry and clear it */
+ for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
+ next = (i + 1) % etm_id_lst->il_max;
+ p = s + next;
+ if (etm_ckpt_il_equal(p, id)) {
+ /* clear the entry */
+ *p = blank;
+ etm_id_lst->il_cnt--;
+
+ /* remove the entry if it is the last one */
+ if (i == etm_id_lst->il_head) {
+ etm_id_lst->il_head = next;
+ }
+ return (i);
+ }
+ }
+
+ return (-1);
+}
+
+
+/*
+ * etm_ckpt_il_restore()
+ * Description:
+ * Restore the idlist named buffer which is the circular list of the
+ * the ereport ids.
+ */
+void
+etm_ckpt_il_restore(fmd_hdl_t *hdl)
+{
+ size_t size; /* buffer size */
+
+ /* get the buffer of the id list */
+ size = fmd_buf_size(hdl, NULL, ETM_CKPT_IL_BUF);
+ if (size < sizeof (etm_ckpt_id_list_t)) {
+ fmd_hdl_debug(hdl, "Buffer name %s do not exist\n",
+ ETM_CKPT_IL_BUF);
+ return;
+ }
+ etm_id_lst = (etm_ckpt_id_list_t *)fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
+ fmd_buf_read(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, size);
+
+ /* check version */
+ if (etm_id_lst->il_ver > ETM_CKPT_VERSION) {
+
+ fmd_hdl_error(hdl, "Unsupport checkpoint version (%#x)\n",
+ etm_id_lst->il_ver);
+ fmd_hdl_free(hdl, (void *) etm_id_lst, size);
+ etm_id_lst = NULL;
+ return;
+ }
+
+ /* check the length */
+ if (etm_id_lst->il_ids_sz != (size - sizeof (etm_ckpt_id_list_t))) {
+ fmd_hdl_debug(hdl, "Invalid ids buffer size (%d, %d)\n",
+ etm_id_lst->il_ids_sz, size);
+ fmd_hdl_free(hdl, (void *) etm_id_lst, size);
+ etm_id_lst = NULL;
+ return;
+ }
+}
+
+/*
+ * etm_ckpt_recover()
+ * Description:
+ * Recover ereports from the checkpointed data and dispatch them to the
+ * ldom queue(s).
+ */
+void
+etm_ckpt_recover(fmd_hdl_t *hdl)
+{
+ int size; /* buffer size */
+ int i, next; /* temp counter */
+ boolean_t dirty = B_FALSE; /* dirty flag */
+ uint64_t did; /* domain id */
+ char name[ETM_LINE_LEN]; /* temp str */
+ char ldom[ETM_LINE_LEN]; /* ldom id */
+ etm_ckpt_erpt_id_t *p, *s; /* temp ereport id */
+ etm_ckpt_erpt_id_t blank; /* blank ereport id */
+ etm_ckpt_erpt_buf_t *ep; /* ereport buffer */
+ size_t sz; /* size of ep */
+ char *buf; /* temp buf */
+ nvlist_t *nvl; /* ereport */
+ etm_iosvc_t *iosvc; /* iosvc data struct */
+
+ /*
+ * restore the circular list of ereport ids
+ */
+ etm_ckpt_il_restore(hdl);
+ if (etm_id_lst == NULL) {
+ fmd_hdl_debug(hdl, "Initialize a new id list\n");
+ size = sizeof (etm_ckpt_id_list_t) +
+ ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
+ etm_id_lst = fmd_hdl_zalloc(hdl, size, FMD_SLEEP);
+ etm_id_lst->il_ver = ETM_CKPT_VERSION;
+ etm_id_lst->il_max = ETM_CKPT_IL_MIN_SIZE;
+ etm_id_lst->il_head = 0;
+ etm_id_lst->il_tail = 0;
+ etm_id_lst->il_ids_sz =
+ ETM_CKPT_IL_MIN_SIZE * sizeof (etm_ckpt_erpt_id_t);
+ fmd_buf_destroy(hdl, NULL, ETM_CKPT_IL_BUF);
+ fmd_buf_create(hdl, NULL, ETM_CKPT_IL_BUF, size);
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
+ size);
+
+ /* commit */
+ fmd_thr_checkpoint(hdl);
+
+ return;
+ }
+
+ /* Empty list */
+ if ((etm_id_lst->il_head == etm_id_lst->il_tail) ||
+ (etm_id_lst->il_cnt == 0)) {
+ return;
+ }
+
+ /* Visit all the entries in the list */
+ bzero(&blank, sizeof (blank));
+ s = (etm_ckpt_erpt_id_t *)((ptrdiff_t)etm_id_lst +
+ sizeof (etm_ckpt_id_list_t));
+ for (i = etm_id_lst->il_head; i != etm_id_lst->il_tail; i = next) {
+ next = (i + 1) % etm_id_lst->il_max;
+ p = s + next;
+ if (etm_ckpt_il_equal(p, &blank)) {
+ fmd_hdl_debug(hdl, "Skip empty entry %d\n", i);
+ continue;
+ }
+
+ etm_ckpt_id2str(p, name, sizeof (name));
+ fmd_hdl_debug(hdl, "Restoring entry %s\n", name);
+ if ((sz = fmd_buf_size(hdl, NULL, name)) == 0) {
+ fmd_hdl_error(hdl, "Clear the stale entry %s\n", name);
+ *p = blank;
+ continue;
+ }
+ ep = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
+ fmd_buf_read(hdl, NULL, name, (void *) ep, sz);
+ buf = (char *)((ptrdiff_t)ep + sizeof (etm_ckpt_erpt_buf_t));
+ nvl = NULL;
+ if (nvlist_unpack(buf, ep->eb_len, &nvl, 0)) {
+ fmd_hdl_debug(hdl, "failed to unpack %s\n", name);
+ fmd_hdl_free(hdl, ep, sz);
+ continue;
+ }
+ fmd_hdl_free(hdl, ep, sz);
+ if (etm_filter_find_ldom_id(hdl, nvl, ldom, ETM_LINE_LEN,
+ &did) || (strcmp(name, ETM_LDOM_PRIMARY) == 0)) {
+ fmd_hdl_debug(hdl, "Discard event %s\n", name);
+ fmd_buf_destroy(hdl, NULL, name);
+ *p = blank;
+ nvlist_free(nvl);
+ dirty = B_TRUE;
+ continue;
+ }
+
+ fmd_hdl_debug(hdl, "Dispatch %s to ldom %s\n", name, ldom);
+
+ /*
+ * Find the queue of the ldom, create it if not exist.
+ * Then insert this event into the queue.
+ */
+ iosvc = etm_iosvc_lookup(hdl, ldom, DS_INVALID_HDL, B_TRUE);
+ if (iosvc != NULL) {
+ (void) etm_pack_ds_msg(hdl, iosvc, NULL, 0, nvl, SP_MSG,
+ ETM_CKPT_RESTORE);
+ }
+ nvlist_free(nvl);
+ }
+ if (dirty) {
+ /* update the buffer of the queue */
+ size = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst,
+ size);
+
+ /* commit */
+ fmd_thr_checkpoint(hdl);
+ }
+
+} /* etm_ckpt_recover */
+
+
+/*
+ * etm_ckpt_add_entry()
+ * Description:
+ * Save an ereport for persistence.
+ */
+int
+etm_ckpt_add_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
+ etm_ckpt_erpt_id_t id;
+ char name[ETM_LINE_LEN];
+ int rc; /* gen use */
+ size_t sz; /* size */
+ size_t buflen; /* sz of packed erpt */
+ uint8_t *buf; /* buffer of erpt */
+ etm_ckpt_erpt_buf_t *hdr;
+
+ /* map ereport to id */
+ bzero(name, ETM_LINE_LEN);
+ rc = etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN);
+ if (rc != 0) {
+ fmd_hdl_debug(hdl, "Invalid ereport\n");
+ return (rc);
+ }
+
+ /*
+ * check for a duplicate entry in the id list
+ * find the ereport buffer and search for the id
+ */
+ if (fmd_buf_size(hdl, NULL, name) > 0 &&
+ etm_ckpt_il_find(hdl, &id) >= 0) {
+ fmd_hdl_debug(hdl, "Duplicate id %s\n", name);
+ return (-1);
+ }
+
+ /* Create the ereport buffer */
+ if (nvlist_size(erpt, &buflen, NV_ENCODE_XDR) != 0) {
+ fmd_hdl_debug(hdl, "nvlist_size fails\n");
+ return (-1);
+ }
+ sz = sizeof (etm_ckpt_erpt_buf_t) + buflen;
+ hdr = (etm_ckpt_erpt_buf_t *)fmd_hdl_zalloc(hdl, sz, FMD_SLEEP);
+ buf = (uint8_t *)((ptrdiff_t)hdr + sizeof (etm_ckpt_erpt_buf_t));
+ hdr->eb_ver = ETM_CKPT_VERSION;
+ hdr->eb_len = buflen;
+ if (nvlist_pack(erpt, (char **)&buf, &buflen, NV_ENCODE_XDR, 0) != 0) {
+ fmd_hdl_free(hdl, hdr, sz);
+ fmd_hdl_debug(hdl, "unpack fails\n");
+ return (-1);
+ }
+ fmd_hdl_debug(hdl, "Add ckpt event(%s, %d)\n", name, sz);
+ fmd_buf_create(hdl, NULL, name, sz);
+ fmd_buf_write(hdl, NULL, name, hdr, sz);
+ fmd_hdl_free(hdl, hdr, sz);
+
+ /* Insert the ereport id into the id list */
+ if (etm_ckpt_il_add(hdl, &id) < 0) {
+ fmd_hdl_debug(hdl, "Insert id %s failed\n", name);
+ fmd_buf_destroy(hdl, NULL, name);
+ return (-1);
+ }
+
+ /* update the buffer of the queue */
+ sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
+
+ /* commit */
+ fmd_thr_checkpoint(hdl);
+
+ return (0);
+}
+
+/*
+ * etm_ckpt_delete_entry()
+ * Description:
+ * Delete an ereport id in the list.
+ */
+static int
+etm_ckpt_delete_entry(fmd_hdl_t *hdl, nvlist_t *erpt) {
+ etm_ckpt_erpt_id_t id;
+ char name[ETM_LINE_LEN];
+ int rc; /* return code */
+ size_t sz; /* size */
+
+ /* get id, id name */
+ bzero(name, ETM_LINE_LEN);
+ if (etm_ckpt_erpt2id(hdl, erpt, &id, name, ETM_LINE_LEN) != 0) {
+ fmd_hdl_debug(hdl, "Invalid ereport\n");
+ return (-1);
+ }
+ fmd_hdl_debug(hdl, "Delete ckpt event(%s)\n", name);
+
+ /* delete the ereport buffer */
+ if (fmd_buf_size(hdl, NULL, name) > 0) {
+ fmd_buf_destroy(hdl, NULL, name);
+ }
+
+ rc = etm_ckpt_il_delete(hdl, &id);
+ if (rc < 0) {
+ fmd_hdl_debug(hdl, "Delete id %s failed\n", name);
+ return (rc);
+ }
+
+ /* update the buffer of the queue */
+ sz = sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz;
+ fmd_buf_write(hdl, NULL, ETM_CKPT_IL_BUF, (void *) etm_id_lst, sz);
+
+ /* commit */
+ fmd_thr_checkpoint(hdl);
+
+ return (rc);
+}
+
+int
+etm_ckpt_add(fmd_hdl_t *hdl, nvlist_t *erpt) {
+
+ int rc; /* return code */
+
+ (void) pthread_mutex_lock(&etm_id_lst_lock);
+
+ rc = etm_ckpt_add_entry(hdl, erpt);
+
+ (void) pthread_mutex_unlock(&etm_id_lst_lock);
+
+ return (rc >= 0 ? 0 : rc);
+}
+
+int
+etm_ckpt_delete(fmd_hdl_t *hdl, nvlist_t *erpt) {
+ int rc; /* return code */
+
+ (void) pthread_mutex_lock(&etm_id_lst_lock);
+
+ rc = etm_ckpt_delete_entry(hdl, erpt);
+
+ (void) pthread_mutex_unlock(&etm_id_lst_lock);
+
+ return (rc >= 0 ? 0 : rc);
+}
+
+/* ARGSUSED */
+void
+etm_ckpt_init(fmd_hdl_t *hdl) {
+ (void) pthread_mutex_init(&etm_id_lst_lock, NULL);
+ etm_id_lst = NULL;
+}
+
+void
+etm_ckpt_fini(fmd_hdl_t *hdl) {
+ if (etm_id_lst != NULL) {
+ fmd_hdl_free(hdl, etm_id_lst,
+ sizeof (etm_ckpt_id_list_t) + etm_id_lst->il_ids_sz);
+ }
+ (void) pthread_mutex_destroy(&etm_id_lst_lock);
+}
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.h b/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.h
new file mode 100644
index 0000000000..d25be56d22
--- /dev/null
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_ckpt.h
@@ -0,0 +1,108 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * etm_ckpt.h
+ *
+ * Header file of checkpointing ereports for persistence
+ *
+ */
+
+#ifndef _ETM_CKPT_H
+#define _ETM_CKPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <fm/fmd_api.h>
+
+#define ETM_CKPT_VERSION 0x10
+#define ETM_CKPT_ERPT_PREFIX "ev"
+#define ETM_LINE_LEN 256
+
+/*
+ * Format of a named buffer that stores an ereport.
+ */
+typedef struct etm_ckpt_erpt_buf {
+ uint8_t eb_ver; /* version major.minor */
+ uint8_t eb_rev; /* reserved field */
+ uint16_t eb_len; /* size of packed ereport */
+ /* nvlist packed erpt event */
+} etm_ckpt_erpt_buf_t;
+
+/*
+ * Ereport id
+ * Each ereport, which is stored in a named buffer, is uniquely identified by
+ * fields in the ereport. The named buffer name is derived from this struct
+ * as following
+ * ev_${ena}_${hash{class)}_${tod[1]}_${primary}
+ */
+typedef struct etm_ckpt_erpt_id {
+ uint64_t ei_ena; /* ereport ena */
+ uint32_t ei_tod1; /* tod[1]: fractional second */
+ uint16_t ei_hash; /* hash(ereport class name) */
+ uint8_t ei_pri; /* primary field */
+ uint8_t ei_rev; /* reserved field */
+} etm_ckpt_erpt_id_t;
+
+/*
+ * A circular list of ereport ids
+ */
+typedef struct etm_ckpt_id_list {
+ uint8_t il_ver; /* version major.minor */
+ uint8_t il_rev1; /* reserve field */
+ uint16_t il_max; /* max number of erpt ids in list */
+ uint16_t il_cnt; /* number of valid ids in list */
+ uint16_t il_head; /* head of the list */
+ uint16_t il_tail; /* tail of the list */
+ uint16_t il_ids_sz; /* size of the array of ids */
+ uint32_t il_rev2; /* reserve field */
+ /* array of ids */
+} etm_ckpt_id_list_t;
+
+#define ETM_CKPT_IL_BUF "idlist"
+#define ETM_CKPT_IL_MIN_SIZE 0x8
+
+/*
+ * Checkpoint options
+ */
+#define ETM_CKPT_NOOP 0x0
+#define ETM_CKPT_SAVE 0x1
+#define ETM_CKPT_RESTORE 0x2
+
+void etm_ckpt_recover(fmd_hdl_t *hdl);
+int etm_ckpt_add(fmd_hdl_t *hdl, nvlist_t *evp);
+int etm_ckpt_delete(fmd_hdl_t *hdl, nvlist_t *evp);
+
+void etm_ckpt_init(fmd_hdl_t *hdl);
+void etm_ckpt_fini(fmd_hdl_t *hdl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETM_CKPT_H */
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.c b/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.c
new file mode 100644
index 0000000000..cb1cfb27c7
--- /dev/null
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.c
@@ -0,0 +1,366 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * etm_filter.c
+ * Description:
+ * Find the ldom that own the resource specified in the detector field
+ * of the ereport.
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fm/ldom.h>
+#include <sys/fm/protocol.h>
+#include <fm/fmd_api.h>
+#include <fm/libtopo.h>
+#include <fm/topo_hc.h>
+
+#include "etm_filter.h"
+
+static etm_prc_t *etm_rcs; /* vector of root complexes */
+static uint16_t etm_rc_cnt; /* count of rc entries in rcs */
+static uint16_t etm_rc_max; /* max entries allowed in rcs */
+static pthread_mutex_t etm_rc_lock; /* lock of the rc vector */
+
+
+extern ldom_hdl_t *etm_lhp; /* libldom handle */
+
+/* ARGSUSED */
+static int
+etm_pciexrc_walker(topo_hdl_t *thp, tnode_t *node, void *arg)
+{
+ int i; /* temp counter */
+ int n; /* temp size of new vector */
+ int err; /* temp error var */
+ char *str; /* topo node value */
+ fmd_hdl_t *hdl = arg; /* etm mod hdl */
+ etm_prc_t *rcl; /* root complex vector */
+ etm_prc_t *p; /* temp pointer */
+ topo_instance_t ins; /* rc id */
+ uint64_t ba; /* bus address */
+
+ /* pciexrc node */
+ if (strcmp(topo_node_name(node), PCIEX_ROOT) != 0)
+ return (TOPO_WALK_NEXT);
+
+ if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV, &str,
+ &err) != 0)
+ return (TOPO_WALK_NEXT);
+
+ /* physical id and bus address of a root complex */
+ ins = topo_node_instance(node);
+ (void) sscanf(str, "/pci@%llx", &ba);
+
+ /*
+ * prc vector is full, so double its size
+ */
+ if (etm_rc_cnt >= etm_rc_max) {
+ n = (etm_rc_max == 0) ? 1 : 2 * etm_rc_max;
+ rcl = fmd_hdl_zalloc(hdl, n * sizeof (etm_prc_t), FMD_SLEEP);
+ for (i = 0, p = rcl; i < n; i++, p++) {
+ p->prc_id = -1;
+ p->prc_status = -1;
+ }
+ if (etm_rcs != NULL) {
+ bcopy(etm_rcs, rcl, etm_rc_max * sizeof (etm_prc_t));
+ fmd_hdl_free(hdl, etm_rcs,
+ etm_rc_max * sizeof (etm_prc_t));
+ }
+ etm_rcs = rcl;
+ etm_rc_max = n;
+ }
+
+ if (etm_rc_cnt >= etm_rc_max) {
+ fmd_hdl_abort(hdl, "rcs is full. Expect counter value %d<%d\n",
+ etm_rc_cnt, etm_rc_max);
+ }
+
+ /* Add the rc at the end of the list */
+ p = etm_rcs + etm_rc_cnt;
+ p->prc_id = ins;
+ p->prc_cfg_handle = ba;
+ etm_rc_cnt++;
+
+ return (TOPO_WALK_NEXT);
+}
+
+/*
+ * etm_pciexrc_init()
+ * Description:
+ * Walk through the topology to find the pciexrc nodes. Then save the
+ * physical instances and bus addreses in a vector.
+ */
+static void
+etm_pciexrc_init(fmd_hdl_t *hdl)
+{
+ topo_hdl_t *thp; /* topo handle */
+ topo_walk_t *twp; /* topo walk handle */
+ int err; /* topo error */
+
+ if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL)
+ return;
+ twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, etm_pciexrc_walker,
+ (void *) hdl, &err);
+ if (twp == NULL) {
+ fmd_hdl_topo_rele(hdl, thp);
+ return;
+ }
+ (void) topo_walk_step(twp, TOPO_WALK_CHILD);
+ topo_walk_fini(twp);
+ fmd_hdl_topo_rele(hdl, thp);
+}
+
+/*
+ * etm_update_prc()
+ * Description:
+ * Query ldmd for the ldom id
+ */
+void
+etm_update_prc(fmd_hdl_t *hdl, etm_prc_t *prc)
+{
+ char name[MAX_LDOM_NAME]; /* domain name */
+ uint64_t virt_cfg_handle; /* bus address from ldmd */
+ uint64_t did; /* domain id */
+
+ if (prc == NULL)
+ return;
+
+ /* call libldom to find the ldom id */
+ prc->prc_status = ldom_find_id(etm_lhp, prc->prc_cfg_handle,
+ LDOM_RSRC_PCI, &virt_cfg_handle, name, MAX_LDOM_NAME, &did);
+ if (prc->prc_status) {
+ return;
+ }
+
+ /* cache the ldom id */
+ prc->prc_did = did;
+ if (prc->prc_name != NULL) {
+ fmd_hdl_free(hdl, prc->prc_name, prc->prc_name_sz);
+ }
+ prc->prc_name_sz = strlen(name) + 1;
+ prc->prc_name = fmd_hdl_zalloc(hdl, prc->prc_name_sz, FMD_SLEEP);
+ (void) strncpy(prc->prc_name, name, prc->prc_name_sz);
+}
+
+/*
+ * etm_find_ldom_id()
+ * Description:
+ * Find the ldom name and the domain id that owns the resource specified in
+ * the ereport detector
+ */
+int
+etm_filter_find_ldom_id(fmd_hdl_t *hdl, nvlist_t *evp, char *name,
+ int name_size, uint64_t *did)
+{
+ char *str; /* temp string */
+ char *s; /* temp string */
+ int i; /* loop counter */
+ int ins; /* instance number */
+ nvlist_t *det; /* ereport detector */
+ nvlist_t **hcl; /* hc name-value pair list */
+ uint_t sz; /* size of hcl */
+ etm_prc_t *prc; /* root complex */
+
+ /* check paramters */
+ if (name == NULL || name_size <= 0) {
+ fmd_hdl_debug(hdl, "Invalid parameters");
+ return (-1);
+ }
+
+ /* must be an ereport */
+ if ((nvlist_lookup_string(evp, FM_CLASS, &str) != 0) ||
+ (strncmp(str, FM_EREPORT_CLASS, strlen(FM_EREPORT_CLASS)) != 0)) {
+ fmd_hdl_debug(hdl, "not an ereport");
+ return (-1);
+ }
+
+ /* the detector is of hc-scheme */
+ if (nvlist_lookup_nvlist(evp, FM_EREPORT_DETECTOR, &det) != 0) {
+ fmd_hdl_debug(hdl, "ereport detector not found");
+ return (-1);
+ }
+ if ((nvlist_lookup_string(det, FM_FMRI_SCHEME, &str) != 0) ||
+ (strcmp(str, FM_FMRI_SCHEME_HC) != 0)) {
+ fmd_hdl_debug(hdl, "detector is not hc-schemed\n");
+ return (-1);
+ }
+
+ /*
+ * Find the pciexrc and extract the instance number
+ */
+ if (nvlist_lookup_nvlist_array(det, FM_FMRI_HC_LIST, &hcl, &sz) != 0) {
+ fmd_hdl_debug(hdl, "%s is not found\n", FM_FMRI_HC_LIST);
+ return (-1);
+ }
+ for (i = 0; i < sz; i++) {
+ if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &str) == 0 &&
+ nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &s) == 0 &&
+ strcmp(str, PCIEX_ROOT) == 0) {
+ (void) sscanf(s, "%d", &ins);
+ break;
+ }
+ }
+ if (i >= sz) {
+ fmd_hdl_debug(hdl, "%s not found\n", PCIEX_ROOT);
+ return (-1);
+ }
+
+ (void) pthread_mutex_lock(&etm_rc_lock);
+
+ /* search the entry by the physical instance number */
+ for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt;
+ i++, prc++) {
+ if (prc->prc_id == ins) {
+ /* update the cached entry */
+ if (prc->prc_status != 0) {
+ etm_update_prc(hdl, prc);
+ }
+ /* check for cached ldom name */
+ if (prc->prc_status == 0 && prc->prc_name != NULL) {
+ *did = prc->prc_did;
+ (void) strncpy(name, prc->prc_name, name_size);
+ (void) pthread_mutex_unlock(&etm_rc_lock);
+ return (0);
+ }
+ break;
+ }
+ }
+ if (i >= etm_rc_cnt) {
+ fmd_hdl_debug(hdl, "prc[%d] not found\n", ins);
+ }
+
+ (void) pthread_mutex_unlock(&etm_rc_lock);
+
+ return (-1);
+} /* etm_find_ldom_id */
+
+/*
+ * etm_find_ldom_name()
+ * Description:
+ * Find the ldom name of a given domain id (did)
+ */
+int
+etm_filter_find_ldom_name(fmd_hdl_t *hdl, uint64_t did, char *name,
+ int name_size)
+{
+ int rc = -1; /* return value */
+ int i; /* loop counter */
+ etm_prc_t *prc; /* root complex */
+
+ (void) pthread_mutex_lock(&etm_rc_lock);
+
+ /* visit all the root complexes to find an entry that matches the did */
+ for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt;
+ i++, prc++) {
+ /* update the cached entry */
+ if (prc->prc_status != 0) {
+ etm_update_prc(hdl, prc);
+ }
+ /* find the cached ldom name */
+ if (prc->prc_status == 0 && prc->prc_did == did) {
+ rc = 0;
+ (void) strncpy(name, prc->prc_name ? prc->prc_name : "",
+ name_size);
+ break;
+ }
+ }
+
+ (void) pthread_mutex_unlock(&etm_rc_lock);
+
+ return (rc);
+} /* etm_find_ldom_name */
+
+/*
+ * etm_filter_handle_ldom_event()
+ * Description:
+ * Invalidate the ldom name in the physical root complex vector.
+ */
+void
+etm_filter_handle_ldom_event(fmd_hdl_t *hdl, etm_async_event_type_t event,
+ char *name) {
+ int i; /* loop counter */
+ etm_prc_t *prc; /* root complex */
+
+ /*
+ * Clear the cached ldom name
+ */
+ switch (event) {
+ case ETM_ASYNC_EVENT_LDOM_ADD:
+ case ETM_ASYNC_EVENT_LDOM_REMOVE:
+ case ETM_ASYNC_EVENT_LDOM_BIND:
+ case ETM_ASYNC_EVENT_LDOM_UNBIND:
+ (void) pthread_mutex_lock(&etm_rc_lock);
+ for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt;
+ i++, prc++) {
+ if (prc->prc_name != NULL &&
+ strcmp(prc->prc_name, name) == 0) {
+ fmd_hdl_free(hdl, prc->prc_name,
+ prc->prc_name_sz);
+ prc->prc_name = NULL;
+ prc->prc_name_sz = 0;
+ prc->prc_status = -1;
+ }
+ }
+ (void) pthread_mutex_unlock(&etm_rc_lock);
+ break;
+ default:
+ break;
+ }
+}
+
+/* ARGSUSED */
+void
+etm_filter_init(fmd_hdl_t *hdl) {
+ etm_rcs = NULL;
+ etm_rc_cnt = 0;
+ etm_rc_max = 0;
+ (void) pthread_mutex_init(&etm_rc_lock, NULL);
+ etm_pciexrc_init(hdl);
+}
+
+void
+etm_filter_fini(fmd_hdl_t *hdl) {
+ int i; /* loop counter */
+ etm_prc_t *prc; /* root complex pointer */
+
+ for (i = 0, prc = etm_rcs; prc != NULL && i < etm_rc_cnt;
+ i++, prc++) {
+ if (prc->prc_name != NULL) {
+ fmd_hdl_free(hdl, prc->prc_name, prc->prc_name_sz);
+ prc->prc_name = NULL;
+ prc->prc_name_sz = 0;
+ prc->prc_status = -1;
+ }
+ }
+ if (etm_rcs != NULL && etm_rc_max > 0) {
+ fmd_hdl_free(hdl, etm_rcs, etm_rc_max * sizeof (etm_prc_t));
+ }
+ (void) pthread_mutex_destroy(&etm_rc_lock);
+}
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.h b/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.h
new file mode 100644
index 0000000000..ef27f4d468
--- /dev/null
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_filter.h
@@ -0,0 +1,69 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * etm_filter.h
+ *
+ * Header file of the event filter
+ *
+ */
+
+#ifndef _ETM_FILTER_H
+#define _ETM_FILTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <fm/fmd_api.h>
+
+#include "etm_iosvc.h"
+
+/* A physical root complex */
+typedef struct etm_prc {
+ int32_t prc_id; /* physical id of the rc */
+ uint64_t prc_cfg_handle; /* bus address */
+ char *prc_name; /* bound ldom name */
+ size_t prc_name_sz; /* size of name */
+ int prc_status; /* ldom query status */
+ uint64_t prc_did; /* ldom id */
+} etm_prc_t;
+
+void etm_filter_init(fmd_hdl_t *hdl);
+void etm_filter_fini(fmd_hdl_t *hdl);
+
+int etm_filter_find_ldom_id(fmd_hdl_t *hdl, nvlist_t *erpt, char *name,
+ int name_size, uint64_t *did);
+int etm_filter_find_ldom_name(fmd_hdl_t *hdl, uint64_t did, char *name,
+ int name_size);
+void etm_filter_handle_ldom_event(fmd_hdl_t *hdl, etm_async_event_type_t event,
+ char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETM_FILTER_H */
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_impl.h b/usr/src/cmd/fm/modules/sun4v/etm/etm_impl.h
index bb6df38b45..9647b8e19d 100644
--- a/usr/src/cmd/fm/modules/sun4v/etm/etm_impl.h
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_impl.h
@@ -35,8 +35,6 @@
#ifndef _ETM_IMPL_H
#define _ETM_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -93,6 +91,7 @@ extern "C" {
#define ETM_PROP_NM_FACILITY "etm_alert_facility"
#define ETM_PROP_NM_MAX_RESP_Q_LEN "etm_resp_q_max_len"
+#define ETM_PROP_NM_FMA_RESP_WAIT_TIME "etm_fma_resp_wait_time"
#define ETM_PROP_NM_BAD_ACC_TO_SEC "etm_bad_acc_to_sec"
diff --git a/usr/src/cmd/fm/modules/sun4v/etm/etm_iosvc.h b/usr/src/cmd/fm/modules/sun4v/etm/etm_iosvc.h
new file mode 100644
index 0000000000..bf862e7fc5
--- /dev/null
+++ b/usr/src/cmd/fm/modules/sun4v/etm/etm_iosvc.h
@@ -0,0 +1,155 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * etm_iosvc.h
+ *
+ * Header file of the support for io service ldom
+ *
+ */
+
+#ifndef _ETM_IO_SVC_H
+#define _ETM_IO_SVC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ------------------------------ includes -----------------------------------
+ */
+
+#include <sys/fm/protocol.h>
+#include <sys/libds.h>
+#include <sys/fm/ldom.h>
+#include <fm/fmd_api.h>
+#include "etm_xport_api.h"
+#include "etm_etm_proto.h"
+
+#include <libnvpair.h>
+
+#include <pthread.h>
+
+#define FORWARDING_FAULTS_TO_CONTROL 0 /* not to forward faults to control */
+#define ASYNC_EVENT_Q_SIZE 100 /* size of the async event q */
+#define NUM_OF_ROOT_DOMAINS 8 /* size of iosvc_list structure array */
+#define MAXLEN 0x6000 /* max size of an FMA event */
+#define FMD_EVN_TTL "__ttl" /* name-value pair for ev_ttl */
+
+typedef enum {
+
+ ETM_ASYNC_EVENT_TOO_LOW = 0, /* range check place holder */
+ ETM_ASYNC_EVENT_LDOM_BIND, /* async event type: ldom event */
+ ETM_ASYNC_EVENT_LDOM_UNBIND, /* async event type: ldom event */
+ ETM_ASYNC_EVENT_LDOM_ADD, /* async event type: ldom event */
+ ETM_ASYNC_EVENT_LDOM_REMOVE, /* async event type: ldom event */
+ ETM_ASYNC_EVENT_DS_REG_CB, /* async event type: DS reg callback */
+ ETM_ASYNC_EVENT_DS_UNREG_CB, /* async event type: DS unreg cllback */
+ ETM_ASYNC_EVENT_TOO_BIG /* range check place holder */
+
+} etm_async_event_type_t; /* async etm event type */
+
+
+typedef enum {
+
+ SP_MSG = 0, /* msg for ereports from SP */
+ FMD_XPRT_OTHER_MSG, /* fmd all other xprt msg */
+ FMD_XPRT_RUN_MSG /* fmd xprt run msg */
+
+} etm_pack_msg_type_t; /* msg type for etm_pack_ds_msg() */
+
+typedef struct etm_iosvc_q_ele {
+
+ char *msg; /* ptr to ETM io svc msg */
+ size_t msg_size; /* sizeof ETM io svc msg */
+ uint_t ckpt_flag; /* checkpoint flags */
+
+ struct etm_iosvc_q_ele *msg_nextp; /* PRIVATE - next ele ptr */
+
+} etm_iosvc_q_ele_t; /* out-going etm msg queue element */
+
+
+
+typedef struct etm_iosvc {
+ char ldom_name[MAX_LDOM_NAME]; /* ldom_name */
+ pthread_cond_t msg_q_cv; /* nudges send msg func more to send */
+ pthread_mutex_t msg_q_lock; /* protects iosvc msg Q */
+ etm_iosvc_q_ele_t
+ *msg_q_head;
+ /* ptr to cur head of the msg Q */
+ etm_iosvc_q_ele_t
+ *msg_q_tail;
+ /* ptr to cur tail of the msg Q */
+ uint32_t msg_q_cur_len;
+ /* cur len of the msg Q */
+ uint32_t msg_q_max_len;
+ /* max len of the msg Q */
+ uint32_t cur_send_xid; /* current trnsaction id for io svc q */
+ uint32_t xid_posted_ev; /* xid of last event posted ok to fmd */
+ ds_hdl_t ds_hdl; /* the ds hdl for this io svc ldom */
+ fmd_xprt_t *fmd_xprt; /* fmd transport layer handle */
+ pthread_t send_tid; /* tid of sending msgs 2 remote iosvc */
+ pthread_t recv_tid; /* tid of recving msgs frm rmte iosvc */
+ pthread_cond_t msg_ack_cv; /* ready 2 send nxt or resend cur one */
+ pthread_mutex_t msg_ack_lock; /* protects msg_ack_cv */
+ int thr_is_dying; /* flag to exit the thread */
+ uint32_t start_sending_Q; /* flag to strt sending msg Q */
+ uint32_t ack_ok; /* indicate if the ACK has come */
+} etm_iosvc_t; /* structure to support io service ldom */
+
+
+typedef struct etm_async_event_ele {
+
+ etm_async_event_type_t event_type; /* async event type */
+ ds_hdl_t ds_hdl; /* ds handle */
+ char ldom_name[MAX_LDOM_NAME]; /* ldom name */
+ ds_domain_hdl_t dhdl; /* ldom handle */
+
+ struct etm_async_event_ele *async_event_nextp;
+ /* next ele ptr */
+
+} etm_async_event_ele_t; /* etm async event queue element */
+
+
+/*
+ * This function
+ */
+extern etm_iosvc_t *etm_iosvc_lookup(fmd_hdl_t *fmd_hdl, char *ldom_name,
+ ds_hdl_t ds_hdl, boolean_t iosvc_create);
+
+
+/*
+ * extern etm_iosvc_t *etm_lookup_iosvc(char *ldom_name);
+ */
+extern int etm_pack_ds_msg(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
+ etm_proto_v1_ev_hdr_t *ev_hdrp, size_t hdr_sz, nvlist_t *evp,
+ etm_pack_msg_type_t msg_type, uint_t ckpt_opt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETM_IO_SVC_H */
diff --git a/usr/src/lib/fm/libldom/Makefile b/usr/src/lib/fm/libldom/Makefile
index a5de1baa50..970b336f1f 100644
--- a/usr/src/lib/fm/libldom/Makefile
+++ b/usr/src/lib/fm/libldom/Makefile
@@ -19,11 +19,9 @@
# 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"
-#
include ../../Makefile.lib
include ../Makefile.lib
@@ -31,6 +29,8 @@ include ../Makefile.lib
FMHDRS = ldom.h
HDRDIR = sparc
+ROOTFMHDRDIR = $(ROOT)/usr/platform/sun4v/include/sys/fm
+
SUBDIRS = $(MACH)
$(BUILD64)SUBDIRS += $(MACH64)
@@ -38,15 +38,21 @@ all := TARGET = all
clean := TARGET = clean
clobber := TARGET = clobber
install := TARGET = install
-install_h := TARGET = install_h
lint := TARGET = lint
.KEEP_STATE:
-all clean clobber install_h lint: $(SUBDIRS)
+all clean clobber lint: $(SUBDIRS)
install: install_h .WAIT $(SUBDIRS)
+install_h: $(ROOTFMHDRS)
+
+$(ROOTFMHDRS): $(ROOTFMHDRDIR)
+
+$(ROOTFMHDRDIR)/%: $(HDRDIR)/%
+ $(INS.file)
+
check: $(CHECKHDRS)
$(SUBDIRS): FRC
diff --git a/usr/src/lib/fm/libldom/Makefile.com b/usr/src/lib/fm/libldom/Makefile.com
index daf82120d6..0c8cba5a2b 100644
--- a/usr/src/lib/fm/libldom/Makefile.com
+++ b/usr/src/lib/fm/libldom/Makefile.com
@@ -26,7 +26,7 @@
LIBRARY = libldom.a
VERS = .1
-LIBSRCS = ldom.c ldmsvcs_utils.c
+LIBSRCS = ldom.c ldom_alloc.c ldmsvcs_utils.c ldom_xmpp_client.c
OBJECTS = $(LIBSRCS:%.c=%.o)
include ../../../Makefile.lib
@@ -37,12 +37,13 @@ SRCDIR = ../sparc
LIBS = $(DYNLIB) $(LINTLIB)
-CPPFLAGS += -I. -I$(SRC)/uts/sun4v -I$(ROOT)/usr/platform/sun4v/include
+CPPFLAGS += -I. -I$(SRC)/uts/sun4v -I$(ROOT)/usr/platform/sun4v/include \
+ -I/usr/include/libxml2 -I/usr/sfw/include
CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS)
LDLIBS += $(MACH_LDLIBS)
-LDLIBS += -lfmd_agent -lnvpair -lscf -lmdesc -lc
+LDLIBS += -lfmd_agent -lnvpair -lscf -lmdesc -lc -lxml2 -lsocket -lumem
LINTFLAGS = -msux
LINTFLAGS64 = -msux -m64
diff --git a/usr/src/lib/fm/libldom/sparc/Makefile b/usr/src/lib/fm/libldom/sparc/Makefile
index 261bf4c60f..1f0c37cf36 100644
--- a/usr/src/lib/fm/libldom/sparc/Makefile
+++ b/usr/src/lib/fm/libldom/sparc/Makefile
@@ -19,11 +19,9 @@
# 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"
-#
MACH_LDLIBS = -L$(ROOT)/usr/lib/fm
@@ -31,19 +29,4 @@ include ../Makefile.com
DYNFLAGS += -R/usr/lib/fm
-FMHDRS = ldom.h
-HDRDIR = .
-
-ROOTFMHDRDIR = $(ROOT)/usr/platform/sun4v/include/sys/fm
-
install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
-
-install_h: $(ROOTFMHDRS)
-
-$(ROOTFMHDRS): $(ROOTFMHDRDIR)
-
-$(ROOTFMHDRDIR):
- $(INS.dir)
-
-$(ROOTFMHDRDIR)/%: $(HDRDIR)/%
- $(INS.file)
diff --git a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c b/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
index 8093406a2f..32e47aa27b 100644
--- a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
+++ b/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.c
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <stdio.h>
+
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -41,6 +42,8 @@
#include <values.h>
#include <libscf.h>
+#include <ctype.h>
+
#include "ldmsvcs_utils.h"
#define ASSERT(cnd) \
@@ -121,7 +124,6 @@ static struct ldmsvcs_info *channel_init(struct ldom_hdl *lhp);
static int channel_openreset(struct ldmsvcs_info *lsp);
static int read_msg(struct ldmsvcs_info *lsp);
-
static int
get_smf_int_val(char *prop_nm, int min, int max, int default_val)
{
@@ -930,8 +932,8 @@ static void
fds_svc_alloc(struct ldom_hdl *lhp, struct ldmsvcs_info *lsp)
{
int i;
- char *name[] = { "fma-phys-cpu-service", "fma-phys-mem-service",
- "fma-pri-service", NULL };
+ static char *name[] = { LDM_DS_NAME_CPU, LDM_DS_NAME_MEM,
+ LDM_DS_NAME_PRI, LDM_DS_NAME_IOD, NULL };
(void) pthread_mutex_init(&lsp->fmas_svcs.mt, NULL);
(void) pthread_cond_init(&lsp->fmas_svcs.cv, NULL);
@@ -972,14 +974,28 @@ fds_svc_lookup(struct ldmsvcs_info *lsp, char *name)
ASSERT(svc != NULL);
- ier = 0;
- twait.tv_sec = time(NULL) + lsp->cv_twait;
- twait.tv_nsec = 0;
+ if (svc->state == DS_SVC_INACTIVE) {
+ /* service is not registered */
+ ier = ETIMEDOUT;
+ } else {
+ ier = 0;
+ twait.tv_sec = time(NULL) + lsp->cv_twait;
+ twait.tv_nsec = 0;
- while (svc->state != DS_SVC_ACTIVE && ier == 0 &&
- lsp->fds_chan.state != CHANNEL_UNUSABLE)
- ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv,
- &lsp->fmas_svcs.mt, &twait);
+ while (svc->state != DS_SVC_ACTIVE && ier == 0 &&
+ lsp->fds_chan.state != CHANNEL_UNUSABLE)
+ ier = pthread_cond_timedwait(&lsp->fmas_svcs.cv,
+ &lsp->fmas_svcs.mt, &twait);
+
+ /*
+ * By now, the ds service should have registered already.
+ * If it does not, ldmd probably does not support this service.
+ * Then mark the service state as inactive.
+ */
+ if (ier == ETIMEDOUT) {
+ svc->state = DS_SVC_INACTIVE;
+ }
+ }
(void) pthread_mutex_unlock(&lsp->fmas_svcs.mt);
@@ -1274,7 +1290,7 @@ cpu_request(struct ldom_hdl *lhp, uint32_t msg_type, uint32_t cpuid)
ds_data_handle_t *D;
fma_cpu_service_req_t *R;
- char *svcname = "fma-phys-cpu-service";
+ char *svcname = LDM_DS_NAME_CPU;
fma_cpu_resp_t *respmsg;
void *resp;
size_t resplen, reqmsglen;
@@ -1358,7 +1374,7 @@ mem_request(struct ldom_hdl *lhp, uint32_t msg_type, uint64_t pa,
ds_data_handle_t *D;
fma_mem_service_req_t *R;
- char *svcname = "fma-phys-mem-service";
+ char *svcname = LDM_DS_NAME_MEM;
fma_mem_resp_t *respmsg;
void *resp;
size_t resplen, reqmsglen;
@@ -1488,7 +1504,7 @@ ldmsvcs_get_core_md(struct ldom_hdl *lhp, uint64_t **buf)
ds_data_handle_t *D;
fma_req_pri_t *R;
- char *svcname = "fma-pri-service";
+ char *svcname = LDM_DS_NAME_PRI;
void *resp;
size_t resplen, reqmsglen;
ssize_t buflen;
@@ -1593,4 +1609,79 @@ ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa)
return (mem_request(lhp, FMA_MEM_REQ_RESURRECT, pa, getpagesize()));
}
+int
+ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type,
+ uint64_t *virt_addr, char *name, int name_len, uint64_t *did)
+{
+
+ ds_hdr_t *H;
+ ds_data_handle_t *D;
+ fma_io_req_t *R;
+
+ char *svcname = LDM_DS_NAME_IOD;
+ void *resp;
+ fma_io_resp_t *iop;
+ size_t resplen, reqmsglen;
+ int offset;
+ int rc;
+
+ if (lhp->lsinfo == NULL)
+ return (-1);
+
+ reqmsglen = sizeof (ds_hdr_t) + sizeof (ds_data_handle_t) +
+ sizeof (fma_io_req_t);
+
+ H = lhp->allocp(reqmsglen);
+ D = (void *)((ptrdiff_t)H + sizeof (ds_hdr_t));
+ R = (void *)((ptrdiff_t)D + sizeof (ds_data_handle_t));
+
+ H->msg_type = DS_DATA;
+ H->payload_len = sizeof (ds_data_handle_t) + sizeof (fma_io_req_t);
+
+ R->req_num = fds_svc_req_num();
+ R->msg_type = type;
+ R->rsrc_address = addr;
+
+ rc = ENOMSG;
+ if ((rc = sendrecv(lhp, R->req_num, H, reqmsglen,
+ &D->svc_handle, svcname, &resp, &resplen)) != 0) {
+ lhp->freep(H, reqmsglen);
+ return (rc);
+ }
+ lhp->freep(H, reqmsglen);
+
+ /*
+ * resp should contain the req_num, status, virtual addr, domain id
+ * and the domain name. The domain name may or may not be present.
+ */
+ offset = sizeof (fma_io_resp_t);
+ if (resplen < offset) {
+ lhp->freep(resp, resplen);
+ return (-1);
+ }
+
+ iop = (fma_io_resp_t *)resp;
+ switch (iop->result) {
+ case FMA_IO_RESP_OK:
+ /* success */
+ rc = 0;
+ *virt_addr = iop->virt_rsrc_address;
+ *did = iop->domain_id;
+ if (name == NULL || name_len <= 0)
+ break;
+ *name = '\0';
+ if (resplen > offset) {
+ (void) strncpy(name, (char *)((ptrdiff_t)resp + offset),
+ name_len);
+ }
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ lhp->freep(resp, resplen);
+ return (rc);
+}
+
/* end file */
diff --git a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.h b/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.h
index eaa5aa1087..135109152f 100644
--- a/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.h
+++ b/usr/src/lib/fm/libldom/sparc/ldmsvcs_utils.h
@@ -26,8 +26,6 @@
#ifndef _LDMSVCS_UTILS_H
#define _LDMSVCS_UTILS_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ldc.h>
@@ -79,6 +77,12 @@ typedef struct fds_channel {
/*
* FMA services
*/
+
+#define LDM_DS_NAME_CPU "fma-phys-cpu-service"
+#define LDM_DS_NAME_MEM "fma-phys-mem-service"
+#define LDM_DS_NAME_PRI "fma-pri-service"
+#define LDM_DS_NAME_IOD "fma-io-domain-service"
+
typedef struct {
uint64_t req_num;
} fma_req_pri_t;
@@ -139,9 +143,28 @@ typedef struct {
} fma_mem_resp_t;
+#define FMA_IO_RESP_OK 0
+#define FMA_IO_RESP_FAILURE 1
+#define FMA_IO_RESP_ILLEGAL 2
+#define FMA_IO_RESP_UNASSIGNED 3
+
+typedef struct {
+ uint64_t req_num;
+ uint32_t msg_type;
+ uint32_t reserved;
+ uint64_t rsrc_address;
+} fma_io_req_t;
+
+typedef struct {
+ uint64_t req_num;
+ uint32_t result;
+ uint32_t reserved;
+ uint64_t virt_rsrc_address;
+ uint64_t domain_id;
+} fma_io_resp_t;
+
+
struct ldom_hdl {
- int major_version;
- int service_ldom;
void *(*allocp)(size_t size);
void (*freep)(void *addr, size_t size);
struct ldmsvcs_info *lsinfo;
@@ -187,6 +210,9 @@ extern int ldmsvcs_cpu_req_online(struct ldom_hdl *lhp, uint32_t cpuid);
extern int ldmsvcs_mem_req_unretire(struct ldom_hdl *lhp, uint64_t pa);
+extern int ldmsvcs_io_req_id(struct ldom_hdl *lhp, uint64_t addr, uint_t type,
+ uint64_t *virt_addr, char *name, int name_len, uint64_t *did);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/fm/libldom/sparc/ldom.c b/usr/src/lib/fm/libldom/sparc/ldom.c
index ce25369490..b44a038b1e 100644
--- a/usr/src/lib/fm/libldom/sparc/ldom.c
+++ b/usr/src/lib/fm/libldom/sparc/ldom.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
@@ -35,6 +36,7 @@
#include <link.h>
#include <assert.h>
+#include <fm/libtopo.h>
#include <sys/processor.h>
#include <sys/stat.h>
#include <sys/mdesc.h>
@@ -48,10 +50,19 @@
#include <sys/pri.h>
#include "ldom.h"
+#include "ldom_alloc.h"
#include "ldmsvcs_utils.h"
+#include "ldom_xmpp_client.h"
#define MD_STR_PLATFORM "platform"
#define MD_STR_DOM_CAPABLE "domaining-enabled"
+#define MD_STR_IODEVICE "iodevice"
+#define MD_STR_NAME "name"
+#define MD_STR_DEVICE_TYPE "device-type"
+#define MD_STR_CFGHDL "cfg-handle"
+#define MD_STR_PCIEX "pciex"
+#define MD_STR_PCI "pci"
+#define MD_STR_NIU "niu"
static int ldom_ldmd_is_up = 0; /* assume stays up if ever seen up */
@@ -222,83 +233,6 @@ get_local_md_prop_value(ldom_hdl_t *lhp, char *node, char *prop, uint64_t *val)
return (rc);
}
-static int
-ldom_getinfo(struct ldom_hdl *lhp)
-{
- static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
- static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
- static int major_version = -1;
- static int service_ldom = -1;
- static int busy_init = 0;
-
- int ier, rc = 0;
- uint64_t domain_capable;
-
- (void) pthread_mutex_lock(&mt);
-
- while (busy_init == 1)
- (void) pthread_cond_wait(&cv, &mt);
-
- if (major_version != -1 && service_ldom != -1) {
- lhp->major_version = major_version;
- lhp->service_ldom = service_ldom;
- (void) pthread_mutex_unlock(&mt);
- return (0);
- }
-
- /*
- * get to this point if major_version and service_ldom have not yet
- * been determined
- */
- busy_init = 1;
- (void) pthread_mutex_unlock(&mt);
-
- /*
- * set defaults which correspond to the case of "LDOMS not
- * available". note that these can (and will) also apply to
- * non-sun4v machines.
- */
- major_version = 0;
- service_ldom = 0;
-
- if (get_local_md_prop_value(lhp, MD_STR_PLATFORM, MD_STR_DOM_CAPABLE,
- &domain_capable) == 0) {
-
- /*
- * LDOMS capable FW is installed; it should be ok to
- * try to communicate with ldmd and if that fails/timesout
- * then use libpri
- */
- major_version = 1;
-
- if ((ier = ldmsvcs_check_channel()) == 0) {
- /*
- * control ldom
- * ldmfma channel between FMA and ldmd only exists
- * on the control domain.
- */
- service_ldom = 1;
- } else if (ier == 1) {
- /*
- * guest ldom
- * non-control ldom such as guest and io service ldom
- */
- service_ldom = 0;
- }
- }
-
- (void) pthread_mutex_lock(&mt);
- lhp->major_version = major_version;
- lhp->service_ldom = service_ldom;
- busy_init = 0;
- (void) pthread_mutex_unlock(&mt);
-
- (void) pthread_cond_broadcast(&cv);
-
- return (rc);
-}
-
-
/*
* search the machine description for a "pid" entry (physical cpuid) and
* return the corresponding "id" entry (virtual cpuid).
@@ -363,6 +297,124 @@ cpu_phys2virt(ldom_hdl_t *lhp, uint32_t cpuid)
return (vid);
}
+static int
+get_type(ldom_hdl_t *lhp, uint32_t *type)
+{
+ int num_nodes, cnt, i, rc;
+ char *p;
+ mde_cookie_t *listp;
+ md_t *mdp;
+ uint64_t domain_capable;
+ uint64_t *bufp;
+ ssize_t bufsize;
+
+ *type = 0;
+
+ /* legacy system */
+ if (get_local_md_prop_value(lhp, MD_STR_PLATFORM, MD_STR_DOM_CAPABLE,
+ &domain_capable) != 0) {
+ *type = LDOM_TYPE_LEGACY;
+ return (0);
+ }
+
+ /*
+ * LDOMS capable FW is installed; it should be ok to
+ * try to communicate with ldmd
+ */
+ if ((rc = ldmsvcs_check_channel()) == 0) {
+ /*
+ * control ldom
+ * ldmfma channel between FMA and ldmd only exists
+ * on the control domain.
+ */
+ *type |= LDOM_TYPE_CONTROL;
+ } else if (rc == -1) {
+ return (rc);
+ }
+
+ /*
+ * root domain and io domain
+ */
+ if ((bufsize = get_local_core_md(lhp, &bufp)) < 1)
+ return (-1);
+ if ((mdp = md_init_intern(bufp, lhp->allocp, lhp->freep)) == NULL) {
+ lhp->freep(bufp, bufsize);
+ return (-1);
+ }
+ if ((num_nodes = md_node_count(mdp)) < 1) {
+ lhp->freep(bufp, bufsize);
+ (void) md_fini(mdp);
+ return (-1);
+ }
+
+ /* Search for the root complex and niu nodes */
+ listp = lhp->allocp(sizeof (mde_cookie_t) * num_nodes);
+ cnt = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
+ md_find_name(mdp, MD_STR_IODEVICE), md_find_name(mdp, "fwd"),
+ listp);
+ for (i = 0, p = NULL; i < cnt; i++) {
+ if ((md_get_prop_str(mdp, listp[i], MD_STR_DEVICE_TYPE, &p)
+ == 0) &&
+ (p != NULL) && (strcmp(p, MD_STR_PCIEX) == 0)) {
+ *type |= LDOM_TYPE_ROOT;
+ break;
+ }
+ }
+ for (i = 0, p = NULL; i < cnt; i++) {
+ if ((md_get_prop_str(mdp, listp[i], MD_STR_NAME, &p) == 0) &&
+ (p != NULL) && (strcmp(p, MD_STR_NIU) == 0)) {
+ *type |= LDOM_TYPE_IO;
+ break;
+ }
+ }
+ lhp->freep(listp, sizeof (mde_cookie_t) * num_nodes);
+ (void) md_fini(mdp);
+ lhp->freep(bufp, bufsize);
+
+ return (0);
+}
+
+int
+ldom_get_type(ldom_hdl_t *lhp, uint32_t *type)
+{
+ static pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+ static uint32_t ltype = 0;
+ static int busy_init = 0;
+
+ int rc = 0;
+
+ (void) pthread_mutex_lock(&mt);
+
+ while (busy_init == 1)
+ (void) pthread_cond_wait(&cv, &mt);
+
+ if (VALID_LDOM_TYPE(ltype) != 0) {
+ *type = ltype;
+ (void) pthread_mutex_unlock(&mt);
+ return (0);
+ }
+
+ /*
+ * get to this point if the ldom_type has not yet been determined
+ */
+ busy_init = 1;
+ (void) pthread_mutex_unlock(&mt);
+
+ rc = get_type(lhp, &ltype);
+ if (rc == 0) {
+ *type = ltype;
+ }
+
+ (void) pthread_mutex_lock(&mt);
+ busy_init = 0;
+ (void) pthread_mutex_unlock(&mt);
+
+ (void) pthread_cond_broadcast(&cv);
+
+ return (rc);
+}
+
int
ldom_fmri_status(ldom_hdl_t *lhp, nvlist_t *nvl)
{
@@ -373,11 +425,8 @@ ldom_fmri_status(ldom_hdl_t *lhp, nvlist_t *nvl)
return (EINVAL);
/*
- * ldom_ldmd_is_up can only be true if ldom_major_version()
- * returned 1 earlier; the major version is constant for the
- * life of the client process
+ * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
*/
-
if (!ldom_ldmd_is_up) {
/* Zeus is unavail; use local routines for status/retire */
@@ -438,11 +487,8 @@ ldom_fmri_retire(ldom_hdl_t *lhp, nvlist_t *nvl)
return (EINVAL);
/*
- * ldom_ldmd_is_up can only be true if ldom_major_version()
- * returned 1 earlier; the major version is constant for the
- * life of the client process
+ * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
*/
-
if (!ldom_ldmd_is_up) {
/* Zeus is unavail; use local routines for status/retire */
@@ -502,11 +548,8 @@ ldom_fmri_unretire(ldom_hdl_t *lhp, nvlist_t *nvl)
return (EINVAL);
/*
- * ldom_ldmd_is_up can only be true if ldom_major_version()
- * returned 1 earlier; the major version is constant for the
- * life of the client process
+ * ldom_ldmd_is_up can only be true if a pri can be obtained from ldmd.
*/
-
if (!ldom_ldmd_is_up) {
/* Zeus is unavail; use local routines for status/retire */
@@ -560,8 +603,10 @@ static int
fmri_blacklist(ldom_hdl_t *lhp, nvlist_t *nvl, int cmd)
{
char *name;
+ uint32_t type = 0;
- if (ldom_major_version(lhp) != 0)
+ if ((ldom_get_type(lhp, &type) != 0) ||
+ ((type & LDOM_TYPE_LEGACY) == 0))
return (0);
if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0)
@@ -624,77 +669,108 @@ ldom_fmri_unblacklist(ldom_hdl_t *lhp, nvlist_t *nvl)
ssize_t
+ldom_get_local_md(ldom_hdl_t *lhp, uint64_t **buf)
+{
+ return (get_local_core_md(lhp, buf));
+}
+
+ssize_t
ldom_get_core_md(ldom_hdl_t *lhp, uint64_t **buf)
{
ssize_t rv; /* return value */
uint64_t tok; /* opaque PRI token */
+ uint32_t type = 0;
- switch (ldom_major_version(lhp)) {
- case 0:
- /* pre LDOMS */
- rv = get_local_core_md(lhp, buf);
- break;
- case 1:
- /* LDOMS 1.0 - Zeus and libpri usable only on service dom */
- if (ldom_on_service(lhp) == 1) {
- if ((rv = ldmsvcs_get_core_md(lhp, buf)) < 1) {
- (void) pthread_mutex_lock(&ldom_pri_lock);
- rv = ldom_pri_get(PRI_GET, &tok,
- buf, lhp->allocp, lhp->freep);
- (void) pthread_mutex_unlock(&ldom_pri_lock);
- } else {
- ldom_ldmd_is_up = 1;
- }
+ (void) ldom_get_type(lhp, &type);
+ if (VALID_LDOM_TYPE(type) == 0) {
+ return (-1);
+ }
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ /* Get the pri from Zeus first. If failed, get it from libpri */
+ if ((rv = ldmsvcs_get_core_md(lhp, buf)) < 1) {
+ (void) pthread_mutex_lock(&ldom_pri_lock);
+ rv = ldom_pri_get(PRI_GET, &tok,
+ buf, lhp->allocp, lhp->freep);
+ (void) pthread_mutex_unlock(&ldom_pri_lock);
} else {
- rv = get_local_core_md(lhp, buf);
+ ldom_ldmd_is_up = 1;
+ xmpp_start();
}
- break;
- default:
- rv = -1;
- break;
+ } else {
+ /* get the local MD */
+ rv = get_local_core_md(lhp, buf);
}
return (rv);
}
-/*
- * version 0 means no LDOMS
- */
int
-ldom_major_version(ldom_hdl_t *lhp)
+ldom_find_id(ldom_hdl_t *lhp, uint64_t addr, ldom_rsrc_t rsrc,
+ uint64_t *virt_addr, char *name, int name_size, uint64_t *did)
{
- if (lhp == NULL)
- return (-1);
+ uint32_t type = 0;
- if (ldom_getinfo(lhp) == 0)
- return (lhp->major_version);
- else
- return (0);
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) == 0) {
+ return (ENOTSUP);
+ }
+ if (!ldom_ldmd_is_up) {
+ return (EAGAIN);
+ }
+ return (ldmsvcs_io_req_id(lhp, addr, rsrc, virt_addr,
+ name, name_size, did));
}
-/*
- * in the absence of ldoms we are on a single OS instance which is the
- * equivalent of the service ldom
- */
int
-ldom_on_service(ldom_hdl_t *lhp)
+ldom_register_event(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
{
- if (lhp == NULL)
- return (-1);
+ uint32_t type = 0;
- if (ldom_getinfo(lhp) == 0)
- return (lhp->service_ldom);
- else
- return (1);
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) == 0) {
+ return (ENOTSUP);
+ }
+
+ return (xmpp_add_client(lhp, cb, data));
}
+int
+ldom_unregister_event(ldom_hdl_t *lhp)
+{
+ uint32_t type = 0;
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) == 0) {
+ return (ENOTSUP);
+ }
+
+ return (xmpp_remove_client(lhp));
+}
+
+/*
+ * ldom_init()
+ * Description:
+ * Return a libldom handle to the caller for uniquely identify the session
+ * betweem the caller and the libldom.so. The handle is used in
+ * subsequent calls into the libldom.so
+ *
+ * If the caller does not provide a alloc()/free(), the libldom uses its
+ * own functions.
+ */
ldom_hdl_t *
ldom_init(void *(*allocp)(size_t size),
void (*freep)(void *addr, size_t size))
{
struct ldom_hdl *lhp;
+ if (allocp == NULL && freep == NULL) {
+ allocp = ldom_alloc;
+ freep = ldom_free;
+ } else if (allocp == NULL || freep == NULL) {
+ /* missing alloc or free functions */
+ return (NULL);
+ }
+
(void) pthread_mutex_lock(&ldom_pri_lock);
if (ldom_pri_init() < 0) {
@@ -710,7 +786,6 @@ ldom_init(void *(*allocp)(size_t size),
(void) pthread_mutex_unlock(&ldom_pri_lock);
- lhp->major_version = -1; /* version not yet determined */
lhp->allocp = allocp;
lhp->freep = freep;
@@ -726,6 +801,7 @@ ldom_fini(ldom_hdl_t *lhp)
if (lhp == NULL)
return;
+ (void) xmpp_remove_client(lhp);
ldmsvcs_fini(lhp);
lhp->freep(lhp, sizeof (struct ldom_hdl));
diff --git a/usr/src/lib/fm/libldom/sparc/ldom.h b/usr/src/lib/fm/libldom/sparc/ldom.h
index 7b8079b819..54b57ff698 100644
--- a/usr/src/lib/fm/libldom/sparc/ldom.h
+++ b/usr/src/lib/fm/libldom/sparc/ldom.h
@@ -26,11 +26,10 @@
#ifndef _LDOM_H
#define _LDOM_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <libnvpair.h>
#include <sys/types.h>
+#include <umem.h>
#ifdef __cplusplus
extern "C" {
@@ -49,9 +48,59 @@ extern int ldom_fmri_blacklist(ldom_hdl_t *lhp, nvlist_t *nvl_fmri);
extern int ldom_fmri_unblacklist(ldom_hdl_t *lhp, nvlist_t *nvl_fmri);
extern ssize_t ldom_get_core_md(ldom_hdl_t *lhp, uint64_t **buf);
+extern ssize_t ldom_get_local_md(ldom_hdl_t *lhp, uint64_t **buf);
+
+/*
+ * domain type
+ */
+#define LDOM_TYPE_LEGACY 0x1
+#define LDOM_TYPE_CONTROL 0x2
+#define LDOM_TYPE_ROOT 0x4
+#define LDOM_TYPE_IO 0x8
+#define LDOM_TYPE_ALL \
+ (LDOM_TYPE_LEGACY | LDOM_TYPE_CONTROL | LDOM_TYPE_ROOT | LDOM_TYPE_IO)
+#define VALID_LDOM_TYPE(t) ((t) & LDOM_TYPE_ALL)
+
+extern int ldom_get_type(ldom_hdl_t *lhp, uint32_t *type_mask);
+
+/*
+ * Resource map
+ */
+typedef enum ldom_rsrc {
+ LDOM_RSRC_PCI,
+ LDOM_RSRC_NIU,
+ LDOM_RSRC_MAX
+} ldom_rsrc_t;
+
+extern int
+ldom_find_id(ldom_hdl_t *lhp, uint64_t addr, ldom_rsrc_t type,
+ uint64_t *virt_addr, char *name, int name_size, uint64_t *id);
+
+/*
+ * event notification
+ */
+typedef enum ldom_event {
+ LDOM_EVENT_UNKNOWN,
+ LDOM_EVENT_ADD,
+ LDOM_EVENT_REMOVE,
+ LDOM_EVENT_BIND,
+ LDOM_EVENT_UNBIND,
+ LDOM_EVENT_START,
+ LDOM_EVENT_STOP,
+ LDOM_EVENT_RESET,
+ LDOM_EVENT_PANIC,
+ LDOM_EVENT_MAX
+} ldom_event_t;
+#define VALID_LDOM_EVENT(e) ((e) > LDOM_EVENT_UNKNOWN && \
+ (e) < LDOM_EVENT_MAX)
+#define MAX_LDOM_NAME 256
-extern int ldom_major_version(ldom_hdl_t *lhp);
-extern int ldom_on_service(ldom_hdl_t *lhp);
+typedef void *ldom_cb_arg_t;
+typedef void (*ldom_reg_cb_t)(char *ldom_name, ldom_event_t event,
+ ldom_cb_arg_t data);
+extern int ldom_register_event(ldom_hdl_t *lhp, ldom_reg_cb_t cb,
+ ldom_cb_arg_t data);
+extern int ldom_unregister_event(ldom_hdl_t *lhp);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/fm/libldom/sparc/ldom_alloc.c b/usr/src/lib/fm/libldom/sparc/ldom_alloc.c
new file mode 100644
index 0000000000..c5c6903111
--- /dev/null
+++ b/usr/src/lib/fm/libldom/sparc/ldom_alloc.c
@@ -0,0 +1,38 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <umem.h>
+
+void *
+ldom_alloc(size_t size)
+{
+ return (umem_alloc(size, UMEM_DEFAULT));
+}
+
+void
+ldom_free(void *data, size_t size)
+{
+ umem_free(data, size);
+}
diff --git a/usr/src/lib/fm/libldom/sparc/ldom_alloc.h b/usr/src/lib/fm/libldom/sparc/ldom_alloc.h
new file mode 100644
index 0000000000..c73b47dc72
--- /dev/null
+++ b/usr/src/lib/fm/libldom/sparc/ldom_alloc.h
@@ -0,0 +1,43 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LDOM_ALLOC_H
+#define _LDOM_ALLOC_H
+
+#include <sys/types.h>
+#include <umem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void *ldom_alloc(size_t size);
+extern void ldom_free(void *data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDOM_ALLOC_H */
diff --git a/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c b/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c
new file mode 100644
index 0000000000..2066ff20cf
--- /dev/null
+++ b/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c
@@ -0,0 +1,790 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ldom_xmpp_client.c Extensible Messaging and Presence Protocol
+ *
+ * Implement an xmpp client to subscribe for domain events from the ldmd.
+ * Notify fmd module clients upon receiving the events.
+ *
+ */
+
+#include "ldom_xmpp_client.h"
+#include "ldom_alloc.h"
+
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <netdb.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libxml/parser.h>
+#include <openssl/ssl.h>
+
+typedef enum conn_state {
+ CONN_STATE_UNKNOWN,
+ CONN_STATE_TLS,
+ CONN_STATE_FEATURE,
+ CONN_STATE_LDM_INTERFACE,
+ CONN_STATE_LDM_EVENT,
+ CONN_STATE_DONE,
+ CONN_STATE_FAILURE,
+ CONN_STATE_MAX
+} conn_state_t;
+
+typedef struct xmpp_conn {
+ int fd;
+ int state;
+ boolean_t tls_started;
+ SSL *ssl;
+ xmlParserCtxtPtr parser;
+} xmpp_conn_t;
+
+/* Forward declaration */
+static int iowrite(xmpp_conn_t *conn, char *buf, int size);
+static void start_element(void *state, const xmlChar *name,
+ const xmlChar **attrs);
+static void end_element(void *state, const xmlChar *name);
+static void error_func(void *state, const char *msg, ...);
+static void xmpp_close(xmpp_conn_t *conn);
+static int start_tls(xmpp_conn_t *conn);
+static void handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size);
+static void handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size);
+
+static int xmpp_enable = 0;
+static pthread_t xmpp_tid = 0;
+static pthread_mutex_t xmpp_tid_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static client_list_t clt_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
+
+
+#define FUNCTION_ADD(_function, _pointer, _lib, _func_name, _ret) \
+ _function = (_pointer)dlsym(_lib, _func_name); \
+ if (_function == NULL) { \
+ _ret += -1; \
+ }
+
+/*
+ * Prototypes and pointers to functions needed from libssl.
+ */
+typedef void (*SSL_load_error_strings_pt)(void);
+typedef int (*SSL_library_init_pt)(void);
+typedef SSL_CTX *(*SSL_CTX_new_pt)(const SSL_METHOD *method);
+typedef SSL_METHOD *(*SSLv23_client_method_pt)(void);
+typedef int (*SSL_write_pt)(SSL *ssl, const void *buf, int num);
+typedef int (*SSL_CTX_use_PrivateKey_file_pt)(SSL_CTX *ctx, const char *file,
+ int type);
+typedef void (*RAND_seed_pt)(const void *buf, int num);
+typedef int (*SSL_get_error_pt)(const SSL *ssl, int ret);
+typedef long (*ERR_get_error_pt)(void);
+typedef char *(*ERR_error_string_pt)(unsigned long e, char *buf);
+typedef int (*SSL_connect_pt)(SSL *ssl);
+typedef int (*SSL_CTX_use_certificate_chain_file_pt)(SSL_CTX *ctx,
+ const char *file);
+typedef int (*SSL_set_fd_pt)(SSL *ssl, int fd);
+typedef void (*SSL_free_pt)(SSL *ssl);
+typedef int (*SSL_read_pt)(SSL *ssl, void *buf, int num);
+typedef SSL *(*SSL_new_pt)(SSL_CTX *ctx);
+typedef SSL_CTX *(*SSL_get_SSL_CTX_pt)(const SSL *ssl);
+typedef void (*SSL_CTX_free_pt)(SSL_CTX *ctx);
+
+static SSL_load_error_strings_pt SSL_load_error_strings_f = NULL;
+static SSL_library_init_pt SSL_library_init_f = NULL;
+static SSL_CTX_new_pt SSL_CTX_new_f = NULL;
+static SSLv23_client_method_pt SSLv23_client_method_f = NULL;
+static SSL_write_pt SSL_write_f = NULL;
+static SSL_CTX_use_PrivateKey_file_pt SSL_CTX_use_PrivateKey_file_f = NULL;
+static RAND_seed_pt RAND_seed_f = NULL;
+static SSL_get_error_pt SSL_get_error_f = NULL;
+static ERR_get_error_pt ERR_get_error_f = NULL;
+static ERR_error_string_pt ERR_error_string_f = NULL;
+static SSL_connect_pt SSL_connect_f = NULL;
+static SSL_CTX_use_certificate_chain_file_pt
+SSL_CTX_use_certificate_chain_file_f = NULL;
+static SSL_set_fd_pt SSL_set_fd_f = NULL;
+static SSL_free_pt SSL_free_f = NULL;
+static SSL_read_pt SSL_read_f = NULL;
+static SSL_new_pt SSL_new_f = NULL;
+static SSL_get_SSL_CTX_pt SSL_get_SSL_CTX_f = NULL;
+static SSL_CTX_free_pt SSL_CTX_free_f = NULL;
+
+static void *xmpp_dl = NULL;
+
+static ldom_event_info_t event_table[] = {
+ { LDOM_EVENT_UNKNOWN, "unknown" },
+ { LDOM_EVENT_ADD, "add-domain" },
+ { LDOM_EVENT_REMOVE, "remove-domain" },
+ { LDOM_EVENT_BIND, "bind-domain" },
+ { LDOM_EVENT_UNBIND, "unbind-domain" },
+ { LDOM_EVENT_START, "start-domain" },
+ { LDOM_EVENT_STOP, "stop-domain" },
+ { LDOM_EVENT_RESET, "domain-reset" },
+ { LDOM_EVENT_PANIC, "panic-domain" },
+ { LDOM_EVENT_MAX, NULL }
+};
+static int event_table_size = \
+ sizeof (event_table) / sizeof (ldom_event_info_t);
+
+static xmlSAXHandler xml_handler = {
+ NULL, /* internalSubsetSAXFunc */
+ NULL, /* isStandaloneSAXFunc */
+ NULL, /* hasInternalSubsetSAXFunc */
+ NULL, /* hasExternalSubsetSAXFunc */
+ NULL, /* resolveEntitySAXFunc */
+ NULL, /* getEntitySAXFunc */
+ NULL, /* entityDeclSAXFunc */
+ NULL, /* notationDeclSAXFunc */
+ NULL, /* attributeDeclSAXFunc */
+ NULL, /* elementDeclSAXFunc */
+ NULL, /* unparsedEntityDeclSAXFunc */
+ NULL, /* setDocumentLocatorSAXFunc */
+ NULL, /* startDocumentSAXFunc */
+ NULL, /* endDocumentSAXFunc */
+ start_element, /* startElementSAXFunc */
+ end_element, /* endElementSAXFunc */
+ NULL, /* referenceSAXFunc */
+ NULL, /* charactersSAXFunc */
+ NULL, /* ignorableWhitespaceSAXFunc */
+ NULL, /* processingInstructionSAXFunc */
+ NULL, /* commentSAXFunc */
+ NULL, /* warningSAXFunc */
+ error_func, /* errorSAXFunc */
+ NULL, /* fatalErrorSAXFunc */
+ NULL, /* getParameterEntitySAXFunc */
+ NULL, /* cdataBlockSAXFunc */
+ NULL, /* externalSubsetSAXFunc */
+ 0, /* unsigned int */
+ NULL, /* void * _private */
+ NULL, /* startElementNsSAX2Func */
+ NULL, /* endElementNsSAX2Func */
+ NULL /* xmlStructuredErrorFunc */
+};
+
+static void
+end_element(void *state, const xmlChar *name)
+{
+ xmpp_conn_t *conn = (xmpp_conn_t *)state;
+
+ if (xmlStrcmp(name, STREAM_NODE) == 0) {
+ conn->state = CONN_STATE_DONE;
+ } else if (xmlStrcmp(name, STARTTLS_NODE) == 0) {
+ (void) iowrite(conn, START_TLS, strlen(START_TLS));
+ } else if (xmlStrcmp(name, PROCEED_NODE) == 0) {
+ if (start_tls(conn)) {
+ conn->state = CONN_STATE_FAILURE;
+ }
+ } else if (xmlStrcmp(name, FEATURE_NODE) == 0) {
+ if (conn->state == CONN_STATE_TLS) {
+ conn->state = CONN_STATE_FEATURE;
+ (void) iowrite(conn, (char *)LDM_REG_DOMAIN_EVENTS,
+ strlen((char *)LDM_REG_DOMAIN_EVENTS));
+ }
+ } else if (xmlStrcmp(name, XML_LDM_INTERFACE) == 0) {
+ conn->state = CONN_STATE_LDM_INTERFACE;
+ } else if (xmlStrcmp(name, XML_LDM_EVENT) == 0) {
+ conn->state = CONN_STATE_LDM_EVENT;
+ } else if (xmlStrcmp(name, XML_FAILURE) == 0) {
+ conn->state = CONN_STATE_FAILURE;
+ }
+}
+
+/*ARGSUSED*/
+static void
+start_element(void *state, const xmlChar *name, const xmlChar **attrs)
+{
+}
+
+/*ARGSUSED*/
+static void
+error_func(void *state, const char *msg, ...)
+{
+}
+
+static int
+xmpp_connect(xmpp_conn_t *conn)
+{
+ int sock;
+ struct sockaddr_in serveraddr;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ return (-1);
+ }
+
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serveraddr.sin_port = htons(XMPP_DEFAULT_PORT);
+ if (connect(sock, (struct sockaddr *)(&serveraddr),
+ sizeof (struct sockaddr_in)) < 0) {
+ return (-1);
+ }
+
+ (void) bzero(conn, sizeof (xmpp_conn_t));
+ conn->fd = sock;
+ conn->tls_started = B_FALSE;
+
+ conn->parser = xmlCreatePushParserCtxt(&xml_handler, (void *) conn,
+ NULL, NULL, NULL);
+ if (conn->parser == NULL) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+xmpp_close(xmpp_conn_t *conn)
+{
+ (void) close(conn->fd);
+ conn->fd = -1;
+ conn->state = CONN_STATE_UNKNOWN;
+ if (conn->parser != NULL) {
+ xmlFreeParserCtxt(conn->parser);
+ conn->parser = NULL;
+ }
+ if (conn->tls_started) {
+ SSL_free_f(conn->ssl);
+ conn->ssl = NULL;
+ }
+ conn->tls_started = B_FALSE;
+}
+
+static int
+ioread(xmpp_conn_t *conn, char *buf, int size)
+{
+ int count;
+ if (conn->tls_started) {
+ count = SSL_read_f(conn->ssl, buf, size);
+ } else {
+ count = read(conn->fd, buf, size);
+ }
+ if (count <= 0) {
+ conn->state = CONN_STATE_FAILURE;
+ }
+
+ return (count);
+}
+
+static int
+iowrite(xmpp_conn_t *conn, char *buf, int size)
+{
+ int count;
+
+ if (conn->tls_started) {
+ count = SSL_write_f(conn->ssl, buf, size);
+ } else {
+ count = send(conn->fd, buf, size, 0);
+ }
+ if (count <= 0) {
+ conn->state = CONN_STATE_FAILURE;
+ }
+
+ return (count);
+}
+
+/*
+ * notify_event()
+ * Description:
+ * Notify all clients an event by going through the client list and invoke
+ * the callback functions.
+ */
+static void
+notify_event(ldom_event_t event, char *ldom_name)
+{
+ client_info_t *p;
+
+ (void) pthread_mutex_lock(&clt_list.lock);
+
+ for (p = clt_list.head; p != NULL; p = p->next) {
+ p->cb(ldom_name, event, p->data);
+ }
+
+ (void) pthread_mutex_unlock(&clt_list.lock);
+}
+
+/*
+ * xmpp_client_thr()
+ * Description:
+ * The main entry fo the xmpp client thread.
+ */
+/*ARGSUSED*/
+static void *
+xmpp_client_thr(void *data)
+{
+ int rc = 0;
+ int cnt;
+ char buf[XMPP_BUF_SIZE];
+ xmpp_conn_t conn;
+
+ /* initialize the conn struct */
+ bzero(&conn, sizeof (xmpp_conn_t));
+
+ while (xmpp_enable) {
+
+ /* keep making a connection until successfully */
+ do {
+ if (rc = xmpp_connect(&conn))
+ (void) sleep(XMPP_SLEEP);
+ } while (rc != 0 && xmpp_enable);
+
+ /* write the stream node */
+ cnt = iowrite(&conn, (char *)STREAM_START,
+ strlen((char *)STREAM_START));
+
+ /* process input */
+ while ((conn.state != CONN_STATE_FAILURE) &&
+ (conn.state != CONN_STATE_DONE) && xmpp_enable) {
+
+ /*
+ * Assume the document size of a ldmd response is
+ * less than 1KB. This assumption is valid with the
+ * current ldmd implementation.
+ * Should the document size exceeds 1KB, the buffer
+ * size should be revisited accordingly.
+ */
+ (void) memset(buf, 0, XMPP_BUF_SIZE);
+ cnt = ioread(&conn, buf, XMPP_BUF_SIZE);
+ if (cnt <= 0)
+ break;
+ if (rc = xmlParseChunk(conn.parser, buf, cnt, 0)) {
+ conn.state = CONN_STATE_FAILURE;
+ }
+
+ switch (conn.state) {
+ case CONN_STATE_LDM_INTERFACE:
+ handle_ldm_resp(&conn, buf, cnt);
+ break;
+ case CONN_STATE_LDM_EVENT:
+ handle_ldm_event(&conn, buf, cnt);
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * For now, the parser is reset after every read.
+ * It should only be reset once after the ssl is opened
+ * in the start_tls().
+ */
+ (void) xmlCtxtResetPush(conn.parser, NULL, NULL, NULL,
+ NULL);
+ }
+ xmpp_close(&conn);
+ (void) sleep(XMPP_SLEEP);
+ }
+ return (NULL);
+}
+
+/*
+ * find_client()
+ * Description:
+ * Walk to the list to find a libldom client
+ */
+static client_info_t *
+find_client(ldom_hdl_t *lhp)
+{
+ client_info_t *p;
+
+ for (p = clt_list.head; p != NULL; p = p->next) {
+ if (p->lhp == lhp)
+ return (p);
+ }
+
+ return (NULL);
+}
+
+/*
+ * xmpp_add_client()
+ * Description:
+ * Add a libldom client from the client list.
+ */
+int
+xmpp_add_client(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
+{
+ client_info_t *clt;
+
+ (void) pthread_mutex_lock(&clt_list.lock);
+ if (find_client(lhp)) {
+ /* already exists */
+ (void) pthread_mutex_unlock(&clt_list.lock);
+ return (-1);
+ }
+
+ /* new client */
+ clt = (client_info_t *)ldom_alloc(sizeof (client_info_t));
+ clt->lhp = lhp;
+ clt->cb = cb;
+ clt->data = data;
+ clt->next = NULL;
+ clt->prev = NULL;
+
+ if (clt_list.head == NULL && clt_list.tail == NULL) {
+ clt_list.head = clt;
+ clt_list.tail = clt;
+ } else {
+ /* append to the list */
+ clt->prev = clt_list.tail;
+ clt_list.tail->next = clt;
+ clt_list.tail = clt;
+ }
+
+ (void) pthread_mutex_unlock(&clt_list.lock);
+ return (0);
+}
+
+/*
+ * xmpp_remove_client()
+ * Description:
+ * Remove a libldom client from the client list.
+ */
+int
+xmpp_remove_client(ldom_hdl_t *lhp)
+{
+ client_info_t *p;
+
+ (void) pthread_mutex_lock(&clt_list.lock);
+ if ((p = find_client(lhp)) == NULL) {
+ /* not present */
+ (void) pthread_mutex_unlock(&clt_list.lock);
+ return (-1);
+ }
+
+ if (clt_list.head == p && clt_list.tail == p) {
+ /* single item list */
+ clt_list.head = NULL;
+ clt_list.tail = NULL;
+ } else if (clt_list.head == p) {
+ /* delete the head */
+ clt_list.head = p->next;
+ clt_list.head->prev = NULL;
+ } else if (clt_list.tail == p) {
+ /* delete the tail */
+ clt_list.tail = p->prev;
+ clt_list.tail->next = NULL;
+ } else {
+ /* delete a middle node */
+ p->next->prev = p->prev;
+ p->prev->next = p->next;
+ }
+ ldom_free(p, sizeof (client_info_t));
+
+ (void) pthread_mutex_unlock(&clt_list.lock);
+ return (0);
+}
+
+/*
+ * xmpp_stop()
+ * Description:
+ * Stop the xmpp client thread
+ */
+/*ARGSUSED*/
+void
+xmpp_stop(void)
+{
+ (void) pthread_mutex_lock(&xmpp_tid_lock);
+ xmpp_enable = 0;
+ if (xmpp_tid) {
+ (void) pthread_kill(xmpp_tid, SIGTERM);
+ (void) pthread_join(xmpp_tid, NULL);
+ xmpp_tid = 0;
+ }
+ (void) pthread_mutex_unlock(&xmpp_tid_lock);
+}
+
+/*
+ * xmpp_start()
+ * Description:
+ * Start the xmpp client thread if have not done so.
+ */
+void
+xmpp_start(void)
+{
+ xmpp_conn_t conn;
+
+ /* Check if the xmmp thread has already started */
+ (void) pthread_mutex_lock(&xmpp_tid_lock);
+ if (xmpp_tid != 0) {
+ (void) pthread_mutex_unlock(&xmpp_tid_lock);
+ return;
+ }
+
+ /* Check if the ldmd supports xmpp by opening a connection */
+ if (xmpp_connect(&conn)) {
+ (void) pthread_mutex_unlock(&xmpp_tid_lock);
+ return;
+ }
+ xmpp_close(&conn);
+ xmpp_enable = 1;
+
+ /*
+ * create xmpp client thread for receiving domain events
+ */
+ (void) pthread_create(&xmpp_tid, NULL, xmpp_client_thr, NULL);
+
+ (void) pthread_mutex_unlock(&xmpp_tid_lock);
+
+ /*
+ * Register a function to stop the above thread upon a termination
+ */
+ (void) atexit(xmpp_stop);
+}
+
+/*
+ * This routine will run through the first time we get a remote XMPP
+ * connection. After that we will not need to do this again. It cannot be run
+ * from main thread at start as we need to alert remote users if the TLS
+ * handshake failed.
+ */
+static int
+load_SSL_lib()
+{
+ int ret = 0;
+
+ /* If we have already opened the library no need to do it again. */
+ if (xmpp_dl != NULL)
+ return (0);
+
+ if ((xmpp_dl = dlopen("/usr/sfw/lib/libssl.so", RTLD_NOW)) == NULL)
+ return (-1);
+
+ FUNCTION_ADD(SSL_load_error_strings_f, SSL_load_error_strings_pt,
+ xmpp_dl, "SSL_load_error_strings", ret);
+ FUNCTION_ADD(SSL_library_init_f, SSL_library_init_pt, xmpp_dl,
+ "SSL_library_init", ret);
+ FUNCTION_ADD(SSL_CTX_new_f, SSL_CTX_new_pt, xmpp_dl,
+ "SSL_CTX_new", ret);
+ FUNCTION_ADD(SSLv23_client_method_f, SSLv23_client_method_pt, xmpp_dl,
+ "SSLv23_client_method", ret);
+ FUNCTION_ADD(SSL_write_f, SSL_write_pt, xmpp_dl, "SSL_write", ret);
+ FUNCTION_ADD(SSL_CTX_use_PrivateKey_file_f,
+ SSL_CTX_use_PrivateKey_file_pt, xmpp_dl,
+ "SSL_CTX_use_PrivateKey_file", ret);
+ FUNCTION_ADD(RAND_seed_f, RAND_seed_pt, xmpp_dl, "RAND_seed", ret);
+ FUNCTION_ADD(SSL_get_error_f, SSL_get_error_pt, xmpp_dl,
+ "SSL_get_error", ret);
+ FUNCTION_ADD(ERR_get_error_f, ERR_get_error_pt, xmpp_dl,
+ "ERR_get_error", ret);
+ FUNCTION_ADD(ERR_error_string_f, ERR_error_string_pt, xmpp_dl,
+ "ERR_error_string", ret);
+ FUNCTION_ADD(SSL_connect_f, SSL_connect_pt, xmpp_dl, "SSL_connect",
+ ret);
+ FUNCTION_ADD(SSL_CTX_use_certificate_chain_file_f,
+ SSL_CTX_use_certificate_chain_file_pt, xmpp_dl,
+ "SSL_CTX_use_certificate_chain_file", ret);
+ FUNCTION_ADD(SSL_set_fd_f, SSL_set_fd_pt, xmpp_dl, "SSL_set_fd", ret);
+ FUNCTION_ADD(SSL_free_f, SSL_free_pt, xmpp_dl, "SSL_free", ret);
+ FUNCTION_ADD(SSL_read_f, SSL_read_pt, xmpp_dl, "SSL_read", ret);
+ FUNCTION_ADD(SSL_new_f, SSL_new_pt, xmpp_dl, "SSL_new", ret);
+ FUNCTION_ADD(SSL_get_SSL_CTX_f, SSL_get_SSL_CTX_pt, xmpp_dl,
+ "SSL_get_SSL_CTX", ret);
+ FUNCTION_ADD(SSL_CTX_free_f, SSL_CTX_free_pt, xmpp_dl,
+ "SSL_CTX_free", ret);
+
+ if (ret < 0)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * start_tls()
+ * Description:
+ * Load the libssl.so if has not done so and open a ssl connection.
+ * It is assumed that there is one xmpp thread to use the ssl connection.
+ * If multi-thread xmpp clients use the ssl connection, addtional work is
+ * needed to ensure the usage of the ssl be thread-safe.
+ */
+static int
+start_tls(xmpp_conn_t *conn)
+{
+ int rv, urand_fd;
+ SSL_CTX *ssl_ctx;
+ char rand_buf[RAND_BUF_SIZE];
+
+ rv = load_SSL_lib();
+ if (rv == -1) {
+ return (rv);
+ }
+
+ urand_fd = open("/dev/random", O_RDONLY);
+ if (urand_fd == -1) {
+ return (-1);
+ }
+ (void) read(urand_fd, rand_buf, RAND_BUF_SIZE);
+
+ SSL_library_init_f();
+ RAND_seed_f(rand_buf, RAND_BUF_SIZE);
+
+ ssl_ctx = SSL_CTX_new_f(SSLv23_client_method_f());
+ if (ssl_ctx == NULL) {
+ return (-1);
+ }
+ conn->ssl = SSL_new_f(ssl_ctx);
+ rv = SSL_set_fd_f(conn->ssl, conn->fd);
+ if (rv == 0) {
+ return (-1);
+ }
+ rv = SSL_connect_f(conn->ssl);
+ if (rv != 1) {
+ return (-1);
+ }
+ conn->tls_started = B_TRUE;
+ conn->state = CONN_STATE_TLS;
+
+ (void) iowrite(conn, STREAM_START, strlen(STREAM_START));
+
+ return (0);
+}
+
+/*
+ * Find and return the first-level subnode (if any) of 'node' which has name
+ * 'name'.
+ */
+xmlNodePtr
+xml_find_subnode(xmlNodePtr node, const xmlChar *name)
+{
+ xmlNodePtr subnode;
+
+ if (node == NULL)
+ return (NULL);
+
+ subnode = node->xmlChildrenNode;
+ while (subnode != NULL) {
+ if (((char *)subnode->name != NULL) &&
+ (xmlStrcmp(subnode->name, name) == 0))
+ break;
+ subnode = subnode->next;
+ }
+
+ return (subnode);
+}
+
+/*
+ * handle_ldm_resp()
+ * Description:
+ * Parse the ldmd response of the domain event registration for the failure
+ * status. If found, set the connection to failure so that it will be
+ * closed and a new xmpp connection is established.
+ */
+void
+handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size)
+{
+ xmlDocPtr xml_output;
+ xmlNodePtr root, resp, status, cmd, action;
+ char *status_str, *action_str;
+
+ if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
+ return;
+ if ((root = xmlDocGetRootElement(xml_output)) == NULL)
+ return;
+
+ /* get the cmd node */
+ if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
+ return;
+ if (strcmp((char *)cmd->name, (char *)XML_CMD) != 0)
+ return;
+
+ /* get the action node and make sure it is the reg-domain-events */
+ if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
+ return;
+ }
+ if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
+ return;
+ if (strcmp(action_str, XML_REGISTER_ACTION) != 0) {
+ xmlFree(action_str);
+ return;
+ }
+ xmlFree(action_str);
+
+ /* check the status of the response */
+ if ((resp = xml_find_subnode(cmd, XML_RESPONSE)) == NULL)
+ return;
+ if ((status = xml_find_subnode(resp, XML_STATUS)) == NULL)
+ return;
+ if ((status_str = (char *)xmlNodeGetContent(status)) == NULL)
+ return;
+ if (strcmp(status_str, (char *)XML_FAILURE) == 0) {
+ conn->state = CONN_STATE_FAILURE;
+ }
+ xmlFree(status_str);
+}
+
+/*
+ * handle_ldm_event()
+ * Description:
+ * Parse the LDM_event for the ldom name and domain action. Then invokes
+ * the clients's callback to notify them the event.
+ */
+/*ARGSUSED*/
+void
+handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size)
+{
+ int i;
+ xmlDocPtr xml_output;
+ xmlNodePtr root, cmd, action, data, envelope, content;
+ char *action_str, *ldom_name;
+ ldom_event_t event = LDOM_EVENT_UNKNOWN;
+
+ if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
+ return;
+ if ((root = xmlDocGetRootElement(xml_output)) == NULL)
+ return;
+
+ /* get the action such as bind-domain, unbind-domain, etc. */
+ if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
+ return;
+ if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
+ return;
+ }
+ if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
+ return;
+ for (i = 0; i < event_table_size; i++) {
+ if (event_table[i].name != NULL &&
+ strcasecmp(event_table[i].name, action_str) == 0) {
+ event = event_table[i].id;
+ break;
+ }
+ }
+ xmlFree(action_str);
+
+ /* get the ldom name */
+ data = xml_find_subnode(cmd, XML_DATA);
+ envelope = xml_find_subnode(data, XML_ENVELOPE);
+ content = xml_find_subnode(envelope, XML_CONTENT);
+ if ((ldom_name = (char *)xmlGetProp(content, XML_ATTR_ID)) == NULL)
+ return;
+
+ /* Notifies all the clients the event */
+ if (VALID_LDOM_EVENT(event)) {
+ notify_event(event, ldom_name);
+ }
+
+ xmlFree(ldom_name);
+}
diff --git a/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.h b/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.h
new file mode 100644
index 0000000000..aa19f41cd4
--- /dev/null
+++ b/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.h
@@ -0,0 +1,114 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ldom_xmpp_client.h Extensible Messaging and Presence Protocol
+ */
+
+#ifndef _LDOM_XMPP_CLIENT_H
+#define _LDOM_XMPP_CLIENT_H
+
+#include <sys/fm/ldom.h>
+
+#include <pthread.h>
+#include <libxml/xmlstring.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XMPP_DEFAULT_PORT 6482
+#define XMPP_BUF_SIZE 1024
+#define RAND_BUF_SIZE 1024
+#define XMPP_SLEEP 3
+
+#define STREAM_NODE (xmlChar *)"stream:stream"
+#define FEATURE_NODE (xmlChar *)"stream:features"
+#define STARTTLS_NODE (xmlChar *)"starttls"
+#define PROCEED_NODE (xmlChar *)"proceed"
+#define XML_LDM_INTERFACE ((xmlChar *)"LDM_interface")
+#define XML_LDM_EVENT ((xmlChar *)"LDM_event")
+
+#define XML_SUCCESS ((xmlChar *)"success")
+#define XML_FAILURE ((xmlChar *)"failure")
+
+#define XML_CMD ((xmlChar *)"cmd")
+#define XML_ACTION ((xmlChar *)"action")
+#define XML_RESPONSE ((xmlChar *)"response")
+#define XML_STATUS ((xmlChar *)"status")
+#define XML_DATA ((xmlChar *)"data")
+#define XML_ENVELOPE ((xmlChar *)"Envelope")
+#define XML_CONTENT ((xmlChar *)"Content")
+
+#define XML_ATTR_ID ((xmlChar *)"id")
+
+#define XML_REGISTER_ACTION "reg-domain-events"
+
+#define STREAM_START "<?xml version='1.0'?><stream:stream " \
+ "xml:lang=\"en\" version=\"1.0\" id=\"xmpp\"" \
+ ">"
+#define START_TLS "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
+
+#define LDM_REG_DOMAIN_EVENTS \
+ "<LDM_interface version=\"1.1\">" \
+ " <cmd>" \
+ " <action>reg-domain-events</action>" \
+ " <data version=\"3.0\"> </data>" \
+ " </cmd>" \
+ "</LDM_interface>"
+
+
+typedef struct ldom_event_info {
+ ldom_event_t id;
+ char *name;
+} ldom_event_info_t;
+
+
+typedef struct client_info {
+ ldom_hdl_t *lhp;
+ ldom_reg_cb_t cb;
+ ldom_cb_arg_t data;
+ struct client_info *next;
+ struct client_info *prev;
+} client_info_t;
+
+typedef struct client_list {
+ client_info_t *head;
+ client_info_t *tail;
+ pthread_mutex_t lock;
+} client_list_t;
+
+
+extern int xmpp_add_client(ldom_hdl_t *lhp, ldom_reg_cb_t cb,
+ ldom_cb_arg_t data);
+extern int xmpp_remove_client(ldom_hdl_t *lhp);
+extern void xmpp_start(void);
+extern void xmpp_stop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDOM_XMPP_CLIENT_H */
diff --git a/usr/src/lib/fm/libldom/sparc/mapfile-vers b/usr/src/lib/fm/libldom/sparc/mapfile-vers
index fee411ff45..359dd5f6a1 100644
--- a/usr/src/lib/fm/libldom/sparc/mapfile-vers
+++ b/usr/src/lib/fm/libldom/sparc/mapfile-vers
@@ -22,21 +22,22 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
SUNWprivate {
global:
ldom_fini;
+ ldom_find_id;
ldom_fmri_blacklist;
ldom_fmri_unblacklist;
ldom_fmri_retire;
ldom_fmri_unretire;
ldom_fmri_status;
ldom_get_core_md;
+ ldom_get_local_md;
+ ldom_get_type;
ldom_init;
- ldom_major_version;
- ldom_on_service;
+ ldom_register_event;
+ ldom_unregister_event;
local:
*;
};
diff --git a/usr/src/lib/fm/libldom/sparcv9/Makefile b/usr/src/lib/fm/libldom/sparcv9/Makefile
index 4502ccb407..1c53dcd407 100644
--- a/usr/src/lib/fm/libldom/sparcv9/Makefile
+++ b/usr/src/lib/fm/libldom/sparcv9/Makefile
@@ -19,11 +19,9 @@
# 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"
-#
MACH_LDLIBS = -L$(ROOT)/usr/lib/fm/$(MACH64)
@@ -33,5 +31,3 @@ include ../../../Makefile.lib.64
DYNFLAGS += -R/usr/lib/fm/$(MACH64)
install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
-
-install_h:
diff --git a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard.c b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard.c
index aaee54ede5..0fc5ade004 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <string.h>
#include <strings.h>
@@ -101,6 +99,7 @@ cpuboard_get_pri_info(topo_mod_t *mod, cpuboard_contents_t cpubs[])
char *pstr = NULL;
char *sn = NULL, *pn = NULL;
char *dn = NULL;
+ uint32_t type = 0;
ldom_hdl_t *lhp;
uint64_t id;
int cpuboards_found = 0;
@@ -118,13 +117,19 @@ cpuboard_get_pri_info(topo_mod_t *mod, cpuboard_contents_t cpubs[])
return (0);
}
- if ((bufsize = ldom_get_core_md(lhp, &bufp)) < 1) {
- topo_mod_dprintf(mod, "ldom_get_core_md error, bufsize=%d\n",
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ bufsize = ldom_get_core_md(lhp, &bufp);
+ } else {
+ bufsize = ldom_get_local_md(lhp, &bufp);
+ }
+ if (bufsize < 1) {
+ topo_mod_dprintf(mod, "Failed to get pri/md, bufsize=%d\n",
bufsize);
ldom_fini(lhp);
return (0);
}
- topo_mod_dprintf(mod, "pri bufsize=%d\n", bufsize);
+ topo_mod_dprintf(mod, "pri/md bufsize=%d\n", bufsize);
if ((mdp = md_init_intern(bufp, cpuboard_topo_alloc,
cpuboard_topo_free)) == NULL ||
@@ -516,7 +521,7 @@ cpuboard_enum(topo_mod_t *mod, tnode_t *parent, const char *name,
topo_strerror(topo_mod_errno(mod)));
return (-1);
}
- if (cpuboard_hb_enum(mod, cpuboard_findrc(mod, i),
+ if (cpuboard_hb_enum(mod, cpuboard_findrc(mod, i), cpub_rcs[i],
cpuboardn, i) < 0) {
topo_node_unbind(cpuboardn);
topo_mod_dprintf(mod, "cpuboard_hb_enum: "
diff --git a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_hostbridge.c b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_hostbridge.c
index 474aa94fda..a07eff31b1 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_hostbridge.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_hostbridge.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <strings.h>
#include <libdevinfo.h>
@@ -79,11 +77,19 @@ cpuboard_node_create(topo_mod_t *mp, tnode_t *parent, const char *name,
}
/*
- * Create a root complex node.
+ * cpuboard_rc_node_create()
+ * Description:
+ * Create a root complex node pciexrc
+ * Parameters:
+ * mp: topo module pointer
+ * parent: topo parent node of the newly created pciexrc node
+ * dnode: Solaris device node of the root complex
+ * rcpath: Used to populated the dev property of the topo pciexrc node if
+ * the local host does not own the root complex.
*/
static tnode_t *
cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
- int inst)
+ char *rcpath, int inst)
{
int err;
tnode_t *rcn;
@@ -107,6 +113,12 @@ cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
if ((dnpath = di_devfs_path(dnode)) != NULL) {
nvlist_t *fmri;
+ /*
+ * The local host owns the root complex, so use the dev path
+ * from the di_devfs_path(), instead of the passed in rcpath,
+ * to populate the dev property.
+ */
+ rcpath = dnpath;
fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION,
dnpath, NULL);
if (fmri == NULL) {
@@ -147,12 +159,14 @@ cpuboard_rc_node_create(topo_mod_t *mp, tnode_t *parent, di_node_t dnode,
return (NULL);
}
/* Add the devfs path property */
- if (dnpath) {
+ if (rcpath) {
if (topo_prop_set_string(rcn, TOPO_PGROUP_IO, TOPO_IO_DEV,
- TOPO_PROP_IMMUTABLE, dnpath, &err) != 0) {
+ TOPO_PROP_IMMUTABLE, rcpath, &err) != 0) {
topo_mod_dprintf(mp, "Failed to set DEV property\n");
topo_mod_seterrno(mp, err);
}
+ }
+ if (dnpath) {
di_devfs_path_free(dnpath);
}
/* T5440 device type is always "pciex" */
@@ -225,7 +239,8 @@ cpuboard_hb_node_create(topo_mod_t *mp, tnode_t *parent, int inst)
* match the cpuboard instance.
*/
int
-cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, tnode_t *cpubn, int brd)
+cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath,
+ tnode_t *cpubn, int brd)
{
int hb;
int rc;
@@ -260,7 +275,7 @@ cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, tnode_t *cpubn, int brd)
return (-1);
}
/* Create the root complex node */
- rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rc);
+ rcnode = cpuboard_rc_node_create(mp, hbnode, dnode, rcpath, rc);
if (rcnode == NULL) {
topo_mod_dprintf(mp,
"unable to create rcnode: %s\n",
diff --git a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_topo.h b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_topo.h
index 9eb5f19725..7d12291f03 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_topo.h
+++ b/usr/src/lib/fm/topo/modules/sun4v/cpuboard/cpuboard_topo.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _CPUBOARD_TOPO_H
#define _CPUBOARD_TOPO_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <fm/topo_hc.h>
#include <fm/topo_mod.h>
@@ -55,7 +53,8 @@ typedef struct {
} cpuboard_contents_t;
/* Shared device tree root node */
-int cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, tnode_t *cpubn, int brd);
+int cpuboard_hb_enum(topo_mod_t *mp, di_node_t dnode, char *rcpath,
+ tnode_t *cpubn, int brd);
/* Until future PRI changes, make connection between cpuboard id and RC */
#define CPUBOARD0_RC "/pci@400"
diff --git a/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_mdesc.c b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_mdesc.c
index 884e29285a..6c81e62107 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_mdesc.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/hostbridge/hb_mdesc.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <strings.h>
#include <umem.h>
@@ -172,6 +170,7 @@ hb_mdesc_init(topo_mod_t *mod, md_info_t *phbmd)
md_t *mdp;
ssize_t bufsiz = 0;
uint64_t *bufp;
+ uint32_t type = 0;
ldom_hdl_t *lhp;
/* get the PRI/MD */
@@ -179,7 +178,14 @@ hb_mdesc_init(topo_mod_t *mod, md_info_t *phbmd)
topo_mod_dprintf(mod, "ldom_init() failed\n");
return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
- if ((bufsiz = ldom_get_core_md(lhp, &bufp)) <= 0) {
+
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ bufsiz = ldom_get_core_md(lhp, &bufp);
+ } else {
+ bufsiz = ldom_get_local_md(lhp, &bufp);
+ }
+ if (bufsiz <= 0) {
topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
ldom_fini(lhp);
return (-1);
diff --git a/usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c b/usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c
index c42c1f852a..d2c0cd5a35 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/motherboard/motherboard.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdlib.h>
#include <string.h>
#include <strings.h>
@@ -129,6 +127,7 @@ mb_get_pri_info(topo_mod_t *mod, char **serialp, char **partp, char **csnp)
int nfrus, num_nodes, i;
char *pstr = NULL;
char *sn, *pn, *dn, *csn;
+ uint32_t type = 0;
ldom_hdl_t *lhp;
lhp = ldom_init(mb_topo_alloc, mb_topo_free);
@@ -145,13 +144,19 @@ mb_get_pri_info(topo_mod_t *mod, char **serialp, char **partp, char **csnp)
return (-1);
}
- if ((bufsize = ldom_get_core_md(lhp, &bufp)) < 1) {
- topo_mod_dprintf(mod, "ldom_get_core_md error, bufsize=%d\n",
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ bufsize = ldom_get_core_md(lhp, &bufp);
+ } else {
+ bufsize = ldom_get_local_md(lhp, &bufp);
+ }
+ if (bufsize < 1) {
+ topo_mod_dprintf(mod, "Failed to get the pri/md (bufsize=%d)\n",
bufsize);
ldom_fini(lhp);
return (-1);
}
- topo_mod_dprintf(mod, "pri bufsize=%d\n", bufsize);
+ topo_mod_dprintf(mod, "pri/md bufsize=%d\n", bufsize);
if ((mdp = md_init_intern(bufp, mb_topo_alloc, mb_topo_free)) == NULL ||
(num_nodes = md_node_count(mdp)) < 1) {
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 5f028e1841..6555a4a2bf 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
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <strings.h>
#include <umem.h>
#include <fm/topo_mod.h>
@@ -316,6 +314,7 @@ cpu_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
uint32_t present = 0;
md_cpumap_t *mcmp;
md_info_t *chip = (md_info_t *)topo_mod_getspecific(mod);
+ uint32_t type = 0;
if (nvlist_lookup_uint8(in, FM_VERSION, &version) != 0 ||
version > FM_CPU_SCHEME_VERSION ||
@@ -341,9 +340,10 @@ cpu_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
if (lhp == NULL) {
return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
+ (void) ldom_get_type(lhp, &type);
status = ldom_fmri_status(lhp, in);
rc = (status == P_FAULTED ||
- (status == P_OFFLINE && ldom_major_version(lhp) == 1));
+ (status == P_OFFLINE && ((type & LDOM_TYPE_CONTROL) != 0)));
ldom_fini(lhp);
/* return the unusable status */
diff --git a/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c b/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c
index b754e278df..6c8a6635e6 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/platform-cpu/cpu_mdesc.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <umem.h>
#include <sys/mdesc.h>
@@ -337,13 +335,21 @@ cpu_mdesc_init(topo_mod_t *mod, md_info_t *chip)
ssize_t bufsiz = 0;
uint64_t *bufp;
ldom_hdl_t *lhp;
+ uint32_t type = 0;
/* get the PRI/MD */
if ((lhp = ldom_init(cpu_alloc, cpu_free)) == NULL) {
topo_mod_dprintf(mod, "ldom_init() failed\n");
return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
- if ((bufsiz = ldom_get_core_md(lhp, &bufp)) <= 0) {
+
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ bufsiz = ldom_get_core_md(lhp, &bufp);
+ } else {
+ bufsiz = ldom_get_local_md(lhp, &bufp);
+ }
+ if (bufsiz <= 0) {
topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
ldom_fini(lhp);
return (-1);
diff --git a/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c b/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c
index a3a617e10e..4639fa44d9 100644
--- a/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c
+++ b/usr/src/lib/fm/topo/modules/sun4v/platform-mem/mem_mdesc.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <umem.h>
#include <sys/mdesc.h>
@@ -420,12 +418,19 @@ mem_mdesc_init(topo_mod_t *mod, md_mem_info_t *mem)
mde_cookie_t *listp;
int num_nodes;
int num_comps = 0;
+ uint32_t type = 0;
/* get the PRI/MD */
if ((lhp = ldom_init(mem_alloc, mem_free)) == NULL) {
return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
- if ((bufsiz = ldom_get_core_md(lhp, &bufp)) <= 0) {
+ (void) ldom_get_type(lhp, &type);
+ if ((type & LDOM_TYPE_CONTROL) != 0) {
+ bufsiz = ldom_get_core_md(lhp, &bufp);
+ } else {
+ bufsiz = ldom_get_local_md(lhp, &bufp);
+ }
+ if (bufsiz <= 0) {
topo_mod_dprintf(mod, "failed to get the PRI/MD\n");
ldom_fini(lhp);
return (-1);