xref: /titanic_51/usr/src/cmd/fm/modules/sun4v/etm/etm.c (revision c5fb5d329e745a7b8cb9ff07eebb42948af7bc4e)
1733a5356Srb144127 /*
2733a5356Srb144127  * CDDL HEADER START
3733a5356Srb144127  *
4733a5356Srb144127  * The contents of this file are subject to the terms of the
531e37bb4Svn83148  * Common Development and Distribution License (the "License").
631e37bb4Svn83148  * You may not use this file except in compliance with the License.
7733a5356Srb144127  *
8733a5356Srb144127  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9733a5356Srb144127  * or http://www.opensolaris.org/os/licensing.
10733a5356Srb144127  * See the License for the specific language governing permissions
11733a5356Srb144127  * and limitations under the License.
12733a5356Srb144127  *
13733a5356Srb144127  * When distributing Covered Code, include this CDDL HEADER in each
14733a5356Srb144127  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15733a5356Srb144127  * If applicable, add the following below this CDDL HEADER, with the
16733a5356Srb144127  * fields enclosed by brackets "[]" replaced with your own identifying
17733a5356Srb144127  * information: Portions Copyright [yyyy] [name of copyright owner]
18733a5356Srb144127  *
19733a5356Srb144127  * CDDL HEADER END
20733a5356Srb144127  */
21733a5356Srb144127 
22733a5356Srb144127 /*
23*c5fb5d32SKarl Davis  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24733a5356Srb144127  * Use is subject to license terms.
25733a5356Srb144127  */
26733a5356Srb144127 
27733a5356Srb144127 /*
28733a5356Srb144127  * etm.c	FMA Event Transport Module implementation, a plugin of FMD
29733a5356Srb144127  *		for sun4v/Ontario
30733a5356Srb144127  *
31733a5356Srb144127  * plugin for sending/receiving FMA events to/from service processor
32733a5356Srb144127  */
33733a5356Srb144127 
34733a5356Srb144127 /*
35733a5356Srb144127  * --------------------------------- includes --------------------------------
36733a5356Srb144127  */
37733a5356Srb144127 
38733a5356Srb144127 #include <sys/fm/protocol.h>
39733a5356Srb144127 #include <sys/fm/util.h>
4031e37bb4Svn83148 #include <sys/fm/ldom.h>
414b476ed5Sdarudy #include <sys/strlog.h>
424b476ed5Sdarudy #include <sys/syslog.h>
4325351652SVuong Nguyen #include <sys/libds.h>
44b8677b72Srb144127 #include <netinet/in.h>
45b8677b72Srb144127 #include <fm/fmd_api.h>
46733a5356Srb144127 
47733a5356Srb144127 #include "etm_xport_api.h"
48733a5356Srb144127 #include "etm_etm_proto.h"
49733a5356Srb144127 #include "etm_impl.h"
5025351652SVuong Nguyen #include "etm_iosvc.h"
5125351652SVuong Nguyen #include "etm_filter.h"
5225351652SVuong Nguyen #include "etm_ckpt.h"
53733a5356Srb144127 
54733a5356Srb144127 #include <pthread.h>
55733a5356Srb144127 #include <signal.h>
56733a5356Srb144127 #include <stropts.h>
57733a5356Srb144127 #include <locale.h>
58733a5356Srb144127 #include <strings.h>
59733a5356Srb144127 #include <stdlib.h>
60733a5356Srb144127 #include <unistd.h>
61733a5356Srb144127 #include <limits.h>
62733a5356Srb144127 #include <values.h>
63733a5356Srb144127 #include <alloca.h>
64733a5356Srb144127 #include <errno.h>
6525351652SVuong Nguyen #include <dlfcn.h>
6625351652SVuong Nguyen #include <link.h>
67733a5356Srb144127 #include <fcntl.h>
68733a5356Srb144127 #include <time.h>
69733a5356Srb144127 
70733a5356Srb144127 /*
71733a5356Srb144127  * ----------------------------- forward decls -------------------------------
72733a5356Srb144127  */
73733a5356Srb144127 
74733a5356Srb144127 static void
75733a5356Srb144127 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class);
76733a5356Srb144127 
7725351652SVuong Nguyen static int
7825351652SVuong Nguyen etm_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *event, nvlist_t *nvl);
7925351652SVuong Nguyen 
8025351652SVuong Nguyen static void
8125351652SVuong Nguyen etm_send_to_remote_root(void *arg);
8225351652SVuong Nguyen 
8325351652SVuong Nguyen static void
8425351652SVuong Nguyen etm_recv_from_remote_root(void *arg);
8525351652SVuong Nguyen 
86d279c7bfSVuong Nguyen static void
87d279c7bfSVuong Nguyen etm_ckpt_remove(fmd_hdl_t *hdl, etm_iosvc_q_ele_t *ele);
88d279c7bfSVuong Nguyen 
89733a5356Srb144127 /*
90733a5356Srb144127  * ------------------------- data structs for FMD ----------------------------
91733a5356Srb144127  */
92733a5356Srb144127 
932c07a099SYanmin Sun static const fmd_hdl_ops_t fmd_ops = {
94733a5356Srb144127 	etm_recv,	/* fmdo_recv */
95733a5356Srb144127 	NULL,		/* fmdo_timeout */
96733a5356Srb144127 	NULL,		/* fmdo_close */
97733a5356Srb144127 	NULL,		/* fmdo_stats */
98733a5356Srb144127 	NULL,		/* fmdo_gc */
9925351652SVuong Nguyen 	etm_send,	/* fmdo_send */
100733a5356Srb144127 };
101733a5356Srb144127 
102733a5356Srb144127 static const fmd_prop_t fmd_props[] = {
103733a5356Srb144127 	{ ETM_PROP_NM_XPORT_ADDRS,		FMD_TYPE_STRING, "" },
104733a5356Srb144127 	{ ETM_PROP_NM_DEBUG_LVL,		FMD_TYPE_INT32, "0" },
105733a5356Srb144127 	{ ETM_PROP_NM_DEBUG_MAX_EV_CNT,		FMD_TYPE_INT32, "-1" },
1064b476ed5Sdarudy 	{ ETM_PROP_NM_CONSOLE,			FMD_TYPE_BOOL, "false" },
1074b476ed5Sdarudy 	{ ETM_PROP_NM_SYSLOGD,			FMD_TYPE_BOOL, "true" },
1084b476ed5Sdarudy 	{ ETM_PROP_NM_FACILITY,			FMD_TYPE_STRING, "LOG_DAEMON" },
109*c5fb5d32SKarl Davis 	{ ETM_PROP_NM_MAX_RESP_Q_LEN,		FMD_TYPE_UINT32, "32" },
1102ca9f232Srb144127 	{ ETM_PROP_NM_BAD_ACC_TO_SEC,		FMD_TYPE_UINT32, "1" },
11125351652SVuong Nguyen 	{ ETM_PROP_NM_FMA_RESP_WAIT_TIME,	FMD_TYPE_INT32, "240" },
112733a5356Srb144127 	{ NULL, 0, NULL }
113733a5356Srb144127 };
114733a5356Srb144127 
1154b476ed5Sdarudy 
116733a5356Srb144127 static const fmd_hdl_info_t fmd_info = {
11725351652SVuong Nguyen 	"FMA Event Transport Module", "1.2", &fmd_ops, fmd_props
118733a5356Srb144127 };
119733a5356Srb144127 
120733a5356Srb144127 /*
121733a5356Srb144127  * ----------------------- private consts and defns --------------------------
122733a5356Srb144127  */
123733a5356Srb144127 
124733a5356Srb144127 /* misc buffer for variable sized protocol header fields */
125733a5356Srb144127 
126733a5356Srb144127 #define	ETM_MISC_BUF_SZ	(4 * 1024)
127733a5356Srb144127 
12825351652SVuong Nguyen static uint32_t
12925351652SVuong Nguyen etm_ldom_type = LDOM_TYPE_LEGACY;
13025351652SVuong Nguyen 
131733a5356Srb144127 /* try limit for IO operations w/ capped exp backoff sleep on retry */
132733a5356Srb144127 
133733a5356Srb144127 /*
134733a5356Srb144127  * Design_Note:	ETM will potentially retry forever IO operations that the
135733a5356Srb144127  *		transport fails with EAGAIN (aka EWOULDBLOCK) rather than
136733a5356Srb144127  *		giving up after some number of seconds. This avoids
137733a5356Srb144127  *		dropping FMA events while the service processor is down,
138733a5356Srb144127  *		but at the risk of pending fmdo_recv() forever and
139733a5356Srb144127  *		overflowing FMD's event queue for ETM.
140733a5356Srb144127  *		A future TBD enhancement would be to always recv
141733a5356Srb144127  *		and send each ETM msg in a single read/write() to reduce
142733a5356Srb144127  *		the risk of failure between ETM msg hdr and body,
143733a5356Srb144127  *		assuming the MTU_SZ is large enough.
144733a5356Srb144127  */
145733a5356Srb144127 
146733a5356Srb144127 #define	ETM_TRY_MAX_CNT		(MAXINT - 1)
147733a5356Srb144127 #define	ETM_TRY_BACKOFF_RATE	(4)
148733a5356Srb144127 #define	ETM_TRY_BACKOFF_CAP	(60)
149733a5356Srb144127 
150e2ff4ac6Srb144127 /* amount to increment protocol transaction id on each new send */
151733a5356Srb144127 
152733a5356Srb144127 #define	ETM_XID_INC		(2)
153733a5356Srb144127 
154b8677b72Srb144127 typedef struct etm_resp_q_ele {
155b8677b72Srb144127 
156b8677b72Srb144127 	etm_xport_conn_t	rqe_conn;	/* open connection to send on */
157b8677b72Srb144127 	etm_proto_v1_pp_t	*rqe_hdrp;	/* ptr to ETM msg hdr */
158b8677b72Srb144127 	size_t			rqe_hdr_sz;	/* sizeof ETM msg hdr */
159b8677b72Srb144127 	int32_t			rqe_resp_code;	/* response code to send */
160b8677b72Srb144127 
161b8677b72Srb144127 	struct etm_resp_q_ele	*rqe_nextp;	/* PRIVATE - next ele ptr */
162b8677b72Srb144127 
163b8677b72Srb144127 } etm_resp_q_ele_t;	/* responder queue element */
164b8677b72Srb144127 
165733a5356Srb144127 /*
166733a5356Srb144127  * ---------------------------- global data ----------------------------------
167733a5356Srb144127  */
168733a5356Srb144127 
16931e37bb4Svn83148 static fmd_hdl_t
17025351652SVuong Nguyen *init_hdl = NULL;	/* used in mem allocator and several other places */
17131e37bb4Svn83148 
172733a5356Srb144127 static int
173733a5356Srb144127 etm_debug_lvl = 0;	/* debug level: 0 is off, 1 is on, 2 is more, etc */
174733a5356Srb144127 
175733a5356Srb144127 static int
176733a5356Srb144127 etm_debug_max_ev_cnt = -1; /* max allowed event count for debugging */
177733a5356Srb144127 
17800ab1250Srb144127 static fmd_xprt_t
17900ab1250Srb144127 *etm_fmd_xprt = NULL;	/* FMD transport layer handle */
18000ab1250Srb144127 
181733a5356Srb144127 static pthread_t
182733a5356Srb144127 etm_svr_tid = NULL;	/* thread id of connection acceptance server */
183733a5356Srb144127 
184b8677b72Srb144127 static pthread_t
185b8677b72Srb144127 etm_resp_tid = NULL;	/* thread id of msg responder */
186b8677b72Srb144127 
187b8677b72Srb144127 static etm_resp_q_ele_t
188b8677b72Srb144127 *etm_resp_q_head = NULL; /* ptr to cur head of responder queue */
189b8677b72Srb144127 
190b8677b72Srb144127 static etm_resp_q_ele_t
191b8677b72Srb144127 *etm_resp_q_tail = NULL; /* ptr to cur tail of responder queue */
192b8677b72Srb144127 
193b8677b72Srb144127 static uint32_t
194b8677b72Srb144127 etm_resp_q_cur_len = 0;	/* cur length (ele cnt) of responder queue */
195b8677b72Srb144127 
196b8677b72Srb144127 static uint32_t
197b8677b72Srb144127 etm_resp_q_max_len = 0;	/* max length (ele cnt) of responder queue */
198b8677b72Srb144127 
1992ca9f232Srb144127 static uint32_t
2002ca9f232Srb144127 etm_bad_acc_to_sec = 0;	/* sleep timeout (in sec) after bad conn accept */
2012ca9f232Srb144127 
202b8677b72Srb144127 static pthread_mutex_t
203b8677b72Srb144127 etm_resp_q_lock = PTHREAD_MUTEX_INITIALIZER;	/* protects responder queue */
204b8677b72Srb144127 
205b8677b72Srb144127 static pthread_cond_t
206b8677b72Srb144127 etm_resp_q_cv = PTHREAD_COND_INITIALIZER;	/* nudges msg responder */
207b8677b72Srb144127 
208733a5356Srb144127 static volatile int
209733a5356Srb144127 etm_is_dying = 0;	/* bool for dying (killing self) */
210733a5356Srb144127 
211733a5356Srb144127 static uint32_t
212e2ff4ac6Srb144127 etm_xid_cur = 0;	/* current transaction id for sends */
213733a5356Srb144127 
214733a5356Srb144127 static uint32_t
215733a5356Srb144127 etm_xid_ping = 0;	/* xid of last CONTROL msg sent requesting ping */
216733a5356Srb144127 
217733a5356Srb144127 static uint32_t
218e2ff4ac6Srb144127 etm_xid_ver_negot = 0;	/* xid of last CONTROL msg sent requesting ver negot */
219e2ff4ac6Srb144127 
220e2ff4ac6Srb144127 static uint32_t
22125351652SVuong Nguyen etm_xid_posted_logged_ev = 0;
22225351652SVuong Nguyen 			/* xid of last FMA_EVENT msg/event posted OK to FMD */
223e2ff4ac6Srb144127 
224b8677b72Srb144127 static uint32_t
225b8677b72Srb144127 etm_xid_posted_sa = 0;	/* xid of last ALERT msg/event posted OK to syslog */
226b8677b72Srb144127 
227e2ff4ac6Srb144127 static uint8_t
228e2ff4ac6Srb144127 etm_resp_ver = ETM_PROTO_V1; /* proto ver [negotiated] for msg sends */
229733a5356Srb144127 
23025351652SVuong Nguyen static uint32_t
23125351652SVuong Nguyen etm_fma_resp_wait_time = 30;	/*  time (sec) wait for fma event resp */
23225351652SVuong Nguyen 
2332ae66659Sjrutt static pthread_mutex_t
2342ae66659Sjrutt etm_write_lock = PTHREAD_MUTEX_INITIALIZER;	/* for write operations */
2352ae66659Sjrutt 
2364b476ed5Sdarudy static log_ctl_t syslog_ctl;	/* log(7D) meta-data for each msg */
2374b476ed5Sdarudy static int syslog_facility;	/* log(7D) facility (part of priority) */
2384b476ed5Sdarudy static int syslog_logfd = -1;	/* log(7D) file descriptor */
2394b476ed5Sdarudy static int syslog_msgfd = -1;	/* sysmsg(7D) file descriptor */
2404b476ed5Sdarudy static int syslog_file = 0;	/* log to syslog_logfd */
2414b476ed5Sdarudy static int syslog_cons = 0;	/* log to syslog_msgfd */
2424b476ed5Sdarudy 
2434b476ed5Sdarudy static const struct facility {
2444b476ed5Sdarudy 	const char *fac_name;
2454b476ed5Sdarudy 	int fac_value;
2464b476ed5Sdarudy } syslog_facs[] = {
2474b476ed5Sdarudy 	{ "LOG_DAEMON", LOG_DAEMON },
2484b476ed5Sdarudy 	{ "LOG_LOCAL0", LOG_LOCAL0 },
2494b476ed5Sdarudy 	{ "LOG_LOCAL1", LOG_LOCAL1 },
2504b476ed5Sdarudy 	{ "LOG_LOCAL2", LOG_LOCAL2 },
2514b476ed5Sdarudy 	{ "LOG_LOCAL3", LOG_LOCAL3 },
2524b476ed5Sdarudy 	{ "LOG_LOCAL4", LOG_LOCAL4 },
2534b476ed5Sdarudy 	{ "LOG_LOCAL5", LOG_LOCAL5 },
2544b476ed5Sdarudy 	{ "LOG_LOCAL6", LOG_LOCAL6 },
2554b476ed5Sdarudy 	{ "LOG_LOCAL7", LOG_LOCAL7 },
2564b476ed5Sdarudy 	{ NULL, 0 }
2574b476ed5Sdarudy };
2584b476ed5Sdarudy 
259733a5356Srb144127 static struct stats {
260733a5356Srb144127 
261733a5356Srb144127 	/* ETM msg counters */
262733a5356Srb144127 
263733a5356Srb144127 	fmd_stat_t etm_rd_hdr_fmaevent;
264733a5356Srb144127 	fmd_stat_t etm_rd_hdr_control;
2654b476ed5Sdarudy 	fmd_stat_t etm_rd_hdr_alert;
266733a5356Srb144127 	fmd_stat_t etm_rd_hdr_response;
267733a5356Srb144127 	fmd_stat_t etm_rd_body_fmaevent;
268733a5356Srb144127 	fmd_stat_t etm_rd_body_control;
2694b476ed5Sdarudy 	fmd_stat_t etm_rd_body_alert;
270733a5356Srb144127 	fmd_stat_t etm_rd_body_response;
271733a5356Srb144127 	fmd_stat_t etm_wr_hdr_fmaevent;
272733a5356Srb144127 	fmd_stat_t etm_wr_hdr_control;
273733a5356Srb144127 	fmd_stat_t etm_wr_hdr_response;
274733a5356Srb144127 	fmd_stat_t etm_wr_body_fmaevent;
275733a5356Srb144127 	fmd_stat_t etm_wr_body_control;
276733a5356Srb144127 	fmd_stat_t etm_wr_body_response;
277733a5356Srb144127 
278b8677b72Srb144127 	fmd_stat_t etm_rd_max_ev_per_msg;
279b8677b72Srb144127 	fmd_stat_t etm_wr_max_ev_per_msg;
280b8677b72Srb144127 
281b8677b72Srb144127 	fmd_stat_t etm_resp_q_cur_len;
282b8677b72Srb144127 	fmd_stat_t etm_resp_q_max_len;
283b8677b72Srb144127 
284733a5356Srb144127 	/* ETM byte counters */
285733a5356Srb144127 
286733a5356Srb144127 	fmd_stat_t etm_wr_fmd_bytes;
287733a5356Srb144127 	fmd_stat_t etm_rd_fmd_bytes;
288733a5356Srb144127 	fmd_stat_t etm_wr_xport_bytes;
289733a5356Srb144127 	fmd_stat_t etm_rd_xport_bytes;
290733a5356Srb144127 
291733a5356Srb144127 	fmd_stat_t etm_magic_drop_bytes;
292733a5356Srb144127 
293733a5356Srb144127 	/* ETM [dropped] FMA event counters */
294733a5356Srb144127 
295733a5356Srb144127 	fmd_stat_t etm_rd_fmd_fmaevent;
296733a5356Srb144127 	fmd_stat_t etm_wr_fmd_fmaevent;
297733a5356Srb144127 
298733a5356Srb144127 	fmd_stat_t etm_rd_drop_fmaevent;
299733a5356Srb144127 	fmd_stat_t etm_wr_drop_fmaevent;
300733a5356Srb144127 
301e2ff4ac6Srb144127 	fmd_stat_t etm_rd_dup_fmaevent;
302e2ff4ac6Srb144127 	fmd_stat_t etm_wr_dup_fmaevent;
303e2ff4ac6Srb144127 
304b8677b72Srb144127 	fmd_stat_t etm_rd_dup_alert;
305b8677b72Srb144127 	fmd_stat_t etm_wr_dup_alert;
306b8677b72Srb144127 
307b8677b72Srb144127 	fmd_stat_t etm_enq_drop_resp_q;
308b8677b72Srb144127 	fmd_stat_t etm_deq_drop_resp_q;
309b8677b72Srb144127 
310733a5356Srb144127 	/* ETM protocol failures */
311733a5356Srb144127 
312733a5356Srb144127 	fmd_stat_t etm_magic_bad;
313733a5356Srb144127 	fmd_stat_t etm_ver_bad;
314733a5356Srb144127 	fmd_stat_t etm_msgtype_bad;
315733a5356Srb144127 	fmd_stat_t etm_subtype_bad;
316733a5356Srb144127 	fmd_stat_t etm_xid_bad;
317733a5356Srb144127 	fmd_stat_t etm_fmaeventlen_bad;
318733a5356Srb144127 	fmd_stat_t etm_respcode_bad;
319733a5356Srb144127 	fmd_stat_t etm_timeout_bad;
320733a5356Srb144127 	fmd_stat_t etm_evlens_bad;
321733a5356Srb144127 
322733a5356Srb144127 	/* IO operation failures */
323733a5356Srb144127 
324733a5356Srb144127 	fmd_stat_t etm_xport_wr_fail;
325733a5356Srb144127 	fmd_stat_t etm_xport_rd_fail;
326733a5356Srb144127 	fmd_stat_t etm_xport_pk_fail;
327733a5356Srb144127 
328733a5356Srb144127 	/* IO operation retries */
329733a5356Srb144127 
330733a5356Srb144127 	fmd_stat_t etm_xport_wr_retry;
331733a5356Srb144127 	fmd_stat_t etm_xport_rd_retry;
332733a5356Srb144127 	fmd_stat_t etm_xport_pk_retry;
333733a5356Srb144127 
334733a5356Srb144127 	/* system and library failures */
335733a5356Srb144127 
336733a5356Srb144127 	fmd_stat_t etm_os_nvlist_pack_fail;
337733a5356Srb144127 	fmd_stat_t etm_os_nvlist_unpack_fail;
338733a5356Srb144127 	fmd_stat_t etm_os_nvlist_size_fail;
339733a5356Srb144127 	fmd_stat_t etm_os_pthread_create_fail;
340733a5356Srb144127 
341733a5356Srb144127 	/* xport API failures */
342733a5356Srb144127 
343733a5356Srb144127 	fmd_stat_t etm_xport_get_ev_addrv_fail;
344733a5356Srb144127 	fmd_stat_t etm_xport_open_fail;
345733a5356Srb144127 	fmd_stat_t etm_xport_close_fail;
346733a5356Srb144127 	fmd_stat_t etm_xport_accept_fail;
347733a5356Srb144127 	fmd_stat_t etm_xport_open_retry;
348733a5356Srb144127 
349733a5356Srb144127 	/* FMD entry point bad arguments */
350733a5356Srb144127 
351733a5356Srb144127 	fmd_stat_t etm_fmd_init_badargs;
352733a5356Srb144127 	fmd_stat_t etm_fmd_fini_badargs;
353733a5356Srb144127 
3544b476ed5Sdarudy 	/* Alert logging errors */
355b8677b72Srb144127 
3564b476ed5Sdarudy 	fmd_stat_t etm_log_err;
3574b476ed5Sdarudy 	fmd_stat_t etm_msg_err;
3584b476ed5Sdarudy 
3592ca9f232Srb144127 	/* miscellaneous stats */
3602ca9f232Srb144127 
3612ca9f232Srb144127 	fmd_stat_t etm_reset_xport;
3622ca9f232Srb144127 
363733a5356Srb144127 } etm_stats = {
364733a5356Srb144127 
365733a5356Srb144127 	/* ETM msg counters */
366733a5356Srb144127 
367733a5356Srb144127 	{ "etm_rd_hdr_fmaevent", FMD_TYPE_UINT64,
368733a5356Srb144127 		"ETM fmaevent msg headers rcvd from xport" },
369733a5356Srb144127 	{ "etm_rd_hdr_control", FMD_TYPE_UINT64,
370733a5356Srb144127 		"ETM control msg headers rcvd from xport" },
3714b476ed5Sdarudy 	{ "etm_rd_hdr_alert", FMD_TYPE_UINT64,
3724b476ed5Sdarudy 		"ETM alert msg headers rcvd from xport" },
373733a5356Srb144127 	{ "etm_rd_hdr_response", FMD_TYPE_UINT64,
374733a5356Srb144127 		"ETM response msg headers rcvd from xport" },
375733a5356Srb144127 	{ "etm_rd_body_fmaevent", FMD_TYPE_UINT64,
376733a5356Srb144127 		"ETM fmaevent msg bodies rcvd from xport" },
377733a5356Srb144127 	{ "etm_rd_body_control", FMD_TYPE_UINT64,
378733a5356Srb144127 		"ETM control msg bodies rcvd from xport" },
3794b476ed5Sdarudy 	{ "etm_rd_body_alert", FMD_TYPE_UINT64,
3804b476ed5Sdarudy 		"ETM alert msg bodies rcvd from xport" },
381733a5356Srb144127 	{ "etm_rd_body_response", FMD_TYPE_UINT64,
382733a5356Srb144127 		"ETM response msg bodies rcvd from xport" },
383733a5356Srb144127 	{ "etm_wr_hdr_fmaevent", FMD_TYPE_UINT64,
384733a5356Srb144127 		"ETM fmaevent msg headers sent to xport" },
385733a5356Srb144127 	{ "etm_wr_hdr_control", FMD_TYPE_UINT64,
386733a5356Srb144127 		"ETM control msg headers sent to xport" },
387733a5356Srb144127 	{ "etm_wr_hdr_response", FMD_TYPE_UINT64,
388733a5356Srb144127 		"ETM response msg headers sent to xport" },
389733a5356Srb144127 	{ "etm_wr_body_fmaevent", FMD_TYPE_UINT64,
390733a5356Srb144127 		"ETM fmaevent msg bodies sent to xport" },
391733a5356Srb144127 	{ "etm_wr_body_control", FMD_TYPE_UINT64,
392733a5356Srb144127 		"ETM control msg bodies sent to xport" },
393733a5356Srb144127 	{ "etm_wr_body_response", FMD_TYPE_UINT64,
394733a5356Srb144127 		"ETM response msg bodies sent to xport" },
395733a5356Srb144127 
396b8677b72Srb144127 	{ "etm_rd_max_ev_per_msg", FMD_TYPE_UINT64,
397b8677b72Srb144127 		"max FMA events per ETM msg from xport" },
398b8677b72Srb144127 	{ "etm_wr_max_ev_per_msg", FMD_TYPE_UINT64,
399b8677b72Srb144127 		"max FMA events per ETM msg to xport" },
400b8677b72Srb144127 
401b8677b72Srb144127 	{ "etm_resp_q_cur_len", FMD_TYPE_UINT64,
402b8677b72Srb144127 		"cur enqueued response msgs to xport" },
403b8677b72Srb144127 	{ "etm_resp_q_max_len", FMD_TYPE_UINT64,
404b8677b72Srb144127 		"max enqueable response msgs to xport" },
405b8677b72Srb144127 
406733a5356Srb144127 	/* ETM byte counters */
407733a5356Srb144127 
408733a5356Srb144127 	{ "etm_wr_fmd_bytes", FMD_TYPE_UINT64,
409733a5356Srb144127 		"bytes of FMA events sent to FMD" },
410733a5356Srb144127 	{ "etm_rd_fmd_bytes", FMD_TYPE_UINT64,
411733a5356Srb144127 		"bytes of FMA events rcvd from FMD" },
412733a5356Srb144127 	{ "etm_wr_xport_bytes", FMD_TYPE_UINT64,
413733a5356Srb144127 		"bytes of FMA events sent to xport" },
414733a5356Srb144127 	{ "etm_rd_xport_bytes", FMD_TYPE_UINT64,
415733a5356Srb144127 		"bytes of FMA events rcvd from xport" },
416733a5356Srb144127 
417733a5356Srb144127 	{ "etm_magic_drop_bytes", FMD_TYPE_UINT64,
418733a5356Srb144127 		"bytes dropped from xport pre magic num" },
419733a5356Srb144127 
420733a5356Srb144127 	/* ETM [dropped] FMA event counters */
421733a5356Srb144127 
422733a5356Srb144127 	{ "etm_rd_fmd_fmaevent", FMD_TYPE_UINT64,
423733a5356Srb144127 		"FMA events rcvd from FMD" },
424733a5356Srb144127 	{ "etm_wr_fmd_fmaevent", FMD_TYPE_UINT64,
425733a5356Srb144127 		"FMA events sent to FMD" },
426733a5356Srb144127 
427733a5356Srb144127 	{ "etm_rd_drop_fmaevent", FMD_TYPE_UINT64,
428733a5356Srb144127 		"dropped FMA events from xport" },
429733a5356Srb144127 	{ "etm_wr_drop_fmaevent", FMD_TYPE_UINT64,
430733a5356Srb144127 		"dropped FMA events to xport" },
431733a5356Srb144127 
432e2ff4ac6Srb144127 	{ "etm_rd_dup_fmaevent", FMD_TYPE_UINT64,
433b8677b72Srb144127 	    "duplicate FMA events rcvd from xport" },
434e2ff4ac6Srb144127 	{ "etm_wr_dup_fmaevent", FMD_TYPE_UINT64,
435b8677b72Srb144127 	    "duplicate FMA events sent to xport" },
436b8677b72Srb144127 
437b8677b72Srb144127 	{ "etm_rd_dup_alert", FMD_TYPE_UINT64,
438b8677b72Srb144127 	    "duplicate ALERTs rcvd from xport" },
439b8677b72Srb144127 	{ "etm_wr_dup_alert", FMD_TYPE_UINT64,
440b8677b72Srb144127 	    "duplicate ALERTs sent to xport" },
441b8677b72Srb144127 
442b8677b72Srb144127 	{ "etm_enq_drop_resp_q", FMD_TYPE_UINT64,
443b8677b72Srb144127 	    "dropped response msgs on enq" },
444b8677b72Srb144127 	{ "etm_deq_drop_resp_q", FMD_TYPE_UINT64,
445b8677b72Srb144127 	    "dropped response msgs on deq" },
446e2ff4ac6Srb144127 
447733a5356Srb144127 	/* ETM protocol failures */
448733a5356Srb144127 
449733a5356Srb144127 	{ "etm_magic_bad", FMD_TYPE_UINT64,
450733a5356Srb144127 		"ETM msgs w/ invalid magic num" },
451733a5356Srb144127 	{ "etm_ver_bad", FMD_TYPE_UINT64,
452733a5356Srb144127 		"ETM msgs w/ invalid protocol version" },
453733a5356Srb144127 	{ "etm_msgtype_bad", FMD_TYPE_UINT64,
454733a5356Srb144127 		"ETM msgs w/ invalid message type" },
455733a5356Srb144127 	{ "etm_subtype_bad", FMD_TYPE_UINT64,
456733a5356Srb144127 		"ETM msgs w/ invalid sub type" },
457733a5356Srb144127 	{ "etm_xid_bad", FMD_TYPE_UINT64,
458733a5356Srb144127 		"ETM msgs w/ unmatched xid" },
459733a5356Srb144127 	{ "etm_fmaeventlen_bad", FMD_TYPE_UINT64,
460733a5356Srb144127 		"ETM msgs w/ invalid FMA event length" },
461733a5356Srb144127 	{ "etm_respcode_bad", FMD_TYPE_UINT64,
462733a5356Srb144127 		"ETM msgs w/ invalid response code" },
463733a5356Srb144127 	{ "etm_timeout_bad", FMD_TYPE_UINT64,
464733a5356Srb144127 		"ETM msgs w/ invalid timeout value" },
465733a5356Srb144127 	{ "etm_evlens_bad", FMD_TYPE_UINT64,
466733a5356Srb144127 		"ETM msgs w/ too many event lengths" },
467733a5356Srb144127 
468733a5356Srb144127 	/* IO operation failures */
469733a5356Srb144127 
470733a5356Srb144127 	{ "etm_xport_wr_fail", FMD_TYPE_UINT64,
471733a5356Srb144127 		"xport write failures" },
472733a5356Srb144127 	{ "etm_xport_rd_fail", FMD_TYPE_UINT64,
473733a5356Srb144127 		"xport read failures" },
474733a5356Srb144127 	{ "etm_xport_pk_fail", FMD_TYPE_UINT64,
475733a5356Srb144127 		"xport peek failures" },
476733a5356Srb144127 
477733a5356Srb144127 	/* IO operation retries */
478733a5356Srb144127 
479733a5356Srb144127 	{ "etm_xport_wr_retry", FMD_TYPE_UINT64,
480733a5356Srb144127 		"xport write retries" },
481733a5356Srb144127 	{ "etm_xport_rd_retry", FMD_TYPE_UINT64,
482733a5356Srb144127 		"xport read retries" },
483733a5356Srb144127 	{ "etm_xport_pk_retry", FMD_TYPE_UINT64,
484733a5356Srb144127 		"xport peek retries" },
485733a5356Srb144127 
486733a5356Srb144127 	/* system and library failures */
487733a5356Srb144127 
488733a5356Srb144127 	{ "etm_os_nvlist_pack_fail", FMD_TYPE_UINT64,
489733a5356Srb144127 		"nvlist_pack failures" },
490733a5356Srb144127 	{ "etm_os_nvlist_unpack_fail", FMD_TYPE_UINT64,
491733a5356Srb144127 		"nvlist_unpack failures" },
492733a5356Srb144127 	{ "etm_os_nvlist_size_fail", FMD_TYPE_UINT64,
493733a5356Srb144127 		"nvlist_size failures" },
494733a5356Srb144127 	{ "etm_os_pthread_create_fail", FMD_TYPE_UINT64,
495733a5356Srb144127 		"pthread_create failures" },
496733a5356Srb144127 
497733a5356Srb144127 	/* transport API failures */
498733a5356Srb144127 
499733a5356Srb144127 	{ "etm_xport_get_ev_addrv_fail", FMD_TYPE_UINT64,
500733a5356Srb144127 		"xport get event addrv API failures" },
501733a5356Srb144127 	{ "etm_xport_open_fail", FMD_TYPE_UINT64,
502733a5356Srb144127 		"xport open API failures" },
503733a5356Srb144127 	{ "etm_xport_close_fail", FMD_TYPE_UINT64,
504733a5356Srb144127 		"xport close API failures" },
505733a5356Srb144127 	{ "etm_xport_accept_fail", FMD_TYPE_UINT64,
506733a5356Srb144127 		"xport accept API failures" },
507733a5356Srb144127 	{ "etm_xport_open_retry", FMD_TYPE_UINT64,
508733a5356Srb144127 		"xport open API retries" },
509733a5356Srb144127 
510733a5356Srb144127 	/* FMD entry point bad arguments */
511733a5356Srb144127 
512733a5356Srb144127 	{ "etm_fmd_init_badargs", FMD_TYPE_UINT64,
513733a5356Srb144127 	    "bad arguments from fmd_init entry point" },
514733a5356Srb144127 	{ "etm_fmd_fini_badargs", FMD_TYPE_UINT64,
5154b476ed5Sdarudy 	    "bad arguments from fmd_fini entry point" },
5164b476ed5Sdarudy 
5174b476ed5Sdarudy 	/* Alert logging errors */
518b8677b72Srb144127 
5194b476ed5Sdarudy 	{ "etm_log_err", FMD_TYPE_UINT64,
5204b476ed5Sdarudy 		"failed to log message to log(7D)" },
5214b476ed5Sdarudy 	{ "etm_msg_err", FMD_TYPE_UINT64,
5222ca9f232Srb144127 		"failed to log message to sysmsg(7D)" },
5232ca9f232Srb144127 
5242ca9f232Srb144127 	/* miscellaneous stats */
5252ca9f232Srb144127 
5262ca9f232Srb144127 	{ "etm_reset_xport", FMD_TYPE_UINT64,
5272ca9f232Srb144127 		"xport resets after xport API failure" }
528733a5356Srb144127 };
529733a5356Srb144127 
53025351652SVuong Nguyen 
53125351652SVuong Nguyen /*
53225351652SVuong Nguyen  * -------------------- global data for Root ldom-------------------------
53325351652SVuong Nguyen  */
53425351652SVuong Nguyen 
53525351652SVuong Nguyen ldom_hdl_t
53625351652SVuong Nguyen *etm_lhp = NULL;		/* ldom pointer */
53725351652SVuong Nguyen 
53825351652SVuong Nguyen static void *etm_dl_hdl = (void *)NULL;
53925351652SVuong Nguyen static const char *etm_dl_path = "libds.so.1";
54025351652SVuong Nguyen static int etm_dl_mode = (RTLD_NOW | RTLD_LOCAL);
54125351652SVuong Nguyen 
54225351652SVuong Nguyen static int(*etm_ds_svc_reg)(ds_capability_t *cap, ds_ops_t *ops) =
54325351652SVuong Nguyen 	(int (*)(ds_capability_t *cap, ds_ops_t *ops))NULL;
54425351652SVuong Nguyen static int(*etm_ds_clnt_reg)(ds_capability_t *cap, ds_ops_t *ops) =
54525351652SVuong Nguyen 	(int (*)(ds_capability_t *cap, ds_ops_t *ops))NULL;
54625351652SVuong Nguyen static int(*etm_ds_send_msg)(ds_hdl_t hdl, void *buf, size_t buflen) =
54725351652SVuong Nguyen 	(int (*)(ds_hdl_t hdl, void *buf, size_t buflen))NULL;
54825351652SVuong Nguyen static int(*etm_ds_recv_msg)(ds_hdl_t hdl, void *buf, size_t buflen,
54925351652SVuong Nguyen     size_t *msglen) =
55025351652SVuong Nguyen 	(int (*)(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen))NULL;
55125351652SVuong Nguyen static int (*etm_ds_fini)(void) = (int (*)(void))NULL;
55225351652SVuong Nguyen 
55325351652SVuong Nguyen static pthread_mutex_t
55425351652SVuong Nguyen iosvc_list_lock =  PTHREAD_MUTEX_INITIALIZER;
55525351652SVuong Nguyen 
55625351652SVuong Nguyen static pthread_t
55725351652SVuong Nguyen etm_async_e_tid = NULL;	/* thread id of io svc async event handler */
55825351652SVuong Nguyen 
55925351652SVuong Nguyen static etm_proto_v1_ev_hdr_t iosvc_hdr = {
56025351652SVuong Nguyen 	ETM_PROTO_MAGIC_NUM,	/* magic number */
56125351652SVuong Nguyen 	ETM_PROTO_V1,		/* default to V1, not checked */
56225351652SVuong Nguyen 	ETM_MSG_TYPE_FMA_EVENT,	/* Root Domain inteoduces only FMA events */
56325351652SVuong Nguyen 	0,			/* sub-type */
56425351652SVuong Nguyen 	0,			/* pad */
56525351652SVuong Nguyen 	0,			/* add the xid at the Q send time */
56625351652SVuong Nguyen 	ETM_PROTO_V1_TIMEOUT_NONE,
56725351652SVuong Nguyen 	0			/* ev_lens, 0-termed, after 1 FMA event */
56825351652SVuong Nguyen };
56925351652SVuong Nguyen 
57025351652SVuong Nguyen /*
57125351652SVuong Nguyen  * static iosvc_list
57225351652SVuong Nguyen  */
57325351652SVuong Nguyen static etm_iosvc_t iosvc_list[NUM_OF_ROOT_DOMAINS] = {
57425351652SVuong Nguyen 	{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0},
57525351652SVuong Nguyen 	{"", 0}, {"", 0}
57625351652SVuong Nguyen };
57725351652SVuong Nguyen 
57825351652SVuong Nguyen static etm_iosvc_t io_svc = {
57925351652SVuong Nguyen 	"\0",				/* ldom_name */
58025351652SVuong Nguyen 	PTHREAD_COND_INITIALIZER,	/* nudges */
58125351652SVuong Nguyen 	PTHREAD_MUTEX_INITIALIZER,	/* protects the iosvc msg Q */
58225351652SVuong Nguyen 	NULL,				/* iosvc msg Q head */
58325351652SVuong Nguyen 	NULL,				/* iosvc msg Q tail */
58425351652SVuong Nguyen 	0,				/* msg Q current length */
58525351652SVuong Nguyen 	100,				/* msg Q max length */
58625351652SVuong Nguyen 	0,				/* current transaction id */
58725351652SVuong Nguyen 	0,				/* xid of last event posted to FMD */
58825351652SVuong Nguyen 	DS_INVALID_HDL,			/* DS handle */
58925351652SVuong Nguyen 	NULL,				/* fmd xprt handle */
59025351652SVuong Nguyen 	NULL,				/* tid 4 send to remote RootDomain */
59125351652SVuong Nguyen 	NULL,				/* tid 4 recv from remote RootDomain */
59225351652SVuong Nguyen 	PTHREAD_COND_INITIALIZER,	/* nudges etm_send_to_remote_root */
59325351652SVuong Nguyen 	PTHREAD_MUTEX_INITIALIZER,	/* protects msg_ack_cv */
59425351652SVuong Nguyen 	0,				/* send/recv threads are not dying */
59525351652SVuong Nguyen 	0,				/* flag for start sending msg Q */
59625351652SVuong Nguyen 	0				/* indicate if the ACK has come  */
59725351652SVuong Nguyen };
59825351652SVuong Nguyen etm_iosvc_t *io_svc_p = &io_svc;
59925351652SVuong Nguyen 
60025351652SVuong Nguyen 
60125351652SVuong Nguyen static uint32_t
60225351652SVuong Nguyen flags;					/* flags for fmd_xprt_open */
60325351652SVuong Nguyen 
60425351652SVuong Nguyen static etm_async_event_ele_t
60525351652SVuong Nguyen async_event_q[ASYNC_EVENT_Q_SIZE];	/* holds the async events */
60625351652SVuong Nguyen 
60725351652SVuong Nguyen static uint32_t
60825351652SVuong Nguyen etm_async_q_head = 0;		/* ptr to cur head of async event queue */
60925351652SVuong Nguyen 
61025351652SVuong Nguyen static uint32_t
61125351652SVuong Nguyen etm_async_q_tail = 0;		/* ptr to cur tail of async event queue */
61225351652SVuong Nguyen 
61325351652SVuong Nguyen static uint32_t
61425351652SVuong Nguyen etm_async_q_cur_len = 0;	/* cur length (ele cnt) of async event queue */
61525351652SVuong Nguyen 
61625351652SVuong Nguyen static uint32_t
61725351652SVuong Nguyen etm_async_q_max_len = ASYNC_EVENT_Q_SIZE;
61825351652SVuong Nguyen 				/* max length (ele cnt) of async event queue */
61925351652SVuong Nguyen 
62025351652SVuong Nguyen static pthread_cond_t
62125351652SVuong Nguyen etm_async_event_q_cv = PTHREAD_COND_INITIALIZER;
62225351652SVuong Nguyen 				/* nudges  async event handler */
62325351652SVuong Nguyen 
62425351652SVuong Nguyen static pthread_mutex_t
62525351652SVuong Nguyen etm_async_event_q_lock = PTHREAD_MUTEX_INITIALIZER;
62625351652SVuong Nguyen 				/* protects async event q */
62725351652SVuong Nguyen 
62825351652SVuong Nguyen static ds_ver_t
62925351652SVuong Nguyen etm_iosvc_vers[] = { { 1, 0} };
63025351652SVuong Nguyen 
63125351652SVuong Nguyen #define	ETM_NVERS	(sizeof (etm_iosvc_vers) / sizeof (ds_ver_t))
63225351652SVuong Nguyen 
63325351652SVuong Nguyen static ds_capability_t
63425351652SVuong Nguyen iosvc_caps = {
63525351652SVuong Nguyen 	"ETM",				/* svc_id */
63625351652SVuong Nguyen 	etm_iosvc_vers,			/* vers */
63725351652SVuong Nguyen 	ETM_NVERS			/* number of vers */
63825351652SVuong Nguyen };
63925351652SVuong Nguyen 
64025351652SVuong Nguyen static void
64125351652SVuong Nguyen etm_iosvc_reg_handler(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
64225351652SVuong Nguyen     ds_domain_hdl_t did);
64325351652SVuong Nguyen 
64425351652SVuong Nguyen static void
64525351652SVuong Nguyen etm_iosvc_unreg_handler(ds_hdl_t hdl, ds_cb_arg_t arg);
64625351652SVuong Nguyen 
64725351652SVuong Nguyen static ds_ops_t
64825351652SVuong Nguyen iosvc_ops = {
64925351652SVuong Nguyen 	etm_iosvc_reg_handler,		/* ds_reg_cb */
65025351652SVuong Nguyen 	etm_iosvc_unreg_handler,	/* ds_unreg_cb */
65125351652SVuong Nguyen 	NULL,				/* ds_data_cb */
65225351652SVuong Nguyen 	NULL				/* cb_arg */
65325351652SVuong Nguyen };
65425351652SVuong Nguyen 
65525351652SVuong Nguyen 
656733a5356Srb144127 /*
657733a5356Srb144127  * -------------------------- support functions ------------------------------
658733a5356Srb144127  */
659733a5356Srb144127 
660733a5356Srb144127 /*
661733a5356Srb144127  * Design_Note:	Each failure worth reporting to FMD should be done using
662733a5356Srb144127  *		a single call to fmd_hdl_error() as it logs an FMA event
663733a5356Srb144127  *		for each call. Also be aware that all the fmd_hdl_*()
664733a5356Srb144127  *		format strings currently use platform specific *printf()
665733a5356Srb144127  *		routines; so "%p" under Solaris does not prepend "0x" to
666733a5356Srb144127  *		the outputted hex digits, while Linux and VxWorks do.
667733a5356Srb144127  */
668733a5356Srb144127 
66925351652SVuong Nguyen 
670733a5356Srb144127 /*
671e2ff4ac6Srb144127  * etm_show_time - display the current time of day (for debugging) using
672e2ff4ac6Srb144127  *		the given FMD module handle and annotation string
673e2ff4ac6Srb144127  */
674e2ff4ac6Srb144127 
675e2ff4ac6Srb144127 static void
676e2ff4ac6Srb144127 etm_show_time(fmd_hdl_t *hdl, char *note_str)
677e2ff4ac6Srb144127 {
678e2ff4ac6Srb144127 	struct timeval		tmv;		/* timeval */
679e2ff4ac6Srb144127 
680e2ff4ac6Srb144127 	(void) gettimeofday(&tmv, NULL);
681e2ff4ac6Srb144127 	fmd_hdl_debug(hdl, "info: %s: cur Unix Epoch time %d.%06d\n",
682e2ff4ac6Srb144127 	    note_str, tmv.tv_sec, tmv.tv_usec);
683e2ff4ac6Srb144127 
684e2ff4ac6Srb144127 } /* etm_show_time() */
685e2ff4ac6Srb144127 
686e2ff4ac6Srb144127 /*
687733a5356Srb144127  * etm_hexdump - hexdump the given buffer (for debugging) using
688733a5356Srb144127  *		the given FMD module handle
689733a5356Srb144127  */
690733a5356Srb144127 
691733a5356Srb144127 static void
692733a5356Srb144127 etm_hexdump(fmd_hdl_t *hdl, void *buf, size_t byte_cnt)
693733a5356Srb144127 {
694733a5356Srb144127 	uint8_t		*bp;		/* byte ptr */
695733a5356Srb144127 	int		i, j;		/* index */
696733a5356Srb144127 	char		cb[80];		/* char buf */
697733a5356Srb144127 	unsigned int	n;		/* a byte of data for sprintf() */
698733a5356Srb144127 
699733a5356Srb144127 	bp = buf;
700733a5356Srb144127 	j = 0;
701733a5356Srb144127 
702733a5356Srb144127 	/*
703733a5356Srb144127 	 * Design_Note:	fmd_hdl_debug() auto adds a newline if missing;
704733a5356Srb144127 	 *		hence cb exists to accumulate a longer string.
705733a5356Srb144127 	 */
706733a5356Srb144127 
707733a5356Srb144127 	for (i = 1; i <= byte_cnt; i++) {
708733a5356Srb144127 		n = *bp++;
709733a5356Srb144127 		(void) sprintf(&cb[j], "%2.2x ", n);
710733a5356Srb144127 		j += 3;
711733a5356Srb144127 		/* add a newline every 16 bytes or at the buffer's end */
712733a5356Srb144127 		if (((i % 16) == 0) || (i >= byte_cnt)) {
713733a5356Srb144127 			cb[j-1] = '\0';
714733a5356Srb144127 			fmd_hdl_debug(hdl, "%s\n", cb);
715733a5356Srb144127 			j = 0;
716733a5356Srb144127 		}
717733a5356Srb144127 	} /* for each byte in the buffer */
718733a5356Srb144127 
719733a5356Srb144127 } /* etm_hexdump() */
720733a5356Srb144127 
721733a5356Srb144127 /*
722733a5356Srb144127  * etm_sleep - sleep the caller for the given number of seconds,
723733a5356Srb144127  *		return 0 or -errno value
724733a5356Srb144127  *
725733a5356Srb144127  * Design_Note:	To avoid interfering with FMD's signal mask (SIGALRM)
726733a5356Srb144127  *		do not use [Solaris] sleep(3C) and instead use
727733a5356Srb144127  *		pthread_cond_wait() or nanosleep(), both of which
728733a5356Srb144127  *		are POSIX spec-ed to leave signal masks alone.
729733a5356Srb144127  *		This is needed for Solaris and Linux (domain and SP).
730733a5356Srb144127  */
731733a5356Srb144127 
732733a5356Srb144127 static int
733733a5356Srb144127 etm_sleep(unsigned sleep_sec)
734733a5356Srb144127 {
735733a5356Srb144127 	struct timespec	tms;	/* for nanosleep() */
736733a5356Srb144127 
737733a5356Srb144127 	tms.tv_sec = sleep_sec;
738733a5356Srb144127 	tms.tv_nsec = 0;
739733a5356Srb144127 
740733a5356Srb144127 	if (nanosleep(&tms, NULL) < 0) {
741733a5356Srb144127 		/* errno assumed set by above call */
742733a5356Srb144127 		return (-errno);
743733a5356Srb144127 	}
744733a5356Srb144127 	return (0);
745733a5356Srb144127 
746733a5356Srb144127 } /* etm_sleep() */
747733a5356Srb144127 
748733a5356Srb144127 /*
749733a5356Srb144127  * etm_conn_open - open a connection to the given transport address,
750733a5356Srb144127  *		return 0 and the opened connection handle
751733a5356Srb144127  *		or -errno value
752733a5356Srb144127  *
753733a5356Srb144127  * caveats:	the err_substr is used in failure cases for calling
754733a5356Srb144127  *		fmd_hdl_error()
755733a5356Srb144127  */
756733a5356Srb144127 
757733a5356Srb144127 static int
758733a5356Srb144127 etm_conn_open(fmd_hdl_t *hdl, char *err_substr,
759733a5356Srb144127 		etm_xport_addr_t addr, etm_xport_conn_t *connp)
760733a5356Srb144127 {
761733a5356Srb144127 	etm_xport_conn_t	conn;	/* connection to return */
762733a5356Srb144127 	int			nev;	/* -errno value */
763733a5356Srb144127 
764733a5356Srb144127 	if ((conn = etm_xport_open(hdl, addr)) == NULL) {
765733a5356Srb144127 		nev = (-errno);
766733a5356Srb144127 		fmd_hdl_error(hdl, "error: %s: errno %d\n",
767733a5356Srb144127 		    err_substr, errno);
768733a5356Srb144127 		etm_stats.etm_xport_open_fail.fmds_value.ui64++;
769733a5356Srb144127 		return (nev);
770733a5356Srb144127 	} else {
771733a5356Srb144127 		*connp = conn;
772733a5356Srb144127 		return (0);
773733a5356Srb144127 	}
774733a5356Srb144127 } /* etm_conn_open() */
775733a5356Srb144127 
776733a5356Srb144127 /*
777733a5356Srb144127  * etm_conn_close - close the given connection,
778733a5356Srb144127  *		return 0 or -errno value
779733a5356Srb144127  *
780733a5356Srb144127  * caveats:	the err_substr is used in failure cases for calling
781733a5356Srb144127  *		fmd_hdl_error()
782733a5356Srb144127  */
783733a5356Srb144127 
784733a5356Srb144127 static int
785733a5356Srb144127 etm_conn_close(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn)
786733a5356Srb144127 {
787733a5356Srb144127 	int	nev;	/* -errno value */
788733a5356Srb144127 
789733a5356Srb144127 	if (etm_xport_close(hdl, conn) == NULL) {
790733a5356Srb144127 		nev = (-errno);
791733a5356Srb144127 		fmd_hdl_error(hdl, "warning: %s: errno %d\n",
792733a5356Srb144127 		    err_substr, errno);
793733a5356Srb144127 		etm_stats.etm_xport_close_fail.fmds_value.ui64++;
794733a5356Srb144127 		return (nev);
795733a5356Srb144127 	} else {
796733a5356Srb144127 		return (0);
797733a5356Srb144127 	}
798733a5356Srb144127 } /* etm_conn_close() */
799733a5356Srb144127 
800733a5356Srb144127 /*
801733a5356Srb144127  * etm_io_op - perform an IO operation on the given connection
802733a5356Srb144127  *		with the given buffer,
803733a5356Srb144127  *		accommodating MTU size and retrying op if needed,
804733a5356Srb144127  *		return how many bytes actually done by the op
805733a5356Srb144127  *		or -errno value
806733a5356Srb144127  *
807733a5356Srb144127  * caveats:	the err_substr is used in failure cases for calling
808733a5356Srb144127  *		fmd_hdl_error()
809733a5356Srb144127  */
810733a5356Srb144127 
811733a5356Srb144127 static ssize_t
812733a5356Srb144127 etm_io_op(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn,
813733a5356Srb144127 				void *buf, size_t byte_cnt, int io_op)
814733a5356Srb144127 {
815733a5356Srb144127 	ssize_t		rv;		/* ret val / byte count */
816733a5356Srb144127 	ssize_t		n;		/* gen use */
817733a5356Srb144127 	uint8_t		*datap;		/* ptr to data */
818733a5356Srb144127 	size_t		mtu_sz;		/* MTU size in bytes */
819733a5356Srb144127 	int		(*io_func_ptr)(fmd_hdl_t *, etm_xport_conn_t,
820733a5356Srb144127 	    void *, size_t);
821733a5356Srb144127 	size_t		io_sz;		/* byte count for io_func_ptr */
822733a5356Srb144127 	int		try_cnt;	/* number of tries done */
823733a5356Srb144127 	int		sleep_sec;	/* exp backoff sleep period in sec */
824733a5356Srb144127 	int		sleep_rv;	/* ret val from sleeping */
825733a5356Srb144127 	fmd_stat_t	io_retry_stat;	/* IO retry stat to update */
826733a5356Srb144127 	fmd_stat_t	io_fail_stat;	/* IO failure stat to update */
827733a5356Srb144127 
828733a5356Srb144127 	if ((conn == NULL) || (buf == NULL)) {
829733a5356Srb144127 		return (-EINVAL);
830733a5356Srb144127 	}
831733a5356Srb144127 	switch (io_op) {
832733a5356Srb144127 	case ETM_IO_OP_RD:
833733a5356Srb144127 		io_func_ptr = etm_xport_read;
834733a5356Srb144127 		io_retry_stat = etm_stats.etm_xport_rd_retry;
835733a5356Srb144127 		io_fail_stat = etm_stats.etm_xport_rd_fail;
836733a5356Srb144127 		break;
837733a5356Srb144127 	case ETM_IO_OP_WR:
838733a5356Srb144127 		io_func_ptr = etm_xport_write;
839733a5356Srb144127 		io_retry_stat = etm_stats.etm_xport_wr_retry;
840733a5356Srb144127 		io_fail_stat = etm_stats.etm_xport_wr_fail;
841733a5356Srb144127 		break;
842733a5356Srb144127 	default:
843733a5356Srb144127 		return (-EINVAL);
844733a5356Srb144127 	}
845733a5356Srb144127 	if (byte_cnt == 0) {
846733a5356Srb144127 		return (byte_cnt);	/* nop */
847733a5356Srb144127 	}
848733a5356Srb144127 
849733a5356Srb144127 	/* obtain [current] MTU size */
850733a5356Srb144127 
851733a5356Srb144127 	if ((n = etm_xport_get_opt(hdl, conn, ETM_XPORT_OPT_MTU_SZ)) < 0) {
852733a5356Srb144127 		mtu_sz = ETM_XPORT_MTU_SZ_DEF;
853733a5356Srb144127 	} else {
854733a5356Srb144127 		mtu_sz = n;
855733a5356Srb144127 	}
856733a5356Srb144127 
857733a5356Srb144127 	/* loop until all IO done, try limit exceeded, or real failure */
858733a5356Srb144127 
859733a5356Srb144127 	rv = 0;
860733a5356Srb144127 	datap = buf;
861733a5356Srb144127 	while (rv < byte_cnt) {
862733a5356Srb144127 		io_sz = MIN((byte_cnt - rv), mtu_sz);
863733a5356Srb144127 		try_cnt = 0;
864733a5356Srb144127 		sleep_sec = 0;
865733a5356Srb144127 
866733a5356Srb144127 		/* when give up, return -errno value even if partly done */
867733a5356Srb144127 
868733a5356Srb144127 		while ((n = (*io_func_ptr)(hdl, conn, datap, io_sz)) ==
869733a5356Srb144127 		    (-EAGAIN)) {
870733a5356Srb144127 			try_cnt++;
871733a5356Srb144127 			if (try_cnt > ETM_TRY_MAX_CNT) {
872733a5356Srb144127 				rv = n;
873733a5356Srb144127 				goto func_ret;
874733a5356Srb144127 			}
875733a5356Srb144127 			if (etm_is_dying) {
876733a5356Srb144127 				rv = (-EINTR);
877733a5356Srb144127 				goto func_ret;
878733a5356Srb144127 			}
879733a5356Srb144127 			if ((sleep_rv = etm_sleep(sleep_sec)) < 0) {
880733a5356Srb144127 				rv = sleep_rv;
881733a5356Srb144127 				goto func_ret;
882733a5356Srb144127 			}
883733a5356Srb144127 			sleep_sec = ((sleep_sec == 0) ? 1 :
884733a5356Srb144127 			    (sleep_sec * ETM_TRY_BACKOFF_RATE));
885733a5356Srb144127 			sleep_sec = MIN(sleep_sec, ETM_TRY_BACKOFF_CAP);
886733a5356Srb144127 			io_retry_stat.fmds_value.ui64++;
887733a5356Srb144127 			if (etm_debug_lvl >= 1) {
888733a5356Srb144127 				fmd_hdl_debug(hdl, "info: retrying io op %d "
889733a5356Srb144127 				    "due to EAGAIN\n", io_op);
890733a5356Srb144127 			}
891733a5356Srb144127 		} /* while trying the io operation */
892733a5356Srb144127 
893733a5356Srb144127 		if (etm_is_dying) {
894733a5356Srb144127 			rv = (-EINTR);
895733a5356Srb144127 			goto func_ret;
896733a5356Srb144127 		}
897733a5356Srb144127 		if (n < 0) {
898733a5356Srb144127 			rv = n;
899733a5356Srb144127 			goto func_ret;
900733a5356Srb144127 		}
901733a5356Srb144127 		/* avoid spinning CPU when given 0 bytes but no error */
902733a5356Srb144127 		if (n == 0) {
903733a5356Srb144127 			if ((sleep_rv = etm_sleep(ETM_SLEEP_QUIK)) < 0) {
904733a5356Srb144127 				rv = sleep_rv;
905733a5356Srb144127 				goto func_ret;
906733a5356Srb144127 			}
907733a5356Srb144127 		}
908733a5356Srb144127 		rv += n;
909733a5356Srb144127 		datap += n;
910733a5356Srb144127 	} /* while still have more data */
911733a5356Srb144127 
912733a5356Srb144127 func_ret:
913733a5356Srb144127 
914733a5356Srb144127 	if (rv < 0) {
915733a5356Srb144127 		io_fail_stat.fmds_value.ui64++;
9162ae66659Sjrutt 		fmd_hdl_debug(hdl, "error: %s: errno %d\n",
917733a5356Srb144127 		    err_substr, (int)(-rv));
918733a5356Srb144127 	}
919733a5356Srb144127 	if (etm_debug_lvl >= 3) {
920733a5356Srb144127 		fmd_hdl_debug(hdl, "info: io op %d ret %d of %d\n",
921733a5356Srb144127 		    io_op, (int)rv, (int)byte_cnt);
922733a5356Srb144127 	}
923733a5356Srb144127 	return (rv);
924733a5356Srb144127 
925733a5356Srb144127 } /* etm_io_op() */
926733a5356Srb144127 
927733a5356Srb144127 /*
928733a5356Srb144127  * etm_magic_read - read the magic number of an ETM message header
929733a5356Srb144127  *		from the given connection into the given buffer,
930733a5356Srb144127  *		return 0 or -errno value
931733a5356Srb144127  *
932733a5356Srb144127  * Design_Note:	This routine is intended to help protect ETM from protocol
933733a5356Srb144127  *		framing errors as might be caused by an SP reset / crash in
934733a5356Srb144127  *		the middle of an ETM message send; the connection will be
935733a5356Srb144127  *		read from for as many bytes as needed until the magic number
936733a5356Srb144127  *		is found using a sliding buffer for comparisons.
937733a5356Srb144127  */
938733a5356Srb144127 
939733a5356Srb144127 static int
940733a5356Srb144127 etm_magic_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, uint32_t *magic_ptr)
941733a5356Srb144127 {
942733a5356Srb144127 	int		rv;		/* ret val */
943733a5356Srb144127 	uint32_t	magic_num;	/* magic number */
944733a5356Srb144127 	int		byte_cnt;	/* count of bytes read */
945733a5356Srb144127 	uint8_t		buf5[4+1];	/* sliding input buffer */
946733a5356Srb144127 	int		i, j;		/* indices into buf5 */
947733a5356Srb144127 	ssize_t		n;		/* gen use */
948733a5356Srb144127 	uint8_t		drop_buf[1024];	/* dropped bytes buffer */
949733a5356Srb144127 
950733a5356Srb144127 	rv = 0;		/* assume success */
951733a5356Srb144127 	magic_num = 0;
952733a5356Srb144127 	byte_cnt = 0;
953733a5356Srb144127 	j = 0;
954733a5356Srb144127 
955733a5356Srb144127 	/* magic number bytes are sent in network (big endian) order */
956733a5356Srb144127 
957733a5356Srb144127 	while (magic_num != ETM_PROTO_MAGIC_NUM) {
958733a5356Srb144127 		if ((n = etm_io_op(hdl, "bad io read on magic",
959733a5356Srb144127 		    conn, &buf5[j], 1, ETM_IO_OP_RD)) < 0) {
960733a5356Srb144127 			rv = n;
961733a5356Srb144127 			goto func_ret;
962733a5356Srb144127 		}
963733a5356Srb144127 		byte_cnt++;
964733a5356Srb144127 		j = MIN((j + 1), sizeof (magic_num));
965733a5356Srb144127 		if (byte_cnt < sizeof (magic_num)) {
966733a5356Srb144127 			continue;
967733a5356Srb144127 		}
968733a5356Srb144127 
969733a5356Srb144127 		if (byte_cnt > sizeof (magic_num)) {
970733a5356Srb144127 			etm_stats.etm_magic_drop_bytes.fmds_value.ui64++;
971733a5356Srb144127 			i = MIN(byte_cnt - j - 1, sizeof (drop_buf) - 1);
972733a5356Srb144127 			drop_buf[i] = buf5[0];
973733a5356Srb144127 			for (i = 0; i < j; i++) {
974733a5356Srb144127 				buf5[i] = buf5[i+1];
975733a5356Srb144127 			} /* for sliding the buffer contents */
976733a5356Srb144127 		}
977733a5356Srb144127 		(void) memcpy(&magic_num, &buf5[0], sizeof (magic_num));
978733a5356Srb144127 		magic_num = ntohl(magic_num);
979733a5356Srb144127 	} /* for reading bytes until find magic number */
980733a5356Srb144127 
981733a5356Srb144127 func_ret:
982733a5356Srb144127 
983733a5356Srb144127 	if (byte_cnt != sizeof (magic_num)) {
9842ae66659Sjrutt 		fmd_hdl_debug(hdl, "warning: bad proto frame "
985733a5356Srb144127 		    "implies corrupt/lost msg(s)\n");
986733a5356Srb144127 	}
987733a5356Srb144127 	if ((byte_cnt > sizeof (magic_num)) && (etm_debug_lvl >= 2)) {
988733a5356Srb144127 		i = MIN(byte_cnt - sizeof (magic_num), sizeof (drop_buf));
989733a5356Srb144127 		fmd_hdl_debug(hdl, "info: magic drop hexdump "
990b8677b72Srb144127 		    "first %d of %d bytes:\n", i,
991b8677b72Srb144127 		    byte_cnt - sizeof (magic_num));
992733a5356Srb144127 		etm_hexdump(hdl, drop_buf, i);
993733a5356Srb144127 	}
994733a5356Srb144127 
995733a5356Srb144127 	if (rv == 0) {
996733a5356Srb144127 		*magic_ptr = magic_num;
997733a5356Srb144127 	}
998733a5356Srb144127 	return (rv);
999733a5356Srb144127 
1000733a5356Srb144127 } /* etm_magic_read() */
1001733a5356Srb144127 
1002733a5356Srb144127 /*
1003733a5356Srb144127  * etm_hdr_read - allocate, read, and validate a [variable sized]
1004733a5356Srb144127  *		ETM message header from the given connection,
1005733a5356Srb144127  *		return the allocated ETM message header
1006733a5356Srb144127  *		(which is guaranteed to be large enough to reuse as a
1007733a5356Srb144127  *		RESPONSE msg hdr) and its size
1008733a5356Srb144127  *		or NULL and set errno on failure
1009733a5356Srb144127  */
1010733a5356Srb144127 
1011733a5356Srb144127 static void *
1012733a5356Srb144127 etm_hdr_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, size_t *szp)
1013733a5356Srb144127 {
1014733a5356Srb144127 	uint8_t			*hdrp;		/* ptr to header to return */
1015733a5356Srb144127 	size_t			hdr_sz;		/* sizeof *hdrp */
1016733a5356Srb144127 	etm_proto_v1_pp_t	pp; 		/* protocol preamble */
1017733a5356Srb144127 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
1018733a5356Srb144127 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1019733a5356Srb144127 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
10204b476ed5Sdarudy 	etm_proto_v3_sa_hdr_t	*sa_hdrp;	/* for ALERT msg */
1021733a5356Srb144127 	uint32_t		*lenp;		/* ptr to FMA event length */
1022733a5356Srb144127 	ssize_t			i, n;		/* gen use */
1023733a5356Srb144127 	uint8_t	misc_buf[ETM_MISC_BUF_SZ];	/* for var sized hdrs */
1024733a5356Srb144127 	int			dummy_int;	/* dummy var to appease lint */
1025733a5356Srb144127 
1026733a5356Srb144127 	hdrp = NULL; hdr_sz = 0;
1027733a5356Srb144127 
1028733a5356Srb144127 	/* read the magic number which starts the protocol preamble */
1029733a5356Srb144127 
1030733a5356Srb144127 	if ((n = etm_magic_read(hdl, conn, &pp.pp_magic_num)) < 0) {
1031733a5356Srb144127 		errno = (-n);
1032733a5356Srb144127 		etm_stats.etm_magic_bad.fmds_value.ui64++;
1033733a5356Srb144127 		return (NULL);
1034733a5356Srb144127 	}
1035733a5356Srb144127 
1036733a5356Srb144127 	/* read the rest of the protocol preamble all at once */
1037733a5356Srb144127 
1038733a5356Srb144127 	if ((n = etm_io_op(hdl, "bad io read on preamble",
1039b8677b72Srb144127 	    conn, &pp.pp_proto_ver, sizeof (pp) - sizeof (pp.pp_magic_num),
1040733a5356Srb144127 	    ETM_IO_OP_RD)) < 0) {
1041733a5356Srb144127 		errno = (-n);
1042733a5356Srb144127 		return (NULL);
1043733a5356Srb144127 	}
1044733a5356Srb144127 
1045733a5356Srb144127 	/*
1046733a5356Srb144127 	 * Design_Note:	The magic number was already network decoded; but
1047733a5356Srb144127 	 *		some other preamble fields also need to be decoded,
1048733a5356Srb144127 	 *		specifically pp_xid and pp_timeout. The rest of the
1049733a5356Srb144127 	 *		preamble fields are byte sized and hence need no
1050733a5356Srb144127 	 *		decoding.
1051733a5356Srb144127 	 */
1052733a5356Srb144127 
1053733a5356Srb144127 	pp.pp_xid = ntohl(pp.pp_xid);
1054733a5356Srb144127 	pp.pp_timeout = ntohl(pp.pp_timeout);
1055733a5356Srb144127 
1056733a5356Srb144127 	/* sanity check the header as best we can */
1057733a5356Srb144127 
1058e2ff4ac6Srb144127 	if ((pp.pp_proto_ver < ETM_PROTO_V1) ||
10594b476ed5Sdarudy 	    (pp.pp_proto_ver > ETM_PROTO_V3)) {
1060733a5356Srb144127 		fmd_hdl_error(hdl, "error: bad proto ver %d\n",
1061733a5356Srb144127 		    (int)pp.pp_proto_ver);
1062733a5356Srb144127 		errno = EPROTO;
1063733a5356Srb144127 		etm_stats.etm_ver_bad.fmds_value.ui64++;
1064733a5356Srb144127 		return (NULL);
1065733a5356Srb144127 	}
1066733a5356Srb144127 
1067733a5356Srb144127 	dummy_int = pp.pp_msg_type;
1068733a5356Srb144127 	if ((dummy_int <= ETM_MSG_TYPE_TOO_LOW) ||
1069733a5356Srb144127 	    (dummy_int >= ETM_MSG_TYPE_TOO_BIG)) {
1070733a5356Srb144127 		fmd_hdl_error(hdl, "error: bad msg type %d", dummy_int);
1071733a5356Srb144127 		errno = EBADMSG;
1072733a5356Srb144127 		etm_stats.etm_msgtype_bad.fmds_value.ui64++;
1073733a5356Srb144127 		return (NULL);
1074733a5356Srb144127 	}
1075733a5356Srb144127 
1076733a5356Srb144127 	/* handle [var sized] hdrs for FMA_EVENT, CONTROL, RESPONSE msgs */
1077733a5356Srb144127 
1078733a5356Srb144127 	if (pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
1079733a5356Srb144127 
1080733a5356Srb144127 		ev_hdrp = (void*)&misc_buf[0];
1081733a5356Srb144127 		hdr_sz = sizeof (*ev_hdrp);
1082733a5356Srb144127 		(void) memcpy(&ev_hdrp->ev_pp, &pp, sizeof (pp));
1083733a5356Srb144127 
1084733a5356Srb144127 		/* sanity check the header's timeout */
1085733a5356Srb144127 
1086e2ff4ac6Srb144127 		if ((ev_hdrp->ev_pp.pp_proto_ver == ETM_PROTO_V1) &&
1087e2ff4ac6Srb144127 		    (ev_hdrp->ev_pp.pp_timeout != ETM_PROTO_V1_TIMEOUT_NONE)) {
1088733a5356Srb144127 			errno = ETIME;
1089733a5356Srb144127 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
1090733a5356Srb144127 			return (NULL);
1091733a5356Srb144127 		}
1092733a5356Srb144127 
1093733a5356Srb144127 		/* get all FMA event lengths from the header */
1094733a5356Srb144127 
1095733a5356Srb144127 		lenp = (uint32_t *)&ev_hdrp->ev_lens[0]; lenp--;
1096733a5356Srb144127 		i = -1;	/* cnt of length entries preceding 0 */
1097733a5356Srb144127 		do {
1098733a5356Srb144127 			i++; lenp++;
1099733a5356Srb144127 			if ((sizeof (*ev_hdrp) + (i * sizeof (*lenp))) >=
1100733a5356Srb144127 			    ETM_MISC_BUF_SZ) {
1101733a5356Srb144127 				errno = E2BIG;	/* ridiculous size */
1102733a5356Srb144127 				etm_stats.etm_evlens_bad.fmds_value.ui64++;
1103733a5356Srb144127 				return (NULL);
1104733a5356Srb144127 			}
1105733a5356Srb144127 			if ((n = etm_io_op(hdl, "bad io read on event len",
1106b8677b72Srb144127 			    conn, lenp, sizeof (*lenp), ETM_IO_OP_RD)) < 0) {
1107733a5356Srb144127 				errno = (-n);
1108733a5356Srb144127 				return (NULL);
1109733a5356Srb144127 			}
1110733a5356Srb144127 			*lenp = ntohl(*lenp);
1111733a5356Srb144127 
1112733a5356Srb144127 		} while (*lenp != 0);
1113733a5356Srb144127 		i += 0; /* first len already counted by sizeof(ev_hdr) */
1114733a5356Srb144127 		hdr_sz += (i * sizeof (*lenp));
1115733a5356Srb144127 
1116733a5356Srb144127 		etm_stats.etm_rd_hdr_fmaevent.fmds_value.ui64++;
1117733a5356Srb144127 
1118733a5356Srb144127 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
1119733a5356Srb144127 
1120733a5356Srb144127 		ctl_hdrp = (void*)&misc_buf[0];
1121733a5356Srb144127 		hdr_sz = sizeof (*ctl_hdrp);
1122733a5356Srb144127 		(void) memcpy(&ctl_hdrp->ctl_pp, &pp, sizeof (pp));
1123733a5356Srb144127 
1124733a5356Srb144127 		/* sanity check the header's sub type (control selector) */
1125733a5356Srb144127 
1126733a5356Srb144127 		if ((ctl_hdrp->ctl_pp.pp_sub_type <= ETM_CTL_SEL_TOO_LOW) ||
1127733a5356Srb144127 		    (ctl_hdrp->ctl_pp.pp_sub_type >= ETM_CTL_SEL_TOO_BIG)) {
1128733a5356Srb144127 			fmd_hdl_error(hdl, "error: bad ctl sub type %d\n",
1129733a5356Srb144127 			    (int)ctl_hdrp->ctl_pp.pp_sub_type);
1130733a5356Srb144127 			errno = EBADMSG;
1131733a5356Srb144127 			etm_stats.etm_subtype_bad.fmds_value.ui64++;
1132733a5356Srb144127 			return (NULL);
1133733a5356Srb144127 		}
1134733a5356Srb144127 
1135733a5356Srb144127 		/* get the control length */
1136733a5356Srb144127 
1137733a5356Srb144127 		if ((n = etm_io_op(hdl, "bad io read on ctl len",
1138b8677b72Srb144127 		    conn, &ctl_hdrp->ctl_len, sizeof (ctl_hdrp->ctl_len),
1139733a5356Srb144127 		    ETM_IO_OP_RD)) < 0) {
1140733a5356Srb144127 			errno = (-n);
1141733a5356Srb144127 			return (NULL);
1142733a5356Srb144127 		}
1143733a5356Srb144127 
1144733a5356Srb144127 		ctl_hdrp->ctl_len = ntohl(ctl_hdrp->ctl_len);
1145733a5356Srb144127 
1146733a5356Srb144127 		etm_stats.etm_rd_hdr_control.fmds_value.ui64++;
1147733a5356Srb144127 
1148733a5356Srb144127 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
1149733a5356Srb144127 
1150733a5356Srb144127 		resp_hdrp = (void*)&misc_buf[0];
1151733a5356Srb144127 		hdr_sz = sizeof (*resp_hdrp);
1152733a5356Srb144127 		(void) memcpy(&resp_hdrp->resp_pp, &pp, sizeof (pp));
1153733a5356Srb144127 
1154733a5356Srb144127 		/* sanity check the header's timeout */
1155733a5356Srb144127 
1156733a5356Srb144127 		if (resp_hdrp->resp_pp.pp_timeout !=
1157733a5356Srb144127 		    ETM_PROTO_V1_TIMEOUT_NONE) {
1158733a5356Srb144127 			errno = ETIME;
1159733a5356Srb144127 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
1160733a5356Srb144127 			return (NULL);
1161733a5356Srb144127 		}
1162733a5356Srb144127 
1163733a5356Srb144127 		/* get the response code and length */
1164733a5356Srb144127 
1165733a5356Srb144127 		if ((n = etm_io_op(hdl, "bad io read on resp code+len",
1166733a5356Srb144127 		    conn, &resp_hdrp->resp_code,
1167b8677b72Srb144127 		    sizeof (resp_hdrp->resp_code)
1168b8677b72Srb144127 		    + sizeof (resp_hdrp->resp_len),
1169733a5356Srb144127 		    ETM_IO_OP_RD)) < 0) {
1170733a5356Srb144127 			errno = (-n);
1171733a5356Srb144127 			return (NULL);
1172733a5356Srb144127 		}
1173733a5356Srb144127 
1174733a5356Srb144127 		resp_hdrp->resp_code = ntohl(resp_hdrp->resp_code);
1175733a5356Srb144127 		resp_hdrp->resp_len = ntohl(resp_hdrp->resp_len);
1176733a5356Srb144127 
1177733a5356Srb144127 		etm_stats.etm_rd_hdr_response.fmds_value.ui64++;
1178733a5356Srb144127 
11794b476ed5Sdarudy 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_ALERT) {
11804b476ed5Sdarudy 
11814b476ed5Sdarudy 		sa_hdrp = (void*)&misc_buf[0];
11824b476ed5Sdarudy 		hdr_sz = sizeof (*sa_hdrp);
11834b476ed5Sdarudy 		(void) memcpy(&sa_hdrp->sa_pp, &pp, sizeof (pp));
11844b476ed5Sdarudy 
11854b476ed5Sdarudy 		/* sanity check the header's protocol version */
11864b476ed5Sdarudy 
11874b476ed5Sdarudy 		if (sa_hdrp->sa_pp.pp_proto_ver != ETM_PROTO_V3) {
11884b476ed5Sdarudy 			errno = EPROTO;
11894b476ed5Sdarudy 			etm_stats.etm_ver_bad.fmds_value.ui64++;
11904b476ed5Sdarudy 			return (NULL);
11914b476ed5Sdarudy 		}
11924b476ed5Sdarudy 
11934b476ed5Sdarudy 		/* get the priority and length */
11944b476ed5Sdarudy 
11954b476ed5Sdarudy 		if ((n = etm_io_op(hdl, "bad io read on sa priority+len",
11964b476ed5Sdarudy 		    conn, &sa_hdrp->sa_priority,
1197b8677b72Srb144127 		    sizeof (sa_hdrp->sa_priority)
1198b8677b72Srb144127 		    + sizeof (sa_hdrp->sa_len),
11994b476ed5Sdarudy 		    ETM_IO_OP_RD)) < 0) {
12004b476ed5Sdarudy 			errno = (-n);
12014b476ed5Sdarudy 			return (NULL);
12024b476ed5Sdarudy 		}
12034b476ed5Sdarudy 
12044b476ed5Sdarudy 		sa_hdrp->sa_priority = ntohl(sa_hdrp->sa_priority);
12054b476ed5Sdarudy 		sa_hdrp->sa_len = ntohl(sa_hdrp->sa_len);
12064b476ed5Sdarudy 
12074b476ed5Sdarudy 		etm_stats.etm_rd_hdr_alert.fmds_value.ui64++;
12084b476ed5Sdarudy 
12094b476ed5Sdarudy 	} /* whether we have FMA_EVENT, ALERT, CONTROL, or RESPONSE msg */
1210733a5356Srb144127 
1211733a5356Srb144127 	/*
1212733a5356Srb144127 	 * choose a header size that allows hdr reuse for RESPONSE msgs,
1213733a5356Srb144127 	 * allocate and populate the message header, and
1214733a5356Srb144127 	 * return alloc size to caller for later free of hdrp
1215733a5356Srb144127 	 */
1216733a5356Srb144127 
1217733a5356Srb144127 	hdr_sz = MAX(hdr_sz, sizeof (*resp_hdrp));
1218733a5356Srb144127 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
1219733a5356Srb144127 	(void) memcpy(hdrp, misc_buf, hdr_sz);
1220733a5356Srb144127 
1221733a5356Srb144127 	if (etm_debug_lvl >= 3) {
1222b8677b72Srb144127 		fmd_hdl_debug(hdl, "info: msg hdr hexdump %d bytes:\n", hdr_sz);
1223733a5356Srb144127 		etm_hexdump(hdl, hdrp, hdr_sz);
1224733a5356Srb144127 	}
1225733a5356Srb144127 	*szp = hdr_sz;
1226733a5356Srb144127 	return (hdrp);
1227733a5356Srb144127 
1228733a5356Srb144127 } /* etm_hdr_read() */
1229733a5356Srb144127 
1230733a5356Srb144127 /*
1231733a5356Srb144127  * etm_hdr_write - create and write a [variable sized] ETM message header
1232733a5356Srb144127  *		to the given connection appropriate for the given FMA event
1233733a5356Srb144127  *		and type of nvlist encoding,
1234733a5356Srb144127  *		return the allocated ETM message header and its size
1235733a5356Srb144127  *		or NULL and set errno on failure
1236733a5356Srb144127  */
1237733a5356Srb144127 
1238733a5356Srb144127 static void*
1239733a5356Srb144127 etm_hdr_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, nvlist_t *evp,
1240733a5356Srb144127 						int encoding, size_t *szp)
1241733a5356Srb144127 {
1242733a5356Srb144127 	etm_proto_v1_ev_hdr_t	*hdrp;		/* for FMA_EVENT msg */
1243733a5356Srb144127 	size_t			hdr_sz;		/* sizeof *hdrp */
1244733a5356Srb144127 	uint32_t		*lenp;		/* ptr to FMA event length */
1245733a5356Srb144127 	size_t			evsz;		/* packed FMA event size */
1246733a5356Srb144127 	ssize_t			n;		/* gen use */
1247733a5356Srb144127 
1248733a5356Srb144127 	/* allocate and populate the message header for 1 FMA event */
1249733a5356Srb144127 
1250733a5356Srb144127 	hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0]));
1251733a5356Srb144127 
1252733a5356Srb144127 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
1253733a5356Srb144127 
1254733a5356Srb144127 	/*
1255e2ff4ac6Srb144127 	 * Design_Note: Although the ETM protocol supports it, we do not (yet)
1256e2ff4ac6Srb144127 	 *		want responses/ACKs on FMA events that we send. All
1257e2ff4ac6Srb144127 	 *		such messages are sent with ETM_PROTO_V1_TIMEOUT_NONE.
1258733a5356Srb144127 	 */
1259733a5356Srb144127 
1260733a5356Srb144127 	hdrp->ev_pp.pp_magic_num = ETM_PROTO_MAGIC_NUM;
1261733a5356Srb144127 	hdrp->ev_pp.pp_magic_num = htonl(hdrp->ev_pp.pp_magic_num);
1262733a5356Srb144127 	hdrp->ev_pp.pp_proto_ver = ETM_PROTO_V1;
1263733a5356Srb144127 	hdrp->ev_pp.pp_msg_type = ETM_MSG_TYPE_FMA_EVENT;
1264733a5356Srb144127 	hdrp->ev_pp.pp_sub_type = 0;
1265733a5356Srb144127 	hdrp->ev_pp.pp_rsvd_pad = 0;
1266733a5356Srb144127 	hdrp->ev_pp.pp_xid = etm_xid_cur;
1267733a5356Srb144127 	hdrp->ev_pp.pp_xid = htonl(hdrp->ev_pp.pp_xid);
1268733a5356Srb144127 	etm_xid_cur += ETM_XID_INC;
1269733a5356Srb144127 	hdrp->ev_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
1270733a5356Srb144127 	hdrp->ev_pp.pp_timeout = htonl(hdrp->ev_pp.pp_timeout);
1271733a5356Srb144127 
1272733a5356Srb144127 	lenp = &hdrp->ev_lens[0];
1273733a5356Srb144127 
1274733a5356Srb144127 	if ((n = nvlist_size(evp, &evsz, encoding)) != 0) {
1275733a5356Srb144127 		errno = n;
1276733a5356Srb144127 		fmd_hdl_free(hdl, hdrp, hdr_sz);
1277733a5356Srb144127 		etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++;
1278733a5356Srb144127 		return (NULL);
1279733a5356Srb144127 	}
1280733a5356Srb144127 
1281733a5356Srb144127 	/* indicate 1 FMA event, network encode its length, and 0-terminate */
1282733a5356Srb144127 
1283b8677b72Srb144127 	etm_stats.etm_wr_max_ev_per_msg.fmds_value.ui64 = 1;
1284b8677b72Srb144127 
1285733a5356Srb144127 	*lenp = evsz; *lenp = htonl(*lenp); lenp++;
1286733a5356Srb144127 	*lenp = 0; *lenp = htonl(*lenp); lenp++;
1287733a5356Srb144127 
1288733a5356Srb144127 	/*
1289733a5356Srb144127 	 * write the network encoded header to the transport, and
1290733a5356Srb144127 	 * return alloc size to caller for later free
1291733a5356Srb144127 	 */
1292733a5356Srb144127 
1293733a5356Srb144127 	if ((n = etm_io_op(hdl, "bad io write on event hdr",
1294733a5356Srb144127 	    conn, hdrp, hdr_sz, ETM_IO_OP_WR)) < 0) {
1295733a5356Srb144127 		errno = (-n);
1296733a5356Srb144127 		fmd_hdl_free(hdl, hdrp, hdr_sz);
1297733a5356Srb144127 		return (NULL);
1298733a5356Srb144127 	}
1299733a5356Srb144127 
1300733a5356Srb144127 	*szp = hdr_sz;
1301733a5356Srb144127 	return (hdrp);
1302733a5356Srb144127 
1303733a5356Srb144127 } /* etm_hdr_write() */
1304733a5356Srb144127 
1305733a5356Srb144127 /*
1306733a5356Srb144127  * etm_post_to_fmd - post the given FMA event to FMD
130700ab1250Srb144127  *			via a FMD transport API call,
1308733a5356Srb144127  *			return 0 or -errno value
1309733a5356Srb144127  *
131000ab1250Srb144127  * caveats:	the FMA event (evp) is freed by FMD,
131100ab1250Srb144127  *		thus callers of this function should
131200ab1250Srb144127  *		immediately discard any ptr they have to the
131300ab1250Srb144127  *		nvlist without freeing or dereferencing it
1314733a5356Srb144127  */
1315733a5356Srb144127 
1316733a5356Srb144127 static int
131725351652SVuong Nguyen etm_post_to_fmd(fmd_hdl_t *hdl, fmd_xprt_t *fmd_xprt, nvlist_t *evp)
1318733a5356Srb144127 {
131900ab1250Srb144127 	ssize_t			ev_sz;		/* sizeof *evp */
1320733a5356Srb144127 
132100ab1250Srb144127 	(void) nvlist_size(evp, (size_t *)&ev_sz, NV_ENCODE_XDR);
1322733a5356Srb144127 
1323e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
1324e2ff4ac6Srb144127 		etm_show_time(hdl, "ante ev post");
1325e2ff4ac6Srb144127 	}
132625351652SVuong Nguyen 	fmd_xprt_post(hdl, fmd_xprt, evp, 0);
1327733a5356Srb144127 	etm_stats.etm_wr_fmd_fmaevent.fmds_value.ui64++;
132800ab1250Srb144127 	etm_stats.etm_wr_fmd_bytes.fmds_value.ui64 += ev_sz;
1329733a5356Srb144127 	if (etm_debug_lvl >= 1) {
133000ab1250Srb144127 		fmd_hdl_debug(hdl, "info: event %p post ok to FMD\n", evp);
1331733a5356Srb144127 	}
1332e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
1333e2ff4ac6Srb144127 		etm_show_time(hdl, "post ev post");
1334e2ff4ac6Srb144127 	}
133500ab1250Srb144127 	return (0);
1336733a5356Srb144127 
1337733a5356Srb144127 } /* etm_post_to_fmd() */
1338733a5356Srb144127 
1339733a5356Srb144127 /*
13404b476ed5Sdarudy  * Ideally we would just use syslog(3C) for outputting our messages.
13414b476ed5Sdarudy  * Unfortunately, as this module is running within the FMA daemon context,
13424b476ed5Sdarudy  * that would create the situation where this module's openlog() would
13434b476ed5Sdarudy  * have the monopoly on syslog(3C) for the daemon and all its modules.
13444b476ed5Sdarudy  * To avoid that situation, this module uses the same logic as the
13454b476ed5Sdarudy  * syslog-msgs FM module to directly call into the log(7D) and sysmsg(7D)
13464b476ed5Sdarudy  * devices for syslog and console.
13474b476ed5Sdarudy  */
13484b476ed5Sdarudy 
13494b476ed5Sdarudy static int
13504b476ed5Sdarudy etm_post_to_syslog(fmd_hdl_t *hdl, uint32_t priority, uint32_t body_sz,
13514b476ed5Sdarudy 							uint8_t *body_buf)
13524b476ed5Sdarudy {
13534b476ed5Sdarudy 	char		*sysmessage;	/* Formatted message */
13544b476ed5Sdarudy 	size_t		formatlen;	/* maximum length of sysmessage */
13554b476ed5Sdarudy 	struct strbuf	ctl, dat;	/* structs pushed to the logfd */
13564b476ed5Sdarudy 	uint32_t	msgid;		/* syslog message ID number */
13574b476ed5Sdarudy 
13584b476ed5Sdarudy 	if ((syslog_file == 0) && (syslog_cons == 0)) {
13594b476ed5Sdarudy 		return (0);
13604b476ed5Sdarudy 	}
13614b476ed5Sdarudy 
13624b476ed5Sdarudy 	if (etm_debug_lvl >= 2) {
13634b476ed5Sdarudy 		etm_show_time(hdl, "ante syslog post");
13644b476ed5Sdarudy 	}
13654b476ed5Sdarudy 
13664b476ed5Sdarudy 	formatlen = body_sz + 64; /* +64 for prefix strings added below */
13674b476ed5Sdarudy 	sysmessage = fmd_hdl_zalloc(hdl, formatlen, FMD_SLEEP);
13684b476ed5Sdarudy 
13694b476ed5Sdarudy 	if (syslog_file) {
13704b476ed5Sdarudy 		STRLOG_MAKE_MSGID(body_buf, msgid);
13714b476ed5Sdarudy 		(void) snprintf(sysmessage, formatlen,
13724b476ed5Sdarudy 		    "SC Alert: [ID %u FACILITY_AND_PRIORITY] %s", msgid,
13734b476ed5Sdarudy 		    body_buf);
13744b476ed5Sdarudy 
13754b476ed5Sdarudy 		syslog_ctl.pri = syslog_facility | priority;
13764b476ed5Sdarudy 
13774b476ed5Sdarudy 		ctl.buf = (void *)&syslog_ctl;
13784b476ed5Sdarudy 		ctl.len = sizeof (syslog_ctl);
13794b476ed5Sdarudy 
13804b476ed5Sdarudy 		dat.buf = sysmessage;
13814b476ed5Sdarudy 		dat.len = strlen(sysmessage) + 1;
13824b476ed5Sdarudy 
13834b476ed5Sdarudy 		if (putmsg(syslog_logfd, &ctl, &dat, 0) != 0) {
13844b476ed5Sdarudy 			fmd_hdl_debug(hdl, "putmsg failed: %s\n",
13854b476ed5Sdarudy 			    strerror(errno));
13864b476ed5Sdarudy 			etm_stats.etm_log_err.fmds_value.ui64++;
13874b476ed5Sdarudy 		}
13884b476ed5Sdarudy 	}
13894b476ed5Sdarudy 
13904b476ed5Sdarudy 	if (syslog_cons) {
13914b476ed5Sdarudy 		(void) snprintf(sysmessage, formatlen,
13924b476ed5Sdarudy 		    "SC Alert: %s\r\n", body_buf);
13934b476ed5Sdarudy 
13944b476ed5Sdarudy 		dat.buf = sysmessage;
13954b476ed5Sdarudy 		dat.len = strlen(sysmessage) + 1;
13964b476ed5Sdarudy 
13974b476ed5Sdarudy 		if (write(syslog_msgfd, dat.buf, dat.len) != dat.len) {
13984b476ed5Sdarudy 			fmd_hdl_debug(hdl, "write failed: %s\n",
13994b476ed5Sdarudy 			    strerror(errno));
14004b476ed5Sdarudy 			etm_stats.etm_msg_err.fmds_value.ui64++;
14014b476ed5Sdarudy 		}
14024b476ed5Sdarudy 	}
14034b476ed5Sdarudy 
14044b476ed5Sdarudy 	fmd_hdl_free(hdl, sysmessage, formatlen);
14054b476ed5Sdarudy 
14064b476ed5Sdarudy 	if (etm_debug_lvl >= 2) {
14074b476ed5Sdarudy 		etm_show_time(hdl, "post syslog post");
14084b476ed5Sdarudy 	}
14094b476ed5Sdarudy 
14104b476ed5Sdarudy 	return (0);
14114b476ed5Sdarudy }
14124b476ed5Sdarudy 
14134b476ed5Sdarudy 
14144b476ed5Sdarudy /*
1415733a5356Srb144127  * etm_req_ver_negot - send an ETM control message to the other end requesting
1416733a5356Srb144127  *			that the ETM protocol version be negotiated/set
1417733a5356Srb144127  */
1418733a5356Srb144127 
1419733a5356Srb144127 static void
1420733a5356Srb144127 etm_req_ver_negot(fmd_hdl_t *hdl)
1421733a5356Srb144127 {
1422733a5356Srb144127 	etm_xport_addr_t	*addrv;		/* default dst addr(s) */
1423733a5356Srb144127 	etm_xport_conn_t	conn;		/* connection to other end */
1424733a5356Srb144127 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1425733a5356Srb144127 	size_t			hdr_sz;		/* sizeof header */
1426733a5356Srb144127 	uint8_t			*body_buf;	/* msg body buffer */
1427733a5356Srb144127 	uint32_t		body_sz;	/* sizeof *body_buf */
1428733a5356Srb144127 	ssize_t			i;		/* gen use */
1429733a5356Srb144127 
1430733a5356Srb144127 	/* populate an ETM control msg to send */
1431733a5356Srb144127 
1432733a5356Srb144127 	hdr_sz = sizeof (*ctl_hdrp);
14334b476ed5Sdarudy 	body_sz = (3 + 1);		/* version bytes plus null byte */
1434733a5356Srb144127 
1435733a5356Srb144127 	ctl_hdrp = fmd_hdl_zalloc(hdl, hdr_sz + body_sz, FMD_SLEEP);
1436733a5356Srb144127 
1437733a5356Srb144127 	ctl_hdrp->ctl_pp.pp_magic_num = htonl(ETM_PROTO_MAGIC_NUM);
1438733a5356Srb144127 	ctl_hdrp->ctl_pp.pp_proto_ver = ETM_PROTO_V1;
1439733a5356Srb144127 	ctl_hdrp->ctl_pp.pp_msg_type = ETM_MSG_TYPE_CONTROL;
1440e2ff4ac6Srb144127 	ctl_hdrp->ctl_pp.pp_sub_type = ETM_CTL_SEL_VER_NEGOT_REQ;
1441733a5356Srb144127 	ctl_hdrp->ctl_pp.pp_rsvd_pad = 0;
1442e2ff4ac6Srb144127 	etm_xid_ver_negot = etm_xid_cur;
1443733a5356Srb144127 	etm_xid_cur += ETM_XID_INC;
1444e2ff4ac6Srb144127 	ctl_hdrp->ctl_pp.pp_xid = htonl(etm_xid_ver_negot);
1445733a5356Srb144127 	ctl_hdrp->ctl_pp.pp_timeout = htonl(ETM_PROTO_V1_TIMEOUT_FOREVER);
1446733a5356Srb144127 	ctl_hdrp->ctl_len = htonl(body_sz);
1447733a5356Srb144127 
1448733a5356Srb144127 	body_buf = (void*)&ctl_hdrp->ctl_len;
1449733a5356Srb144127 	body_buf += sizeof (ctl_hdrp->ctl_len);
14504b476ed5Sdarudy 	*body_buf++ = ETM_PROTO_V3;
1451e2ff4ac6Srb144127 	*body_buf++ = ETM_PROTO_V2;
1452733a5356Srb144127 	*body_buf++ = ETM_PROTO_V1;
1453733a5356Srb144127 	*body_buf++ = '\0';
1454733a5356Srb144127 
1455733a5356Srb144127 	/*
1456733a5356Srb144127 	 * open and close a connection to send the ETM control msg
1457733a5356Srb144127 	 * to any/all of the default dst addrs
1458733a5356Srb144127 	 */
1459733a5356Srb144127 
1460733a5356Srb144127 	if ((addrv = etm_xport_get_ev_addrv(hdl, NULL)) == NULL) {
1461733a5356Srb144127 		fmd_hdl_error(hdl,
1462733a5356Srb144127 		    "error: bad ctl dst addrs errno %d\n", errno);
1463733a5356Srb144127 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
1464733a5356Srb144127 		goto func_ret;
1465733a5356Srb144127 	}
1466733a5356Srb144127 
1467733a5356Srb144127 	for (i = 0; addrv[i] != NULL; i++) {
1468733a5356Srb144127 
1469733a5356Srb144127 		if (etm_conn_open(hdl, "bad conn open during ver negot",
1470733a5356Srb144127 		    addrv[i], &conn) < 0) {
1471733a5356Srb144127 			continue;
1472733a5356Srb144127 		}
1473733a5356Srb144127 		if (etm_io_op(hdl, "bad io write on ctl hdr+body",
1474b8677b72Srb144127 		    conn, ctl_hdrp, hdr_sz + body_sz, ETM_IO_OP_WR) >= 0) {
1475733a5356Srb144127 			etm_stats.etm_wr_hdr_control.fmds_value.ui64++;
1476733a5356Srb144127 			etm_stats.etm_wr_body_control.fmds_value.ui64++;
1477733a5356Srb144127 		}
1478733a5356Srb144127 		(void) etm_conn_close(hdl, "bad conn close during ver negot",
1479733a5356Srb144127 		    conn);
1480733a5356Srb144127 
1481733a5356Srb144127 	} /* foreach dst addr */
1482733a5356Srb144127 
1483733a5356Srb144127 func_ret:
1484733a5356Srb144127 
1485733a5356Srb144127 	if (addrv != NULL) {
1486733a5356Srb144127 		etm_xport_free_addrv(hdl, addrv);
1487733a5356Srb144127 	}
1488733a5356Srb144127 	fmd_hdl_free(hdl, ctl_hdrp, hdr_sz + body_sz);
1489733a5356Srb144127 
1490733a5356Srb144127 } /* etm_req_ver_negot() */
1491733a5356Srb144127 
149225351652SVuong Nguyen 
149325351652SVuong Nguyen 
149425351652SVuong Nguyen /*
149525351652SVuong Nguyen  * etm_iosvc_msg_enq - add element to tail of ETM iosvc msg queue
149625351652SVuong Nguyen  * etm_iosvc_msg_deq - del element from head of ETM iosvc msg  queue
149725351652SVuong Nguyen  * need to grab the mutex lock before calling this routine
149825351652SVuong Nguyen  * return >0 for success, or -errno value
149925351652SVuong Nguyen  */
150025351652SVuong Nguyen static int
150125351652SVuong Nguyen etm_iosvc_msg_enq(fmd_hdl_t *hdl, etm_iosvc_t *iosvc, etm_iosvc_q_ele_t *msgp)
150225351652SVuong Nguyen {
150325351652SVuong Nguyen 	etm_iosvc_q_ele_t		*newp;	/* ptr to new msg q ele */
150425351652SVuong Nguyen 
150525351652SVuong Nguyen 	if (iosvc->msg_q_cur_len >= iosvc->msg_q_max_len) {
150625351652SVuong Nguyen 		fmd_hdl_debug(hdl, "warning: enq to full msg queue\n");
150725351652SVuong Nguyen 		return (-E2BIG);
150825351652SVuong Nguyen 	}
150925351652SVuong Nguyen 
151025351652SVuong Nguyen 	newp = fmd_hdl_zalloc(hdl, sizeof (*newp), FMD_SLEEP);
151125351652SVuong Nguyen 	(void) memcpy(newp, msgp, sizeof (*newp));
151225351652SVuong Nguyen 	newp->msg_nextp = NULL;
151325351652SVuong Nguyen 
151425351652SVuong Nguyen 	if (iosvc->msg_q_cur_len == 0) {
151525351652SVuong Nguyen 		iosvc->msg_q_head = newp;
151625351652SVuong Nguyen 	} else {
151725351652SVuong Nguyen 		iosvc->msg_q_tail->msg_nextp = newp;
151825351652SVuong Nguyen 	}
151925351652SVuong Nguyen 
152025351652SVuong Nguyen 	iosvc->msg_q_tail = newp;
152125351652SVuong Nguyen 	iosvc->msg_q_cur_len++;
152225351652SVuong Nguyen 	fmd_hdl_debug(hdl, "info: current msg queue length %d\n",
152325351652SVuong Nguyen 	    iosvc->msg_q_cur_len);
152425351652SVuong Nguyen 
152525351652SVuong Nguyen 	return (1);
152625351652SVuong Nguyen 
152725351652SVuong Nguyen } /* etm_iosvc_msg_enq() */
152825351652SVuong Nguyen 
152925351652SVuong Nguyen static int
153025351652SVuong Nguyen etm_iosvc_msg_deq(fmd_hdl_t *hdl, etm_iosvc_t *iosvc, etm_iosvc_q_ele_t *msgp)
153125351652SVuong Nguyen {
153225351652SVuong Nguyen 	etm_iosvc_q_ele_t	*oldp;	/* ptr to old msg q ele */
153325351652SVuong Nguyen 
153425351652SVuong Nguyen 	if (iosvc->msg_q_cur_len == 0) {
153525351652SVuong Nguyen 		fmd_hdl_debug(hdl, "warning: deq from empty responder queue\n");
153625351652SVuong Nguyen 		return (-ENOENT);
153725351652SVuong Nguyen 	}
153825351652SVuong Nguyen 
153925351652SVuong Nguyen 	(void) memcpy(msgp, iosvc->msg_q_head, sizeof (*msgp));
154025351652SVuong Nguyen 	msgp->msg_nextp = NULL;
154125351652SVuong Nguyen 
154225351652SVuong Nguyen 	oldp = iosvc->msg_q_head;
154325351652SVuong Nguyen 	iosvc->msg_q_head = iosvc->msg_q_head->msg_nextp;
154425351652SVuong Nguyen 
154525351652SVuong Nguyen 	/*
154625351652SVuong Nguyen 	 * free the mem alloc-ed in etm_iosvc_msg_enq()
154725351652SVuong Nguyen 	 */
154825351652SVuong Nguyen 	fmd_hdl_free(hdl, oldp, sizeof (*oldp));
154925351652SVuong Nguyen 
155025351652SVuong Nguyen 	iosvc->msg_q_cur_len--;
155125351652SVuong Nguyen 	if (iosvc->msg_q_cur_len == 0) {
155225351652SVuong Nguyen 		iosvc->msg_q_tail = NULL;
155325351652SVuong Nguyen 	}
155425351652SVuong Nguyen 
155525351652SVuong Nguyen 	return (1);
155625351652SVuong Nguyen 
155725351652SVuong Nguyen } /* etm_iosvc_msg_deq() */
155825351652SVuong Nguyen 
155925351652SVuong Nguyen 
156025351652SVuong Nguyen /*
156125351652SVuong Nguyen  * etm_msg_enq_head():
156225351652SVuong Nguyen  * enq the msg to the head of the Q.
156325351652SVuong Nguyen  * If the Q is full, drop the msg at the tail then enq the msg at head.
156425351652SVuong Nguyen  * need to grab mutex lock iosvc->msg_q_lock before calling this routine.
156525351652SVuong Nguyen  */
156625351652SVuong Nguyen static void
156725351652SVuong Nguyen etm_msg_enq_head(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
156825351652SVuong Nguyen     etm_iosvc_q_ele_t *msg_ele)
156925351652SVuong Nguyen {
157025351652SVuong Nguyen 
157125351652SVuong Nguyen 	etm_iosvc_q_ele_t	*newp;	/* iosvc msg ele ptr */
157225351652SVuong Nguyen 
157325351652SVuong Nguyen 	if (iosvc->msg_q_cur_len >= iosvc->msg_q_max_len) {
157425351652SVuong Nguyen 		fmd_hdl_debug(fmd_hdl,
157525351652SVuong Nguyen 		    "warning: add to head of a full msg queue."
157625351652SVuong Nguyen 		    " Drop the msg at the tail\n");
157725351652SVuong Nguyen 		/*
157825351652SVuong Nguyen 		 * drop the msg at the tail
157925351652SVuong Nguyen 		 */
158025351652SVuong Nguyen 		newp = iosvc->msg_q_head;
158125351652SVuong Nguyen 		while (newp->msg_nextp != iosvc->msg_q_tail) {
158225351652SVuong Nguyen 			newp = newp->msg_nextp;
158325351652SVuong Nguyen 		}
158425351652SVuong Nguyen 
158525351652SVuong Nguyen 		/*
158625351652SVuong Nguyen 		 * free the msg in iosvc->msg_q_tail->msg
158725351652SVuong Nguyen 		 * free the mem pointed to by iosvc->msg_q_tail
158825351652SVuong Nguyen 		 */
158925351652SVuong Nguyen 		fmd_hdl_free(fmd_hdl, iosvc->msg_q_tail->msg,
159025351652SVuong Nguyen 		    iosvc->msg_q_tail->msg_size);
159125351652SVuong Nguyen 		fmd_hdl_free(fmd_hdl, iosvc->msg_q_tail, sizeof (*newp));
159225351652SVuong Nguyen 		iosvc->msg_q_tail = newp;
159325351652SVuong Nguyen 		iosvc->msg_q_tail->msg_nextp = NULL;
159425351652SVuong Nguyen 		iosvc->msg_q_cur_len--;
159525351652SVuong Nguyen 	}
159625351652SVuong Nguyen 
159725351652SVuong Nguyen 	/*
159825351652SVuong Nguyen 	 * enq the msg to the head
159925351652SVuong Nguyen 	 */
160025351652SVuong Nguyen 	newp = fmd_hdl_zalloc(fmd_hdl, sizeof (*newp), FMD_SLEEP);
160125351652SVuong Nguyen 	(void) memcpy(newp, msg_ele, sizeof (*newp));
160225351652SVuong Nguyen 	if (iosvc->msg_q_cur_len == 0) {
160325351652SVuong Nguyen 		newp->msg_nextp = NULL;
160425351652SVuong Nguyen 		iosvc->msg_q_tail = newp;
160525351652SVuong Nguyen 	} else {
160625351652SVuong Nguyen 		newp->msg_nextp = iosvc->msg_q_head;
160725351652SVuong Nguyen 	}
160825351652SVuong Nguyen 	iosvc->msg_q_head = newp;
160925351652SVuong Nguyen 	iosvc->msg_q_cur_len++;
161025351652SVuong Nguyen } /* etm_msg_enq_head() */
161125351652SVuong Nguyen 
161225351652SVuong Nguyen /*
1613d279c7bfSVuong Nguyen  * etm_iosvc_cleanup():
1614d279c7bfSVuong Nguyen  * Clean up an iosvc structure
1615d279c7bfSVuong Nguyen  * 1) close the fmd_xprt if it has not been closed
1616d279c7bfSVuong Nguyen  * 2) Terminate the send/revc threads
1617d279c7bfSVuong Nguyen  * 3) If the clean_msg_q flag is set, free all fma events in the queue. In
1618d279c7bfSVuong Nguyen  *    addition, if the chpt_remove flag is set, delete the checkpoint so that
1619d279c7bfSVuong Nguyen  *    the events are not persisted.
162025351652SVuong Nguyen  */
162125351652SVuong Nguyen static void
1622d279c7bfSVuong Nguyen etm_iosvc_cleanup(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc, boolean_t clean_msg_q,
1623d279c7bfSVuong Nguyen     boolean_t ckpt_remove)
162425351652SVuong Nguyen {
162525351652SVuong Nguyen 
162625351652SVuong Nguyen 	etm_iosvc_q_ele_t	msg_ele;	/* io svc msg Q ele */
162725351652SVuong Nguyen 
162825351652SVuong Nguyen 	iosvc->thr_is_dying = 1;
162925351652SVuong Nguyen 
16302c07a099SYanmin Sun 	iosvc->ds_hdl = DS_INVALID_HDL;
16312c07a099SYanmin Sun 	if (iosvc->fmd_xprt != NULL) {
16322c07a099SYanmin Sun 		fmd_xprt_close(fmd_hdl, iosvc->fmd_xprt);
16332c07a099SYanmin Sun 		iosvc->fmd_xprt = NULL;
16342c07a099SYanmin Sun 	} /* if fmd-xprt has been opened */
16352c07a099SYanmin Sun 
163625351652SVuong Nguyen 	if (iosvc->send_tid != NULL) {
163725351652SVuong Nguyen 		fmd_thr_signal(fmd_hdl, iosvc->send_tid);
163825351652SVuong Nguyen 		fmd_thr_destroy(fmd_hdl, iosvc->send_tid);
163925351652SVuong Nguyen 		iosvc->send_tid = NULL;
164025351652SVuong Nguyen 	} /* if io svc send thread was created ok */
164125351652SVuong Nguyen 
164225351652SVuong Nguyen 	if (iosvc->recv_tid != NULL) {
164325351652SVuong Nguyen 		fmd_thr_signal(fmd_hdl, iosvc->recv_tid);
164425351652SVuong Nguyen 		fmd_thr_destroy(fmd_hdl, iosvc->recv_tid);
164525351652SVuong Nguyen 		iosvc->recv_tid = NULL;
164625351652SVuong Nguyen 	} /* if root domain recv thread was created */
164725351652SVuong Nguyen 
16482c07a099SYanmin Sun 
16492c07a099SYanmin Sun 	if (clean_msg_q) {
165025351652SVuong Nguyen 		iosvc->ldom_name[0] = '\0';
165125351652SVuong Nguyen 
165225351652SVuong Nguyen 		(void) pthread_mutex_lock(&iosvc->msg_q_lock);
165325351652SVuong Nguyen 		while (iosvc->msg_q_cur_len > 0) {
165425351652SVuong Nguyen 			(void) etm_iosvc_msg_deq(fmd_hdl, iosvc, &msg_ele);
1655d279c7bfSVuong Nguyen 			if (ckpt_remove == B_TRUE &&
1656d279c7bfSVuong Nguyen 			    msg_ele.ckpt_flag != ETM_CKPT_NOOP) {
1657d279c7bfSVuong Nguyen 				etm_ckpt_remove(fmd_hdl, &msg_ele);
1658d279c7bfSVuong Nguyen 			}
165925351652SVuong Nguyen 			fmd_hdl_free(fmd_hdl, msg_ele.msg, msg_ele.msg_size);
166025351652SVuong Nguyen 		}
166125351652SVuong Nguyen 		(void) pthread_mutex_unlock(&iosvc->msg_q_lock);
16622c07a099SYanmin Sun 	}
166325351652SVuong Nguyen 
166425351652SVuong Nguyen 	return;
166525351652SVuong Nguyen 
166625351652SVuong Nguyen } /* etm_iosvc_cleanup() */
166725351652SVuong Nguyen 
166825351652SVuong Nguyen /*
166925351652SVuong Nguyen  * etm_iosvc_lookup(using ldom_name or ds_hdl when ldom_name is empty)
167025351652SVuong Nguyen  * not found, create one, add to iosvc_list
167125351652SVuong Nguyen  */
167225351652SVuong Nguyen etm_iosvc_t *
167325351652SVuong Nguyen etm_iosvc_lookup(fmd_hdl_t *fmd_hdl, char *ldom_name, ds_hdl_t ds_hdl,
167425351652SVuong Nguyen     boolean_t iosvc_create)
167525351652SVuong Nguyen {
167625351652SVuong Nguyen 	uint32_t		i;			/* for loop var */
167725351652SVuong Nguyen 	int32_t			first_empty_slot = -1;	/* remember that */
167825351652SVuong Nguyen 
167925351652SVuong Nguyen 	for (i = 0; i < NUM_OF_ROOT_DOMAINS; i++) {
168025351652SVuong Nguyen 		if (ldom_name[0] == '\0') {
168125351652SVuong Nguyen 			/*
168225351652SVuong Nguyen 			 * search by hdl passed in
168325351652SVuong Nguyen 			 * the only time this is used is at ds_unreg_cb time.
168425351652SVuong Nguyen 			 * there is no ldom name, only the valid ds_hdl.
168525351652SVuong Nguyen 			 * find an iosvc with the matching ds_hdl.
168625351652SVuong Nguyen 			 * ignore the iosvc_create flag, should never need to
168725351652SVuong Nguyen 			 * create an iosvc for ds_unreg_cb
168825351652SVuong Nguyen 			 */
168925351652SVuong Nguyen 			if (ds_hdl == iosvc_list[i].ds_hdl) {
169025351652SVuong Nguyen 				if (etm_debug_lvl >= 2) {
169125351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
169225351652SVuong Nguyen 			    "info: found an iosvc at slot %d w/ ds_hdl %d \n",
169325351652SVuong Nguyen 				    i, iosvc_list[i].ds_hdl);
169425351652SVuong Nguyen 				}
169525351652SVuong Nguyen 				if (iosvc_list[i].ldom_name[0] != '\0')
169625351652SVuong Nguyen 					if (etm_debug_lvl >= 2) {
169725351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
169825351652SVuong Nguyen 				    "info: found an iosvc w/ ldom_name %s \n",
169925351652SVuong Nguyen 						    iosvc_list[i].ldom_name);
170025351652SVuong Nguyen 				}
170125351652SVuong Nguyen 				return (&iosvc_list[i]);
170225351652SVuong Nguyen 			} else {
170325351652SVuong Nguyen 				continue;
170425351652SVuong Nguyen 			}
170525351652SVuong Nguyen 		} else if (iosvc_list[i].ldom_name[0] != '\0') {
170625351652SVuong Nguyen 			/*
170725351652SVuong Nguyen 			 * this is  an non-empty iosvc structure slot
170825351652SVuong Nguyen 			 */
170925351652SVuong Nguyen 			if (strcmp(ldom_name, iosvc_list[i].ldom_name) == 0) {
171025351652SVuong Nguyen 				/*
171125351652SVuong Nguyen 				 * found an iosvc structure that matches the
171225351652SVuong Nguyen 				 * passed in ldom_name, return the ptr
171325351652SVuong Nguyen 				 */
171425351652SVuong Nguyen 				if (etm_debug_lvl >= 2) {
171525351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl, "info: found an "
171625351652SVuong Nguyen 					    "iosvc at slot %d w/ ds_hdl %d \n",
171725351652SVuong Nguyen 					    i, iosvc_list[i].ds_hdl);
171825351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl, "info: found an "
171925351652SVuong Nguyen 					    "iosvc w/ ldom_name %s \n",
172025351652SVuong Nguyen 					    iosvc_list[i].ldom_name);
172125351652SVuong Nguyen 				}
172225351652SVuong Nguyen 				return (&iosvc_list[i]);
172325351652SVuong Nguyen 			} else {
172425351652SVuong Nguyen 				/*
172525351652SVuong Nguyen 				 * non-empty slot with no-matching name,
172625351652SVuong Nguyen 				 * move on to next slot.
172725351652SVuong Nguyen 				 */
172825351652SVuong Nguyen 				continue;
172925351652SVuong Nguyen 			}
173025351652SVuong Nguyen 		} else {
173125351652SVuong Nguyen 			/*
173225351652SVuong Nguyen 			 * found the 1st slot with ldom name being empty
173325351652SVuong Nguyen 			 * remember the slot #, will be used for creating one
173425351652SVuong Nguyen 			 */
173525351652SVuong Nguyen 			if (first_empty_slot == -1) {
173625351652SVuong Nguyen 				first_empty_slot = i;
173725351652SVuong Nguyen 			}
173825351652SVuong Nguyen 		}
173925351652SVuong Nguyen 	}
174025351652SVuong Nguyen 	if (iosvc_create == B_TRUE && first_empty_slot >= 0) {
174125351652SVuong Nguyen 		/*
174225351652SVuong Nguyen 		 * this is the case we need to add an iosvc at first_empty_slot
174325351652SVuong Nguyen 		 * for the ldom_name at iosvc_list[first_empty_slot]
174425351652SVuong Nguyen 		 */
174525351652SVuong Nguyen 		fmd_hdl_debug(fmd_hdl,
174625351652SVuong Nguyen 		    "info: create an iosvc with ldom name %s\n",
174725351652SVuong Nguyen 		    ldom_name);
174825351652SVuong Nguyen 		i = first_empty_slot;
174925351652SVuong Nguyen 		(void) memcpy(&iosvc_list[i], &io_svc, sizeof (etm_iosvc_t));
175025351652SVuong Nguyen 		(void) strcpy(iosvc_list[i].ldom_name, ldom_name);
175125351652SVuong Nguyen 		fmd_hdl_debug(fmd_hdl, "info: iosvc #%d has ldom name %s\n",
175225351652SVuong Nguyen 		    i, iosvc_list[i].ldom_name);
175325351652SVuong Nguyen 		return (&iosvc_list[i]);
175425351652SVuong Nguyen 	} else {
175525351652SVuong Nguyen 		return (NULL);
175625351652SVuong Nguyen 	}
175725351652SVuong Nguyen 
175825351652SVuong Nguyen } /* etm_iosvc_lookup() */
175925351652SVuong Nguyen 
176025351652SVuong Nguyen 
176125351652SVuong Nguyen /*
176225351652SVuong Nguyen  * etm_ckpt_remove:
176325351652SVuong Nguyen  * remove the ckpt for the iosvc element
176425351652SVuong Nguyen  */
176525351652SVuong Nguyen static void
176625351652SVuong Nguyen etm_ckpt_remove(fmd_hdl_t *hdl, etm_iosvc_q_ele_t *ele) {
176725351652SVuong Nguyen 	int		err;			/* temp error */
176825351652SVuong Nguyen 	nvlist_t	*evp = NULL;		/* event pointer */
176925351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t	*hdrp;		/* hdr for FMA_EVENT */
177025351652SVuong Nguyen 	char		*buf;			/* packed event pointer */
177125351652SVuong Nguyen 
177225351652SVuong Nguyen 	if ((ele->ckpt_flag == ETM_CKPT_NOOP) ||
177325351652SVuong Nguyen 	    (etm_ldom_type != LDOM_TYPE_CONTROL)) {
177425351652SVuong Nguyen 		return;
177525351652SVuong Nguyen 	}
177625351652SVuong Nguyen 
177725351652SVuong Nguyen 	/* the pointer to the packed event in the etm message */
177825351652SVuong Nguyen 	hdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)ele->msg);
177925351652SVuong Nguyen 	buf = (char *)((ptrdiff_t)hdrp + sizeof (*hdrp)
178025351652SVuong Nguyen 	    + (1 * sizeof (hdrp->ev_lens[0])));
178125351652SVuong Nguyen 
178225351652SVuong Nguyen 	/* unpack it, then uncheckpoited it */
178325351652SVuong Nguyen 	if ((err = nvlist_unpack(buf, hdrp->ev_lens[0], &evp, 0)) != 0) {
178425351652SVuong Nguyen 		fmd_hdl_debug(hdl, "failed to unpack event(rc=%d)\n", err);
178525351652SVuong Nguyen 		return;
178625351652SVuong Nguyen 	}
178725351652SVuong Nguyen 	(void) etm_ckpt_delete(hdl, evp);
178825351652SVuong Nguyen 	nvlist_free(evp);
178925351652SVuong Nguyen }
179025351652SVuong Nguyen 
179125351652SVuong Nguyen /*
179225351652SVuong Nguyen  * etm_send_ds_msg()
179325351652SVuong Nguyen  * call ds_send_msg() to send the msg passed in.
179425351652SVuong Nguyen  * timedcond_wait for the ACK to come back.
179525351652SVuong Nguyen  * if the ACK doesn't come in the specified time, retrun -EAGAIN.
179625351652SVuong Nguyen  * other wise, return 1.
179725351652SVuong Nguyen  */
179825351652SVuong Nguyen int
179925351652SVuong Nguyen etm_send_ds_msg(fmd_hdl_t *fmd_hdl, boolean_t ckpt_remove, etm_iosvc_t *iosvc,
180025351652SVuong Nguyen     etm_iosvc_q_ele_t *msg_ele, etm_proto_v1_ev_hdr_t *evhdrp)
180125351652SVuong Nguyen {
180225351652SVuong Nguyen 	uint32_t		rc;		/* for return code  */
180325351652SVuong Nguyen 
180425351652SVuong Nguyen 	struct timeval		tv;
180525351652SVuong Nguyen 	struct timespec		timeout;
180625351652SVuong Nguyen 
180725351652SVuong Nguyen 
180825351652SVuong Nguyen 	/*
180925351652SVuong Nguyen 	 * call ds_send_msg(). Return (-EAGAIN) if not successful
181025351652SVuong Nguyen 	 */
181125351652SVuong Nguyen 	if ((rc = (*etm_ds_send_msg)(iosvc->ds_hdl, msg_ele->msg,
181225351652SVuong Nguyen 	    msg_ele->msg_size)) != 0) {
181325351652SVuong Nguyen 		fmd_hdl_debug(fmd_hdl, "info: ds_send_msg rc %d xid %d\n",
181425351652SVuong Nguyen 		    rc, evhdrp->ev_pp.pp_xid);
181525351652SVuong Nguyen 			return (-EAGAIN);
181625351652SVuong Nguyen 	}
181725351652SVuong Nguyen 
181825351652SVuong Nguyen 	/*
181925351652SVuong Nguyen 	 * wait on the cv for resp msg for cur_send_xid
182025351652SVuong Nguyen 	 */
182125351652SVuong Nguyen 	(void *) pthread_mutex_lock(&iosvc->msg_ack_lock);
182225351652SVuong Nguyen 
182325351652SVuong Nguyen 	(void) gettimeofday(&tv, 0);
182425351652SVuong Nguyen 	timeout.tv_sec = tv.tv_sec + etm_fma_resp_wait_time;
182525351652SVuong Nguyen 	timeout.tv_nsec = 0;
182625351652SVuong Nguyen 
182725351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl, "info: waiting on msg_ack_cv for ldom %s\n",
182825351652SVuong Nguyen 	    iosvc->ldom_name);
182925351652SVuong Nguyen 	rc = pthread_cond_timedwait(&iosvc->msg_ack_cv, &iosvc->msg_ack_lock,
183025351652SVuong Nguyen 	    &timeout);
183125351652SVuong Nguyen 	(void *) pthread_mutex_unlock(&iosvc->msg_ack_lock);
183225351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl,  "info: msg_ack_cv returns with rc %d\n", rc);
183325351652SVuong Nguyen 
183425351652SVuong Nguyen 	/*
183525351652SVuong Nguyen 	 * check to see if ack_ok is non-zero
183625351652SVuong Nguyen 	 * if non-zero, resp msg has been received
183725351652SVuong Nguyen 	 */
183825351652SVuong Nguyen 	if (iosvc->ack_ok != 0) {
183925351652SVuong Nguyen 		/*
184025351652SVuong Nguyen 		 * ACK came ok,  this send is successful,
184125351652SVuong Nguyen 		 * tell the caller ready to send next.
184225351652SVuong Nguyen 		 * free mem alloc-ed in
184325351652SVuong Nguyen 		 * etm_pack_ds_msg
184425351652SVuong Nguyen 		 */
184525351652SVuong Nguyen 		if (ckpt_remove == B_TRUE &&
184625351652SVuong Nguyen 		    etm_ldom_type == LDOM_TYPE_CONTROL) {
184725351652SVuong Nguyen 			etm_ckpt_remove(fmd_hdl, msg_ele);
184825351652SVuong Nguyen 		}
184925351652SVuong Nguyen 		fmd_hdl_free(fmd_hdl, msg_ele->msg, msg_ele->msg_size);
185025351652SVuong Nguyen 		iosvc->cur_send_xid++;
185125351652SVuong Nguyen 		return (1);
185225351652SVuong Nguyen 	} else {
185325351652SVuong Nguyen 		/*
185425351652SVuong Nguyen 		 * the ACK did not come on time
185525351652SVuong Nguyen 		 * tell the caller to resend cur_send_xid
185625351652SVuong Nguyen 		 */
185725351652SVuong Nguyen 		return (-EAGAIN);
185825351652SVuong Nguyen 	} /* iosvc->ack_ok != 0 */
185925351652SVuong Nguyen } /* etm_send_ds_msg() */
186025351652SVuong Nguyen 
186125351652SVuong Nguyen /*
186225351652SVuong Nguyen  * both events from fmdo_send entry point and from SP are using the
186325351652SVuong Nguyen  * etm_proto_v1_ev_hdr_t as its header and it will be the same header for all
186425351652SVuong Nguyen  * ds send/recv msgs.
186525351652SVuong Nguyen  * Idealy, we should use the hdr coming with the SP FMA event. Since fmdo_send
186625351652SVuong Nguyen  * entry point can be called before FMA events from SP, we can't rely on
186725351652SVuong Nguyen  * the SP FMA event hdr. Use the static hdr for packing ds msgs for fmdo_send
186825351652SVuong Nguyen  * events.
186925351652SVuong Nguyen  * return >0 for success, or -errno value
187025351652SVuong Nguyen  * Design assumption: there is one FMA event per ds msg
187125351652SVuong Nguyen  */
187225351652SVuong Nguyen int
187325351652SVuong Nguyen etm_pack_ds_msg(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
187425351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t *ev_hdrp, size_t hdr_sz, nvlist_t *evp,
187525351652SVuong Nguyen 	etm_pack_msg_type_t msg_type, uint_t ckpt_opt)
187625351652SVuong Nguyen {
187725351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t	*hdrp;		/* for FMA_EVENT msg */
187825351652SVuong Nguyen 	uint32_t		*lenp;		/* ptr to FMA event length */
187925351652SVuong Nguyen 	size_t			evsz;		/* packed FMA event size */
188025351652SVuong Nguyen 	char 			*buf;
188125351652SVuong Nguyen 	uint32_t		rc;		/* for return code  */
188225351652SVuong Nguyen 	char 			*msg;		/* body of msg to be Qed */
188325351652SVuong Nguyen 
188425351652SVuong Nguyen 	etm_iosvc_q_ele_t	msg_ele;	/* io svc msg Q ele */
188525351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t	*evhdrp;
188625351652SVuong Nguyen 
188725351652SVuong Nguyen 
188825351652SVuong Nguyen 	if (ev_hdrp == NULL) {
188925351652SVuong Nguyen 		hdrp = &iosvc_hdr;
189025351652SVuong Nguyen 	} else {
189125351652SVuong Nguyen 		hdrp = ev_hdrp;
189225351652SVuong Nguyen 	}
189325351652SVuong Nguyen 
189425351652SVuong Nguyen 	/*
189525351652SVuong Nguyen 	 * determine hdr_sz if 0, otherwise use the one passed in hdr_sz
189625351652SVuong Nguyen 	 */
189725351652SVuong Nguyen 
189825351652SVuong Nguyen 	if (hdr_sz == 0) {
189925351652SVuong Nguyen 		hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0]));
190025351652SVuong Nguyen 	}
190125351652SVuong Nguyen 
190225351652SVuong Nguyen 	/*
190325351652SVuong Nguyen 	 * determine evp size
190425351652SVuong Nguyen 	 */
190525351652SVuong Nguyen 	(void) nvlist_size(evp, &evsz, NV_ENCODE_XDR);
190625351652SVuong Nguyen 
190725351652SVuong Nguyen 	/* indicate 1 FMA event, no network encoding, and 0-terminate */
190825351652SVuong Nguyen 	lenp = &hdrp->ev_lens[0];
190925351652SVuong Nguyen 	*lenp = evsz;
191025351652SVuong Nguyen 
191125351652SVuong Nguyen 	/*
191225351652SVuong Nguyen 	 * now the total of mem needs to be alloc-ed/ds msg size is
191325351652SVuong Nguyen 	 * hdr_sz + evsz
191425351652SVuong Nguyen 	 * msg will be freed in etm_send_to_remote_root() after ds_send_msg()
191525351652SVuong Nguyen 	 */
191625351652SVuong Nguyen 	msg = fmd_hdl_zalloc(fmd_hdl, hdr_sz + evsz, FMD_SLEEP);
191725351652SVuong Nguyen 
191825351652SVuong Nguyen 
191925351652SVuong Nguyen 	/*
192025351652SVuong Nguyen 	 * copy hdr, 0 terminate the length vector,  and then evp
192125351652SVuong Nguyen 	 */
192225351652SVuong Nguyen 	(void) memcpy(msg, hdrp, sizeof (*hdrp));
192325351652SVuong Nguyen 	hdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)msg);
192425351652SVuong Nguyen 	lenp = &hdrp->ev_lens[0];
192525351652SVuong Nguyen 	lenp++;
192625351652SVuong Nguyen 	*lenp = 0;
192725351652SVuong Nguyen 
192825351652SVuong Nguyen 	buf = fmd_hdl_zalloc(fmd_hdl, evsz, FMD_SLEEP);
192925351652SVuong Nguyen 	(void) nvlist_pack(evp, (char **)&buf, &evsz, NV_ENCODE_XDR, 0);
193025351652SVuong Nguyen 	(void) memcpy(msg + hdr_sz, buf, evsz);
193125351652SVuong Nguyen 	fmd_hdl_free(fmd_hdl, buf, evsz);
193225351652SVuong Nguyen 
193325351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl, "info: hdr_sz= %d evsz= %d in etm_pack_ds_msg"
193425351652SVuong Nguyen 	    "for ldom %s\n", hdr_sz, evsz, iosvc->ldom_name);
193525351652SVuong Nguyen 	msg_ele.msg = msg;
193625351652SVuong Nguyen 	msg_ele.msg_size = hdr_sz + evsz;
193725351652SVuong Nguyen 	msg_ele.ckpt_flag = ckpt_opt;
193825351652SVuong Nguyen 
193925351652SVuong Nguyen 	/*
194025351652SVuong Nguyen 	 * decide what to do with the msg:
194125351652SVuong Nguyen 	 * if SP ereports (msg_type == SP_MSG), always enq the msg
194225351652SVuong Nguyen 	 * if not SP ereports, ie, fmd xprt control msgs, enq it _only_ after
194325351652SVuong Nguyen 	 * resource.fm.xprt.run has been sent (which sets start_sending_Q to 1)
194425351652SVuong Nguyen 	 */
194525351652SVuong Nguyen 	if ((msg_type == SP_MSG) ||
194625351652SVuong Nguyen 	    (msg_type != SP_MSG) && (iosvc->start_sending_Q == 1)) {
194725351652SVuong Nguyen 		/*
194825351652SVuong Nguyen 		 * this is the case when the msg needs to be enq-ed
194925351652SVuong Nguyen 		 */
195025351652SVuong Nguyen 		(void) pthread_mutex_lock(&iosvc->msg_q_lock);
195125351652SVuong Nguyen 		rc = etm_iosvc_msg_enq(fmd_hdl, iosvc, &msg_ele);
195225351652SVuong Nguyen 		if ((rc > 0) && (ckpt_opt & ETM_CKPT_SAVE) &&
195325351652SVuong Nguyen 		    (etm_ldom_type == LDOM_TYPE_CONTROL)) {
195425351652SVuong Nguyen 			(void) etm_ckpt_add(fmd_hdl, evp);
195525351652SVuong Nguyen 		}
195625351652SVuong Nguyen 		if (iosvc->msg_q_cur_len == 1)
195725351652SVuong Nguyen 			(void) pthread_cond_signal(&iosvc->msg_q_cv);
195825351652SVuong Nguyen 		(void) pthread_mutex_unlock(&iosvc->msg_q_lock);
195925351652SVuong Nguyen 	} else {
196025351652SVuong Nguyen 		/*
196125351652SVuong Nguyen 		 * fmd RDWR xprt procotol startup msgs, send it now!
196225351652SVuong Nguyen 		 */
196325351652SVuong Nguyen 		iosvc->ack_ok = 0;
196425351652SVuong Nguyen 		evhdrp = (etm_proto_v1_ev_hdr_t *)((ptrdiff_t)msg_ele.msg);
196525351652SVuong Nguyen 		evhdrp->ev_pp.pp_xid = iosvc->cur_send_xid + 1;
196625351652SVuong Nguyen 		while (!iosvc->ack_ok && iosvc->ds_hdl != DS_INVALID_HDL &&
196725351652SVuong Nguyen 		    !etm_is_dying) {
196825351652SVuong Nguyen 			if (etm_send_ds_msg(fmd_hdl, B_FALSE, iosvc, &msg_ele,
196925351652SVuong Nguyen 			    evhdrp) < 0) {
197025351652SVuong Nguyen 				continue;
197125351652SVuong Nguyen 			}
197225351652SVuong Nguyen 		}
197325351652SVuong Nguyen 		if (msg_type == FMD_XPRT_RUN_MSG)
197425351652SVuong Nguyen 			iosvc->start_sending_Q = 1;
197525351652SVuong Nguyen 	}
197625351652SVuong Nguyen 
197725351652SVuong Nguyen 	return (rc);
197825351652SVuong Nguyen 
197925351652SVuong Nguyen } /* etm_pack_ds_msg() */
198025351652SVuong Nguyen 
1981733a5356Srb144127 /*
1982b8677b72Srb144127  * Design_Note:	For all etm_resp_q_*() functions and etm_resp_q_* globals,
1983b8677b72Srb144127  *		the mutex etm_resp_q_lock must be held by the caller.
1984e2ff4ac6Srb144127  */
1985e2ff4ac6Srb144127 
1986e2ff4ac6Srb144127 /*
1987b8677b72Srb144127  * etm_resp_q_enq - add element to tail of ETM responder queue
1988b8677b72Srb144127  * etm_resp_q_deq - del element from head of ETM responder queue
1989b8677b72Srb144127  *
1990b8677b72Srb144127  * return >0 for success, or -errno value
1991b8677b72Srb144127  */
1992b8677b72Srb144127 
1993b8677b72Srb144127 static int
1994b8677b72Srb144127 etm_resp_q_enq(fmd_hdl_t *hdl, etm_resp_q_ele_t *rqep)
1995b8677b72Srb144127 {
1996b8677b72Srb144127 	etm_resp_q_ele_t	*newp;	/* ptr to new resp q ele */
1997b8677b72Srb144127 
1998b8677b72Srb144127 	if (etm_resp_q_cur_len >= etm_resp_q_max_len) {
1999b8677b72Srb144127 		fmd_hdl_debug(hdl, "warning: enq to full responder queue\n");
2000b8677b72Srb144127 		etm_stats.etm_enq_drop_resp_q.fmds_value.ui64++;
2001b8677b72Srb144127 		return (-E2BIG);
2002b8677b72Srb144127 	}
2003b8677b72Srb144127 
2004b8677b72Srb144127 	newp = fmd_hdl_zalloc(hdl, sizeof (*newp), FMD_SLEEP);
2005b8677b72Srb144127 	(void) memcpy(newp, rqep, sizeof (*newp));
2006b8677b72Srb144127 	newp->rqe_nextp = NULL;
2007b8677b72Srb144127 
2008b8677b72Srb144127 	if (etm_resp_q_cur_len == 0) {
2009b8677b72Srb144127 		etm_resp_q_head = newp;
2010b8677b72Srb144127 	} else {
2011b8677b72Srb144127 		etm_resp_q_tail->rqe_nextp = newp;
2012b8677b72Srb144127 	}
2013b8677b72Srb144127 	etm_resp_q_tail = newp;
2014b8677b72Srb144127 	etm_resp_q_cur_len++;
2015b8677b72Srb144127 	etm_stats.etm_resp_q_cur_len.fmds_value.ui64 = etm_resp_q_cur_len;
2016b8677b72Srb144127 
2017b8677b72Srb144127 	return (1);
2018b8677b72Srb144127 
2019b8677b72Srb144127 } /* etm_resp_q_enq() */
2020b8677b72Srb144127 
2021b8677b72Srb144127 static int
2022b8677b72Srb144127 etm_resp_q_deq(fmd_hdl_t *hdl, etm_resp_q_ele_t *rqep)
2023b8677b72Srb144127 {
2024b8677b72Srb144127 	etm_resp_q_ele_t	*oldp;	/* ptr to old resp q ele */
2025b8677b72Srb144127 
2026b8677b72Srb144127 	if (etm_resp_q_cur_len == 0) {
2027b8677b72Srb144127 		fmd_hdl_debug(hdl, "warning: deq from empty responder queue\n");
2028b8677b72Srb144127 		etm_stats.etm_deq_drop_resp_q.fmds_value.ui64++;
2029b8677b72Srb144127 		return (-ENOENT);
2030b8677b72Srb144127 	}
2031b8677b72Srb144127 
2032b8677b72Srb144127 	(void) memcpy(rqep, etm_resp_q_head, sizeof (*rqep));
2033b8677b72Srb144127 	rqep->rqe_nextp = NULL;
2034b8677b72Srb144127 
2035b8677b72Srb144127 	oldp = etm_resp_q_head;
2036b8677b72Srb144127 	etm_resp_q_head = etm_resp_q_head->rqe_nextp;
2037b8677b72Srb144127 	fmd_hdl_free(hdl, oldp, sizeof (*oldp));
2038b8677b72Srb144127 
2039b8677b72Srb144127 	etm_resp_q_cur_len--;
2040b8677b72Srb144127 	etm_stats.etm_resp_q_cur_len.fmds_value.ui64 = etm_resp_q_cur_len;
2041b8677b72Srb144127 	if (etm_resp_q_cur_len == 0) {
2042b8677b72Srb144127 		etm_resp_q_tail = NULL;
2043b8677b72Srb144127 	}
2044b8677b72Srb144127 
2045b8677b72Srb144127 	return (1);
2046b8677b72Srb144127 
2047b8677b72Srb144127 } /* etm_resp_q_deq() */
2048b8677b72Srb144127 
2049b8677b72Srb144127 /*
2050b8677b72Srb144127  * etm_maybe_enq_response - check the given message header to see
2051e2ff4ac6Srb144127  *				whether a response has been requested,
2052b8677b72Srb144127  *				if so then enqueue the given connection
2053b8677b72Srb144127  *				and header for later transport by the
2054b8677b72Srb144127  *				responder thread as an ETM response msg,
2055b8677b72Srb144127  *				return 0 for nop, >0 success, or -errno value
2056e2ff4ac6Srb144127  */
2057e2ff4ac6Srb144127 
2058e2ff4ac6Srb144127 static ssize_t
2059b8677b72Srb144127 etm_maybe_enq_response(fmd_hdl_t *hdl, etm_xport_conn_t conn,
2060b8677b72Srb144127     void *hdrp, uint32_t hdr_sz, int32_t resp_code)
2061e2ff4ac6Srb144127 {
2062e2ff4ac6Srb144127 	ssize_t			rv;		/* ret val */
2063e2ff4ac6Srb144127 	etm_proto_v1_pp_t	*ppp;		/* protocol preamble ptr */
2064e2ff4ac6Srb144127 	uint8_t			orig_msg_type;	/* orig hdr's message type */
2065e2ff4ac6Srb144127 	uint32_t		orig_timeout;	/* orig hdr's timeout */
2066b8677b72Srb144127 	etm_resp_q_ele_t	rqe;		/* responder queue ele */
2067e2ff4ac6Srb144127 
2068e2ff4ac6Srb144127 	ppp = hdrp;
2069e2ff4ac6Srb144127 	orig_msg_type = ppp->pp_msg_type;
2070e2ff4ac6Srb144127 	orig_timeout = ppp->pp_timeout;
2071e2ff4ac6Srb144127 
2072e2ff4ac6Srb144127 	/* bail out now if no response is to be sent */
2073e2ff4ac6Srb144127 
2074e2ff4ac6Srb144127 	if (orig_timeout == ETM_PROTO_V1_TIMEOUT_NONE) {
2075e2ff4ac6Srb144127 		return (0);
2076e2ff4ac6Srb144127 	} /* if a nop */
2077e2ff4ac6Srb144127 
2078e2ff4ac6Srb144127 	if ((orig_msg_type != ETM_MSG_TYPE_FMA_EVENT) &&
20794b476ed5Sdarudy 	    (orig_msg_type != ETM_MSG_TYPE_ALERT) &&
2080e2ff4ac6Srb144127 	    (orig_msg_type != ETM_MSG_TYPE_CONTROL)) {
2081b8677b72Srb144127 		fmd_hdl_debug(hdl, "warning: bad msg type 0x%x\n",
2082b8677b72Srb144127 		    orig_msg_type);
2083e2ff4ac6Srb144127 		return (-EINVAL);
2084e2ff4ac6Srb144127 	} /* if inappropriate hdr for a response msg */
2085e2ff4ac6Srb144127 
2086b8677b72Srb144127 	/*
2087b8677b72Srb144127 	 * enqueue the msg hdr and nudge the responder thread
2088b8677b72Srb144127 	 * if the responder queue was previously empty
2089b8677b72Srb144127 	 */
2090b8677b72Srb144127 
2091b8677b72Srb144127 	rqe.rqe_conn = conn;
2092b8677b72Srb144127 	rqe.rqe_hdrp = hdrp;
2093b8677b72Srb144127 	rqe.rqe_hdr_sz = hdr_sz;
2094b8677b72Srb144127 	rqe.rqe_resp_code = resp_code;
2095b8677b72Srb144127 
2096b8677b72Srb144127 	(void) pthread_mutex_lock(&etm_resp_q_lock);
2097*c5fb5d32SKarl Davis 
2098*c5fb5d32SKarl Davis 	if (etm_resp_q_cur_len == etm_resp_q_max_len)
2099*c5fb5d32SKarl Davis 		(void) pthread_cond_wait(&etm_resp_q_cv, &etm_resp_q_lock);
2100*c5fb5d32SKarl Davis 
2101b8677b72Srb144127 	rv = etm_resp_q_enq(hdl, &rqe);
2102b8677b72Srb144127 	if (etm_resp_q_cur_len == 1)
2103b8677b72Srb144127 		(void) pthread_cond_signal(&etm_resp_q_cv);
2104b8677b72Srb144127 	(void) pthread_mutex_unlock(&etm_resp_q_lock);
2105b8677b72Srb144127 
2106b8677b72Srb144127 	return (rv);
2107b8677b72Srb144127 
2108b8677b72Srb144127 } /* etm_maybe_enq_response() */
2109b8677b72Srb144127 
2110b8677b72Srb144127 /*
2111b8677b72Srb144127  * Design_Note:	We rely on the fact that all message types have
2112b8677b72Srb144127  *		a common protocol preamble; if this fact should
2113b8677b72Srb144127  *		ever change it may break the code below. We also
2114b8677b72Srb144127  *		rely on the fact that FMA_EVENT and CONTROL headers
2115b8677b72Srb144127  *		returned by etm_hdr_read() will be sized large enough
2116b8677b72Srb144127  *		to reuse them as RESPONSE headers if the remote endpt
2117b8677b72Srb144127  *		asked for a response via the pp_timeout field.
2118b8677b72Srb144127  */
2119b8677b72Srb144127 
2120b8677b72Srb144127 /*
2121b8677b72Srb144127  * etm_send_response - use the given message header and response code
2122b8677b72Srb144127  *			to construct an appropriate response message,
2123b8677b72Srb144127  *			and send it back on the given connection,
2124b8677b72Srb144127  *			return >0 for success, or -errno value
2125b8677b72Srb144127  */
2126b8677b72Srb144127 
2127b8677b72Srb144127 static ssize_t
2128b8677b72Srb144127 etm_send_response(fmd_hdl_t *hdl, etm_xport_conn_t conn,
2129b8677b72Srb144127     void *hdrp, int32_t resp_code)
2130b8677b72Srb144127 {
2131b8677b72Srb144127 	ssize_t			rv;		/* ret val */
2132b8677b72Srb144127 	etm_proto_v1_pp_t	*ppp;		/* protocol preamble ptr */
2133b8677b72Srb144127 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
2134b8677b72Srb144127 	uint8_t			resp_body[4];	/* response body if needed */
2135b8677b72Srb144127 	uint8_t			*resp_msg;	/* response hdr+body */
2136b8677b72Srb144127 	size_t			hdr_sz;		/* sizeof response hdr */
2137b8677b72Srb144127 	uint8_t			orig_msg_type;	/* orig hdr's message type */
2138b8677b72Srb144127 
2139b8677b72Srb144127 	ppp = hdrp;
2140b8677b72Srb144127 	orig_msg_type = ppp->pp_msg_type;
2141e2ff4ac6Srb144127 
2142e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
2143e2ff4ac6Srb144127 		etm_show_time(hdl, "ante resp send");
2144e2ff4ac6Srb144127 	}
2145e2ff4ac6Srb144127 
2146b8677b72Srb144127 	/* reuse the given header as a response header */
2147b8677b72Srb144127 
2148e2ff4ac6Srb144127 	resp_hdrp = hdrp;
2149e2ff4ac6Srb144127 	resp_hdrp->resp_code = resp_code;
2150e2ff4ac6Srb144127 	resp_hdrp->resp_len = 0;		/* default is empty body */
2151e2ff4ac6Srb144127 
2152e2ff4ac6Srb144127 	if ((orig_msg_type == ETM_MSG_TYPE_CONTROL) &&
2153e2ff4ac6Srb144127 	    (ppp->pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ)) {
2154e2ff4ac6Srb144127 		resp_body[0] = ETM_PROTO_V2;
21554b476ed5Sdarudy 		resp_body[1] = ETM_PROTO_V3;
21564b476ed5Sdarudy 		resp_body[2] = 0;
21574b476ed5Sdarudy 		resp_hdrp->resp_len = 3;
2158e2ff4ac6Srb144127 	} /* if should send our/negotiated proto ver in resp body */
2159e2ff4ac6Srb144127 
2160e2ff4ac6Srb144127 	/* respond with the proto ver that was negotiated */
2161e2ff4ac6Srb144127 
2162e2ff4ac6Srb144127 	resp_hdrp->resp_pp.pp_proto_ver = etm_resp_ver;
2163e2ff4ac6Srb144127 	resp_hdrp->resp_pp.pp_msg_type = ETM_MSG_TYPE_RESPONSE;
2164e2ff4ac6Srb144127 	resp_hdrp->resp_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
2165e2ff4ac6Srb144127 
2166e2ff4ac6Srb144127 	/*
2167e2ff4ac6Srb144127 	 * send the whole response msg in one write, header and body;
2168e2ff4ac6Srb144127 	 * avoid the alloc-and-copy if we can reuse the hdr as the msg,
2169b8677b72Srb144127 	 * ie, if the body is empty. update the response stats.
2170e2ff4ac6Srb144127 	 */
2171e2ff4ac6Srb144127 
2172e2ff4ac6Srb144127 	hdr_sz = sizeof (etm_proto_v1_resp_hdr_t);
2173e2ff4ac6Srb144127 
2174e2ff4ac6Srb144127 	resp_msg = hdrp;
2175e2ff4ac6Srb144127 	if (resp_hdrp->resp_len > 0) {
2176e2ff4ac6Srb144127 		resp_msg = fmd_hdl_zalloc(hdl, hdr_sz + resp_hdrp->resp_len,
2177e2ff4ac6Srb144127 		    FMD_SLEEP);
2178e2ff4ac6Srb144127 		(void) memcpy(resp_msg, resp_hdrp, hdr_sz);
2179e2ff4ac6Srb144127 		(void) memcpy(resp_msg + hdr_sz, resp_body,
2180e2ff4ac6Srb144127 		    resp_hdrp->resp_len);
2181e2ff4ac6Srb144127 	}
2182e2ff4ac6Srb144127 
21832ae66659Sjrutt 	(void) pthread_mutex_lock(&etm_write_lock);
2184b8677b72Srb144127 	rv = etm_io_op(hdl, "bad io write on resp msg", conn,
2185b8677b72Srb144127 	    resp_msg, hdr_sz + resp_hdrp->resp_len, ETM_IO_OP_WR);
21862ae66659Sjrutt 	(void) pthread_mutex_unlock(&etm_write_lock);
2187b8677b72Srb144127 	if (rv < 0) {
2188e2ff4ac6Srb144127 		goto func_ret;
2189e2ff4ac6Srb144127 	}
2190e2ff4ac6Srb144127 
2191e2ff4ac6Srb144127 	etm_stats.etm_wr_hdr_response.fmds_value.ui64++;
2192e2ff4ac6Srb144127 	etm_stats.etm_wr_body_response.fmds_value.ui64++;
2193e2ff4ac6Srb144127 
2194e2ff4ac6Srb144127 	fmd_hdl_debug(hdl, "info: sent V%u RESPONSE msg to xport "
2195e2ff4ac6Srb144127 	    "xid 0x%x code %d len %u\n",
2196e2ff4ac6Srb144127 	    (unsigned int)resp_hdrp->resp_pp.pp_proto_ver,
2197e2ff4ac6Srb144127 	    resp_hdrp->resp_pp.pp_xid, resp_hdrp->resp_code,
2198e2ff4ac6Srb144127 	    resp_hdrp->resp_len);
2199e2ff4ac6Srb144127 func_ret:
2200e2ff4ac6Srb144127 
2201e2ff4ac6Srb144127 	if (resp_hdrp->resp_len > 0) {
2202e2ff4ac6Srb144127 		fmd_hdl_free(hdl, resp_msg, hdr_sz + resp_hdrp->resp_len);
2203e2ff4ac6Srb144127 	}
2204e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
2205e2ff4ac6Srb144127 		etm_show_time(hdl, "post resp send");
2206e2ff4ac6Srb144127 	}
2207e2ff4ac6Srb144127 	return (rv);
2208e2ff4ac6Srb144127 
2209b8677b72Srb144127 } /* etm_send_response() */
2210e2ff4ac6Srb144127 
2211e2ff4ac6Srb144127 /*
22122ca9f232Srb144127  * etm_reset_xport - reset the transport layer (via fini;init)
22132ca9f232Srb144127  *			presumably for an error condition we cannot
22142ca9f232Srb144127  *			otherwise recover from (ex: hung LDC channel)
22152ca9f232Srb144127  *
22162ca9f232Srb144127  * caveats - no checking/locking is done to ensure an existing connection
22172ca9f232Srb144127  *		is idle during an xport reset; we don't want to deadlock
22182ca9f232Srb144127  *		and presumably the transport is stuck/unusable anyway
22192ca9f232Srb144127  */
22202ca9f232Srb144127 
22212ca9f232Srb144127 static void
22222ca9f232Srb144127 etm_reset_xport(fmd_hdl_t *hdl)
22232ca9f232Srb144127 {
22242ca9f232Srb144127 	(void) etm_xport_fini(hdl);
22252ca9f232Srb144127 	(void) etm_xport_init(hdl);
22262ca9f232Srb144127 	etm_stats.etm_reset_xport.fmds_value.ui64++;
22272ca9f232Srb144127 
22282ca9f232Srb144127 } /* etm_reset_xport() */
22292ca9f232Srb144127 
22302ca9f232Srb144127 /*
2231733a5356Srb144127  * etm_handle_new_conn - receive an ETM message sent from the other end via
2232733a5356Srb144127  *			the given open connection, pull out any FMA events
2233733a5356Srb144127  *			and post them to the local FMD (or handle any ETM
2234733a5356Srb144127  *			control or response msg); when done, close the
2235733a5356Srb144127  *			connection
2236733a5356Srb144127  */
2237733a5356Srb144127 
2238733a5356Srb144127 static void
2239733a5356Srb144127 etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
2240733a5356Srb144127 {
2241733a5356Srb144127 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
2242733a5356Srb144127 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
2243733a5356Srb144127 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
22444b476ed5Sdarudy 	etm_proto_v3_sa_hdr_t	*sa_hdrp;	/* for ALERT msg */
224525351652SVuong Nguyen 	etm_iosvc_t		*iosvc;		/* iosvc data structure */
2246e2ff4ac6Srb144127 	int32_t			resp_code;	/* response code */
2247b8677b72Srb144127 	ssize_t			enq_rv;		/* resp_q enqueue status */
2248733a5356Srb144127 	size_t			hdr_sz;		/* sizeof header */
224925351652SVuong Nguyen 	size_t			evsz;		/* FMA event size */
2250733a5356Srb144127 	uint8_t			*body_buf;	/* msg body buffer */
2251733a5356Srb144127 	uint32_t		body_sz;	/* sizeof body_buf */
2252e2ff4ac6Srb144127 	uint32_t		ev_cnt;		/* count of FMA events */
2253733a5356Srb144127 	uint8_t			*bp;		/* byte ptr within body_buf */
2254733a5356Srb144127 	nvlist_t		*evp;		/* ptr to unpacked FMA event */
2255733a5356Srb144127 	char			*class;		/* FMA event class */
2256733a5356Srb144127 	ssize_t			i, n;		/* gen use */
22572ca9f232Srb144127 	int			should_reset_xport; /* bool to reset xport */
225825351652SVuong Nguyen 	char			ldom_name[MAX_LDOM_NAME]; /* ldom name */
225925351652SVuong Nguyen 	int			rc;		/* return code */
226025351652SVuong Nguyen 	uint64_t		did;		/* domain id */
226125351652SVuong Nguyen 
2262733a5356Srb144127 
2263e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
2264e2ff4ac6Srb144127 		etm_show_time(hdl, "ante conn handle");
2265e2ff4ac6Srb144127 	}
2266733a5356Srb144127 	fmd_hdl_debug(hdl, "info: handling new conn %p\n", conn);
2267733a5356Srb144127 
22682ca9f232Srb144127 	should_reset_xport = 0;
2269733a5356Srb144127 	ev_hdrp = NULL;
2270733a5356Srb144127 	ctl_hdrp = NULL;
2271733a5356Srb144127 	resp_hdrp = NULL;
22724b476ed5Sdarudy 	sa_hdrp = NULL;
2273733a5356Srb144127 	body_buf = NULL;
2274733a5356Srb144127 	class = NULL;
2275733a5356Srb144127 	evp = NULL;
2276e2ff4ac6Srb144127 	resp_code = 0;	/* default is success */
2277b8677b72Srb144127 	enq_rv = 0;	/* default is nop, ie, did not enqueue */
2278733a5356Srb144127 
2279733a5356Srb144127 	/* read a network decoded message header from the connection */
2280733a5356Srb144127 
2281733a5356Srb144127 	if ((ev_hdrp = etm_hdr_read(hdl, conn, &hdr_sz)) == NULL) {
2282733a5356Srb144127 		/* errno assumed set by above call */
22832ca9f232Srb144127 		should_reset_xport = (errno == ENOTACTIVE);
22842ae66659Sjrutt 		fmd_hdl_debug(hdl, "error: FMA event dropped: "
2285733a5356Srb144127 		    "bad hdr read errno %d\n", errno);
2286733a5356Srb144127 		etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
2287733a5356Srb144127 		goto func_ret;
2288733a5356Srb144127 	}
2289733a5356Srb144127 
2290733a5356Srb144127 	/*
2291733a5356Srb144127 	 * handle the message based on its preamble pp_msg_type
2292733a5356Srb144127 	 * which is known to be valid from etm_hdr_read() checks
2293733a5356Srb144127 	 */
2294733a5356Srb144127 
2295733a5356Srb144127 	if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
2296733a5356Srb144127 
2297733a5356Srb144127 		fmd_hdl_debug(hdl, "info: rcvd FMA_EVENT msg from xport\n");
2298733a5356Srb144127 
2299733a5356Srb144127 		/* allocate buf large enough for whole body / all FMA events */
2300733a5356Srb144127 
2301733a5356Srb144127 		body_sz = 0;
2302733a5356Srb144127 		for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) {
2303733a5356Srb144127 			body_sz += ev_hdrp->ev_lens[i];
2304733a5356Srb144127 		} /* for summing sizes of all FMA events */
2305b8677b72Srb144127 		if (i > etm_stats.etm_rd_max_ev_per_msg.fmds_value.ui64)
2306b8677b72Srb144127 			etm_stats.etm_rd_max_ev_per_msg.fmds_value.ui64 = i;
2307e2ff4ac6Srb144127 		ev_cnt = i;
2308733a5356Srb144127 
2309733a5356Srb144127 		if (etm_debug_lvl >= 1) {
2310e2ff4ac6Srb144127 			fmd_hdl_debug(hdl, "info: event lengths %u sum %u\n",
2311e2ff4ac6Srb144127 			    ev_cnt, body_sz);
2312733a5356Srb144127 		}
2313733a5356Srb144127 
2314733a5356Srb144127 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
2315733a5356Srb144127 
2316733a5356Srb144127 		/* read all the FMA events at once */
2317733a5356Srb144127 
2318733a5356Srb144127 		if ((n = etm_io_op(hdl, "FMA event dropped: "
2319b8677b72Srb144127 		    "bad io read on event bodies", conn, body_buf, body_sz,
2320733a5356Srb144127 		    ETM_IO_OP_RD)) < 0) {
23212ca9f232Srb144127 			should_reset_xport = (n == -ENOTACTIVE);
2322733a5356Srb144127 			etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
2323733a5356Srb144127 			goto func_ret;
2324733a5356Srb144127 		}
2325733a5356Srb144127 
2326733a5356Srb144127 		etm_stats.etm_rd_xport_bytes.fmds_value.ui64 += body_sz;
2327e2ff4ac6Srb144127 		etm_stats.etm_rd_body_fmaevent.fmds_value.ui64 += ev_cnt;
2328733a5356Srb144127 
2329b8677b72Srb144127 		/*
2330b8677b72Srb144127 		 * now that we've read the entire ETM msg from the conn,
2331b8677b72Srb144127 		 * which avoids later ETM protocol framing errors if we didn't,
2332b8677b72Srb144127 		 * check for dup msg/xid against last good FMD posting,
2333b8677b72Srb144127 		 * if a dup then resend response but skip repost to FMD
2334b8677b72Srb144127 		 */
2335b8677b72Srb144127 
233625351652SVuong Nguyen 		if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_logged_ev) {
2337b8677b72Srb144127 			enq_rv = etm_maybe_enq_response(hdl, conn,
2338b8677b72Srb144127 			    ev_hdrp, hdr_sz, 0);
2339b8677b72Srb144127 			fmd_hdl_debug(hdl, "info: skipping dup FMA event post "
234025351652SVuong Nguyen 			    "xid 0x%x\n", etm_xid_posted_logged_ev);
2341b8677b72Srb144127 			etm_stats.etm_rd_dup_fmaevent.fmds_value.ui64++;
2342b8677b72Srb144127 			goto func_ret;
2343b8677b72Srb144127 		}
2344b8677b72Srb144127 
2345733a5356Srb144127 		/* unpack each FMA event and post it to FMD */
2346733a5356Srb144127 
2347733a5356Srb144127 		bp = body_buf;
23482ae66659Sjrutt 		for (i = 0; i < ev_cnt; i++) {
2349733a5356Srb144127 			if ((n = nvlist_unpack((char *)bp,
2350733a5356Srb144127 			    ev_hdrp->ev_lens[i], &evp, 0)) != 0) {
2351e2ff4ac6Srb144127 				resp_code = (-n);
2352b8677b72Srb144127 				enq_rv = etm_maybe_enq_response(hdl, conn,
2353b8677b72Srb144127 				    ev_hdrp, hdr_sz, resp_code);
2354733a5356Srb144127 				fmd_hdl_error(hdl, "error: FMA event dropped: "
2355b8677b72Srb144127 				    "bad event body unpack errno %d\n", n);
2356733a5356Srb144127 				if (etm_debug_lvl >= 2) {
2357733a5356Srb144127 					fmd_hdl_debug(hdl, "info: FMA event "
2358733a5356Srb144127 					    "hexdump %d bytes:\n",
2359733a5356Srb144127 					    ev_hdrp->ev_lens[i]);
2360733a5356Srb144127 					etm_hexdump(hdl, bp,
2361733a5356Srb144127 					    ev_hdrp->ev_lens[i]);
2362733a5356Srb144127 				}
2363733a5356Srb144127 				etm_stats.etm_os_nvlist_unpack_fail.fmds_value.
2364733a5356Srb144127 				    ui64++;
2365733a5356Srb144127 				etm_stats.etm_rd_drop_fmaevent.fmds_value.
2366733a5356Srb144127 				    ui64++;
2367733a5356Srb144127 				bp += ev_hdrp->ev_lens[i];
2368733a5356Srb144127 				continue;
2369733a5356Srb144127 			}
237025351652SVuong Nguyen 
2371733a5356Srb144127 			if (etm_debug_lvl >= 1) {
2372733a5356Srb144127 				(void) nvlist_lookup_string(evp, FM_CLASS,
2373733a5356Srb144127 				    &class);
2374733a5356Srb144127 				if (class == NULL) {
2375733a5356Srb144127 					class = "NULL";
2376733a5356Srb144127 				}
2377733a5356Srb144127 				fmd_hdl_debug(hdl, "info: FMA event %p "
2378733a5356Srb144127 				    "class %s\n", evp, class);
2379733a5356Srb144127 			}
238025351652SVuong Nguyen 
238125351652SVuong Nguyen 			rc = nvlist_size(evp, &evsz, NV_ENCODE_XDR);
238225351652SVuong Nguyen 			fmd_hdl_debug(hdl,
238325351652SVuong Nguyen 			    "info: evp size before pack ds msg %d\n", evsz);
238425351652SVuong Nguyen 			ldom_name[0] = '\0';
238525351652SVuong Nguyen 			rc = etm_filter_find_ldom_id(hdl, evp, ldom_name,
238625351652SVuong Nguyen 			    MAX_LDOM_NAME, &did);
238725351652SVuong Nguyen 
238825351652SVuong Nguyen 			/*
238925351652SVuong Nguyen 			 * if rc is zero and the ldom_name is not "primary",
239025351652SVuong Nguyen 			 * the evp belongs to a root domain, put the evp in an
239125351652SVuong Nguyen 			 * outgoing etm queue,
239225351652SVuong Nguyen 			 * in all other cases, whether ldom_name is primary or
239325351652SVuong Nguyen 			 * can't find a ldom name, call etm_post_to_fmd
239425351652SVuong Nguyen 			 */
239525351652SVuong Nguyen 			if ((rc == 0) && strcmp(ldom_name, "primary") &&
239625351652SVuong Nguyen 			    strcmp(ldom_name, "")) {
239725351652SVuong Nguyen 				/*
239825351652SVuong Nguyen 				 * use the ldom_name, guaranteered at this point
239925351652SVuong Nguyen 				 * to be a valid ldom name/non-NULL, to find the
240025351652SVuong Nguyen 				 * iosvc data.
240125351652SVuong Nguyen 				 * add an iosvc struct if can not find one
240225351652SVuong Nguyen 				 */
240325351652SVuong Nguyen 				(void) pthread_mutex_unlock(&iosvc_list_lock);
240425351652SVuong Nguyen 				iosvc = etm_iosvc_lookup(hdl, ldom_name,
240525351652SVuong Nguyen 				    DS_INVALID_HDL, B_TRUE);
240625351652SVuong Nguyen 				(void) pthread_mutex_unlock(&iosvc_list_lock);
240725351652SVuong Nguyen 				if (iosvc == NULL) {
240825351652SVuong Nguyen 					fmd_hdl_debug(hdl,
240925351652SVuong Nguyen 					    "error: can't find iosvc for ldom "
241025351652SVuong Nguyen 					    "name %s\n", ldom_name);
241125351652SVuong Nguyen 				} else {
241225351652SVuong Nguyen 					resp_code = 0;
241325351652SVuong Nguyen 					(void) etm_pack_ds_msg(hdl, iosvc,
241425351652SVuong Nguyen 					    ev_hdrp, hdr_sz, evp,
241525351652SVuong Nguyen 					    SP_MSG, ETM_CKPT_SAVE);
241625351652SVuong Nguyen 					/*
241725351652SVuong Nguyen 					 * call the new fmd_xprt_log()
241825351652SVuong Nguyen 					 */
241925351652SVuong Nguyen 					fmd_xprt_log(hdl, etm_fmd_xprt, evp, 0);
242025351652SVuong Nguyen 					etm_xid_posted_logged_ev =
242125351652SVuong Nguyen 					    ev_hdrp->ev_pp.pp_xid;
2422b8677b72Srb144127 				}
242325351652SVuong Nguyen 			} else {
242425351652SVuong Nguyen 				/*
242525351652SVuong Nguyen 				 * post the fma event to the control fmd
242625351652SVuong Nguyen 				 */
242725351652SVuong Nguyen 				resp_code = etm_post_to_fmd(hdl, etm_fmd_xprt,
242825351652SVuong Nguyen 				    evp);
242925351652SVuong Nguyen 				if (resp_code >= 0) {
243025351652SVuong Nguyen 					etm_xid_posted_logged_ev =
243125351652SVuong Nguyen 					    ev_hdrp->ev_pp.pp_xid;
243225351652SVuong Nguyen 				}
243325351652SVuong Nguyen 			}
243425351652SVuong Nguyen 
243500ab1250Srb144127 			evp = NULL;
2436b8677b72Srb144127 			enq_rv = etm_maybe_enq_response(hdl, conn,
2437b8677b72Srb144127 			    ev_hdrp, hdr_sz, resp_code);
2438733a5356Srb144127 			bp += ev_hdrp->ev_lens[i];
2439733a5356Srb144127 		} /* foreach FMA event in the body buffer */
2440733a5356Srb144127 
2441733a5356Srb144127 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
2442733a5356Srb144127 
2443733a5356Srb144127 		ctl_hdrp = (void*)ev_hdrp;
2444733a5356Srb144127 
2445733a5356Srb144127 		fmd_hdl_debug(hdl, "info: rcvd CONTROL msg from xport\n");
2446733a5356Srb144127 		if (etm_debug_lvl >= 1) {
2447733a5356Srb144127 			fmd_hdl_debug(hdl, "info: ctl sel %d xid 0x%x\n",
2448733a5356Srb144127 			    (int)ctl_hdrp->ctl_pp.pp_sub_type,
2449733a5356Srb144127 			    ctl_hdrp->ctl_pp.pp_xid);
2450733a5356Srb144127 		}
2451733a5356Srb144127 
2452733a5356Srb144127 		/*
2453e2ff4ac6Srb144127 		 * if we have a VER_NEGOT_REQ read the body and validate
2454733a5356Srb144127 		 * the protocol version set contained therein,
2455733a5356Srb144127 		 * otherwise we have a PING_REQ (which has no body)
2456733a5356Srb144127 		 * and we [also] fall thru to the code which sends a
2457733a5356Srb144127 		 * response msg if the pp_timeout field requested one
2458733a5356Srb144127 		 */
2459733a5356Srb144127 
2460e2ff4ac6Srb144127 		if (ctl_hdrp->ctl_pp.pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ) {
2461733a5356Srb144127 
2462733a5356Srb144127 			body_sz = ctl_hdrp->ctl_len;
2463733a5356Srb144127 			body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
2464733a5356Srb144127 
2465733a5356Srb144127 			if ((n = etm_io_op(hdl, "bad io read on ctl body",
2466b8677b72Srb144127 			    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
24672ca9f232Srb144127 				should_reset_xport = (n == -ENOTACTIVE);
2468733a5356Srb144127 				goto func_ret;
2469733a5356Srb144127 			}
2470733a5356Srb144127 
2471e2ff4ac6Srb144127 			/* complain if version set completely incompatible */
2472733a5356Srb144127 
2473733a5356Srb144127 			for (i = 0; i < body_sz; i++) {
2474e2ff4ac6Srb144127 				if ((body_buf[i] == ETM_PROTO_V1) ||
24754b476ed5Sdarudy 				    (body_buf[i] == ETM_PROTO_V2) ||
24764b476ed5Sdarudy 				    (body_buf[i] == ETM_PROTO_V3)) {
2477733a5356Srb144127 					break;
2478733a5356Srb144127 				}
2479733a5356Srb144127 			}
2480e2ff4ac6Srb144127 			if (i >= body_sz) {
2481733a5356Srb144127 				etm_stats.etm_ver_bad.fmds_value.ui64++;
2482e2ff4ac6Srb144127 				resp_code = (-EPROTO);
2483733a5356Srb144127 			}
2484733a5356Srb144127 
2485733a5356Srb144127 		} /* if got version set request */
2486733a5356Srb144127 
2487733a5356Srb144127 		etm_stats.etm_rd_body_control.fmds_value.ui64++;
2488733a5356Srb144127 
2489b8677b72Srb144127 		enq_rv = etm_maybe_enq_response(hdl, conn,
2490b8677b72Srb144127 		    ctl_hdrp, hdr_sz, resp_code);
2491733a5356Srb144127 
2492733a5356Srb144127 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
2493733a5356Srb144127 
2494733a5356Srb144127 		resp_hdrp = (void*)ev_hdrp;
2495733a5356Srb144127 
2496733a5356Srb144127 		fmd_hdl_debug(hdl, "info: rcvd RESPONSE msg from xport\n");
2497733a5356Srb144127 		if (etm_debug_lvl >= 1) {
2498733a5356Srb144127 			fmd_hdl_debug(hdl, "info: resp xid 0x%x\n",
2499733a5356Srb144127 			    (int)resp_hdrp->resp_pp.pp_xid);
2500733a5356Srb144127 		}
2501733a5356Srb144127 
2502733a5356Srb144127 		body_sz = resp_hdrp->resp_len;
2503733a5356Srb144127 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
2504733a5356Srb144127 
2505733a5356Srb144127 		if ((n = etm_io_op(hdl, "bad io read on resp len",
2506733a5356Srb144127 		    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
25072ca9f232Srb144127 			should_reset_xport = (n == -ENOTACTIVE);
2508733a5356Srb144127 			goto func_ret;
2509733a5356Srb144127 		}
2510733a5356Srb144127 
2511733a5356Srb144127 		etm_stats.etm_rd_body_response.fmds_value.ui64++;
2512733a5356Srb144127 
2513733a5356Srb144127 		/*
2514e2ff4ac6Srb144127 		 * look up the xid to interpret the response body
2515733a5356Srb144127 		 *
2516e2ff4ac6Srb144127 		 * ping is a nop; for ver negot confirm that a supported
2517e2ff4ac6Srb144127 		 * protocol version was negotiated and remember which one
2518733a5356Srb144127 		 */
2519733a5356Srb144127 
2520733a5356Srb144127 		if ((resp_hdrp->resp_pp.pp_xid != etm_xid_ping) &&
2521e2ff4ac6Srb144127 		    (resp_hdrp->resp_pp.pp_xid != etm_xid_ver_negot)) {
2522733a5356Srb144127 			etm_stats.etm_xid_bad.fmds_value.ui64++;
2523733a5356Srb144127 			goto func_ret;
2524733a5356Srb144127 		}
2525733a5356Srb144127 
2526e2ff4ac6Srb144127 		if (resp_hdrp->resp_pp.pp_xid == etm_xid_ver_negot) {
2527e2ff4ac6Srb144127 			if ((body_buf[0] < ETM_PROTO_V1) ||
25284b476ed5Sdarudy 			    (body_buf[0] > ETM_PROTO_V3)) {
2529733a5356Srb144127 				etm_stats.etm_ver_bad.fmds_value.ui64++;
2530733a5356Srb144127 				goto func_ret;
2531733a5356Srb144127 			}
2532e2ff4ac6Srb144127 			etm_resp_ver = body_buf[0];
2533e2ff4ac6Srb144127 		} /* if have resp to last req to negotiate proto ver */
2534733a5356Srb144127 
25354b476ed5Sdarudy 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_ALERT) {
25364b476ed5Sdarudy 
25374b476ed5Sdarudy 		sa_hdrp = (void*)ev_hdrp;
25384b476ed5Sdarudy 
25394b476ed5Sdarudy 		fmd_hdl_debug(hdl, "info: rcvd ALERT msg from xport\n");
25404b476ed5Sdarudy 		if (etm_debug_lvl >= 1) {
25414b476ed5Sdarudy 			fmd_hdl_debug(hdl, "info: sa sel %d xid 0x%x\n",
25424b476ed5Sdarudy 			    (int)sa_hdrp->sa_pp.pp_sub_type,
25434b476ed5Sdarudy 			    sa_hdrp->sa_pp.pp_xid);
25444b476ed5Sdarudy 		}
25454b476ed5Sdarudy 
25464b476ed5Sdarudy 		body_sz = sa_hdrp->sa_len;
25474b476ed5Sdarudy 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
25484b476ed5Sdarudy 
25494b476ed5Sdarudy 		if ((n = etm_io_op(hdl, "bad io read on sa body",
2550b8677b72Srb144127 		    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
25512ca9f232Srb144127 			should_reset_xport = (n == -ENOTACTIVE);
25524b476ed5Sdarudy 			goto func_ret;
25534b476ed5Sdarudy 		}
25544b476ed5Sdarudy 
25554b476ed5Sdarudy 		etm_stats.etm_rd_body_alert.fmds_value.ui64++;
25564b476ed5Sdarudy 
2557b8677b72Srb144127 		/*
2558b8677b72Srb144127 		 * now that we've read the entire ETM msg from the conn,
2559b8677b72Srb144127 		 * which avoids later ETM protocol framing errors if we didn't,
2560b8677b72Srb144127 		 * check for dup msg/xid against last good syslog posting,
2561b8677b72Srb144127 		 * if a dup then resend response but skip repost to syslog
2562b8677b72Srb144127 		 */
2563b8677b72Srb144127 
2564b8677b72Srb144127 		if (sa_hdrp->sa_pp.pp_xid == etm_xid_posted_sa) {
2565b8677b72Srb144127 			enq_rv = etm_maybe_enq_response(hdl, conn,
2566b8677b72Srb144127 			    sa_hdrp, hdr_sz, 0);
2567b8677b72Srb144127 			fmd_hdl_debug(hdl, "info: skipping dup ALERT post "
2568b8677b72Srb144127 			    "xid 0x%x\n", etm_xid_posted_sa);
2569b8677b72Srb144127 			etm_stats.etm_rd_dup_alert.fmds_value.ui64++;
2570b8677b72Srb144127 			goto func_ret;
2571b8677b72Srb144127 		}
2572b8677b72Srb144127 
25734b476ed5Sdarudy 		resp_code = etm_post_to_syslog(hdl, sa_hdrp->sa_priority,
25744b476ed5Sdarudy 		    body_sz, body_buf);
2575b8677b72Srb144127 		if (resp_code >= 0) {
2576b8677b72Srb144127 			etm_xid_posted_sa = sa_hdrp->sa_pp.pp_xid;
2577b8677b72Srb144127 		}
2578b8677b72Srb144127 		enq_rv = etm_maybe_enq_response(hdl, conn,
2579b8677b72Srb144127 		    sa_hdrp, hdr_sz, resp_code);
25804b476ed5Sdarudy 	} /* whether we have a FMA_EVENT, CONTROL, RESPONSE or ALERT msg */
2581733a5356Srb144127 
2582733a5356Srb144127 func_ret:
2583733a5356Srb144127 
2584e2ff4ac6Srb144127 	if (etm_debug_lvl >= 2) {
2585e2ff4ac6Srb144127 		etm_show_time(hdl, "post conn handle");
2586733a5356Srb144127 	}
2587b8677b72Srb144127 
2588b8677b72Srb144127 	/*
2589b8677b72Srb144127 	 * if no responder ele was enqueued, close the conn now
2590b8677b72Srb144127 	 * and free the ETM msg hdr; the ETM msg body is not needed
2591b8677b72Srb144127 	 * by the responder thread and should always be freed here
2592b8677b72Srb144127 	 */
2593b8677b72Srb144127 
2594b8677b72Srb144127 	if (enq_rv <= 0) {
2595b8677b72Srb144127 		(void) etm_conn_close(hdl, "bad conn close after msg recv",
2596b8677b72Srb144127 		    conn);
2597733a5356Srb144127 		if (ev_hdrp != NULL) {
2598733a5356Srb144127 			fmd_hdl_free(hdl, ev_hdrp, hdr_sz);
2599733a5356Srb144127 		}
2600b8677b72Srb144127 	}
2601733a5356Srb144127 	if (body_buf != NULL) {
2602733a5356Srb144127 		fmd_hdl_free(hdl, body_buf, body_sz);
2603733a5356Srb144127 	}
26042ca9f232Srb144127 	if (should_reset_xport) {
26052ca9f232Srb144127 		etm_reset_xport(hdl);
26062ca9f232Srb144127 	}
2607733a5356Srb144127 } /* etm_handle_new_conn() */
2608733a5356Srb144127 
2609733a5356Srb144127 /*
26102ca9f232Srb144127  * etm_handle_bad_accept - recover from a failed connection acceptance
26112ca9f232Srb144127  */
26122ca9f232Srb144127 
26132ca9f232Srb144127 static void
26142ca9f232Srb144127 etm_handle_bad_accept(fmd_hdl_t *hdl, int nev)
26152ca9f232Srb144127 {
26162ca9f232Srb144127 	int	should_reset_xport; /* bool to reset xport */
26172ca9f232Srb144127 
26182ca9f232Srb144127 	should_reset_xport = (nev == -ENOTACTIVE);
26192ca9f232Srb144127 	fmd_hdl_debug(hdl, "error: bad conn accept errno %d\n", (-nev));
26202ca9f232Srb144127 	etm_stats.etm_xport_accept_fail.fmds_value.ui64++;
26212ca9f232Srb144127 	(void) etm_sleep(etm_bad_acc_to_sec); /* avoid spinning CPU */
26222ca9f232Srb144127 	if (should_reset_xport) {
26232ca9f232Srb144127 		etm_reset_xport(hdl);
26242ca9f232Srb144127 	}
26252ca9f232Srb144127 } /* etm_handle_bad_accept() */
26262ca9f232Srb144127 
26272ca9f232Srb144127 /*
2628733a5356Srb144127  * etm_server - loop forever accepting new connections
2629733a5356Srb144127  *		using the given FMD handle,
2630733a5356Srb144127  *		handling any ETM msgs sent from the other side
2631733a5356Srb144127  *		via each such connection
2632733a5356Srb144127  */
2633733a5356Srb144127 
2634733a5356Srb144127 static void
2635733a5356Srb144127 etm_server(void *arg)
2636733a5356Srb144127 {
2637733a5356Srb144127 	etm_xport_conn_t	conn;		/* connection handle */
26382ca9f232Srb144127 	int			nev;		/* -errno val */
2639733a5356Srb144127 	fmd_hdl_t		*hdl;		/* FMD handle */
2640733a5356Srb144127 
2641733a5356Srb144127 	hdl = arg;
2642733a5356Srb144127 
2643733a5356Srb144127 	fmd_hdl_debug(hdl, "info: connection server starting\n");
2644733a5356Srb144127 
264525351652SVuong Nguyen 	/*
264625351652SVuong Nguyen 	 * Restore the checkpointed events and dispatch them before starting to
264725351652SVuong Nguyen 	 * receive more events from the sp.
264825351652SVuong Nguyen 	 */
264925351652SVuong Nguyen 	etm_ckpt_recover(hdl);
265025351652SVuong Nguyen 
2651733a5356Srb144127 	while (!etm_is_dying) {
265200ab1250Srb144127 
2653733a5356Srb144127 		if ((conn = etm_xport_accept(hdl, NULL)) == NULL) {
2654733a5356Srb144127 			/* errno assumed set by above call */
26552ca9f232Srb144127 			nev = (-errno);
2656733a5356Srb144127 			if (etm_is_dying) {
2657733a5356Srb144127 				break;
2658733a5356Srb144127 			}
26592ca9f232Srb144127 			etm_handle_bad_accept(hdl, nev);
2660733a5356Srb144127 			continue;
2661733a5356Srb144127 		}
2662733a5356Srb144127 
2663b8677b72Srb144127 		/* handle the new message/connection, closing it when done */
2664733a5356Srb144127 
2665733a5356Srb144127 		etm_handle_new_conn(hdl, conn);
2666733a5356Srb144127 
2667733a5356Srb144127 	} /* while accepting new connections until ETM dies */
2668733a5356Srb144127 
2669733a5356Srb144127 	/* ETM is dying (probably due to "fmadm unload etm") */
2670733a5356Srb144127 
2671733a5356Srb144127 	fmd_hdl_debug(hdl, "info: connection server is dying\n");
2672b8677b72Srb144127 
2673733a5356Srb144127 } /* etm_server() */
2674733a5356Srb144127 
2675b8677b72Srb144127 /*
2676b8677b72Srb144127  * etm_responder - loop forever waiting for new responder queue elements
2677b8677b72Srb144127  *		to be enqueued, for each one constructing and sending
2678b8677b72Srb144127  *		an ETM response msg to the other side, and closing its
2679b8677b72Srb144127  *		associated connection when appropriate
2680b8677b72Srb144127  *
2681b8677b72Srb144127  *	this thread exists to ensure that the etm_server() thread
2682b8677b72Srb144127  *	never pends indefinitely waiting on the xport write lock, and is
2683b8677b72Srb144127  *	hence always available to accept new connections and handle
2684b8677b72Srb144127  *	incoming messages
2685b8677b72Srb144127  *
2686b8677b72Srb144127  *	this design relies on the fact that each connection accepted and
2687b8677b72Srb144127  *	returned by the ETM xport layer is unique, and each can be closed
2688b8677b72Srb144127  *	independently of the others while multiple connections are
2689b8677b72Srb144127  *	outstanding
2690b8677b72Srb144127  */
2691b8677b72Srb144127 
2692b8677b72Srb144127 static void
2693b8677b72Srb144127 etm_responder(void *arg)
2694b8677b72Srb144127 {
2695b8677b72Srb144127 	ssize_t			n;		/* gen use */
2696b8677b72Srb144127 	fmd_hdl_t		*hdl;		/* FMD handle */
2697b8677b72Srb144127 	etm_resp_q_ele_t	rqe;		/* responder queue ele */
2698b8677b72Srb144127 
2699b8677b72Srb144127 	hdl = arg;
2700b8677b72Srb144127 
2701b8677b72Srb144127 	fmd_hdl_debug(hdl, "info: responder server starting\n");
2702b8677b72Srb144127 
2703b8677b72Srb144127 	while (!etm_is_dying) {
2704b8677b72Srb144127 
2705b8677b72Srb144127 		(void) pthread_mutex_lock(&etm_resp_q_lock);
2706b8677b72Srb144127 
2707b8677b72Srb144127 		while (etm_resp_q_cur_len == 0) {
2708b8677b72Srb144127 			(void) pthread_cond_wait(&etm_resp_q_cv,
2709b8677b72Srb144127 			    &etm_resp_q_lock);
2710b8677b72Srb144127 			if (etm_is_dying) {
2711b8677b72Srb144127 				(void) pthread_mutex_unlock(&etm_resp_q_lock);
2712b8677b72Srb144127 				goto func_ret;
2713b8677b72Srb144127 			}
2714b8677b72Srb144127 		} /* while the responder queue is empty, wait to be nudged */
2715b8677b72Srb144127 
2716b8677b72Srb144127 		/*
2717b8677b72Srb144127 		 * for every responder ele that has been enqueued,
2718b8677b72Srb144127 		 * dequeue and send it as an ETM response msg,
2719b8677b72Srb144127 		 * closing its associated conn and freeing its hdr
2720b8677b72Srb144127 		 *
2721b8677b72Srb144127 		 * enter the queue draining loop holding the responder
2722b8677b72Srb144127 		 * queue lock, but do not hold the lock indefinitely
2723b8677b72Srb144127 		 * (the actual send may pend us indefinitely),
2724b8677b72Srb144127 		 * so that other threads will never pend for long
2725b8677b72Srb144127 		 * trying to enqueue a new element
2726b8677b72Srb144127 		 */
2727b8677b72Srb144127 
2728b8677b72Srb144127 		while (etm_resp_q_cur_len > 0) {
2729b8677b72Srb144127 
2730b8677b72Srb144127 			(void) etm_resp_q_deq(hdl, &rqe);
2731*c5fb5d32SKarl Davis 
2732*c5fb5d32SKarl Davis 			if ((etm_resp_q_cur_len + 1) == etm_resp_q_max_len)
2733*c5fb5d32SKarl Davis 				(void) pthread_cond_signal(&etm_resp_q_cv);
2734*c5fb5d32SKarl Davis 
2735b8677b72Srb144127 			(void) pthread_mutex_unlock(&etm_resp_q_lock);
2736b8677b72Srb144127 
2737b8677b72Srb144127 			if ((n = etm_send_response(hdl, rqe.rqe_conn,
2738b8677b72Srb144127 			    rqe.rqe_hdrp, rqe.rqe_resp_code)) < 0) {
2739b8677b72Srb144127 				fmd_hdl_error(hdl, "error: bad resp send "
2740b8677b72Srb144127 				    "errno %d\n", (-n));
2741b8677b72Srb144127 			}
2742b8677b72Srb144127 
2743b8677b72Srb144127 			(void) etm_conn_close(hdl, "bad conn close after resp",
2744b8677b72Srb144127 			    rqe.rqe_conn);
2745b8677b72Srb144127 			fmd_hdl_free(hdl, rqe.rqe_hdrp, rqe.rqe_hdr_sz);
2746b8677b72Srb144127 
2747b8677b72Srb144127 			if (etm_is_dying) {
2748b8677b72Srb144127 				goto func_ret;
2749b8677b72Srb144127 			}
2750b8677b72Srb144127 			(void) pthread_mutex_lock(&etm_resp_q_lock);
2751b8677b72Srb144127 
2752b8677b72Srb144127 		} /* while draining the responder queue */
2753b8677b72Srb144127 
2754b8677b72Srb144127 		(void) pthread_mutex_unlock(&etm_resp_q_lock);
2755b8677b72Srb144127 
2756b8677b72Srb144127 	} /* while awaiting and sending resp msgs until ETM dies */
2757b8677b72Srb144127 
2758b8677b72Srb144127 func_ret:
2759b8677b72Srb144127 
2760b8677b72Srb144127 	/* ETM is dying (probably due to "fmadm unload etm") */
2761b8677b72Srb144127 
2762b8677b72Srb144127 	fmd_hdl_debug(hdl, "info: responder server is dying\n");
2763b8677b72Srb144127 
2764b8677b72Srb144127 	(void) pthread_mutex_lock(&etm_resp_q_lock);
2765b8677b72Srb144127 	if (etm_resp_q_cur_len > 0) {
2766b8677b72Srb144127 		fmd_hdl_error(hdl, "warning: %d response msgs dropped\n",
2767b8677b72Srb144127 		    (int)etm_resp_q_cur_len);
2768b8677b72Srb144127 		while (etm_resp_q_cur_len > 0) {
2769b8677b72Srb144127 			(void) etm_resp_q_deq(hdl, &rqe);
2770b8677b72Srb144127 			(void) etm_conn_close(hdl, "bad conn close after deq",
2771b8677b72Srb144127 			    rqe.rqe_conn);
2772b8677b72Srb144127 			fmd_hdl_free(hdl, rqe.rqe_hdrp, rqe.rqe_hdr_sz);
2773b8677b72Srb144127 		}
2774b8677b72Srb144127 	}
2775b8677b72Srb144127 	(void) pthread_mutex_unlock(&etm_resp_q_lock);
2776b8677b72Srb144127 
2777b8677b72Srb144127 } /* etm_responder() */
2778b8677b72Srb144127 
277931e37bb4Svn83148 static void *
278031e37bb4Svn83148 etm_init_alloc(size_t size)
278131e37bb4Svn83148 {
278231e37bb4Svn83148 	return (fmd_hdl_alloc(init_hdl, size, FMD_SLEEP));
278331e37bb4Svn83148 }
278431e37bb4Svn83148 
278531e37bb4Svn83148 static void
278631e37bb4Svn83148 etm_init_free(void *addr, size_t size)
278731e37bb4Svn83148 {
278831e37bb4Svn83148 	fmd_hdl_free(init_hdl, addr, size);
278931e37bb4Svn83148 }
279031e37bb4Svn83148 
2791733a5356Srb144127 /*
279225351652SVuong Nguyen  * ---------------------root ldom support functions -----------------------
279325351652SVuong Nguyen  */
279425351652SVuong Nguyen 
279525351652SVuong Nguyen /*
279625351652SVuong Nguyen  * use a static array async_event_q instead of dynamicaly allocated mem  queue
279725351652SVuong Nguyen  * for etm_async_q_enq and etm_async_q_deq.
279825351652SVuong Nguyen  * This is not running in an fmd aux thread, can't use the fmd_hdl_* funcs.
279925351652SVuong Nguyen  * caller needs to grab the mutex lock before calling this func.
280025351652SVuong Nguyen  * return >0 for success, or -errno value
280125351652SVuong Nguyen  */
280225351652SVuong Nguyen static int
280325351652SVuong Nguyen etm_async_q_enq(etm_async_event_ele_t *async_e)
280425351652SVuong Nguyen {
280525351652SVuong Nguyen 
280625351652SVuong Nguyen 	if (etm_async_q_cur_len >= etm_async_q_max_len) {
280725351652SVuong Nguyen 		/* etm_stats.etm_enq_drop_async_q.fmds_value.ui64++; */
280825351652SVuong Nguyen 		return (-E2BIG);
280925351652SVuong Nguyen 	}
281025351652SVuong Nguyen 
281125351652SVuong Nguyen 	(void) memcpy(&async_event_q[etm_async_q_tail], async_e,
281225351652SVuong Nguyen 	    sizeof (*async_e));
281325351652SVuong Nguyen 
281425351652SVuong Nguyen 	etm_async_q_tail++;
281525351652SVuong Nguyen 	if (etm_async_q_tail == etm_async_q_max_len) {
281625351652SVuong Nguyen 		etm_async_q_tail = 0;
281725351652SVuong Nguyen 	}
281825351652SVuong Nguyen 	etm_async_q_cur_len++;
281925351652SVuong Nguyen 
282025351652SVuong Nguyen /* etm_stats.etm_async_q_cur_len.fmds_value.ui64 = etm_async_q_cur_len; */
282125351652SVuong Nguyen 
282225351652SVuong Nguyen 	return (1);
282325351652SVuong Nguyen 
282425351652SVuong Nguyen } /* etm_async_q_enq() */
282525351652SVuong Nguyen 
282625351652SVuong Nguyen 
282725351652SVuong Nguyen static int
282825351652SVuong Nguyen etm_async_q_deq(etm_async_event_ele_t *async_e)
282925351652SVuong Nguyen {
283025351652SVuong Nguyen 
283125351652SVuong Nguyen 	if (etm_async_q_cur_len == 0) {
283225351652SVuong Nguyen 		/* etm_stats.etm_deq_drop_async_q.fmds_value.ui64++; */
283325351652SVuong Nguyen 		return (-ENOENT);
283425351652SVuong Nguyen 	}
283525351652SVuong Nguyen 
283625351652SVuong Nguyen 	(void) memcpy(async_e, &async_event_q[etm_async_q_head],
283725351652SVuong Nguyen 	    sizeof (*async_e));
283825351652SVuong Nguyen 
283925351652SVuong Nguyen 	etm_async_q_head++;
284025351652SVuong Nguyen 	if (etm_async_q_head == etm_async_q_max_len) {
284125351652SVuong Nguyen 		etm_async_q_head = 0;
284225351652SVuong Nguyen 	}
284325351652SVuong Nguyen 	etm_async_q_cur_len--;
284425351652SVuong Nguyen 
284525351652SVuong Nguyen 	return (1);
284625351652SVuong Nguyen } /* etm_async_q_deq */
284725351652SVuong Nguyen 
284825351652SVuong Nguyen 
284925351652SVuong Nguyen /*
28502c07a099SYanmin Sun  * setting up the fields in iosvc at DS_REG_CB time
28512c07a099SYanmin Sun  */
28522c07a099SYanmin Sun void
28532c07a099SYanmin Sun etm_iosvc_setup(fmd_hdl_t *fmd_hdl, etm_iosvc_t *iosvc,
28542c07a099SYanmin Sun 	etm_async_event_ele_t *async_e)
28552c07a099SYanmin Sun {
28562c07a099SYanmin Sun 	iosvc->ds_hdl = async_e->ds_hdl;
28572c07a099SYanmin Sun 	iosvc->cur_send_xid = 0;
28582c07a099SYanmin Sun 	iosvc->xid_posted_ev = 0;
28592c07a099SYanmin Sun 	iosvc->start_sending_Q = 0;
28602c07a099SYanmin Sun 
28612c07a099SYanmin Sun 	/*
28622c07a099SYanmin Sun 	 * open the fmd xprt if it
28632c07a099SYanmin Sun 	 * hasn't been previously opened
28642c07a099SYanmin Sun 	 */
28652c07a099SYanmin Sun 	fmd_hdl_debug(fmd_hdl,  "info: before fmd_xprt_open ldom_name is %s\n",
28662c07a099SYanmin Sun 	    async_e->ldom_name);
28672c07a099SYanmin Sun 
28682c07a099SYanmin Sun 	if (iosvc->fmd_xprt == NULL) {
28692c07a099SYanmin Sun 		iosvc->fmd_xprt = fmd_xprt_open(fmd_hdl, flags, NULL, iosvc);
28702c07a099SYanmin Sun 	}
28712c07a099SYanmin Sun 
28722c07a099SYanmin Sun 	iosvc->thr_is_dying = 0;
28732c07a099SYanmin Sun 	if (iosvc->recv_tid == NULL) {
28742c07a099SYanmin Sun 		iosvc->recv_tid = fmd_thr_create(fmd_hdl,
28752c07a099SYanmin Sun 		    etm_recv_from_remote_root, iosvc);
28762c07a099SYanmin Sun 	}
28772c07a099SYanmin Sun 	if (iosvc->send_tid == NULL) {
28782c07a099SYanmin Sun 		iosvc->send_tid = fmd_thr_create(fmd_hdl,
28792c07a099SYanmin Sun 		    etm_send_to_remote_root, iosvc);
28802c07a099SYanmin Sun 	}
28812c07a099SYanmin Sun } /* etm_iosvc_setup() */
28822c07a099SYanmin Sun 
28832c07a099SYanmin Sun 
28842c07a099SYanmin Sun /*
288525351652SVuong Nguyen  * ds userland interface ds_reg_cb  callback func
288625351652SVuong Nguyen  */
288725351652SVuong Nguyen 
288825351652SVuong Nguyen /* ARGSUSED */
288925351652SVuong Nguyen static void
289025351652SVuong Nguyen etm_iosvc_reg_handler(ds_hdl_t ds_hdl, ds_cb_arg_t arg, ds_ver_t *ver,
289125351652SVuong Nguyen 	ds_domain_hdl_t dhdl)
289225351652SVuong Nguyen {
289325351652SVuong Nguyen 	etm_async_event_ele_t	async_ele;
289425351652SVuong Nguyen 
289525351652SVuong Nguyen 
289625351652SVuong Nguyen 	/*
289725351652SVuong Nguyen 	 * do version check here.
289825351652SVuong Nguyen 	 * checked the ver received here against etm_iosvc_vers here
289925351652SVuong Nguyen 	 */
290025351652SVuong Nguyen 	if (etm_iosvc_vers[0].major != ver->major ||
290125351652SVuong Nguyen 	    etm_iosvc_vers[0].minor != ver->minor) {
290225351652SVuong Nguyen 		/*
290325351652SVuong Nguyen 		 * can't log an fmd debug msg,
290425351652SVuong Nguyen 		 * not running in an fmd aux thread
290525351652SVuong Nguyen 		 */
290625351652SVuong Nguyen 		return;
290725351652SVuong Nguyen 	}
290825351652SVuong Nguyen 
290925351652SVuong Nguyen 	/*
291025351652SVuong Nguyen 	 * the callback should have a valid ldom_name
291125351652SVuong Nguyen 	 * can't log fmd debugging msg here since this is not in an fmd aux
291225351652SVuong Nguyen 	 * thread. log fmd debug msg in etm_async_event_handle()
291325351652SVuong Nguyen 	 */
291425351652SVuong Nguyen 	async_ele.ds_hdl = ds_hdl;
291525351652SVuong Nguyen 	async_ele.dhdl = dhdl;
291625351652SVuong Nguyen 	async_ele.ldom_name[0] = '\0';
291725351652SVuong Nguyen 	async_ele.event_type = ETM_ASYNC_EVENT_DS_REG_CB;
291825351652SVuong Nguyen 	(void) pthread_mutex_lock(&etm_async_event_q_lock);
291925351652SVuong Nguyen 	(void) etm_async_q_enq(&async_ele);
292025351652SVuong Nguyen 	if (etm_async_q_cur_len == 1)
292125351652SVuong Nguyen 		(void) pthread_cond_signal(&etm_async_event_q_cv);
292225351652SVuong Nguyen 	(void) pthread_mutex_unlock(&etm_async_event_q_lock);
292325351652SVuong Nguyen 
292425351652SVuong Nguyen } /* etm_iosvc_reg_handler */
292525351652SVuong Nguyen 
292625351652SVuong Nguyen 
292725351652SVuong Nguyen /*
292825351652SVuong Nguyen  * ds userland interface ds_unreg_cb  callback func
292925351652SVuong Nguyen  */
293025351652SVuong Nguyen 
293125351652SVuong Nguyen /*ARGSUSED*/
293225351652SVuong Nguyen static void
293325351652SVuong Nguyen etm_iosvc_unreg_handler(ds_hdl_t hdl, ds_cb_arg_t arg)
293425351652SVuong Nguyen {
293525351652SVuong Nguyen 	etm_async_event_ele_t	async_ele;
293625351652SVuong Nguyen 
293725351652SVuong Nguyen 	/*
293825351652SVuong Nguyen 	 * fill in async_ele and enqueue async_ele
293925351652SVuong Nguyen 	 */
294025351652SVuong Nguyen 	async_ele.ldom_name[0] = '\0';
294125351652SVuong Nguyen 	async_ele.ds_hdl = hdl;
294225351652SVuong Nguyen 	async_ele.event_type = ETM_ASYNC_EVENT_DS_UNREG_CB;
294325351652SVuong Nguyen 	(void) pthread_mutex_lock(&etm_async_event_q_lock);
294425351652SVuong Nguyen 	(void) etm_async_q_enq(&async_ele);
294525351652SVuong Nguyen 	if (etm_async_q_cur_len == 1)
294625351652SVuong Nguyen 		(void) pthread_cond_signal(&etm_async_event_q_cv);
294725351652SVuong Nguyen 	(void) pthread_mutex_unlock(&etm_async_event_q_lock);
294825351652SVuong Nguyen } /* etm_iosvc_unreg_handler */
294925351652SVuong Nguyen 
295025351652SVuong Nguyen /*
295125351652SVuong Nguyen  * ldom event registration callback func
295225351652SVuong Nguyen  */
295325351652SVuong Nguyen 
295425351652SVuong Nguyen /* ARGSUSED */
295525351652SVuong Nguyen static void
295625351652SVuong Nguyen ldom_event_handler(char *ldom_name, ldom_event_t event, ldom_cb_arg_t data)
295725351652SVuong Nguyen {
295825351652SVuong Nguyen 	etm_async_event_ele_t	async_ele;
295925351652SVuong Nguyen 
296025351652SVuong Nguyen 	/*
296125351652SVuong Nguyen 	 * the callback will have a valid ldom_name
296225351652SVuong Nguyen 	 */
296325351652SVuong Nguyen 	async_ele.ldom_name[0] = '\0';
296425351652SVuong Nguyen 	if (ldom_name)
296525351652SVuong Nguyen 		(void) strcpy(async_ele.ldom_name, ldom_name);
296625351652SVuong Nguyen 	async_ele.ds_hdl = DS_INVALID_HDL;
296725351652SVuong Nguyen 
296825351652SVuong Nguyen 	/*
296925351652SVuong Nguyen 	 * fill in async_ele and enq async_ele
297025351652SVuong Nguyen 	 */
297125351652SVuong Nguyen 	switch (event) {
297225351652SVuong Nguyen 	case LDOM_EVENT_BIND:
297325351652SVuong Nguyen 		async_ele.event_type = ETM_ASYNC_EVENT_LDOM_BIND;
297425351652SVuong Nguyen 		break;
297525351652SVuong Nguyen 	case LDOM_EVENT_UNBIND:
297625351652SVuong Nguyen 		async_ele.event_type = ETM_ASYNC_EVENT_LDOM_UNBIND;
297725351652SVuong Nguyen 		break;
297825351652SVuong Nguyen 	case LDOM_EVENT_ADD:
297925351652SVuong Nguyen 		async_ele.event_type = ETM_ASYNC_EVENT_LDOM_ADD;
298025351652SVuong Nguyen 		break;
298125351652SVuong Nguyen 	case LDOM_EVENT_REMOVE:
298225351652SVuong Nguyen 		async_ele.event_type = ETM_ASYNC_EVENT_LDOM_REMOVE;
298325351652SVuong Nguyen 		break;
298425351652SVuong Nguyen 	default:
298525351652SVuong Nguyen 		/*
298625351652SVuong Nguyen 		 * for all other ldom events, do nothing
298725351652SVuong Nguyen 		 */
298825351652SVuong Nguyen 		return;
298925351652SVuong Nguyen 	} /* switch (event) */
299025351652SVuong Nguyen 
299125351652SVuong Nguyen 	(void) pthread_mutex_lock(&etm_async_event_q_lock);
299225351652SVuong Nguyen 	(void) etm_async_q_enq(&async_ele);
299325351652SVuong Nguyen 	if (etm_async_q_cur_len == 1)
299425351652SVuong Nguyen 		(void) pthread_cond_signal(&etm_async_event_q_cv);
299525351652SVuong Nguyen 	(void) pthread_mutex_unlock(&etm_async_event_q_lock);
299625351652SVuong Nguyen 
299725351652SVuong Nguyen } /* ldom_event_handler */
299825351652SVuong Nguyen 
299925351652SVuong Nguyen 
300025351652SVuong Nguyen /*
300125351652SVuong Nguyen  * This is running as an fmd aux thread.
300225351652SVuong Nguyen  * This is the func that actually handle the events, which include:
300325351652SVuong Nguyen  * 1. ldom events. ldom events are  on Control Domain only
300425351652SVuong Nguyen  * 2. any DS userland callback funcs
300525351652SVuong Nguyen  * these events are already Q-ed in the async_event_ele_q
300625351652SVuong Nguyen  * deQ and process the events accordingly
300725351652SVuong Nguyen  */
300825351652SVuong Nguyen static void
300925351652SVuong Nguyen etm_async_event_handler(void *arg)
301025351652SVuong Nguyen {
301125351652SVuong Nguyen 
301225351652SVuong Nguyen 	fmd_hdl_t		*fmd_hdl = (fmd_hdl_t *)arg;
301325351652SVuong Nguyen 	etm_iosvc_t		*iosvc;		/* ptr 2 iosvc struct */
301425351652SVuong Nguyen 	etm_async_event_ele_t	async_e;
301525351652SVuong Nguyen 
301625351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl, "info: etm_async_event_handler starting\n");
301725351652SVuong Nguyen 	/*
301825351652SVuong Nguyen 	 *  handle etm is not dying and Q len > 0
301925351652SVuong Nguyen 	 */
302025351652SVuong Nguyen 	while (!etm_is_dying) {
302125351652SVuong Nguyen 		/*
302225351652SVuong Nguyen 		 * grab the lock to check the Q len
302325351652SVuong Nguyen 		 */
302425351652SVuong Nguyen 		(void) pthread_mutex_lock(&etm_async_event_q_lock);
302525351652SVuong Nguyen 		fmd_hdl_debug(fmd_hdl, "info: etm_async_q_cur_len %d\n",
302625351652SVuong Nguyen 		    etm_async_q_cur_len);
302725351652SVuong Nguyen 
302825351652SVuong Nguyen 		while (etm_async_q_cur_len > 0) {
302925351652SVuong Nguyen 			(void) etm_async_q_deq(&async_e);
303025351652SVuong Nguyen 			(void) pthread_mutex_unlock(&etm_async_event_q_lock);
303125351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
303225351652SVuong Nguyen 			    "info: processing an async event type %d ds_hdl"
303325351652SVuong Nguyen 			    " %d\n", async_e.event_type, async_e.ds_hdl);
303425351652SVuong Nguyen 			if (async_e.ldom_name[0] != '\0') {
303525351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
303625351652SVuong Nguyen 				    "info: procssing async evt ldom_name %s\n",
303725351652SVuong Nguyen 				    async_e.ldom_name);
303825351652SVuong Nguyen 			}
303925351652SVuong Nguyen 
304025351652SVuong Nguyen 			/*
304125351652SVuong Nguyen 			 * at this point, if async_e.ldom_name is not NULL,
304225351652SVuong Nguyen 			 * we have a valid iosvc strcut ptr.
304325351652SVuong Nguyen 			 * the only time async_e.ldom_name is NULL is  at
304425351652SVuong Nguyen 			 * ds_unreg_cb()
304525351652SVuong Nguyen 			 */
304625351652SVuong Nguyen 			switch (async_e.event_type)  {
304725351652SVuong Nguyen 			case ETM_ASYNC_EVENT_LDOM_UNBIND:
304825351652SVuong Nguyen 			case ETM_ASYNC_EVENT_LDOM_REMOVE:
304925351652SVuong Nguyen 				/*
305025351652SVuong Nguyen 				 * we have a valid ldom_name,
305125351652SVuong Nguyen 				 * etm_lookup_struct(ldom_name)
305225351652SVuong Nguyen 				 * do nothing if can't find an iosvc
305325351652SVuong Nguyen 				 * no iosvc clean up to do
305425351652SVuong Nguyen 				 */
305525351652SVuong Nguyen 				(void) pthread_mutex_lock(
305625351652SVuong Nguyen 				    &iosvc_list_lock);
305725351652SVuong Nguyen 				iosvc = etm_iosvc_lookup(fmd_hdl,
305825351652SVuong Nguyen 				    async_e.ldom_name,
305925351652SVuong Nguyen 				    async_e.ds_hdl, B_FALSE);
306025351652SVuong Nguyen 				if (iosvc == NULL) {
306125351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
306225351652SVuong Nguyen 					    "error: can't find iosvc for ldom "
306325351652SVuong Nguyen 					    "name %s\n",
306425351652SVuong Nguyen 					    async_e.ldom_name);
306525351652SVuong Nguyen 					(void) pthread_mutex_unlock(
306625351652SVuong Nguyen 					    &iosvc_list_lock);
306725351652SVuong Nguyen 					break;
306825351652SVuong Nguyen 				}
3069d279c7bfSVuong Nguyen 				/*
3070d279c7bfSVuong Nguyen 				 * Clean up the queue, delete all messages and
3071d279c7bfSVuong Nguyen 				 * do not persist checkpointed fma events.
3072d279c7bfSVuong Nguyen 				 */
3073d279c7bfSVuong Nguyen 				etm_iosvc_cleanup(fmd_hdl, iosvc, B_TRUE,
3074d279c7bfSVuong Nguyen 				    B_TRUE);
307525351652SVuong Nguyen 				(void) pthread_mutex_unlock(
307625351652SVuong Nguyen 				    &iosvc_list_lock);
307725351652SVuong Nguyen 				break;
307825351652SVuong Nguyen 
307925351652SVuong Nguyen 			case ETM_ASYNC_EVENT_LDOM_BIND:
308025351652SVuong Nguyen 
308125351652SVuong Nguyen 				/*
308225351652SVuong Nguyen 				 * create iosvc if it has not been
308325351652SVuong Nguyen 				 * created
308425351652SVuong Nguyen 				 * async_e.ds_hdl is invalid
308525351652SVuong Nguyen 				 * async_e.ldom_name is valid ldom_name
308625351652SVuong Nguyen 				 */
308725351652SVuong Nguyen 				(void) pthread_mutex_lock(
308825351652SVuong Nguyen 				    &iosvc_list_lock);
308925351652SVuong Nguyen 				iosvc = etm_iosvc_lookup(fmd_hdl,
309025351652SVuong Nguyen 				    async_e.ldom_name,
309125351652SVuong Nguyen 				    async_e.ds_hdl, B_TRUE);
309225351652SVuong Nguyen 				if (iosvc == NULL) {
309325351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
309425351652SVuong Nguyen 					    "error: can't create iosvc for "
309525351652SVuong Nguyen 					    "async evnt %d\n",
309625351652SVuong Nguyen 					    async_e.event_type);
309725351652SVuong Nguyen 					(void) pthread_mutex_unlock(
309825351652SVuong Nguyen 					    &iosvc_list_lock);
309925351652SVuong Nguyen 					break;
310025351652SVuong Nguyen 				}
310125351652SVuong Nguyen 				(void) strcpy(iosvc->ldom_name,
310225351652SVuong Nguyen 				    async_e.ldom_name);
310325351652SVuong Nguyen 				iosvc->ds_hdl = async_e.ds_hdl;
310425351652SVuong Nguyen 				(void) pthread_mutex_unlock(
310525351652SVuong Nguyen 				    &iosvc_list_lock);
310625351652SVuong Nguyen 				break;
310725351652SVuong Nguyen 
310825351652SVuong Nguyen 			case ETM_ASYNC_EVENT_DS_REG_CB:
310925351652SVuong Nguyen 				if (etm_ldom_type == LDOM_TYPE_CONTROL) {
311025351652SVuong Nguyen 					/*
311125351652SVuong Nguyen 					 * find the root ldom name from
311225351652SVuong Nguyen 					 * ldom domain hdl/id
311325351652SVuong Nguyen 					 */
311425351652SVuong Nguyen 					if (etm_filter_find_ldom_name(
311525351652SVuong Nguyen 					    fmd_hdl, async_e.dhdl,
311625351652SVuong Nguyen 					    async_e.ldom_name,
311725351652SVuong Nguyen 					    MAX_LDOM_NAME) != 0) {
311825351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
311925351652SVuong Nguyen 						    "error: can't find root "
312025351652SVuong Nguyen 						    "domain name from did %d\n",
312125351652SVuong Nguyen 						    async_e.dhdl);
312225351652SVuong Nguyen 						break;
312325351652SVuong Nguyen 					} else {
312425351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
312525351652SVuong Nguyen 						    "info: etm_filter_find_"
312625351652SVuong Nguyen 						    "ldom_name returned %s\n",
312725351652SVuong Nguyen 						    async_e.ldom_name);
312825351652SVuong Nguyen 					}
312925351652SVuong Nguyen 					/*
313025351652SVuong Nguyen 					 * now we should have a valid
313125351652SVuong Nguyen 					 * root domain name.
313225351652SVuong Nguyen 					 * lookup the iosvc struct
313325351652SVuong Nguyen 					 * associated with the ldom_name
313425351652SVuong Nguyen 					 * and init the iosvc struct
313525351652SVuong Nguyen 					 */
313625351652SVuong Nguyen 					(void) pthread_mutex_lock(
313725351652SVuong Nguyen 					    &iosvc_list_lock);
313825351652SVuong Nguyen 					iosvc = etm_iosvc_lookup(
313925351652SVuong Nguyen 					    fmd_hdl, async_e.ldom_name,
314025351652SVuong Nguyen 					    async_e.ds_hdl, B_TRUE);
314125351652SVuong Nguyen 					if (iosvc == NULL) {
314225351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
314325351652SVuong Nguyen 						    "error: can't create iosvc "
314425351652SVuong Nguyen 						    "for async evnt %d\n",
314525351652SVuong Nguyen 						    async_e.event_type);
314625351652SVuong Nguyen 						(void) pthread_mutex_unlock(
314725351652SVuong Nguyen 						    &iosvc_list_lock);
314825351652SVuong Nguyen 						break;
314925351652SVuong Nguyen 					}
315025351652SVuong Nguyen 
31512c07a099SYanmin Sun 					etm_iosvc_setup(fmd_hdl, iosvc,
31522c07a099SYanmin Sun 					    &async_e);
315325351652SVuong Nguyen 					(void) pthread_mutex_unlock(
315425351652SVuong Nguyen 					    &iosvc_list_lock);
315525351652SVuong Nguyen 				} else {
315625351652SVuong Nguyen 					iosvc = &io_svc;
315725351652SVuong Nguyen 					(void) strcpy(iosvc->ldom_name,
315825351652SVuong Nguyen 					    async_e.ldom_name);
315925351652SVuong Nguyen 
31602c07a099SYanmin Sun 					etm_iosvc_setup(fmd_hdl, iosvc,
31612c07a099SYanmin Sun 					    &async_e);
316225351652SVuong Nguyen 				}
316325351652SVuong Nguyen 				break;
316425351652SVuong Nguyen 
316525351652SVuong Nguyen 			case ETM_ASYNC_EVENT_DS_UNREG_CB:
316625351652SVuong Nguyen 				/*
316725351652SVuong Nguyen 				 * decide which iosvc struct to perform
316825351652SVuong Nguyen 				 * this UNREG callback on.
316925351652SVuong Nguyen 				 */
317025351652SVuong Nguyen 				if (etm_ldom_type == LDOM_TYPE_CONTROL) {
317125351652SVuong Nguyen 					(void) pthread_mutex_lock(
317225351652SVuong Nguyen 					    &iosvc_list_lock);
317325351652SVuong Nguyen 					/*
317425351652SVuong Nguyen 					 * lookup the iosvc struct w/
317525351652SVuong Nguyen 					 * ds_hdl
317625351652SVuong Nguyen 					 */
317725351652SVuong Nguyen 					iosvc = etm_iosvc_lookup(
317825351652SVuong Nguyen 					    fmd_hdl, async_e.ldom_name,
317925351652SVuong Nguyen 					    async_e.ds_hdl, B_FALSE);
318025351652SVuong Nguyen 					if (iosvc == NULL) {
318125351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
318225351652SVuong Nguyen 						    "error: can't find iosvc "
318325351652SVuong Nguyen 						    "for async evnt %d\n",
318425351652SVuong Nguyen 						    async_e.event_type);
318525351652SVuong Nguyen 					(void) pthread_mutex_unlock(
318625351652SVuong Nguyen 					    &iosvc_list_lock);
318725351652SVuong Nguyen 						break;
318825351652SVuong Nguyen 					}
318925351652SVuong Nguyen 
319025351652SVuong Nguyen 					/*
319125351652SVuong Nguyen 					 * ds_hdl and fmd_xprt_open
319225351652SVuong Nguyen 					 * go hand to hand together
319325351652SVuong Nguyen 					 * after unreg_cb,
319425351652SVuong Nguyen 					 * ds_hdl is INVALID and
319525351652SVuong Nguyen 					 * fmd_xprt is closed.
319625351652SVuong Nguyen 					 * the ldom name and the msg Q
319725351652SVuong Nguyen 					 * remains in iosvc_list
319825351652SVuong Nguyen 					 */
319925351652SVuong Nguyen 					if (iosvc->ldom_name != '\0')
320025351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
320125351652SVuong Nguyen 						    "info: iosvc  w/ ldom_name "
320225351652SVuong Nguyen 						    "%s \n", iosvc->ldom_name);
320325351652SVuong Nguyen 
320425351652SVuong Nguyen 					/*
32052c07a099SYanmin Sun 					 * destroy send/recv threads and
32062c07a099SYanmin Sun 					 * other clean up on Control side.
320725351652SVuong Nguyen 					 */
32082c07a099SYanmin Sun 					etm_iosvc_cleanup(fmd_hdl, iosvc,
3209d279c7bfSVuong Nguyen 					    B_FALSE, B_FALSE);
321025351652SVuong Nguyen 					(void) pthread_mutex_unlock(
321125351652SVuong Nguyen 					    &iosvc_list_lock);
321225351652SVuong Nguyen 				} else {
321325351652SVuong Nguyen 					iosvc = &io_svc;
321425351652SVuong Nguyen 					/*
32152c07a099SYanmin Sun 					 * destroy send/recv threads and
32162c07a099SYanmin Sun 					 * then clean up on Root side.
321725351652SVuong Nguyen 					 */
32182c07a099SYanmin Sun 					etm_iosvc_cleanup(fmd_hdl, iosvc,
3219d279c7bfSVuong Nguyen 					    B_FALSE, B_FALSE);
322025351652SVuong Nguyen 				}
322125351652SVuong Nguyen 				break;
322225351652SVuong Nguyen 
322325351652SVuong Nguyen 			default:
322425351652SVuong Nguyen 				/*
322525351652SVuong Nguyen 				 * for all other events, etm doesn't care.
322625351652SVuong Nguyen 				 * already logged an fmd info msg w/
322725351652SVuong Nguyen 				 * the event type. Do nothing here.
322825351652SVuong Nguyen 				 */
322925351652SVuong Nguyen 				break;
323025351652SVuong Nguyen 			} /* switch (async_e.event_type) */
323125351652SVuong Nguyen 
323225351652SVuong Nguyen 			if (etm_ldom_type == LDOM_TYPE_CONTROL) {
323325351652SVuong Nguyen 				etm_filter_handle_ldom_event(fmd_hdl,
323425351652SVuong Nguyen 				    async_e.event_type, async_e.ldom_name);
323525351652SVuong Nguyen 			}
323625351652SVuong Nguyen 
323725351652SVuong Nguyen 			/*
323825351652SVuong Nguyen 			 * grab the lock to check the q length again
323925351652SVuong Nguyen 			 */
324025351652SVuong Nguyen 			(void) pthread_mutex_lock(&etm_async_event_q_lock);
324125351652SVuong Nguyen 
324225351652SVuong Nguyen 			if (etm_is_dying) {
324325351652SVuong Nguyen 				break;
324425351652SVuong Nguyen 			}
324525351652SVuong Nguyen 		}	/* etm_async_q_cur_len */
324625351652SVuong Nguyen 
324725351652SVuong Nguyen 		/*
324825351652SVuong Nguyen 		 * we have the mutex lock at this point, whether
324925351652SVuong Nguyen 		 * . etm_is_dying  and/or
325025351652SVuong Nguyen 		 * . q_len == 0
325125351652SVuong Nguyen 		 */
325225351652SVuong Nguyen 		if (!etm_is_dying && etm_async_q_cur_len == 0) {
325325351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
325425351652SVuong Nguyen 			    "info: cond wait on async_event_q_cv\n");
325525351652SVuong Nguyen 			(void) pthread_cond_wait(&etm_async_event_q_cv,
325625351652SVuong Nguyen 			    &etm_async_event_q_lock);
325725351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
325825351652SVuong Nguyen 			    "info: cond wait on async_event_q_cv rtns\n");
325925351652SVuong Nguyen 		}
326025351652SVuong Nguyen 		(void) pthread_mutex_unlock(&etm_async_event_q_lock);
326125351652SVuong Nguyen 	} /* etm_is_dying */
326225351652SVuong Nguyen 
326325351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl,
326425351652SVuong Nguyen 	    "info: etm async event handler thread exiting\n");
326525351652SVuong Nguyen 
326625351652SVuong Nguyen } /* etm_async_event_handler */
326725351652SVuong Nguyen 
326825351652SVuong Nguyen /*
326925351652SVuong Nguyen  * deQ what's in iosvc msg Q
327025351652SVuong Nguyen  * send iosvc_msgp to the remote io svc ldom by calling ds_send_msg()
327125351652SVuong Nguyen  * the iosvc_msgp already has the packed msg, which is hdr + 1 fma event
327225351652SVuong Nguyen  */
327325351652SVuong Nguyen static void
327425351652SVuong Nguyen etm_send_to_remote_root(void *arg)
327525351652SVuong Nguyen {
327625351652SVuong Nguyen 
327725351652SVuong Nguyen 	etm_iosvc_t		*iosvc = (etm_iosvc_t *)arg;	/* iosvc ptr */
327825351652SVuong Nguyen 	etm_iosvc_q_ele_t	msg_ele;	/* iosvc msg ele */
327925351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* hdr for FMA_EVENT */
328025351652SVuong Nguyen 	fmd_hdl_t		*fmd_hdl = init_hdl;	/* fmd handle */
328125351652SVuong Nguyen 
328225351652SVuong Nguyen 
328325351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl,
328425351652SVuong Nguyen 	    "info: send to remote iosvc starting w/ ldom_name %s\n",
328525351652SVuong Nguyen 	    iosvc->ldom_name);
328625351652SVuong Nguyen 
328725351652SVuong Nguyen 	/*
328825351652SVuong Nguyen 	 *  loop forever until etm_is_dying or thr_is_dying
328925351652SVuong Nguyen 	 */
329025351652SVuong Nguyen 	while (!etm_is_dying && !iosvc->thr_is_dying) {
329125351652SVuong Nguyen 		if (iosvc->ds_hdl != DS_INVALID_HDL &&
329225351652SVuong Nguyen 		    iosvc->start_sending_Q > 0) {
329325351652SVuong Nguyen 			(void) pthread_mutex_lock(&iosvc->msg_q_lock);
329425351652SVuong Nguyen 			while (iosvc->msg_q_cur_len > 0 &&
329525351652SVuong Nguyen 			    iosvc->ds_hdl != DS_INVALID_HDL)  {
329625351652SVuong Nguyen 				(void) etm_iosvc_msg_deq(fmd_hdl, iosvc,
329725351652SVuong Nguyen 				    &msg_ele);
329825351652SVuong Nguyen 				if (etm_debug_lvl >= 3) {
329925351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl, "info: valid "
330025351652SVuong Nguyen 					    "ds_hdl before ds_send_msg \n");
330125351652SVuong Nguyen 				}
330225351652SVuong Nguyen 				(void) pthread_mutex_unlock(&iosvc->msg_q_lock);
330325351652SVuong Nguyen 
330425351652SVuong Nguyen 				iosvc->ack_ok = 0;
330525351652SVuong Nguyen 				ev_hdrp = (etm_proto_v1_ev_hdr_t *)
330625351652SVuong Nguyen 				    ((ptrdiff_t)msg_ele.msg);
330725351652SVuong Nguyen 				ev_hdrp->ev_pp.pp_xid = iosvc->cur_send_xid + 1;
330825351652SVuong Nguyen 				while (!iosvc->ack_ok &&
330925351652SVuong Nguyen 				    iosvc->ds_hdl != DS_INVALID_HDL &&
331025351652SVuong Nguyen 				    !etm_is_dying) {
331125351652SVuong Nguyen 					/*
331225351652SVuong Nguyen 					 * call ds_send_msg() to send the msg,
331325351652SVuong Nguyen 					 * wait for the recv end to send the
331425351652SVuong Nguyen 					 * resp msg back.
331525351652SVuong Nguyen 					 * If resp msg is recv-ed, ack_ok
331625351652SVuong Nguyen 					 * will be set to 1.
331725351652SVuong Nguyen 					 * otherwise, retry.
331825351652SVuong Nguyen 					 */
331925351652SVuong Nguyen 					if (etm_send_ds_msg(fmd_hdl, B_TRUE,
332025351652SVuong Nguyen 					    iosvc, &msg_ele, ev_hdrp) < 0) {
332125351652SVuong Nguyen 						continue;
332225351652SVuong Nguyen 					}
332325351652SVuong Nguyen 
332425351652SVuong Nguyen 					if (etm_is_dying || iosvc->thr_is_dying)
332525351652SVuong Nguyen 						break;
332625351652SVuong Nguyen 				}
332725351652SVuong Nguyen 
332825351652SVuong Nguyen 				/*
332925351652SVuong Nguyen 				 * if out of the while loop but !ack_ok, ie,
333025351652SVuong Nguyen 				 * ds_hdl becomes invalid at some point
333125351652SVuong Nguyen 				 * while waiting the resp msg, we need to put
333225351652SVuong Nguyen 				 * the msg back to the head of the Q.
333325351652SVuong Nguyen 				 */
333425351652SVuong Nguyen 				if (!iosvc->ack_ok) {
333525351652SVuong Nguyen 					(void) pthread_mutex_lock(
333625351652SVuong Nguyen 					    &iosvc->msg_q_lock);
333725351652SVuong Nguyen 					/*
333825351652SVuong Nguyen 					 * put the msg back to the head of Q.
333925351652SVuong Nguyen 					 * If the Q is full at this point,
334025351652SVuong Nguyen 					 * drop the msg at the tail, enq this
334125351652SVuong Nguyen 					 * msg to the head.
334225351652SVuong Nguyen 					 */
334325351652SVuong Nguyen 					etm_msg_enq_head(fmd_hdl, iosvc,
334425351652SVuong Nguyen 					    &msg_ele);
334525351652SVuong Nguyen 					(void) pthread_mutex_unlock(
334625351652SVuong Nguyen 					    &iosvc->msg_q_lock);
334725351652SVuong Nguyen 				}
334825351652SVuong Nguyen 
334925351652SVuong Nguyen 				/*
335025351652SVuong Nguyen 				 *
335125351652SVuong Nguyen 				 * grab the lock to check the Q len again
335225351652SVuong Nguyen 				 */
335325351652SVuong Nguyen 				(void) pthread_mutex_lock(&iosvc->msg_q_lock);
335425351652SVuong Nguyen 				if (etm_is_dying || iosvc->thr_is_dying) {
335525351652SVuong Nguyen 					break;
335625351652SVuong Nguyen 				}
335725351652SVuong Nguyen 			} /* while dequeing iosvc msgs to send */
335825351652SVuong Nguyen 
335925351652SVuong Nguyen 			/*
336025351652SVuong Nguyen 			 * we have the mutex lock for msg_q_lock at this point
336125351652SVuong Nguyen 			 * we are here because
336225351652SVuong Nguyen 			 * 1) q_len == 0: then wait on the cv for Q to be filled
336325351652SVuong Nguyen 			 * 2) etm_is_dying
336425351652SVuong Nguyen 			 */
336525351652SVuong Nguyen 			if (!etm_is_dying && !iosvc->thr_is_dying &&
336625351652SVuong Nguyen 			    iosvc->msg_q_cur_len == 0) {
336725351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
336825351652SVuong Nguyen 				    "info: waiting on msg_q_cv\n");
336925351652SVuong Nguyen 				(void) pthread_cond_wait(&iosvc->msg_q_cv,
337025351652SVuong Nguyen 				    &iosvc->msg_q_lock);
337125351652SVuong Nguyen 			}
337225351652SVuong Nguyen 			(void) pthread_mutex_unlock(&iosvc->msg_q_lock);
337325351652SVuong Nguyen 			if (etm_is_dying || iosvc->thr_is_dying)  {
337425351652SVuong Nguyen 				break;
337525351652SVuong Nguyen 			}
337625351652SVuong Nguyen 		} else {
337725351652SVuong Nguyen 			(void) etm_sleep(1);
337825351652SVuong Nguyen 		} /* wait for the start_sendingQ > 0 */
337925351652SVuong Nguyen 	} /* etm_is_dying or thr_is_dying */
338025351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl, "info; etm send thread exiting \n");
338125351652SVuong Nguyen } /* etm_send_to_remote_root */
338225351652SVuong Nguyen 
338325351652SVuong Nguyen 
338425351652SVuong Nguyen /*
338525351652SVuong Nguyen  * receive etm msgs from the remote root ldom by calling ds_recv_msg()
338625351652SVuong Nguyen  * if FMA events/ereports, call fmd_xprt_post() to post to fmd
338725351652SVuong Nguyen  * send ACK back by calling ds_send_msg()
338825351652SVuong Nguyen  */
338925351652SVuong Nguyen static void
339025351652SVuong Nguyen etm_recv_from_remote_root(void *arg)
339125351652SVuong Nguyen {
339225351652SVuong Nguyen 	etm_iosvc_t		*iosvc = (etm_iosvc_t *)arg;	/* iosvc ptr */
339325351652SVuong Nguyen 	etm_proto_v1_pp_t	*pp;		/* protocol preamble */
339425351652SVuong Nguyen 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
339525351652SVuong Nguyen 	etm_proto_v1_resp_hdr_t	*resp_hdrp;	/* for RESPONSE msg */
339625351652SVuong Nguyen 	int32_t			resp_code = 0;	/* default is success */
339725351652SVuong Nguyen 	int32_t			rc;		/* return value */
339825351652SVuong Nguyen 	size_t			maxlen = MAXLEN;
339925351652SVuong Nguyen 						/* max msg len */
340025351652SVuong Nguyen 	char 			msgbuf[MAXLEN];	/* recv msg buf */
340125351652SVuong Nguyen 	size_t			msg_size;	/* recv msg size */
340225351652SVuong Nguyen 	size_t			hdr_sz;		/* sizeof *hdrp */
340325351652SVuong Nguyen 	size_t			evsz;		/* sizeof *evp */
340425351652SVuong Nguyen 	size_t			fma_event_size;	/* sizeof FMA event  */
340525351652SVuong Nguyen 	nvlist_t 		*evp;		/* ptr to the nvlist */
340625351652SVuong Nguyen 	char			*buf;		/* ptr to the nvlist */
340725351652SVuong Nguyen 	static uint32_t		mem_alloc = 0;	/* indicate if alloc mem */
340825351652SVuong Nguyen 	char 			*msg;		/* ptr to alloc mem */
340925351652SVuong Nguyen 	fmd_hdl_t		*fmd_hdl = init_hdl;
341025351652SVuong Nguyen 
341125351652SVuong Nguyen 
341225351652SVuong Nguyen 
341325351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl,
341425351652SVuong Nguyen 	    "info: recv from remote iosvc starting with ldom name %s \n",
341525351652SVuong Nguyen 	    iosvc->ldom_name);
341625351652SVuong Nguyen 
341725351652SVuong Nguyen 	/*
341825351652SVuong Nguyen 	 * loop forever until etm_is_dying or the thread is dying
341925351652SVuong Nguyen 	 */
342025351652SVuong Nguyen 
342125351652SVuong Nguyen 	msg = msgbuf;
342225351652SVuong Nguyen 	while (!etm_is_dying && !iosvc->thr_is_dying) {
342325351652SVuong Nguyen 		if (iosvc->ds_hdl == DS_INVALID_HDL) {
342425351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
342525351652SVuong Nguyen 			    "info: ds_hdl is invalid in recv thr\n");
342625351652SVuong Nguyen 			(void) etm_sleep(1);
342725351652SVuong Nguyen 			continue;
342825351652SVuong Nguyen 		}
342925351652SVuong Nguyen 
343025351652SVuong Nguyen 		/*
343125351652SVuong Nguyen 		 * for now, there are FMA_EVENT and ACK msg type.
343225351652SVuong Nguyen 		 * use FMA_EVENT buf as the maxlen, hdr+1 fma event.
343325351652SVuong Nguyen 		 * FMA_EVENT is big enough to hold an ACK msg.
343425351652SVuong Nguyen 		 * the actual msg size received is in msg_size.
343525351652SVuong Nguyen 		 */
343625351652SVuong Nguyen 		rc = (*etm_ds_recv_msg)(iosvc->ds_hdl, msg, maxlen, &msg_size);
343725351652SVuong Nguyen 		if (rc == EFBIG) {
343825351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
343925351652SVuong Nguyen 			    "info: ds_recv_msg needs mem the size of %d\n",
344025351652SVuong Nguyen 			    msg_size);
344125351652SVuong Nguyen 			msg = fmd_hdl_zalloc(fmd_hdl, msg_size, FMD_SLEEP);
344225351652SVuong Nguyen 			mem_alloc = 1;
344325351652SVuong Nguyen 		} else if (rc == 0) {
344425351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
344525351652SVuong Nguyen 			    "info: ds_recv_msg received a msg ok\n");
344625351652SVuong Nguyen 			/*
344725351652SVuong Nguyen 			 * check the magic # in  msg.hdr
344825351652SVuong Nguyen 			 */
344925351652SVuong Nguyen 			pp = (etm_proto_v1_pp_t *)((ptrdiff_t)msg);
345025351652SVuong Nguyen 			if (pp->pp_magic_num != ETM_PROTO_MAGIC_NUM) {
345125351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
345225351652SVuong Nguyen 				    "info: bad ds recv on magic\n");
345325351652SVuong Nguyen 				continue;
345425351652SVuong Nguyen 			}
345525351652SVuong Nguyen 
345625351652SVuong Nguyen 			/*
345725351652SVuong Nguyen 			 * check the msg type against msg_size to be sure
345825351652SVuong Nguyen 			 * that received msg is not a truncated msg
345925351652SVuong Nguyen 			 */
346025351652SVuong Nguyen 			if (pp->pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
346125351652SVuong Nguyen 
346225351652SVuong Nguyen 				ev_hdrp = (etm_proto_v1_ev_hdr_t *)
346325351652SVuong Nguyen 				    ((ptrdiff_t)msg);
346425351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl, "info: ds received "
346525351652SVuong Nguyen 				    "FMA EVENT xid=%d msg_size=%d\n",
346625351652SVuong Nguyen 				    ev_hdrp->ev_pp.pp_xid, msg_size);
346725351652SVuong Nguyen 				hdr_sz = sizeof (*ev_hdrp) +
346825351652SVuong Nguyen 				    1*(sizeof (ev_hdrp->ev_lens[0]));
346925351652SVuong Nguyen 				fma_event_size = hdr_sz + ev_hdrp->ev_lens[0];
347025351652SVuong Nguyen 				if (fma_event_size != msg_size) {
347125351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl, "info: wrong "
347225351652SVuong Nguyen 					    "ev msg size received\n");
347325351652SVuong Nguyen 					continue;
347425351652SVuong Nguyen 					/*
347525351652SVuong Nguyen 					 * Simply  do nothing. The send side
347625351652SVuong Nguyen 					 * will timedcond_wait waiting on the
347725351652SVuong Nguyen 					 * resp msg will timeout and
347825351652SVuong Nguyen 					 * re-send the same msg.
347925351652SVuong Nguyen 					 */
348025351652SVuong Nguyen 				}
348125351652SVuong Nguyen 				if (etm_debug_lvl >= 3) {
348225351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,  "info: recv msg"
348325351652SVuong Nguyen 					    " size %d hdrsz %d evp size %d\n",
348425351652SVuong Nguyen 					    msg_size, hdr_sz,
348525351652SVuong Nguyen 					    ev_hdrp->ev_lens[0]);
348625351652SVuong Nguyen 				}
348725351652SVuong Nguyen 
348825351652SVuong Nguyen 				if (ev_hdrp->ev_pp.pp_xid !=
348925351652SVuong Nguyen 				    iosvc->xid_posted_ev) {
349025351652SVuong Nguyen 					/*
349125351652SVuong Nguyen 					 * different from last xid posted to
349225351652SVuong Nguyen 					 * fmd, post to fmd now.
349325351652SVuong Nguyen 					 */
349425351652SVuong Nguyen 					buf = msg + hdr_sz;
349525351652SVuong Nguyen 					rc = nvlist_unpack(buf,
349625351652SVuong Nguyen 					    ev_hdrp->ev_lens[0], &evp, 0);
349725351652SVuong Nguyen 					rc = nvlist_size(evp, &evsz,
349825351652SVuong Nguyen 					    NV_ENCODE_XDR);
349925351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
350025351652SVuong Nguyen 					    "info: evp size %d before fmd"
350125351652SVuong Nguyen 					    "post\n", evsz);
350225351652SVuong Nguyen 
350325351652SVuong Nguyen 					if ((rc = etm_post_to_fmd(fmd_hdl,
350425351652SVuong Nguyen 					    iosvc->fmd_xprt, evp)) >= 0) {
350525351652SVuong Nguyen 						fmd_hdl_debug(fmd_hdl,
350625351652SVuong Nguyen 						    "info: xid posted to fmd %d"
350725351652SVuong Nguyen 						    "\n",
350825351652SVuong Nguyen 						    ev_hdrp->ev_pp.pp_xid);
350925351652SVuong Nguyen 						iosvc->xid_posted_ev =
351025351652SVuong Nguyen 						    ev_hdrp->ev_pp.pp_xid;
351125351652SVuong Nguyen 					}
351225351652SVuong Nguyen 				}
351325351652SVuong Nguyen 
351425351652SVuong Nguyen 				/*
351525351652SVuong Nguyen 				 * ready to  send the RESPONSE msg back
351625351652SVuong Nguyen 				 * reuse the msg buffer as the response buffer
351725351652SVuong Nguyen 				 */
351825351652SVuong Nguyen 				resp_hdrp = (etm_proto_v1_resp_hdr_t *)
351925351652SVuong Nguyen 				    ((ptrdiff_t)msg);
352025351652SVuong Nguyen 				resp_hdrp->resp_pp.pp_msg_type =
352125351652SVuong Nguyen 				    ETM_MSG_TYPE_RESPONSE;
352225351652SVuong Nguyen 
352325351652SVuong Nguyen 				resp_hdrp->resp_code = resp_code;
352425351652SVuong Nguyen 				resp_hdrp->resp_len = sizeof (*resp_hdrp);
352525351652SVuong Nguyen 
352625351652SVuong Nguyen 				/*
352725351652SVuong Nguyen 				 * send the whole response msg in one send
352825351652SVuong Nguyen 				 */
352925351652SVuong Nguyen 				if ((*etm_ds_send_msg)(iosvc->ds_hdl, msg,
353025351652SVuong Nguyen 				    sizeof (*resp_hdrp)) != 0) {
353125351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
353225351652SVuong Nguyen 					    "info: send response msg failed\n");
353325351652SVuong Nguyen 				} else {
353425351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
353525351652SVuong Nguyen 					    "info: ds send resp msg ok"
353625351652SVuong Nguyen 					    "size %d\n", sizeof (*resp_hdrp));
353725351652SVuong Nguyen 				}
353825351652SVuong Nguyen 			} else if (pp->pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
353925351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
354025351652SVuong Nguyen 				    "info: ds received respond msg xid=%d"
354125351652SVuong Nguyen 				    "msg_size=%d for ldom %s\n", pp->pp_xid,
354225351652SVuong Nguyen 				    msg_size, iosvc->ldom_name);
354325351652SVuong Nguyen 				if (sizeof (*resp_hdrp) != msg_size) {
354425351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
354525351652SVuong Nguyen 					    "info: wrong resp msg size"
354625351652SVuong Nguyen 					    "received\n");
354725351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
354825351652SVuong Nguyen 					    "info: resp msg size %d recv resp"
354925351652SVuong Nguyen 					    "msg size %d\n",
355025351652SVuong Nguyen 					    sizeof (*resp_hdrp), msg_size);
355125351652SVuong Nguyen 					continue;
355225351652SVuong Nguyen 				}
355325351652SVuong Nguyen 				/*
355425351652SVuong Nguyen 				 * is the pp.pp_xid == iosvc->cur_send_xid+1,
355525351652SVuong Nguyen 				 * if so, nudge the send routine to send next
355625351652SVuong Nguyen 				 */
355725351652SVuong Nguyen 				if (pp->pp_xid != iosvc->cur_send_xid+1) {
355825351652SVuong Nguyen 					fmd_hdl_debug(fmd_hdl,
355925351652SVuong Nguyen 					    "info: ds received resp msg xid=%d "
356025351652SVuong Nguyen 					    "doesn't match cur_send_id=%d\n",
356125351652SVuong Nguyen 					    pp->pp_xid, iosvc->cur_send_xid+1);
356225351652SVuong Nguyen 					continue;
356325351652SVuong Nguyen 				}
356425351652SVuong Nguyen 				(void) pthread_mutex_lock(&iosvc->msg_ack_lock);
356525351652SVuong Nguyen 				iosvc->ack_ok = 1;
356625351652SVuong Nguyen 				(void) pthread_cond_signal(&iosvc->msg_ack_cv);
356725351652SVuong Nguyen 				(void) pthread_mutex_unlock(
356825351652SVuong Nguyen 				    &iosvc->msg_ack_lock);
356925351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
357025351652SVuong Nguyen 				    "info: signaling msg_ack_cv\n");
357125351652SVuong Nguyen 			} else {
357225351652SVuong Nguyen 				/*
357325351652SVuong Nguyen 				 * place holder for future msg types
357425351652SVuong Nguyen 				 */
357525351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
357625351652SVuong Nguyen 				    "info: ds received unrecognized msg\n");
357725351652SVuong Nguyen 			}
357825351652SVuong Nguyen 			if (mem_alloc) {
357925351652SVuong Nguyen 				fmd_hdl_free(fmd_hdl, msg, msg_size);
358025351652SVuong Nguyen 				mem_alloc = 0;
358125351652SVuong Nguyen 				msg = msgbuf;
358225351652SVuong Nguyen 			}
358325351652SVuong Nguyen 		} else {
358425351652SVuong Nguyen 			if (etm_debug_lvl >= 3) {
358525351652SVuong Nguyen 				fmd_hdl_debug(fmd_hdl,
358625351652SVuong Nguyen 				    "info: ds_recv_msg() failed\n");
358725351652SVuong Nguyen 			}
358825351652SVuong Nguyen 		} /* ds_recv_msg() returns */
358925351652SVuong Nguyen 	} /* etm_is_dying */
359025351652SVuong Nguyen 
359125351652SVuong Nguyen 	/*
359225351652SVuong Nguyen 	 * need to free the mem allocated in msg upon exiting the thread
359325351652SVuong Nguyen 	 */
359425351652SVuong Nguyen 	if (mem_alloc) {
359525351652SVuong Nguyen 		fmd_hdl_free(fmd_hdl, msg, msg_size);
359625351652SVuong Nguyen 		mem_alloc = 0;
359725351652SVuong Nguyen 		msg = msgbuf;
359825351652SVuong Nguyen 	}
359925351652SVuong Nguyen 	fmd_hdl_debug(fmd_hdl, "info; etm recv thread exiting \n");
360025351652SVuong Nguyen } /* etm_recv_from_remote_root */
360125351652SVuong Nguyen 
360225351652SVuong Nguyen 
360325351652SVuong Nguyen 
360425351652SVuong Nguyen /*
360525351652SVuong Nguyen  * etm_ds_init
360625351652SVuong Nguyen  *		initialize DS services function pointers by calling
360725351652SVuong Nguyen  *		dlopen() followed by  dlsym() for each ds func.
360825351652SVuong Nguyen  *		if any dlopen() or dlsym() call fails, return -ENOENT
360925351652SVuong Nguyen  *		return >0 for successs, -ENOENT for failure
361025351652SVuong Nguyen  */
361125351652SVuong Nguyen static int
361225351652SVuong Nguyen etm_ds_init(fmd_hdl_t *hdl)
361325351652SVuong Nguyen {
361425351652SVuong Nguyen 	int rc = 0;
361525351652SVuong Nguyen 
361625351652SVuong Nguyen 	if ((etm_dl_hdl = dlopen(etm_dl_path, etm_dl_mode)) == NULL) {
361725351652SVuong Nguyen 		fmd_hdl_debug(hdl, "error: failed to dlopen %s\n", etm_dl_path);
361825351652SVuong Nguyen 		return (-ENOENT);
361925351652SVuong Nguyen 	}
362025351652SVuong Nguyen 
362125351652SVuong Nguyen 	etm_ds_svc_reg = (int (*)(ds_capability_t *cap, ds_ops_t *ops))
362225351652SVuong Nguyen 	    dlsym(etm_dl_hdl, "ds_svc_reg");
362325351652SVuong Nguyen 	if (etm_ds_svc_reg == NULL) {
362425351652SVuong Nguyen 		fmd_hdl_debug(hdl,
362525351652SVuong Nguyen 		    "error: failed to dlsym ds_svc_reg() w/ error %s\n",
362625351652SVuong Nguyen 		    dlerror());
362725351652SVuong Nguyen 		rc = -ENOENT;
362825351652SVuong Nguyen 	}
362925351652SVuong Nguyen 
363025351652SVuong Nguyen 
363125351652SVuong Nguyen 	etm_ds_clnt_reg = (int (*)(ds_capability_t *cap, ds_ops_t *ops))
363225351652SVuong Nguyen 	    dlsym(etm_dl_hdl, "ds_clnt_reg");
363325351652SVuong Nguyen 	if (etm_ds_clnt_reg == NULL) {
363425351652SVuong Nguyen 		fmd_hdl_debug(hdl,
363525351652SVuong Nguyen 		    "error: dlsym(ds_clnt_reg) failed w/ errno %d\n", errno);
363625351652SVuong Nguyen 		rc = -ENOENT;
363725351652SVuong Nguyen 	}
363825351652SVuong Nguyen 
363925351652SVuong Nguyen 	etm_ds_send_msg = (int (*)(ds_hdl_t hdl, void *buf, size_t buflen))
364025351652SVuong Nguyen 	    dlsym(etm_dl_hdl, "ds_send_msg");
364125351652SVuong Nguyen 	if (etm_ds_send_msg == NULL) {
364225351652SVuong Nguyen 		fmd_hdl_debug(hdl, "error: dlsym(ds_send_msg) failed\n");
364325351652SVuong Nguyen 		rc = -ENOENT;
364425351652SVuong Nguyen 	}
364525351652SVuong Nguyen 
364625351652SVuong Nguyen 	etm_ds_recv_msg = (int (*)(ds_hdl_t hdl, void *buf, size_t buflen,
364725351652SVuong Nguyen 	    size_t *msglen))dlsym(etm_dl_hdl, "ds_recv_msg");
364825351652SVuong Nguyen 	if (etm_ds_recv_msg == NULL) {
364925351652SVuong Nguyen 		fmd_hdl_debug(hdl, "error: dlsym(ds_recv_msg) failed\n");
365025351652SVuong Nguyen 		rc = -ENOENT;
365125351652SVuong Nguyen 	}
365225351652SVuong Nguyen 
365325351652SVuong Nguyen 	etm_ds_fini = (int (*)(void))dlsym(etm_dl_hdl, "ds_fini");
365425351652SVuong Nguyen 	if (etm_ds_fini == NULL) {
365525351652SVuong Nguyen 		fmd_hdl_debug(hdl, "error: dlsym(ds_fini) failed\n");
365625351652SVuong Nguyen 		rc = -ENOENT;
365725351652SVuong Nguyen 	}
365825351652SVuong Nguyen 
365925351652SVuong Nguyen 	if (rc == -ENOENT) {
366025351652SVuong Nguyen 		(void) dlclose(etm_dl_hdl);
366125351652SVuong Nguyen 	}
366225351652SVuong Nguyen 	return (rc);
366325351652SVuong Nguyen 
366425351652SVuong Nguyen } /* etm_ds_init() */
366525351652SVuong Nguyen 
366625351652SVuong Nguyen 
366725351652SVuong Nguyen /*
3668733a5356Srb144127  * -------------------------- FMD entry points -------------------------------
3669733a5356Srb144127  */
3670733a5356Srb144127 
3671733a5356Srb144127 /*
3672733a5356Srb144127  * _fmd_init - initialize the transport for use by ETM and start the
3673733a5356Srb144127  *		server daemon to accept new connections to us
3674733a5356Srb144127  *
3675733a5356Srb144127  *		FMD will read our *.conf and subscribe us to FMA events
3676733a5356Srb144127  */
3677733a5356Srb144127 
3678733a5356Srb144127 void
3679733a5356Srb144127 _fmd_init(fmd_hdl_t *hdl)
3680733a5356Srb144127 {
3681e2ff4ac6Srb144127 	struct timeval		tmv;		/* timeval */
3682733a5356Srb144127 	ssize_t			n;		/* gen use */
36834b476ed5Sdarudy 	const struct facility	*fp;		/* syslog facility matching */
36844b476ed5Sdarudy 	char			*facname;	/* syslog facility property */
368525351652SVuong Nguyen 	uint32_t		type_mask;	/* type of the local host */
368625351652SVuong Nguyen 	int			rc;		/* funcs return code */
368725351652SVuong Nguyen 
3688733a5356Srb144127 
3689733a5356Srb144127 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
3690733a5356Srb144127 		return; /* invalid data in configuration file */
3691733a5356Srb144127 	}
3692733a5356Srb144127 
3693733a5356Srb144127 	fmd_hdl_debug(hdl, "info: module initializing\n");
3694733a5356Srb144127 
369531e37bb4Svn83148 	init_hdl = hdl;
369625351652SVuong Nguyen 	etm_lhp = ldom_init(etm_init_alloc, etm_init_free);
369731e37bb4Svn83148 
369831e37bb4Svn83148 	/*
369925351652SVuong Nguyen 	 * decide the ldom type, do initialization accordingly
370031e37bb4Svn83148 	 */
370125351652SVuong Nguyen 	if ((rc = ldom_get_type(etm_lhp, &type_mask)) != 0) {
370225351652SVuong Nguyen 		fmd_hdl_debug(hdl, "error: can't decide ldom type\n");
370331e37bb4Svn83148 		fmd_hdl_debug(hdl, "info: module unregistering\n");
370425351652SVuong Nguyen 		ldom_fini(etm_lhp);
370531e37bb4Svn83148 		fmd_hdl_unregister(hdl);
370631e37bb4Svn83148 		return;
370725351652SVuong Nguyen 	}
370825351652SVuong Nguyen 
370925351652SVuong Nguyen 	if ((type_mask & LDOM_TYPE_LEGACY) || (type_mask & LDOM_TYPE_CONTROL)) {
371025351652SVuong Nguyen 		if (type_mask & LDOM_TYPE_LEGACY) {
371125351652SVuong Nguyen 			/*
371225351652SVuong Nguyen 			 * running on a legacy sun4v domain,
371325351652SVuong Nguyen 			 * act as the the old sun4v
371425351652SVuong Nguyen 			 */
371525351652SVuong Nguyen 			etm_ldom_type = LDOM_TYPE_LEGACY;
371625351652SVuong Nguyen 			fmd_hdl_debug(hdl, "info: running as the old sun4v\n");
371725351652SVuong Nguyen 			ldom_fini(etm_lhp);
371825351652SVuong Nguyen 		} else if (type_mask & LDOM_TYPE_CONTROL) {
371925351652SVuong Nguyen 			etm_ldom_type = LDOM_TYPE_CONTROL;
372025351652SVuong Nguyen 			fmd_hdl_debug(hdl, "info: running as control domain\n");
372125351652SVuong Nguyen 
372225351652SVuong Nguyen 			/*
372325351652SVuong Nguyen 			 * looking for libds.so.1.
372425351652SVuong Nguyen 			 * If not found, don't do DS registration. As a result,
372525351652SVuong Nguyen 			 * there will be no DS callbacks or other DS services.
372625351652SVuong Nguyen 			 */
372725351652SVuong Nguyen 			if (etm_ds_init(hdl) >= 0) {
372825351652SVuong Nguyen 				etm_filter_init(hdl);
372925351652SVuong Nguyen 				etm_ckpt_init(hdl);
373025351652SVuong Nguyen 
373125351652SVuong Nguyen 				flags = FMD_XPRT_RDWR | FMD_XPRT_ACCEPT;
373225351652SVuong Nguyen 
373325351652SVuong Nguyen 				/*
373425351652SVuong Nguyen 				 * ds client registration
373525351652SVuong Nguyen 				 */
373625351652SVuong Nguyen 				if ((rc = (*etm_ds_clnt_reg)(&iosvc_caps,
373725351652SVuong Nguyen 				    &iosvc_ops))) {
373825351652SVuong Nguyen 					fmd_hdl_debug(hdl,
373925351652SVuong Nguyen 					"error: ds_clnt_reg(): errno %d\n", rc);
374025351652SVuong Nguyen 				}
374131e37bb4Svn83148 			} else {
374225351652SVuong Nguyen 				fmd_hdl_debug(hdl, "error: dlopen() libds "
374325351652SVuong Nguyen 				    "failed, continue without the DS services");
374425351652SVuong Nguyen 			}
374525351652SVuong Nguyen 
374625351652SVuong Nguyen 			/*
374725351652SVuong Nguyen 			 * register for ldom status events
374825351652SVuong Nguyen 			 */
374925351652SVuong Nguyen 			if ((rc = ldom_register_event(etm_lhp,
375025351652SVuong Nguyen 			    ldom_event_handler, hdl))) {
375125351652SVuong Nguyen 				fmd_hdl_debug(hdl,
375225351652SVuong Nguyen 				    "error: ldom_register_event():"
375325351652SVuong Nguyen 				    " errno %d\n", rc);
375425351652SVuong Nguyen 			}
375525351652SVuong Nguyen 
375625351652SVuong Nguyen 			/*
375725351652SVuong Nguyen 			 * create the thread for handling both the ldom status
375825351652SVuong Nguyen 			 * change and service events
375925351652SVuong Nguyen 			 */
376025351652SVuong Nguyen 			etm_async_e_tid = fmd_thr_create(hdl,
376125351652SVuong Nguyen 			    etm_async_event_handler, hdl);
376231e37bb4Svn83148 		}
376331e37bb4Svn83148 
3764733a5356Srb144127 		/* setup statistics and properties from FMD */
3765733a5356Srb144127 
3766733a5356Srb144127 		(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
376725351652SVuong Nguyen 		    sizeof (etm_stats) / sizeof (fmd_stat_t),
376825351652SVuong Nguyen 		    (fmd_stat_t *)&etm_stats);
3769733a5356Srb144127 
377025351652SVuong Nguyen 		etm_fma_resp_wait_time = fmd_prop_get_int32(hdl,
377125351652SVuong Nguyen 		    ETM_PROP_NM_FMA_RESP_WAIT_TIME);
3772733a5356Srb144127 		etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
3773733a5356Srb144127 		etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl,
3774733a5356Srb144127 		    ETM_PROP_NM_DEBUG_MAX_EV_CNT);
3775733a5356Srb144127 		fmd_hdl_debug(hdl, "info: etm_debug_lvl %d "
377625351652SVuong Nguyen 		    "etm_debug_max_ev_cnt %d\n", etm_debug_lvl,
377725351652SVuong Nguyen 		    etm_debug_max_ev_cnt);
3778b8677b72Srb144127 
3779b8677b72Srb144127 		etm_resp_q_max_len = fmd_prop_get_int32(hdl,
3780b8677b72Srb144127 		    ETM_PROP_NM_MAX_RESP_Q_LEN);
378125351652SVuong Nguyen 		etm_stats.etm_resp_q_max_len.fmds_value.ui64 =
378225351652SVuong Nguyen 		    etm_resp_q_max_len;
37832ca9f232Srb144127 		etm_bad_acc_to_sec = fmd_prop_get_int32(hdl,
37842ca9f232Srb144127 		    ETM_PROP_NM_BAD_ACC_TO_SEC);
3785733a5356Srb144127 
378625351652SVuong Nguyen 		/*
378725351652SVuong Nguyen 		 * obtain an FMD transport handle so we can post
378825351652SVuong Nguyen 		 * FMA events later
378925351652SVuong Nguyen 		 */
379000ab1250Srb144127 
379100ab1250Srb144127 		etm_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
379200ab1250Srb144127 
379325351652SVuong Nguyen 		/*
379425351652SVuong Nguyen 		 * encourage protocol transaction id to be unique per module
379525351652SVuong Nguyen 		 * load
379625351652SVuong Nguyen 		 */
3797e2ff4ac6Srb144127 
3798e2ff4ac6Srb144127 		(void) gettimeofday(&tmv, NULL);
3799e2ff4ac6Srb144127 		etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) |
3800e2ff4ac6Srb144127 		    ((unsigned long)tmv.tv_usec >> 10));
3801e2ff4ac6Srb144127 
3802b8677b72Srb144127 		/* init the ETM transport */
3803733a5356Srb144127 
3804733a5356Srb144127 		if ((n = etm_xport_init(hdl)) != 0) {
380525351652SVuong Nguyen 			fmd_hdl_error(hdl, "error: bad xport init errno %d\n",
380625351652SVuong Nguyen 			    (-n));
3807733a5356Srb144127 			fmd_hdl_unregister(hdl);
3808733a5356Srb144127 			return;
3809733a5356Srb144127 		}
3810733a5356Srb144127 
38114b476ed5Sdarudy 		/*
38124b476ed5Sdarudy 		 * Cache any properties we use every time we receive an alert.
38134b476ed5Sdarudy 		 */
38144b476ed5Sdarudy 		syslog_file = fmd_prop_get_int32(hdl, ETM_PROP_NM_SYSLOGD);
38154b476ed5Sdarudy 		syslog_cons = fmd_prop_get_int32(hdl, ETM_PROP_NM_CONSOLE);
38164b476ed5Sdarudy 
38174b476ed5Sdarudy 		if (syslog_file && (syslog_logfd = open("/dev/conslog",
38184b476ed5Sdarudy 		    O_WRONLY | O_NOCTTY)) == -1) {
381925351652SVuong Nguyen 			fmd_hdl_error(hdl,
382025351652SVuong Nguyen 			    "error: failed to open /dev/conslog");
38214b476ed5Sdarudy 			syslog_file = 0;
38224b476ed5Sdarudy 		}
38234b476ed5Sdarudy 
38244b476ed5Sdarudy 		if (syslog_cons && (syslog_msgfd = open("/dev/sysmsg",
38254b476ed5Sdarudy 		    O_WRONLY | O_NOCTTY)) == -1) {
38264b476ed5Sdarudy 			fmd_hdl_error(hdl, "error: failed to open /dev/sysmsg");
38274b476ed5Sdarudy 			syslog_cons = 0;
38284b476ed5Sdarudy 		}
38294b476ed5Sdarudy 
38304b476ed5Sdarudy 		if (syslog_file) {
38314b476ed5Sdarudy 			/*
383225351652SVuong Nguyen 			 * Look up the value of the "facility" property and
383325351652SVuong Nguyen 			 * use it to determine * what syslog LOG_* facility
383425351652SVuong Nguyen 			 * value we use to fill in our log_ctl_t.
38354b476ed5Sdarudy 			 */
383625351652SVuong Nguyen 			facname = fmd_prop_get_string(hdl,
383725351652SVuong Nguyen 			    ETM_PROP_NM_FACILITY);
38384b476ed5Sdarudy 
38394b476ed5Sdarudy 			for (fp = syslog_facs; fp->fac_name != NULL; fp++) {
38404b476ed5Sdarudy 				if (strcmp(fp->fac_name, facname) == 0)
38414b476ed5Sdarudy 					break;
38424b476ed5Sdarudy 			}
38434b476ed5Sdarudy 
38444b476ed5Sdarudy 			if (fp->fac_name == NULL) {
38454b476ed5Sdarudy 				fmd_hdl_error(hdl, "error: invalid 'facility'"
38464b476ed5Sdarudy 				    " setting: %s\n", facname);
38474b476ed5Sdarudy 				syslog_file = 0;
38484b476ed5Sdarudy 			} else {
38494b476ed5Sdarudy 				syslog_facility = fp->fac_value;
38504b476ed5Sdarudy 				syslog_ctl.flags = SL_CONSOLE | SL_LOGONLY;
38514b476ed5Sdarudy 			}
38524b476ed5Sdarudy 
38534b476ed5Sdarudy 			fmd_prop_free_string(hdl, facname);
38544b476ed5Sdarudy 		}
38554b476ed5Sdarudy 
3856b8677b72Srb144127 		/*
385725351652SVuong Nguyen 		 * start the message responder and the connection acceptance
385825351652SVuong Nguyen 		 * server; request protocol version be negotiated after waiting
385925351652SVuong Nguyen 		 * a second for the receiver to be ready to start handshaking
3860b8677b72Srb144127 		 */
3861b8677b72Srb144127 
3862b8677b72Srb144127 		etm_resp_tid = fmd_thr_create(hdl, etm_responder, hdl);
3863733a5356Srb144127 		etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl);
386431e37bb4Svn83148 
386531e37bb4Svn83148 		(void) etm_sleep(ETM_SLEEP_QUIK);
3866733a5356Srb144127 		etm_req_ver_negot(hdl);
3867733a5356Srb144127 
386825351652SVuong Nguyen 	} else if (type_mask & LDOM_TYPE_ROOT) {
386925351652SVuong Nguyen 		etm_ldom_type = LDOM_TYPE_ROOT;
387025351652SVuong Nguyen 		fmd_hdl_debug(hdl, "info: running as root domain\n");
387125351652SVuong Nguyen 
387225351652SVuong Nguyen 		/*
387325351652SVuong Nguyen 		 * looking for libds.so.1.
387425351652SVuong Nguyen 		 * If not found, don't do DS registration. As a result,
387525351652SVuong Nguyen 		 * there will be no DS callbacks or other DS services.
387625351652SVuong Nguyen 		 */
387725351652SVuong Nguyen 		if (etm_ds_init(hdl) < 0) {
387825351652SVuong Nguyen 			fmd_hdl_debug(hdl,
387925351652SVuong Nguyen 			    "error: dlopen() libds failed, "
388025351652SVuong Nguyen 			    "module unregistering\n");
388125351652SVuong Nguyen 			ldom_fini(etm_lhp);
388225351652SVuong Nguyen 			fmd_hdl_unregister(hdl);
388325351652SVuong Nguyen 			return;
388425351652SVuong Nguyen 		}
388525351652SVuong Nguyen 
388625351652SVuong Nguyen 		/*
388725351652SVuong Nguyen 		 * DS service registration
388825351652SVuong Nguyen 		 */
388925351652SVuong Nguyen 		if ((rc = (*etm_ds_svc_reg)(&iosvc_caps, &iosvc_ops))) {
389025351652SVuong Nguyen 			fmd_hdl_debug(hdl, "error: ds_svc_reg(): errno %d\n",
389125351652SVuong Nguyen 			    rc);
389225351652SVuong Nguyen 		}
389325351652SVuong Nguyen 
389425351652SVuong Nguyen 		/*
389525351652SVuong Nguyen 		 * this thread is created for ds_reg_cb/ds_unreg_cb
389625351652SVuong Nguyen 		 */
389725351652SVuong Nguyen 		etm_async_e_tid = fmd_thr_create(hdl,
389825351652SVuong Nguyen 		    etm_async_event_handler, hdl);
389925351652SVuong Nguyen 
390025351652SVuong Nguyen 		flags = FMD_XPRT_RDWR;
390125351652SVuong Nguyen 	} else if ((type_mask & LDOM_TYPE_IO) || (type_mask == 0)) {
390225351652SVuong Nguyen 		/*
390325351652SVuong Nguyen 		 * Do not load this module if it is
390425351652SVuong Nguyen 		 * . runing on a non-root ldom
390525351652SVuong Nguyen 		 * . the domain owns no io devices
390625351652SVuong Nguyen 		 */
390725351652SVuong Nguyen 		fmd_hdl_debug(hdl,
390825351652SVuong Nguyen 		    "info: non-root ldom, module unregistering\n");
390925351652SVuong Nguyen 		ldom_fini(etm_lhp);
391025351652SVuong Nguyen 		fmd_hdl_unregister(hdl);
391125351652SVuong Nguyen 		return;
391225351652SVuong Nguyen 	} else {
391325351652SVuong Nguyen 		/*
391425351652SVuong Nguyen 		 * place holder, all other cases. unload etm for now
391525351652SVuong Nguyen 		 */
391625351652SVuong Nguyen 		fmd_hdl_debug(hdl,
391725351652SVuong Nguyen 		    "info: other ldom type, module unregistering\n");
391825351652SVuong Nguyen 		ldom_fini(etm_lhp);
391925351652SVuong Nguyen 		fmd_hdl_unregister(hdl);
392025351652SVuong Nguyen 		return;
392125351652SVuong Nguyen 	}
392225351652SVuong Nguyen 
3923733a5356Srb144127 	fmd_hdl_debug(hdl, "info: module initialized ok\n");
3924733a5356Srb144127 
3925733a5356Srb144127 } /* _fmd_init() */
3926733a5356Srb144127 
3927733a5356Srb144127 /*
3928733a5356Srb144127  * etm_recv - receive an FMA event from FMD and transport it
3929733a5356Srb144127  *		to the remote endpoint
3930733a5356Srb144127  */
3931733a5356Srb144127 
3932733a5356Srb144127 /*ARGSUSED*/
3933733a5356Srb144127 void
3934733a5356Srb144127 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
3935733a5356Srb144127 {
3936733a5356Srb144127 	etm_xport_addr_t	*addrv;	/* vector of transport addresses */
3937733a5356Srb144127 	etm_xport_conn_t	conn;	/* connection handle */
3938733a5356Srb144127 	etm_proto_v1_ev_hdr_t	*hdrp;	/* for FMA_EVENT msg */
3939733a5356Srb144127 	ssize_t			i, n;	/* gen use */
3940733a5356Srb144127 	size_t			sz;	/* header size */
3941733a5356Srb144127 	size_t			buflen;	/* size of packed FMA event */
3942733a5356Srb144127 	uint8_t			*buf;	/* tmp buffer for packed FMA event */
3943733a5356Srb144127 
394425351652SVuong Nguyen 	/*
394525351652SVuong Nguyen 	 * if this is running on a Root Domain, ignore the events,
394625351652SVuong Nguyen 	 * return right away
394725351652SVuong Nguyen 	 */
394825351652SVuong Nguyen 	if (etm_ldom_type == LDOM_TYPE_ROOT)
394925351652SVuong Nguyen 		return;
395025351652SVuong Nguyen 
3951733a5356Srb144127 	buflen = 0;
3952b8677b72Srb144127 	if ((n = nvlist_size(evp, &buflen, NV_ENCODE_XDR)) != 0) {
3953b8677b72Srb144127 		fmd_hdl_error(hdl, "error: FMA event dropped: "
3954b8677b72Srb144127 		    "event size errno %d class %s\n", n, class);
3955b8677b72Srb144127 		etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++;
3956b8677b72Srb144127 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
3957b8677b72Srb144127 		return;
3958b8677b72Srb144127 	}
3959733a5356Srb144127 
3960733a5356Srb144127 	fmd_hdl_debug(hdl, "info: rcvd event %p from FMD\n", evp);
3961733a5356Srb144127 	fmd_hdl_debug(hdl, "info: cnt %llu class %s\n",
3962733a5356Srb144127 	    etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64, class);
3963733a5356Srb144127 
3964b8677b72Srb144127 	etm_stats.etm_rd_fmd_bytes.fmds_value.ui64 += buflen;
3965b8677b72Srb144127 	etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64++;
3966b8677b72Srb144127 
3967733a5356Srb144127 	/*
3968733a5356Srb144127 	 * if the debug limit has been set, avoid excessive traffic,
3969733a5356Srb144127 	 * for example, an infinite cycle using loopback nodes
3970733a5356Srb144127 	 */
3971733a5356Srb144127 
3972733a5356Srb144127 	if ((etm_debug_max_ev_cnt >= 0) &&
3973733a5356Srb144127 	    (etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64 >
3974733a5356Srb144127 	    etm_debug_max_ev_cnt)) {
3975733a5356Srb144127 		fmd_hdl_debug(hdl, "warning: FMA event dropped: "
3976733a5356Srb144127 		    "event %p cnt %llu > debug max %d\n", evp,
3977733a5356Srb144127 		    etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64,
3978733a5356Srb144127 		    etm_debug_max_ev_cnt);
3979733a5356Srb144127 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
3980733a5356Srb144127 		return;
3981733a5356Srb144127 	}
3982733a5356Srb144127 
3983733a5356Srb144127 	/* allocate a buffer for the FMA event and nvlist pack it */
3984733a5356Srb144127 
3985733a5356Srb144127 	buf = fmd_hdl_zalloc(hdl, buflen, FMD_SLEEP);
3986733a5356Srb144127 
398725351652SVuong Nguyen 	/*
398825351652SVuong Nguyen 	 * increment the ttl value if the event is from remote (a root domain)
398925351652SVuong Nguyen 	 * uncomment this when enabling fault forwarding from Root domains
399025351652SVuong Nguyen 	 * to Control domain.
399125351652SVuong Nguyen 	 *
399225351652SVuong Nguyen 	 * uint8_t			ttl;
399325351652SVuong Nguyen 	 * if (fmd_event_local(hdl, evp) != FMD_EVF_LOCAL) {
399425351652SVuong Nguyen 	 *	if (nvlist_lookup_uint8(evp, FMD_EVN_TTL, &ttl) == 0) {
399525351652SVuong Nguyen 	 *		(void) nvlist_remove(evp, FMD_EVN_TTL, DATA_TYPE_UINT8);
399625351652SVuong Nguyen 	 *		(void) nvlist_add_uint8(evp, FMD_EVN_TTL, ttl + 1);
399725351652SVuong Nguyen 	 *	}
399825351652SVuong Nguyen 	 * }
399925351652SVuong Nguyen 	 */
400025351652SVuong Nguyen 
4001733a5356Srb144127 	if ((n = nvlist_pack(evp, (char **)&buf, &buflen,
4002733a5356Srb144127 	    NV_ENCODE_XDR, 0)) != 0) {
4003733a5356Srb144127 		fmd_hdl_error(hdl, "error: FMA event dropped: "
4004b8677b72Srb144127 		    "event pack errno %d class %s\n", n, class);
4005733a5356Srb144127 		etm_stats.etm_os_nvlist_pack_fail.fmds_value.ui64++;
4006733a5356Srb144127 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
4007733a5356Srb144127 		fmd_hdl_free(hdl, buf, buflen);
4008733a5356Srb144127 		return;
4009733a5356Srb144127 	}
4010733a5356Srb144127 
4011733a5356Srb144127 	/* get vector of dst addrs and send the FMA event to each one */
4012733a5356Srb144127 
4013733a5356Srb144127 	if ((addrv = etm_xport_get_ev_addrv(hdl, evp)) == NULL) {
4014733a5356Srb144127 		fmd_hdl_error(hdl, "error: FMA event dropped: "
4015733a5356Srb144127 		    "bad event dst addrs errno %d\n", errno);
4016733a5356Srb144127 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
4017733a5356Srb144127 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
4018733a5356Srb144127 		fmd_hdl_free(hdl, buf, buflen);
4019733a5356Srb144127 		return;
4020733a5356Srb144127 	}
4021733a5356Srb144127 
4022733a5356Srb144127 	for (i = 0; addrv[i] != NULL; i++) {
4023733a5356Srb144127 
4024733a5356Srb144127 		/* open a new connection to this dst addr */
4025733a5356Srb144127 
4026733a5356Srb144127 		if ((n = etm_conn_open(hdl, "FMA event dropped: "
4027b8677b72Srb144127 		    "bad conn open on new ev", addrv[i], &conn)) < 0) {
4028733a5356Srb144127 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
4029733a5356Srb144127 			continue;
4030733a5356Srb144127 		}
4031733a5356Srb144127 
40322ae66659Sjrutt 		(void) pthread_mutex_lock(&etm_write_lock);
40332ae66659Sjrutt 
4034733a5356Srb144127 		/* write the ETM message header */
4035733a5356Srb144127 
4036733a5356Srb144127 		if ((hdrp = etm_hdr_write(hdl, conn, evp, NV_ENCODE_XDR,
4037733a5356Srb144127 		    &sz)) == NULL) {
40382ae66659Sjrutt 			(void) pthread_mutex_unlock(&etm_write_lock);
4039733a5356Srb144127 			fmd_hdl_error(hdl, "error: FMA event dropped: "
4040733a5356Srb144127 			    "bad hdr write errno %d\n", errno);
4041733a5356Srb144127 			(void) etm_conn_close(hdl,
4042733a5356Srb144127 			    "bad conn close per bad hdr wr", conn);
4043733a5356Srb144127 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
4044733a5356Srb144127 			continue;
4045733a5356Srb144127 		}
4046733a5356Srb144127 
4047733a5356Srb144127 		fmd_hdl_free(hdl, hdrp, sz);	/* header not needed */
4048733a5356Srb144127 		etm_stats.etm_wr_hdr_fmaevent.fmds_value.ui64++;
4049733a5356Srb144127 		fmd_hdl_debug(hdl, "info: hdr xport write ok for event %p\n",
4050733a5356Srb144127 		    evp);
4051733a5356Srb144127 
4052733a5356Srb144127 		/* write the ETM message body, ie, the packed nvlist */
4053733a5356Srb144127 
4054733a5356Srb144127 		if ((n = etm_io_op(hdl, "FMA event dropped: "
4055733a5356Srb144127 		    "bad io write on event", conn,
4056733a5356Srb144127 		    buf, buflen, ETM_IO_OP_WR)) < 0) {
40572ae66659Sjrutt 			(void) pthread_mutex_unlock(&etm_write_lock);
4058733a5356Srb144127 			(void) etm_conn_close(hdl,
4059733a5356Srb144127 			    "bad conn close per bad body wr", conn);
4060733a5356Srb144127 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
4061733a5356Srb144127 			continue;
4062733a5356Srb144127 		}
4063733a5356Srb144127 
40642ae66659Sjrutt 		(void) pthread_mutex_unlock(&etm_write_lock);
40652ae66659Sjrutt 
4066733a5356Srb144127 		etm_stats.etm_wr_body_fmaevent.fmds_value.ui64++;
4067733a5356Srb144127 		etm_stats.etm_wr_xport_bytes.fmds_value.ui64 += buflen;
4068733a5356Srb144127 		fmd_hdl_debug(hdl, "info: body xport write ok for event %p\n",
4069733a5356Srb144127 		    evp);
4070733a5356Srb144127 
4071733a5356Srb144127 		/* close the connection */
4072733a5356Srb144127 
4073733a5356Srb144127 		(void) etm_conn_close(hdl, "bad conn close after event send",
4074733a5356Srb144127 		    conn);
4075733a5356Srb144127 	} /* foreach dst addr in the vector */
4076733a5356Srb144127 
4077733a5356Srb144127 	etm_xport_free_addrv(hdl, addrv);
4078733a5356Srb144127 	fmd_hdl_free(hdl, buf, buflen);
4079733a5356Srb144127 
4080733a5356Srb144127 } /* etm_recv() */
4081733a5356Srb144127 
408225351652SVuong Nguyen 
408325351652SVuong Nguyen /*
408425351652SVuong Nguyen  * etm_send -	receive an FMA event from FMD and enQ it in the iosvc.Q.
408525351652SVuong Nguyen  *		etm_send_to_remote_root() deQ and xprt the FMA events to a
408625351652SVuong Nguyen  *		remote root domain
408725351652SVuong Nguyen  *		return FMD_SEND_SUCCESS for success,
408825351652SVuong Nguyen  *		       FMD_SEND_FAILED for error
408925351652SVuong Nguyen  */
409025351652SVuong Nguyen 
409125351652SVuong Nguyen /*ARGSUSED*/
409225351652SVuong Nguyen int
409325351652SVuong Nguyen etm_send(fmd_hdl_t *fmd_hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl)
409425351652SVuong Nguyen {
409525351652SVuong Nguyen 	uint32_t	pack_it;	/* whether to pack/enq the event */
409625351652SVuong Nguyen 	etm_pack_msg_type_t	msg_type;
409725351652SVuong Nguyen 					/* tell etm_pack_ds_msg() what to do */
409825351652SVuong Nguyen 	etm_iosvc_t	*iosvc;		/* ptr to cur iosvc struct */
409925351652SVuong Nguyen 	char 		*class;		/* nvlist class name */
410025351652SVuong Nguyen 
410125351652SVuong Nguyen 	pack_it = 1;
410225351652SVuong Nguyen 	msg_type = FMD_XPRT_OTHER_MSG;
410325351652SVuong Nguyen 
410425351652SVuong Nguyen 	(void) nvlist_lookup_string(nvl, FM_CLASS, &class);
410525351652SVuong Nguyen 	if (class == NULL) {
410625351652SVuong Nguyen 		pack_it = 0;
410725351652SVuong Nguyen 	} else  {
410825351652SVuong Nguyen 		if (etm_debug_lvl >= 1) {
410925351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
411025351652SVuong Nguyen 			    "info: evp class= %s in etm_send\n", class);
411125351652SVuong Nguyen 		}
411225351652SVuong Nguyen 
411325351652SVuong Nguyen 		if (etm_ldom_type ==  LDOM_TYPE_CONTROL) {
411425351652SVuong Nguyen 			iosvc =
411525351652SVuong Nguyen 			    (etm_iosvc_t *)fmd_xprt_getspecific(fmd_hdl, xp);
411625351652SVuong Nguyen 
411725351652SVuong Nguyen 			/*
411825351652SVuong Nguyen 			 * check the flag FORWARDING_FAULTS_TO_CONTROL to
411925351652SVuong Nguyen 			 * decide if or not to drop fault subscription
412025351652SVuong Nguyen 			 * control msgs
412125351652SVuong Nguyen 			 */
412225351652SVuong Nguyen 			if (strcmp(class, "resource.fm.xprt.subscribe") == 0) {
412325351652SVuong Nguyen 				pack_it = 0;
412425351652SVuong Nguyen 				/*
412525351652SVuong Nguyen 				 * if (FORWARDING_FAULTS_TO_CONTROL == 1) {
412625351652SVuong Nguyen 				 * (void) nvlist_lookup_string(nvl,
412725351652SVuong Nguyen 				 *    FM_RSRC_XPRT_SUBCLASS, &subclass);
412825351652SVuong Nguyen 				 * if (strcmp(subclass, "list.suspect")
412925351652SVuong Nguyen 				 *    == 0) {
413025351652SVuong Nguyen 				 *	pack_it = 1;
413125351652SVuong Nguyen 				 *	msg_action = FMD_XPRT_OTHER_MSG;
413225351652SVuong Nguyen 				 * }
413325351652SVuong Nguyen 				 * if (strcmp(subclass, "list.repaired")
413425351652SVuong Nguyen 				 *    == 0) {
413525351652SVuong Nguyen 				 *	pack_it = 1;
413625351652SVuong Nguyen 				 *	msg_action = FMD_XPRT_OTHER_MSG;
413725351652SVuong Nguyen 				 * }
413825351652SVuong Nguyen 				 * }
413925351652SVuong Nguyen 				 */
414025351652SVuong Nguyen 			}
414125351652SVuong Nguyen 			if (strcmp(class, "resource.fm.xprt.run") == 0) {
414225351652SVuong Nguyen 				pack_it = 1;
414325351652SVuong Nguyen 				msg_type = FMD_XPRT_RUN_MSG;
414425351652SVuong Nguyen 			}
414525351652SVuong Nguyen 		} else { /* has to be the root domain ldom */
414625351652SVuong Nguyen 			iosvc = &io_svc;
414725351652SVuong Nguyen 			/*
414825351652SVuong Nguyen 			 * drop all ereport and fault subscriptions
414925351652SVuong Nguyen 			 * are we dropping too much here, more than just ereport
415025351652SVuong Nguyen 			 * and fault subscriptions? need to check
415125351652SVuong Nguyen 			 */
415225351652SVuong Nguyen 			if (strcmp(class, "resource.fm.xprt.subscribe") == 0)
415325351652SVuong Nguyen 				pack_it = 0;
415425351652SVuong Nguyen 			if (strcmp(class, "resource.fm.xprt.run") == 0) {
415525351652SVuong Nguyen 				pack_it = 1;
415625351652SVuong Nguyen 				msg_type = FMD_XPRT_RUN_MSG;
415725351652SVuong Nguyen 			}
415825351652SVuong Nguyen 		}
415925351652SVuong Nguyen 	}
416025351652SVuong Nguyen 
416125351652SVuong Nguyen 	if (pack_it)  {
416225351652SVuong Nguyen 		if (etm_debug_lvl >= 1) {
416325351652SVuong Nguyen 			fmd_hdl_debug(fmd_hdl,
416425351652SVuong Nguyen 			    "info: ldom name returned from xprt get specific="
416525351652SVuong Nguyen 			    "%s xprt=%lld\n", iosvc->ldom_name, xp);
416625351652SVuong Nguyen 		}
416725351652SVuong Nguyen 		/*
416825351652SVuong Nguyen 		 * pack the etm msg for the DS library and  enq in io_svc->Q
416925351652SVuong Nguyen 		 * when the hdrp is NULL, the packing func will use the static
417025351652SVuong Nguyen 		 * iosvc_hdr
417125351652SVuong Nguyen 		 */
417225351652SVuong Nguyen 		(void) etm_pack_ds_msg(fmd_hdl, iosvc, NULL, 0, nvl, msg_type,
417325351652SVuong Nguyen 		    ETM_CKPT_NOOP);
417425351652SVuong Nguyen 	}
417525351652SVuong Nguyen 
417625351652SVuong Nguyen 	return (FMD_SEND_SUCCESS);
417725351652SVuong Nguyen 
417825351652SVuong Nguyen } /* etm_send() */
417925351652SVuong Nguyen 
418025351652SVuong Nguyen 
418125351652SVuong Nguyen 
4182733a5356Srb144127 /*
4183733a5356Srb144127  * _fmd_fini - stop the server daemon and teardown the transport
4184733a5356Srb144127  */
4185733a5356Srb144127 
4186733a5356Srb144127 void
4187733a5356Srb144127 _fmd_fini(fmd_hdl_t *hdl)
4188733a5356Srb144127 {
4189733a5356Srb144127 	ssize_t			n;		/* gen use */
419025351652SVuong Nguyen 	etm_iosvc_t		*iosvc;		/* ptr to insvc struct */
419125351652SVuong Nguyen 	etm_iosvc_q_ele_t	msg_ele;	/* iosvc msg ele */
419225351652SVuong Nguyen 	uint32_t		i;		/* for loop var */
4193733a5356Srb144127 
4194b8677b72Srb144127 	fmd_hdl_debug(hdl, "info: module finalizing\n");
4195733a5356Srb144127 
4196b8677b72Srb144127 	/* kill the connection server and responder ; wait for them to die */
4197733a5356Srb144127 
4198733a5356Srb144127 	etm_is_dying = 1;
4199733a5356Srb144127 
4200733a5356Srb144127 	if (etm_svr_tid != NULL) {
4201733a5356Srb144127 		fmd_thr_signal(hdl, etm_svr_tid);
4202733a5356Srb144127 		fmd_thr_destroy(hdl, etm_svr_tid);
4203733a5356Srb144127 		etm_svr_tid = NULL;
4204733a5356Srb144127 	} /* if server thread was successfully created */
4205733a5356Srb144127 
4206b8677b72Srb144127 	if (etm_resp_tid != NULL) {
4207b8677b72Srb144127 		fmd_thr_signal(hdl, etm_resp_tid);
4208b8677b72Srb144127 		fmd_thr_destroy(hdl, etm_resp_tid);
4209b8677b72Srb144127 		etm_resp_tid = NULL;
4210b8677b72Srb144127 	} /* if responder thread was successfully created */
4211b8677b72Srb144127 
421225351652SVuong Nguyen 	if (etm_async_e_tid != NULL) {
421325351652SVuong Nguyen 		fmd_thr_signal(hdl, etm_async_e_tid);
421425351652SVuong Nguyen 		fmd_thr_destroy(hdl, etm_async_e_tid);
421525351652SVuong Nguyen 		etm_async_e_tid = NULL;
421625351652SVuong Nguyen 	} /* if async event handler thread was successfully created */
4217733a5356Srb144127 
421825351652SVuong Nguyen 
421925351652SVuong Nguyen 	if ((etm_ldom_type == LDOM_TYPE_LEGACY) ||
422025351652SVuong Nguyen 	    (etm_ldom_type == LDOM_TYPE_CONTROL)) {
422125351652SVuong Nguyen 
422225351652SVuong Nguyen 		/* teardown the transport and cleanup syslogging */
4223733a5356Srb144127 		if ((n = etm_xport_fini(hdl)) != 0) {
422425351652SVuong Nguyen 			fmd_hdl_error(hdl, "warning: xport fini errno %d\n",
422525351652SVuong Nguyen 			    (-n));
4226733a5356Srb144127 		}
422700ab1250Srb144127 		if (etm_fmd_xprt != NULL) {
422800ab1250Srb144127 			fmd_xprt_close(hdl, etm_fmd_xprt);
422900ab1250Srb144127 		}
4230733a5356Srb144127 
42314b476ed5Sdarudy 		if (syslog_logfd != -1) {
42324b476ed5Sdarudy 			(void) close(syslog_logfd);
42334b476ed5Sdarudy 		}
42344b476ed5Sdarudy 		if (syslog_msgfd != -1) {
42354b476ed5Sdarudy 			(void) close(syslog_msgfd);
42364b476ed5Sdarudy 		}
423725351652SVuong Nguyen 	}
423825351652SVuong Nguyen 
423925351652SVuong Nguyen 	if (etm_ldom_type == LDOM_TYPE_CONTROL)  {
424025351652SVuong Nguyen 		if (ldom_unregister_event(etm_lhp))
424125351652SVuong Nguyen 			fmd_hdl_debug(hdl, "ldom_unregister_event() failed\n");
424225351652SVuong Nguyen 
424325351652SVuong Nguyen 		/*
4244d279c7bfSVuong Nguyen 		 * On control domain side, there may be multiple iosvc struct
4245d279c7bfSVuong Nguyen 		 * in use, one for each bound/active domain. Each struct
4246d279c7bfSVuong Nguyen 		 * manages a queue of fma events destined to the root domain.
4247d279c7bfSVuong Nguyen 		 * Need to go thru every iosvc struct to clean up its resources.
424825351652SVuong Nguyen 		 */
424925351652SVuong Nguyen 		for (i = 0; i < NUM_OF_ROOT_DOMAINS; i++) {
425025351652SVuong Nguyen 			if (iosvc_list[i].ldom_name[0] != '\0') {
425125351652SVuong Nguyen 				/*
425225351652SVuong Nguyen 				 * found an iosvc struct for a root domain
425325351652SVuong Nguyen 				 */
425425351652SVuong Nguyen 				iosvc = &iosvc_list[i];
425525351652SVuong Nguyen 				(void) pthread_mutex_lock(&iosvc_list_lock);
4256d279c7bfSVuong Nguyen 				etm_iosvc_cleanup(hdl, iosvc, B_TRUE, B_FALSE);
425725351652SVuong Nguyen 				(void) pthread_mutex_unlock(&iosvc_list_lock);
425825351652SVuong Nguyen 
425925351652SVuong Nguyen 			} else {
426025351652SVuong Nguyen 				/*
426125351652SVuong Nguyen 				 * reach the end of existing iosvc structures
426225351652SVuong Nguyen 				 */
426325351652SVuong Nguyen 				continue;
426425351652SVuong Nguyen 			}
426525351652SVuong Nguyen 		} /* for i<NUM_OF_ROOT_DOMAINS */
426625351652SVuong Nguyen 		etm_ckpt_fini(hdl);
426725351652SVuong Nguyen 		etm_filter_fini(hdl);
426825351652SVuong Nguyen 
426925351652SVuong Nguyen 		ldom_fini(etm_lhp);
427025351652SVuong Nguyen 
427125351652SVuong Nguyen 	} else if (etm_ldom_type == LDOM_TYPE_ROOT) {
4272d279c7bfSVuong Nguyen 		/*
4273d279c7bfSVuong Nguyen 		 * On root domain side, there is only one iosvc struct in use.
4274d279c7bfSVuong Nguyen 		 */
427525351652SVuong Nguyen 		iosvc = &io_svc;
427625351652SVuong Nguyen 		if (iosvc->send_tid != NULL) {
427725351652SVuong Nguyen 			fmd_thr_signal(hdl, iosvc->send_tid);
427825351652SVuong Nguyen 			fmd_thr_destroy(hdl, iosvc->send_tid);
427925351652SVuong Nguyen 			iosvc->send_tid = NULL;
428025351652SVuong Nguyen 		} /* if io svc send thread was successfully created */
428125351652SVuong Nguyen 
428225351652SVuong Nguyen 		if (iosvc->recv_tid != NULL) {
428325351652SVuong Nguyen 			fmd_thr_signal(hdl, iosvc->recv_tid);
428425351652SVuong Nguyen 			fmd_thr_destroy(hdl, iosvc->recv_tid);
428525351652SVuong Nguyen 			iosvc->recv_tid = NULL;
428625351652SVuong Nguyen 		} /* if io svc receive thread was successfully created */
428725351652SVuong Nguyen 
428825351652SVuong Nguyen 		(void) pthread_mutex_lock(&iosvc->msg_q_lock);
428925351652SVuong Nguyen 		while (iosvc->msg_q_cur_len > 0) {
429025351652SVuong Nguyen 			(void) etm_iosvc_msg_deq(hdl, iosvc, &msg_ele);
429125351652SVuong Nguyen 			fmd_hdl_free(hdl, msg_ele.msg, msg_ele.msg_size);
429225351652SVuong Nguyen 		}
429325351652SVuong Nguyen 		(void) pthread_mutex_unlock(&iosvc->msg_q_lock);
429425351652SVuong Nguyen 
429525351652SVuong Nguyen 		if (iosvc->fmd_xprt != NULL)
429625351652SVuong Nguyen 			fmd_xprt_close(hdl, iosvc->fmd_xprt);
429725351652SVuong Nguyen 		ldom_fini(etm_lhp);
429825351652SVuong Nguyen 	}
429925351652SVuong Nguyen 	if (etm_ds_fini) {
430025351652SVuong Nguyen 		(*etm_ds_fini)();
430125351652SVuong Nguyen 		(void) dlclose(etm_dl_hdl);
430225351652SVuong Nguyen 	}
43034b476ed5Sdarudy 
4304733a5356Srb144127 	fmd_hdl_debug(hdl, "info: module finalized ok\n");
4305733a5356Srb144127 
4306733a5356Srb144127 } /* _fmd_fini() */
4307