xref: /titanic_52/usr/src/cmd/fm/modules/sun4v/etm/etm.c (revision 47911a7d5f24c2fc37e7b5bcc696fe32e750c16c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * etm.c	FMA Event Transport Module implementation, a plugin of FMD
29  *		for sun4v/Ontario
30  *
31  * plugin for sending/receiving FMA events to/from service processor
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 /*
37  * --------------------------------- includes --------------------------------
38  */
39 
40 #include <sys/fm/protocol.h>
41 #include <sys/fm/util.h>
42 #include <sys/fm/ldom.h>
43 #include <sys/strlog.h>
44 #include <sys/syslog.h>
45 #include <netinet/in.h>
46 #include <fm/fmd_api.h>
47 
48 #include "etm_xport_api.h"
49 #include "etm_etm_proto.h"
50 #include "etm_impl.h"
51 
52 #include <pthread.h>
53 #include <signal.h>
54 #include <stropts.h>
55 #include <locale.h>
56 #include <strings.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <limits.h>
60 #include <values.h>
61 #include <alloca.h>
62 #include <errno.h>
63 #include <fcntl.h>
64 #include <time.h>
65 
66 /*
67  * ----------------------------- forward decls -------------------------------
68  */
69 
70 static void
71 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class);
72 
73 /*
74  * ------------------------- data structs for FMD ----------------------------
75  */
76 
77 static const fmd_hdl_ops_t fmd_ops = {
78 	etm_recv,	/* fmdo_recv */
79 	NULL,		/* fmdo_timeout */
80 	NULL,		/* fmdo_close */
81 	NULL,		/* fmdo_stats */
82 	NULL,		/* fmdo_gc */
83 	NULL,		/* fmdo_send */
84 };
85 
86 static const fmd_prop_t fmd_props[] = {
87 	{ ETM_PROP_NM_XPORT_ADDRS,	FMD_TYPE_STRING, "" },
88 	{ ETM_PROP_NM_DEBUG_LVL,	FMD_TYPE_INT32, "0" },
89 	{ ETM_PROP_NM_DEBUG_MAX_EV_CNT,	FMD_TYPE_INT32, "-1" },
90 	{ ETM_PROP_NM_CONSOLE,		FMD_TYPE_BOOL, "false" },
91 	{ ETM_PROP_NM_SYSLOGD,		FMD_TYPE_BOOL, "true" },
92 	{ ETM_PROP_NM_FACILITY,		FMD_TYPE_STRING, "LOG_DAEMON" },
93 	{ ETM_PROP_NM_MAX_RESP_Q_LEN,	FMD_TYPE_INT32, "512" },
94 	{ NULL, 0, NULL }
95 };
96 
97 
98 static const fmd_hdl_info_t fmd_info = {
99 	"FMA Event Transport Module", "1.1", &fmd_ops, fmd_props
100 };
101 
102 /*
103  * ----------------------- private consts and defns --------------------------
104  */
105 
106 /* misc buffer for variable sized protocol header fields */
107 
108 #define	ETM_MISC_BUF_SZ	(4 * 1024)
109 
110 /* try limit for IO operations w/ capped exp backoff sleep on retry */
111 
112 /*
113  * Design_Note:	ETM will potentially retry forever IO operations that the
114  *		transport fails with EAGAIN (aka EWOULDBLOCK) rather than
115  *		giving up after some number of seconds. This avoids
116  *		dropping FMA events while the service processor is down,
117  *		but at the risk of pending fmdo_recv() forever and
118  *		overflowing FMD's event queue for ETM.
119  *		A future TBD enhancement would be to always recv
120  *		and send each ETM msg in a single read/write() to reduce
121  *		the risk of failure between ETM msg hdr and body,
122  *		assuming the MTU_SZ is large enough.
123  */
124 
125 #define	ETM_TRY_MAX_CNT		(MAXINT - 1)
126 #define	ETM_TRY_BACKOFF_RATE	(4)
127 #define	ETM_TRY_BACKOFF_CAP	(60)
128 
129 /* amount to increment protocol transaction id on each new send */
130 
131 #define	ETM_XID_INC	(2)
132 
133 typedef struct etm_resp_q_ele {
134 
135 	etm_xport_conn_t	rqe_conn;	/* open connection to send on */
136 	etm_proto_v1_pp_t	*rqe_hdrp;	/* ptr to ETM msg hdr */
137 	size_t			rqe_hdr_sz;	/* sizeof ETM msg hdr */
138 	int32_t			rqe_resp_code;	/* response code to send */
139 
140 	struct etm_resp_q_ele	*rqe_nextp;	/* PRIVATE - next ele ptr */
141 
142 } etm_resp_q_ele_t;	/* responder queue element */
143 
144 /*
145  * ---------------------------- global data ----------------------------------
146  */
147 
148 static fmd_hdl_t
149 *init_hdl = NULL;	/* used in mem allocator at init time */
150 
151 static int
152 etm_debug_lvl = 0;	/* debug level: 0 is off, 1 is on, 2 is more, etc */
153 
154 static int
155 etm_debug_max_ev_cnt = -1; /* max allowed event count for debugging */
156 
157 static fmd_xprt_t
158 *etm_fmd_xprt = NULL;	/* FMD transport layer handle */
159 
160 static pthread_t
161 etm_svr_tid = NULL;	/* thread id of connection acceptance server */
162 
163 static pthread_t
164 etm_resp_tid = NULL;	/* thread id of msg responder */
165 
166 static etm_resp_q_ele_t
167 *etm_resp_q_head = NULL; /* ptr to cur head of responder queue */
168 
169 static etm_resp_q_ele_t
170 *etm_resp_q_tail = NULL; /* ptr to cur tail of responder queue */
171 
172 static uint32_t
173 etm_resp_q_cur_len = 0;	/* cur length (ele cnt) of responder queue */
174 
175 static uint32_t
176 etm_resp_q_max_len = 0;	/* max length (ele cnt) of responder queue */
177 
178 static pthread_mutex_t
179 etm_resp_q_lock = PTHREAD_MUTEX_INITIALIZER;	/* protects responder queue */
180 
181 static pthread_cond_t
182 etm_resp_q_cv = PTHREAD_COND_INITIALIZER;	/* nudges msg responder */
183 
184 static volatile int
185 etm_is_dying = 0;	/* bool for dying (killing self) */
186 
187 static uint32_t
188 etm_xid_cur = 0;	/* current transaction id for sends */
189 
190 static uint32_t
191 etm_xid_ping = 0;	/* xid of last CONTROL msg sent requesting ping */
192 
193 static uint32_t
194 etm_xid_ver_negot = 0;	/* xid of last CONTROL msg sent requesting ver negot */
195 
196 static uint32_t
197 etm_xid_posted_ev = 0;	/* xid of last FMA_EVENT msg/event posted OK to FMD */
198 
199 static uint32_t
200 etm_xid_posted_sa = 0;	/* xid of last ALERT msg/event posted OK to syslog */
201 
202 static uint8_t
203 etm_resp_ver = ETM_PROTO_V1; /* proto ver [negotiated] for msg sends */
204 
205 static pthread_mutex_t
206 etm_write_lock = PTHREAD_MUTEX_INITIALIZER;	/* for write operations */
207 
208 static log_ctl_t syslog_ctl;	/* log(7D) meta-data for each msg */
209 static int syslog_facility;	/* log(7D) facility (part of priority) */
210 static int syslog_logfd = -1;	/* log(7D) file descriptor */
211 static int syslog_msgfd = -1;	/* sysmsg(7D) file descriptor */
212 static int syslog_file = 0;	/* log to syslog_logfd */
213 static int syslog_cons = 0;	/* log to syslog_msgfd */
214 
215 static const struct facility {
216 	const char *fac_name;
217 	int fac_value;
218 } syslog_facs[] = {
219 	{ "LOG_DAEMON", LOG_DAEMON },
220 	{ "LOG_LOCAL0", LOG_LOCAL0 },
221 	{ "LOG_LOCAL1", LOG_LOCAL1 },
222 	{ "LOG_LOCAL2", LOG_LOCAL2 },
223 	{ "LOG_LOCAL3", LOG_LOCAL3 },
224 	{ "LOG_LOCAL4", LOG_LOCAL4 },
225 	{ "LOG_LOCAL5", LOG_LOCAL5 },
226 	{ "LOG_LOCAL6", LOG_LOCAL6 },
227 	{ "LOG_LOCAL7", LOG_LOCAL7 },
228 	{ NULL, 0 }
229 };
230 
231 static struct stats {
232 
233 	/* ETM msg counters */
234 
235 	fmd_stat_t etm_rd_hdr_fmaevent;
236 	fmd_stat_t etm_rd_hdr_control;
237 	fmd_stat_t etm_rd_hdr_alert;
238 	fmd_stat_t etm_rd_hdr_response;
239 	fmd_stat_t etm_rd_body_fmaevent;
240 	fmd_stat_t etm_rd_body_control;
241 	fmd_stat_t etm_rd_body_alert;
242 	fmd_stat_t etm_rd_body_response;
243 	fmd_stat_t etm_wr_hdr_fmaevent;
244 	fmd_stat_t etm_wr_hdr_control;
245 	fmd_stat_t etm_wr_hdr_response;
246 	fmd_stat_t etm_wr_body_fmaevent;
247 	fmd_stat_t etm_wr_body_control;
248 	fmd_stat_t etm_wr_body_response;
249 
250 	fmd_stat_t etm_rd_max_ev_per_msg;
251 	fmd_stat_t etm_wr_max_ev_per_msg;
252 
253 	fmd_stat_t etm_resp_q_cur_len;
254 	fmd_stat_t etm_resp_q_max_len;
255 
256 	/* ETM byte counters */
257 
258 	fmd_stat_t etm_wr_fmd_bytes;
259 	fmd_stat_t etm_rd_fmd_bytes;
260 	fmd_stat_t etm_wr_xport_bytes;
261 	fmd_stat_t etm_rd_xport_bytes;
262 
263 	fmd_stat_t etm_magic_drop_bytes;
264 
265 	/* ETM [dropped] FMA event counters */
266 
267 	fmd_stat_t etm_rd_fmd_fmaevent;
268 	fmd_stat_t etm_wr_fmd_fmaevent;
269 
270 	fmd_stat_t etm_rd_drop_fmaevent;
271 	fmd_stat_t etm_wr_drop_fmaevent;
272 
273 	fmd_stat_t etm_rd_dup_fmaevent;
274 	fmd_stat_t etm_wr_dup_fmaevent;
275 
276 	fmd_stat_t etm_rd_dup_alert;
277 	fmd_stat_t etm_wr_dup_alert;
278 
279 	fmd_stat_t etm_enq_drop_resp_q;
280 	fmd_stat_t etm_deq_drop_resp_q;
281 
282 	/* ETM protocol failures */
283 
284 	fmd_stat_t etm_magic_bad;
285 	fmd_stat_t etm_ver_bad;
286 	fmd_stat_t etm_msgtype_bad;
287 	fmd_stat_t etm_subtype_bad;
288 	fmd_stat_t etm_xid_bad;
289 	fmd_stat_t etm_fmaeventlen_bad;
290 	fmd_stat_t etm_respcode_bad;
291 	fmd_stat_t etm_timeout_bad;
292 	fmd_stat_t etm_evlens_bad;
293 
294 	/* IO operation failures */
295 
296 	fmd_stat_t etm_xport_wr_fail;
297 	fmd_stat_t etm_xport_rd_fail;
298 	fmd_stat_t etm_xport_pk_fail;
299 
300 	/* IO operation retries */
301 
302 	fmd_stat_t etm_xport_wr_retry;
303 	fmd_stat_t etm_xport_rd_retry;
304 	fmd_stat_t etm_xport_pk_retry;
305 
306 	/* system and library failures */
307 
308 	fmd_stat_t etm_os_nvlist_pack_fail;
309 	fmd_stat_t etm_os_nvlist_unpack_fail;
310 	fmd_stat_t etm_os_nvlist_size_fail;
311 	fmd_stat_t etm_os_pthread_create_fail;
312 
313 	/* xport API failures */
314 
315 	fmd_stat_t etm_xport_get_ev_addrv_fail;
316 	fmd_stat_t etm_xport_open_fail;
317 	fmd_stat_t etm_xport_close_fail;
318 	fmd_stat_t etm_xport_accept_fail;
319 	fmd_stat_t etm_xport_open_retry;
320 
321 	/* FMD entry point bad arguments */
322 
323 	fmd_stat_t etm_fmd_recv_badargs;
324 	fmd_stat_t etm_fmd_init_badargs;
325 	fmd_stat_t etm_fmd_fini_badargs;
326 
327 	/* Alert logging errors */
328 
329 	fmd_stat_t etm_log_err;
330 	fmd_stat_t etm_msg_err;
331 
332 } etm_stats = {
333 
334 	/* ETM msg counters */
335 
336 	{ "etm_rd_hdr_fmaevent", FMD_TYPE_UINT64,
337 		"ETM fmaevent msg headers rcvd from xport" },
338 	{ "etm_rd_hdr_control", FMD_TYPE_UINT64,
339 		"ETM control msg headers rcvd from xport" },
340 	{ "etm_rd_hdr_alert", FMD_TYPE_UINT64,
341 		"ETM alert msg headers rcvd from xport" },
342 	{ "etm_rd_hdr_response", FMD_TYPE_UINT64,
343 		"ETM response msg headers rcvd from xport" },
344 	{ "etm_rd_body_fmaevent", FMD_TYPE_UINT64,
345 		"ETM fmaevent msg bodies rcvd from xport" },
346 	{ "etm_rd_body_control", FMD_TYPE_UINT64,
347 		"ETM control msg bodies rcvd from xport" },
348 	{ "etm_rd_body_alert", FMD_TYPE_UINT64,
349 		"ETM alert msg bodies rcvd from xport" },
350 	{ "etm_rd_body_response", FMD_TYPE_UINT64,
351 		"ETM response msg bodies rcvd from xport" },
352 	{ "etm_wr_hdr_fmaevent", FMD_TYPE_UINT64,
353 		"ETM fmaevent msg headers sent to xport" },
354 	{ "etm_wr_hdr_control", FMD_TYPE_UINT64,
355 		"ETM control msg headers sent to xport" },
356 	{ "etm_wr_hdr_response", FMD_TYPE_UINT64,
357 		"ETM response msg headers sent to xport" },
358 	{ "etm_wr_body_fmaevent", FMD_TYPE_UINT64,
359 		"ETM fmaevent msg bodies sent to xport" },
360 	{ "etm_wr_body_control", FMD_TYPE_UINT64,
361 		"ETM control msg bodies sent to xport" },
362 	{ "etm_wr_body_response", FMD_TYPE_UINT64,
363 		"ETM response msg bodies sent to xport" },
364 
365 	{ "etm_rd_max_ev_per_msg", FMD_TYPE_UINT64,
366 		"max FMA events per ETM msg from xport" },
367 	{ "etm_wr_max_ev_per_msg", FMD_TYPE_UINT64,
368 		"max FMA events per ETM msg to xport" },
369 
370 	{ "etm_resp_q_cur_len", FMD_TYPE_UINT64,
371 		"cur enqueued response msgs to xport" },
372 	{ "etm_resp_q_max_len", FMD_TYPE_UINT64,
373 		"max enqueable response msgs to xport" },
374 
375 	/* ETM byte counters */
376 
377 	{ "etm_wr_fmd_bytes", FMD_TYPE_UINT64,
378 		"bytes of FMA events sent to FMD" },
379 	{ "etm_rd_fmd_bytes", FMD_TYPE_UINT64,
380 		"bytes of FMA events rcvd from FMD" },
381 	{ "etm_wr_xport_bytes", FMD_TYPE_UINT64,
382 		"bytes of FMA events sent to xport" },
383 	{ "etm_rd_xport_bytes", FMD_TYPE_UINT64,
384 		"bytes of FMA events rcvd from xport" },
385 
386 	{ "etm_magic_drop_bytes", FMD_TYPE_UINT64,
387 		"bytes dropped from xport pre magic num" },
388 
389 	/* ETM [dropped] FMA event counters */
390 
391 	{ "etm_rd_fmd_fmaevent", FMD_TYPE_UINT64,
392 		"FMA events rcvd from FMD" },
393 	{ "etm_wr_fmd_fmaevent", FMD_TYPE_UINT64,
394 		"FMA events sent to FMD" },
395 
396 	{ "etm_rd_drop_fmaevent", FMD_TYPE_UINT64,
397 		"dropped FMA events from xport" },
398 	{ "etm_wr_drop_fmaevent", FMD_TYPE_UINT64,
399 		"dropped FMA events to xport" },
400 
401 	{ "etm_rd_dup_fmaevent", FMD_TYPE_UINT64,
402 	    "duplicate FMA events rcvd from xport" },
403 	{ "etm_wr_dup_fmaevent", FMD_TYPE_UINT64,
404 	    "duplicate FMA events sent to xport" },
405 
406 	{ "etm_rd_dup_alert", FMD_TYPE_UINT64,
407 	    "duplicate ALERTs rcvd from xport" },
408 	{ "etm_wr_dup_alert", FMD_TYPE_UINT64,
409 	    "duplicate ALERTs sent to xport" },
410 
411 	{ "etm_enq_drop_resp_q", FMD_TYPE_UINT64,
412 	    "dropped response msgs on enq" },
413 	{ "etm_deq_drop_resp_q", FMD_TYPE_UINT64,
414 	    "dropped response msgs on deq" },
415 
416 	/* ETM protocol failures */
417 
418 	{ "etm_magic_bad", FMD_TYPE_UINT64,
419 		"ETM msgs w/ invalid magic num" },
420 	{ "etm_ver_bad", FMD_TYPE_UINT64,
421 		"ETM msgs w/ invalid protocol version" },
422 	{ "etm_msgtype_bad", FMD_TYPE_UINT64,
423 		"ETM msgs w/ invalid message type" },
424 	{ "etm_subtype_bad", FMD_TYPE_UINT64,
425 		"ETM msgs w/ invalid sub type" },
426 	{ "etm_xid_bad", FMD_TYPE_UINT64,
427 		"ETM msgs w/ unmatched xid" },
428 	{ "etm_fmaeventlen_bad", FMD_TYPE_UINT64,
429 		"ETM msgs w/ invalid FMA event length" },
430 	{ "etm_respcode_bad", FMD_TYPE_UINT64,
431 		"ETM msgs w/ invalid response code" },
432 	{ "etm_timeout_bad", FMD_TYPE_UINT64,
433 		"ETM msgs w/ invalid timeout value" },
434 	{ "etm_evlens_bad", FMD_TYPE_UINT64,
435 		"ETM msgs w/ too many event lengths" },
436 
437 	/* IO operation failures */
438 
439 	{ "etm_xport_wr_fail", FMD_TYPE_UINT64,
440 		"xport write failures" },
441 	{ "etm_xport_rd_fail", FMD_TYPE_UINT64,
442 		"xport read failures" },
443 	{ "etm_xport_pk_fail", FMD_TYPE_UINT64,
444 		"xport peek failures" },
445 
446 	/* IO operation retries */
447 
448 	{ "etm_xport_wr_retry", FMD_TYPE_UINT64,
449 		"xport write retries" },
450 	{ "etm_xport_rd_retry", FMD_TYPE_UINT64,
451 		"xport read retries" },
452 	{ "etm_xport_pk_retry", FMD_TYPE_UINT64,
453 		"xport peek retries" },
454 
455 	/* system and library failures */
456 
457 	{ "etm_os_nvlist_pack_fail", FMD_TYPE_UINT64,
458 		"nvlist_pack failures" },
459 	{ "etm_os_nvlist_unpack_fail", FMD_TYPE_UINT64,
460 		"nvlist_unpack failures" },
461 	{ "etm_os_nvlist_size_fail", FMD_TYPE_UINT64,
462 		"nvlist_size failures" },
463 	{ "etm_os_pthread_create_fail", FMD_TYPE_UINT64,
464 		"pthread_create failures" },
465 
466 	/* transport API failures */
467 
468 	{ "etm_xport_get_ev_addrv_fail", FMD_TYPE_UINT64,
469 		"xport get event addrv API failures" },
470 	{ "etm_xport_open_fail", FMD_TYPE_UINT64,
471 		"xport open API failures" },
472 	{ "etm_xport_close_fail", FMD_TYPE_UINT64,
473 		"xport close API failures" },
474 	{ "etm_xport_accept_fail", FMD_TYPE_UINT64,
475 		"xport accept API failures" },
476 	{ "etm_xport_open_retry", FMD_TYPE_UINT64,
477 		"xport open API retries" },
478 
479 	/* FMD entry point bad arguments */
480 
481 	{ "etm_fmd_recv_badargs", FMD_TYPE_UINT64,
482 		"bad arguments from fmd_recv entry point" },
483 	{ "etm_fmd_init_badargs", FMD_TYPE_UINT64,
484 		"bad arguments from fmd_init entry point" },
485 	{ "etm_fmd_fini_badargs", FMD_TYPE_UINT64,
486 		"bad arguments from fmd_fini entry point" },
487 
488 	/* Alert logging errors */
489 
490 	{ "etm_log_err", FMD_TYPE_UINT64,
491 		"failed to log message to log(7D)" },
492 	{ "etm_msg_err", FMD_TYPE_UINT64,
493 		"failed to log message to sysmsg(7D)" }
494 };
495 
496 /*
497  * -------------------------- support functions ------------------------------
498  */
499 
500 /*
501  * Design_Note:	Each failure worth reporting to FMD should be done using
502  *		a single call to fmd_hdl_error() as it logs an FMA event
503  *		for each call. Also be aware that all the fmd_hdl_*()
504  *		format strings currently use platform specific *printf()
505  *		routines; so "%p" under Solaris does not prepend "0x" to
506  *		the outputted hex digits, while Linux and VxWorks do.
507  */
508 
509 /*
510  * etm_show_time - display the current time of day (for debugging) using
511  *		the given FMD module handle and annotation string
512  */
513 
514 static void
515 etm_show_time(fmd_hdl_t *hdl, char *note_str)
516 {
517 	struct timeval		tmv;		/* timeval */
518 
519 	(void) gettimeofday(&tmv, NULL);
520 	fmd_hdl_debug(hdl, "info: %s: cur Unix Epoch time %d.%06d\n",
521 	    note_str, tmv.tv_sec, tmv.tv_usec);
522 
523 } /* etm_show_time() */
524 
525 /*
526  * etm_hexdump - hexdump the given buffer (for debugging) using
527  *		the given FMD module handle
528  */
529 
530 static void
531 etm_hexdump(fmd_hdl_t *hdl, void *buf, size_t byte_cnt)
532 {
533 	uint8_t		*bp;		/* byte ptr */
534 	int		i, j;		/* index */
535 	char		cb[80];		/* char buf */
536 	unsigned int	n;		/* a byte of data for sprintf() */
537 
538 	bp = buf;
539 	j = 0;
540 
541 	/*
542 	 * Design_Note:	fmd_hdl_debug() auto adds a newline if missing;
543 	 *		hence cb exists to accumulate a longer string.
544 	 */
545 
546 	for (i = 1; i <= byte_cnt; i++) {
547 		n = *bp++;
548 		(void) sprintf(&cb[j], "%2.2x ", n);
549 		j += 3;
550 		/* add a newline every 16 bytes or at the buffer's end */
551 		if (((i % 16) == 0) || (i >= byte_cnt)) {
552 			cb[j-1] = '\0';
553 			fmd_hdl_debug(hdl, "%s\n", cb);
554 			j = 0;
555 		}
556 	} /* for each byte in the buffer */
557 
558 } /* etm_hexdump() */
559 
560 /*
561  * etm_sleep - sleep the caller for the given number of seconds,
562  *		return 0 or -errno value
563  *
564  * Design_Note:	To avoid interfering with FMD's signal mask (SIGALRM)
565  *		do not use [Solaris] sleep(3C) and instead use
566  *		pthread_cond_wait() or nanosleep(), both of which
567  *		are POSIX spec-ed to leave signal masks alone.
568  *		This is needed for Solaris and Linux (domain and SP).
569  */
570 
571 static int
572 etm_sleep(unsigned sleep_sec)
573 {
574 	struct timespec	tms;	/* for nanosleep() */
575 
576 	tms.tv_sec = sleep_sec;
577 	tms.tv_nsec = 0;
578 
579 	if (nanosleep(&tms, NULL) < 0) {
580 		/* errno assumed set by above call */
581 		return (-errno);
582 	}
583 	return (0);
584 
585 } /* etm_sleep() */
586 
587 /*
588  * etm_conn_open - open a connection to the given transport address,
589  *		return 0 and the opened connection handle
590  *		or -errno value
591  *
592  * caveats:	the err_substr is used in failure cases for calling
593  *		fmd_hdl_error()
594  */
595 
596 static int
597 etm_conn_open(fmd_hdl_t *hdl, char *err_substr,
598 		etm_xport_addr_t addr, etm_xport_conn_t *connp)
599 {
600 	etm_xport_conn_t	conn;	/* connection to return */
601 	int			nev;	/* -errno value */
602 
603 	if ((conn = etm_xport_open(hdl, addr)) == NULL) {
604 		nev = (-errno);
605 		fmd_hdl_error(hdl, "error: %s: errno %d\n",
606 		    err_substr, errno);
607 		etm_stats.etm_xport_open_fail.fmds_value.ui64++;
608 		return (nev);
609 	} else {
610 		*connp = conn;
611 		return (0);
612 	}
613 } /* etm_conn_open() */
614 
615 /*
616  * etm_conn_close - close the given connection,
617  *		return 0 or -errno value
618  *
619  * caveats:	the err_substr is used in failure cases for calling
620  *		fmd_hdl_error()
621  */
622 
623 static int
624 etm_conn_close(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn)
625 {
626 	int	nev;	/* -errno value */
627 
628 	if (etm_xport_close(hdl, conn) == NULL) {
629 		nev = (-errno);
630 		fmd_hdl_error(hdl, "warning: %s: errno %d\n",
631 		    err_substr, errno);
632 		etm_stats.etm_xport_close_fail.fmds_value.ui64++;
633 		return (nev);
634 	} else {
635 		return (0);
636 	}
637 } /* etm_conn_close() */
638 
639 /*
640  * etm_io_op - perform an IO operation on the given connection
641  *		with the given buffer,
642  *		accommodating MTU size and retrying op if needed,
643  *		return how many bytes actually done by the op
644  *		or -errno value
645  *
646  * caveats:	the err_substr is used in failure cases for calling
647  *		fmd_hdl_error()
648  */
649 
650 static ssize_t
651 etm_io_op(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn,
652 				void *buf, size_t byte_cnt, int io_op)
653 {
654 	ssize_t		rv;		/* ret val / byte count */
655 	ssize_t		n;		/* gen use */
656 	uint8_t		*datap;		/* ptr to data */
657 	size_t		mtu_sz;		/* MTU size in bytes */
658 	int		(*io_func_ptr)(fmd_hdl_t *, etm_xport_conn_t,
659 	    void *, size_t);
660 	size_t		io_sz;		/* byte count for io_func_ptr */
661 	int		try_cnt;	/* number of tries done */
662 	int		sleep_sec;	/* exp backoff sleep period in sec */
663 	int		sleep_rv;	/* ret val from sleeping */
664 	fmd_stat_t	io_retry_stat;	/* IO retry stat to update */
665 	fmd_stat_t	io_fail_stat;	/* IO failure stat to update */
666 
667 	if ((conn == NULL) || (buf == NULL)) {
668 		return (-EINVAL);
669 	}
670 	switch (io_op) {
671 		case ETM_IO_OP_RD:
672 			io_func_ptr = etm_xport_read;
673 			io_retry_stat = etm_stats.etm_xport_rd_retry;
674 			io_fail_stat = etm_stats.etm_xport_rd_fail;
675 			break;
676 		case ETM_IO_OP_WR:
677 			io_func_ptr = etm_xport_write;
678 			io_retry_stat = etm_stats.etm_xport_wr_retry;
679 			io_fail_stat = etm_stats.etm_xport_wr_fail;
680 			break;
681 		default:
682 			return (-EINVAL);
683 	}
684 	if (byte_cnt == 0) {
685 		return (byte_cnt);	/* nop */
686 	}
687 
688 	/* obtain [current] MTU size */
689 
690 	if ((n = etm_xport_get_opt(hdl, conn, ETM_XPORT_OPT_MTU_SZ)) < 0) {
691 		mtu_sz = ETM_XPORT_MTU_SZ_DEF;
692 	} else {
693 		mtu_sz = n;
694 	}
695 
696 	/* loop until all IO done, try limit exceeded, or real failure */
697 
698 	rv = 0;
699 	datap = buf;
700 	while (rv < byte_cnt) {
701 		io_sz = MIN((byte_cnt - rv), mtu_sz);
702 		try_cnt = 0;
703 		sleep_sec = 0;
704 
705 		/* when give up, return -errno value even if partly done */
706 
707 		while ((n = (*io_func_ptr)(hdl, conn, datap, io_sz)) ==
708 		    (-EAGAIN)) {
709 			try_cnt++;
710 			if (try_cnt > ETM_TRY_MAX_CNT) {
711 				rv = n;
712 				goto func_ret;
713 			}
714 			if (etm_is_dying) {
715 				rv = (-EINTR);
716 				goto func_ret;
717 			}
718 			if ((sleep_rv = etm_sleep(sleep_sec)) < 0) {
719 				rv = sleep_rv;
720 				goto func_ret;
721 			}
722 			sleep_sec = ((sleep_sec == 0) ? 1 :
723 			    (sleep_sec * ETM_TRY_BACKOFF_RATE));
724 			sleep_sec = MIN(sleep_sec, ETM_TRY_BACKOFF_CAP);
725 			io_retry_stat.fmds_value.ui64++;
726 			if (etm_debug_lvl >= 1) {
727 				fmd_hdl_debug(hdl, "info: retrying io op %d "
728 				    "due to EAGAIN\n", io_op);
729 			}
730 		} /* while trying the io operation */
731 
732 		if (etm_is_dying) {
733 			rv = (-EINTR);
734 			goto func_ret;
735 		}
736 		if (n < 0) {
737 			rv = n;
738 			goto func_ret;
739 		}
740 		/* avoid spinning CPU when given 0 bytes but no error */
741 		if (n == 0) {
742 			if ((sleep_rv = etm_sleep(ETM_SLEEP_QUIK)) < 0) {
743 				rv = sleep_rv;
744 				goto func_ret;
745 			}
746 		}
747 		rv += n;
748 		datap += n;
749 	} /* while still have more data */
750 
751 func_ret:
752 
753 	if (rv < 0) {
754 		io_fail_stat.fmds_value.ui64++;
755 		fmd_hdl_debug(hdl, "error: %s: errno %d\n",
756 		    err_substr, (int)(-rv));
757 	}
758 	if (etm_debug_lvl >= 3) {
759 		fmd_hdl_debug(hdl, "info: io op %d ret %d of %d\n",
760 		    io_op, (int)rv, (int)byte_cnt);
761 	}
762 	return (rv);
763 
764 } /* etm_io_op() */
765 
766 /*
767  * etm_magic_read - read the magic number of an ETM message header
768  *		from the given connection into the given buffer,
769  *		return 0 or -errno value
770  *
771  * Design_Note:	This routine is intended to help protect ETM from protocol
772  *		framing errors as might be caused by an SP reset / crash in
773  *		the middle of an ETM message send; the connection will be
774  *		read from for as many bytes as needed until the magic number
775  *		is found using a sliding buffer for comparisons.
776  */
777 
778 static int
779 etm_magic_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, uint32_t *magic_ptr)
780 {
781 	int		rv;		/* ret val */
782 	uint32_t	magic_num;	/* magic number */
783 	int		byte_cnt;	/* count of bytes read */
784 	uint8_t		buf5[4+1];	/* sliding input buffer */
785 	int		i, j;		/* indices into buf5 */
786 	ssize_t		n;		/* gen use */
787 	uint8_t		drop_buf[1024];	/* dropped bytes buffer */
788 
789 	rv = 0;		/* assume success */
790 	magic_num = 0;
791 	byte_cnt = 0;
792 	j = 0;
793 
794 	/* magic number bytes are sent in network (big endian) order */
795 
796 	while (magic_num != ETM_PROTO_MAGIC_NUM) {
797 		if ((n = etm_io_op(hdl, "bad io read on magic",
798 		    conn, &buf5[j], 1, ETM_IO_OP_RD)) < 0) {
799 			rv = n;
800 			goto func_ret;
801 		}
802 		byte_cnt++;
803 		j = MIN((j + 1), sizeof (magic_num));
804 		if (byte_cnt < sizeof (magic_num)) {
805 			continue;
806 		}
807 
808 		if (byte_cnt > sizeof (magic_num)) {
809 			etm_stats.etm_magic_drop_bytes.fmds_value.ui64++;
810 			i = MIN(byte_cnt - j - 1, sizeof (drop_buf) - 1);
811 			drop_buf[i] = buf5[0];
812 			for (i = 0; i < j; i++) {
813 				buf5[i] = buf5[i+1];
814 			} /* for sliding the buffer contents */
815 		}
816 		(void) memcpy(&magic_num, &buf5[0], sizeof (magic_num));
817 		magic_num = ntohl(magic_num);
818 	} /* for reading bytes until find magic number */
819 
820 func_ret:
821 
822 	if (byte_cnt != sizeof (magic_num)) {
823 		fmd_hdl_debug(hdl, "warning: bad proto frame "
824 		    "implies corrupt/lost msg(s)\n");
825 	}
826 	if ((byte_cnt > sizeof (magic_num)) && (etm_debug_lvl >= 2)) {
827 		i = MIN(byte_cnt - sizeof (magic_num), sizeof (drop_buf));
828 		fmd_hdl_debug(hdl, "info: magic drop hexdump "
829 		    "first %d of %d bytes:\n", i,
830 		    byte_cnt - sizeof (magic_num));
831 		etm_hexdump(hdl, drop_buf, i);
832 	}
833 
834 	if (rv == 0) {
835 		*magic_ptr = magic_num;
836 	}
837 	return (rv);
838 
839 } /* etm_magic_read() */
840 
841 /*
842  * etm_hdr_read - allocate, read, and validate a [variable sized]
843  *		ETM message header from the given connection,
844  *		return the allocated ETM message header
845  *		(which is guaranteed to be large enough to reuse as a
846  *		RESPONSE msg hdr) and its size
847  *		or NULL and set errno on failure
848  */
849 
850 static void *
851 etm_hdr_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, size_t *szp)
852 {
853 	uint8_t			*hdrp;		/* ptr to header to return */
854 	size_t			hdr_sz;		/* sizeof *hdrp */
855 	etm_proto_v1_pp_t	pp; 		/* protocol preamble */
856 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
857 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
858 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
859 	etm_proto_v3_sa_hdr_t	*sa_hdrp;	/* for ALERT msg */
860 	uint32_t		*lenp;		/* ptr to FMA event length */
861 	ssize_t			i, n;		/* gen use */
862 	uint8_t	misc_buf[ETM_MISC_BUF_SZ];	/* for var sized hdrs */
863 	int			dummy_int;	/* dummy var to appease lint */
864 
865 	hdrp = NULL; hdr_sz = 0;
866 
867 	/* read the magic number which starts the protocol preamble */
868 
869 	if ((n = etm_magic_read(hdl, conn, &pp.pp_magic_num)) < 0) {
870 		errno = (-n);
871 		etm_stats.etm_magic_bad.fmds_value.ui64++;
872 		return (NULL);
873 	}
874 
875 	/* read the rest of the protocol preamble all at once */
876 
877 	if ((n = etm_io_op(hdl, "bad io read on preamble",
878 	    conn, &pp.pp_proto_ver, sizeof (pp) - sizeof (pp.pp_magic_num),
879 	    ETM_IO_OP_RD)) < 0) {
880 		errno = (-n);
881 		return (NULL);
882 	}
883 
884 	/*
885 	 * Design_Note:	The magic number was already network decoded; but
886 	 *		some other preamble fields also need to be decoded,
887 	 *		specifically pp_xid and pp_timeout. The rest of the
888 	 *		preamble fields are byte sized and hence need no
889 	 *		decoding.
890 	 */
891 
892 	pp.pp_xid = ntohl(pp.pp_xid);
893 	pp.pp_timeout = ntohl(pp.pp_timeout);
894 
895 	/* sanity check the header as best we can */
896 
897 	if ((pp.pp_proto_ver < ETM_PROTO_V1) ||
898 	    (pp.pp_proto_ver > ETM_PROTO_V3)) {
899 		fmd_hdl_error(hdl, "error: bad proto ver %d\n",
900 		    (int)pp.pp_proto_ver);
901 		errno = EPROTO;
902 		etm_stats.etm_ver_bad.fmds_value.ui64++;
903 		return (NULL);
904 	}
905 
906 	dummy_int = pp.pp_msg_type;
907 	if ((dummy_int <= ETM_MSG_TYPE_TOO_LOW) ||
908 	    (dummy_int >= ETM_MSG_TYPE_TOO_BIG)) {
909 		fmd_hdl_error(hdl, "error: bad msg type %d", dummy_int);
910 		errno = EBADMSG;
911 		etm_stats.etm_msgtype_bad.fmds_value.ui64++;
912 		return (NULL);
913 	}
914 
915 	/* handle [var sized] hdrs for FMA_EVENT, CONTROL, RESPONSE msgs */
916 
917 	if (pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
918 
919 		ev_hdrp = (void*)&misc_buf[0];
920 		hdr_sz = sizeof (*ev_hdrp);
921 		(void) memcpy(&ev_hdrp->ev_pp, &pp, sizeof (pp));
922 
923 		/* sanity check the header's timeout */
924 
925 		if ((ev_hdrp->ev_pp.pp_proto_ver == ETM_PROTO_V1) &&
926 		    (ev_hdrp->ev_pp.pp_timeout != ETM_PROTO_V1_TIMEOUT_NONE)) {
927 			errno = ETIME;
928 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
929 			return (NULL);
930 		}
931 
932 		/* get all FMA event lengths from the header */
933 
934 		lenp = (uint32_t *)&ev_hdrp->ev_lens[0]; lenp--;
935 		i = -1;	/* cnt of length entries preceding 0 */
936 		do {
937 			i++; lenp++;
938 			if ((sizeof (*ev_hdrp) + (i * sizeof (*lenp))) >=
939 			    ETM_MISC_BUF_SZ) {
940 				errno = E2BIG;	/* ridiculous size */
941 				etm_stats.etm_evlens_bad.fmds_value.ui64++;
942 				return (NULL);
943 			}
944 			if ((n = etm_io_op(hdl, "bad io read on event len",
945 			    conn, lenp, sizeof (*lenp), ETM_IO_OP_RD)) < 0) {
946 				errno = (-n);
947 				return (NULL);
948 			}
949 			*lenp = ntohl(*lenp);
950 
951 		} while (*lenp != 0);
952 		i += 0; /* first len already counted by sizeof(ev_hdr) */
953 		hdr_sz += (i * sizeof (*lenp));
954 
955 		etm_stats.etm_rd_hdr_fmaevent.fmds_value.ui64++;
956 
957 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
958 
959 		ctl_hdrp = (void*)&misc_buf[0];
960 		hdr_sz = sizeof (*ctl_hdrp);
961 		(void) memcpy(&ctl_hdrp->ctl_pp, &pp, sizeof (pp));
962 
963 		/* sanity check the header's sub type (control selector) */
964 
965 		if ((ctl_hdrp->ctl_pp.pp_sub_type <= ETM_CTL_SEL_TOO_LOW) ||
966 		    (ctl_hdrp->ctl_pp.pp_sub_type >= ETM_CTL_SEL_TOO_BIG)) {
967 			fmd_hdl_error(hdl, "error: bad ctl sub type %d\n",
968 			    (int)ctl_hdrp->ctl_pp.pp_sub_type);
969 			errno = EBADMSG;
970 			etm_stats.etm_subtype_bad.fmds_value.ui64++;
971 			return (NULL);
972 		}
973 
974 		/* get the control length */
975 
976 		if ((n = etm_io_op(hdl, "bad io read on ctl len",
977 		    conn, &ctl_hdrp->ctl_len, sizeof (ctl_hdrp->ctl_len),
978 		    ETM_IO_OP_RD)) < 0) {
979 			errno = (-n);
980 			return (NULL);
981 		}
982 
983 		ctl_hdrp->ctl_len = ntohl(ctl_hdrp->ctl_len);
984 
985 		etm_stats.etm_rd_hdr_control.fmds_value.ui64++;
986 
987 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
988 
989 		resp_hdrp = (void*)&misc_buf[0];
990 		hdr_sz = sizeof (*resp_hdrp);
991 		(void) memcpy(&resp_hdrp->resp_pp, &pp, sizeof (pp));
992 
993 		/* sanity check the header's timeout */
994 
995 		if (resp_hdrp->resp_pp.pp_timeout !=
996 		    ETM_PROTO_V1_TIMEOUT_NONE) {
997 			errno = ETIME;
998 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
999 			return (NULL);
1000 		}
1001 
1002 		/* get the response code and length */
1003 
1004 		if ((n = etm_io_op(hdl, "bad io read on resp code+len",
1005 		    conn, &resp_hdrp->resp_code,
1006 		    sizeof (resp_hdrp->resp_code)
1007 		    + sizeof (resp_hdrp->resp_len),
1008 		    ETM_IO_OP_RD)) < 0) {
1009 			errno = (-n);
1010 			return (NULL);
1011 		}
1012 
1013 		resp_hdrp->resp_code = ntohl(resp_hdrp->resp_code);
1014 		resp_hdrp->resp_len = ntohl(resp_hdrp->resp_len);
1015 
1016 		etm_stats.etm_rd_hdr_response.fmds_value.ui64++;
1017 
1018 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_ALERT) {
1019 
1020 		sa_hdrp = (void*)&misc_buf[0];
1021 		hdr_sz = sizeof (*sa_hdrp);
1022 		(void) memcpy(&sa_hdrp->sa_pp, &pp, sizeof (pp));
1023 
1024 		/* sanity check the header's protocol version */
1025 
1026 		if (sa_hdrp->sa_pp.pp_proto_ver != ETM_PROTO_V3) {
1027 			errno = EPROTO;
1028 			etm_stats.etm_ver_bad.fmds_value.ui64++;
1029 			return (NULL);
1030 		}
1031 
1032 		/* get the priority and length */
1033 
1034 		if ((n = etm_io_op(hdl, "bad io read on sa priority+len",
1035 		    conn, &sa_hdrp->sa_priority,
1036 		    sizeof (sa_hdrp->sa_priority)
1037 		    + sizeof (sa_hdrp->sa_len),
1038 		    ETM_IO_OP_RD)) < 0) {
1039 			errno = (-n);
1040 			return (NULL);
1041 		}
1042 
1043 		sa_hdrp->sa_priority = ntohl(sa_hdrp->sa_priority);
1044 		sa_hdrp->sa_len = ntohl(sa_hdrp->sa_len);
1045 
1046 		etm_stats.etm_rd_hdr_alert.fmds_value.ui64++;
1047 
1048 	} /* whether we have FMA_EVENT, ALERT, CONTROL, or RESPONSE msg */
1049 
1050 	/*
1051 	 * choose a header size that allows hdr reuse for RESPONSE msgs,
1052 	 * allocate and populate the message header, and
1053 	 * return alloc size to caller for later free of hdrp
1054 	 */
1055 
1056 	hdr_sz = MAX(hdr_sz, sizeof (*resp_hdrp));
1057 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
1058 	(void) memcpy(hdrp, misc_buf, hdr_sz);
1059 
1060 	if (etm_debug_lvl >= 3) {
1061 		fmd_hdl_debug(hdl, "info: msg hdr hexdump %d bytes:\n", hdr_sz);
1062 		etm_hexdump(hdl, hdrp, hdr_sz);
1063 	}
1064 	*szp = hdr_sz;
1065 	return (hdrp);
1066 
1067 } /* etm_hdr_read() */
1068 
1069 /*
1070  * etm_hdr_write - create and write a [variable sized] ETM message header
1071  *		to the given connection appropriate for the given FMA event
1072  *		and type of nvlist encoding,
1073  *		return the allocated ETM message header and its size
1074  *		or NULL and set errno on failure
1075  */
1076 
1077 static void*
1078 etm_hdr_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, nvlist_t *evp,
1079 						int encoding, size_t *szp)
1080 {
1081 	etm_proto_v1_ev_hdr_t	*hdrp;		/* for FMA_EVENT msg */
1082 	size_t			hdr_sz;		/* sizeof *hdrp */
1083 	uint32_t		*lenp;		/* ptr to FMA event length */
1084 	size_t			evsz;		/* packed FMA event size */
1085 	ssize_t			n;		/* gen use */
1086 
1087 	/* allocate and populate the message header for 1 FMA event */
1088 
1089 	hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0]));
1090 
1091 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
1092 
1093 	/*
1094 	 * Design_Note: Although the ETM protocol supports it, we do not (yet)
1095 	 *		want responses/ACKs on FMA events that we send. All
1096 	 *		such messages are sent with ETM_PROTO_V1_TIMEOUT_NONE.
1097 	 */
1098 
1099 	hdrp->ev_pp.pp_magic_num = ETM_PROTO_MAGIC_NUM;
1100 	hdrp->ev_pp.pp_magic_num = htonl(hdrp->ev_pp.pp_magic_num);
1101 	hdrp->ev_pp.pp_proto_ver = ETM_PROTO_V1;
1102 	hdrp->ev_pp.pp_msg_type = ETM_MSG_TYPE_FMA_EVENT;
1103 	hdrp->ev_pp.pp_sub_type = 0;
1104 	hdrp->ev_pp.pp_rsvd_pad = 0;
1105 	hdrp->ev_pp.pp_xid = etm_xid_cur;
1106 	hdrp->ev_pp.pp_xid = htonl(hdrp->ev_pp.pp_xid);
1107 	etm_xid_cur += ETM_XID_INC;
1108 	hdrp->ev_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
1109 	hdrp->ev_pp.pp_timeout = htonl(hdrp->ev_pp.pp_timeout);
1110 
1111 	lenp = &hdrp->ev_lens[0];
1112 
1113 	if ((n = nvlist_size(evp, &evsz, encoding)) != 0) {
1114 		errno = n;
1115 		fmd_hdl_free(hdl, hdrp, hdr_sz);
1116 		etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++;
1117 		return (NULL);
1118 	}
1119 
1120 	/* indicate 1 FMA event, network encode its length, and 0-terminate */
1121 
1122 	etm_stats.etm_wr_max_ev_per_msg.fmds_value.ui64 = 1;
1123 
1124 	*lenp = evsz; *lenp = htonl(*lenp); lenp++;
1125 	*lenp = 0; *lenp = htonl(*lenp); lenp++;
1126 
1127 	/*
1128 	 * write the network encoded header to the transport, and
1129 	 * return alloc size to caller for later free
1130 	 */
1131 
1132 	if ((n = etm_io_op(hdl, "bad io write on event hdr",
1133 	    conn, hdrp, hdr_sz, ETM_IO_OP_WR)) < 0) {
1134 		errno = (-n);
1135 		fmd_hdl_free(hdl, hdrp, hdr_sz);
1136 		return (NULL);
1137 	}
1138 
1139 	*szp = hdr_sz;
1140 	return (hdrp);
1141 
1142 } /* etm_hdr_write() */
1143 
1144 /*
1145  * etm_post_to_fmd - post the given FMA event to FMD
1146  *			via a FMD transport API call,
1147  *			return 0 or -errno value
1148  *
1149  * caveats:	the FMA event (evp) is freed by FMD,
1150  *		thus callers of this function should
1151  *		immediately discard any ptr they have to the
1152  *		nvlist without freeing or dereferencing it
1153  */
1154 
1155 static int
1156 etm_post_to_fmd(fmd_hdl_t *hdl, nvlist_t *evp)
1157 {
1158 	ssize_t			ev_sz;		/* sizeof *evp */
1159 
1160 	(void) nvlist_size(evp, (size_t *)&ev_sz, NV_ENCODE_XDR);
1161 
1162 	if (etm_debug_lvl >= 2) {
1163 		etm_show_time(hdl, "ante ev post");
1164 	}
1165 	fmd_xprt_post(hdl, etm_fmd_xprt, evp, 0);
1166 	etm_stats.etm_wr_fmd_fmaevent.fmds_value.ui64++;
1167 	etm_stats.etm_wr_fmd_bytes.fmds_value.ui64 += ev_sz;
1168 	if (etm_debug_lvl >= 1) {
1169 		fmd_hdl_debug(hdl, "info: event %p post ok to FMD\n", evp);
1170 	}
1171 	if (etm_debug_lvl >= 2) {
1172 		etm_show_time(hdl, "post ev post");
1173 	}
1174 	return (0);
1175 
1176 } /* etm_post_to_fmd() */
1177 
1178 /*
1179  * Ideally we would just use syslog(3C) for outputting our messages.
1180  * Unfortunately, as this module is running within the FMA daemon context,
1181  * that would create the situation where this module's openlog() would
1182  * have the monopoly on syslog(3C) for the daemon and all its modules.
1183  * To avoid that situation, this module uses the same logic as the
1184  * syslog-msgs FM module to directly call into the log(7D) and sysmsg(7D)
1185  * devices for syslog and console.
1186  */
1187 
1188 static int
1189 etm_post_to_syslog(fmd_hdl_t *hdl, uint32_t priority, uint32_t body_sz,
1190 							uint8_t *body_buf)
1191 {
1192 	char		*sysmessage;	/* Formatted message */
1193 	size_t		formatlen;	/* maximum length of sysmessage */
1194 	struct strbuf	ctl, dat;	/* structs pushed to the logfd */
1195 	uint32_t	msgid;		/* syslog message ID number */
1196 
1197 	if ((syslog_file == 0) && (syslog_cons == 0)) {
1198 		return (0);
1199 	}
1200 
1201 	if (etm_debug_lvl >= 2) {
1202 		etm_show_time(hdl, "ante syslog post");
1203 	}
1204 
1205 	formatlen = body_sz + 64; /* +64 for prefix strings added below */
1206 	sysmessage = fmd_hdl_zalloc(hdl, formatlen, FMD_SLEEP);
1207 
1208 	if (syslog_file) {
1209 		STRLOG_MAKE_MSGID(body_buf, msgid);
1210 		(void) snprintf(sysmessage, formatlen,
1211 		    "SC Alert: [ID %u FACILITY_AND_PRIORITY] %s", msgid,
1212 		    body_buf);
1213 
1214 		syslog_ctl.pri = syslog_facility | priority;
1215 
1216 		ctl.buf = (void *)&syslog_ctl;
1217 		ctl.len = sizeof (syslog_ctl);
1218 
1219 		dat.buf = sysmessage;
1220 		dat.len = strlen(sysmessage) + 1;
1221 
1222 		if (putmsg(syslog_logfd, &ctl, &dat, 0) != 0) {
1223 			fmd_hdl_debug(hdl, "putmsg failed: %s\n",
1224 			    strerror(errno));
1225 			etm_stats.etm_log_err.fmds_value.ui64++;
1226 		}
1227 	}
1228 
1229 	if (syslog_cons) {
1230 		(void) snprintf(sysmessage, formatlen,
1231 		    "SC Alert: %s\r\n", body_buf);
1232 
1233 		dat.buf = sysmessage;
1234 		dat.len = strlen(sysmessage) + 1;
1235 
1236 		if (write(syslog_msgfd, dat.buf, dat.len) != dat.len) {
1237 			fmd_hdl_debug(hdl, "write failed: %s\n",
1238 			    strerror(errno));
1239 			etm_stats.etm_msg_err.fmds_value.ui64++;
1240 		}
1241 	}
1242 
1243 	fmd_hdl_free(hdl, sysmessage, formatlen);
1244 
1245 	if (etm_debug_lvl >= 2) {
1246 		etm_show_time(hdl, "post syslog post");
1247 	}
1248 
1249 	return (0);
1250 }
1251 
1252 
1253 /*
1254  * etm_req_ver_negot - send an ETM control message to the other end requesting
1255  *			that the ETM protocol version be negotiated/set
1256  */
1257 
1258 static void
1259 etm_req_ver_negot(fmd_hdl_t *hdl)
1260 {
1261 	etm_xport_addr_t	*addrv;		/* default dst addr(s) */
1262 	etm_xport_conn_t	conn;		/* connection to other end */
1263 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1264 	size_t			hdr_sz;		/* sizeof header */
1265 	uint8_t			*body_buf;	/* msg body buffer */
1266 	uint32_t		body_sz;	/* sizeof *body_buf */
1267 	ssize_t			i;		/* gen use */
1268 
1269 	/* populate an ETM control msg to send */
1270 
1271 	hdr_sz = sizeof (*ctl_hdrp);
1272 	body_sz = (3 + 1);		/* version bytes plus null byte */
1273 
1274 	ctl_hdrp = fmd_hdl_zalloc(hdl, hdr_sz + body_sz, FMD_SLEEP);
1275 
1276 	ctl_hdrp->ctl_pp.pp_magic_num = htonl(ETM_PROTO_MAGIC_NUM);
1277 	ctl_hdrp->ctl_pp.pp_proto_ver = ETM_PROTO_V1;
1278 	ctl_hdrp->ctl_pp.pp_msg_type = ETM_MSG_TYPE_CONTROL;
1279 	ctl_hdrp->ctl_pp.pp_sub_type = ETM_CTL_SEL_VER_NEGOT_REQ;
1280 	ctl_hdrp->ctl_pp.pp_rsvd_pad = 0;
1281 	etm_xid_ver_negot = etm_xid_cur;
1282 	etm_xid_cur += ETM_XID_INC;
1283 	ctl_hdrp->ctl_pp.pp_xid = htonl(etm_xid_ver_negot);
1284 	ctl_hdrp->ctl_pp.pp_timeout = htonl(ETM_PROTO_V1_TIMEOUT_FOREVER);
1285 	ctl_hdrp->ctl_len = htonl(body_sz);
1286 
1287 	body_buf = (void*)&ctl_hdrp->ctl_len;
1288 	body_buf += sizeof (ctl_hdrp->ctl_len);
1289 	*body_buf++ = ETM_PROTO_V3;
1290 	*body_buf++ = ETM_PROTO_V2;
1291 	*body_buf++ = ETM_PROTO_V1;
1292 	*body_buf++ = '\0';
1293 
1294 	/*
1295 	 * open and close a connection to send the ETM control msg
1296 	 * to any/all of the default dst addrs
1297 	 */
1298 
1299 	if ((addrv = etm_xport_get_ev_addrv(hdl, NULL)) == NULL) {
1300 		fmd_hdl_error(hdl,
1301 		    "error: bad ctl dst addrs errno %d\n", errno);
1302 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
1303 		goto func_ret;
1304 	}
1305 
1306 	for (i = 0; addrv[i] != NULL; i++) {
1307 
1308 		if (etm_conn_open(hdl, "bad conn open during ver negot",
1309 		    addrv[i], &conn) < 0) {
1310 			continue;
1311 		}
1312 		if (etm_io_op(hdl, "bad io write on ctl hdr+body",
1313 		    conn, ctl_hdrp, hdr_sz + body_sz, ETM_IO_OP_WR) >= 0) {
1314 			etm_stats.etm_wr_hdr_control.fmds_value.ui64++;
1315 			etm_stats.etm_wr_body_control.fmds_value.ui64++;
1316 		}
1317 		(void) etm_conn_close(hdl, "bad conn close during ver negot",
1318 		    conn);
1319 
1320 	} /* foreach dst addr */
1321 
1322 func_ret:
1323 
1324 	if (addrv != NULL) {
1325 		etm_xport_free_addrv(hdl, addrv);
1326 	}
1327 	fmd_hdl_free(hdl, ctl_hdrp, hdr_sz + body_sz);
1328 
1329 } /* etm_req_ver_negot() */
1330 
1331 /*
1332  * Design_Note:	For all etm_resp_q_*() functions and etm_resp_q_* globals,
1333  *		the mutex etm_resp_q_lock must be held by the caller.
1334  */
1335 
1336 /*
1337  * etm_resp_q_enq - add element to tail of ETM responder queue
1338  * etm_resp_q_deq - del element from head of ETM responder queue
1339  *
1340  * return >0 for success, or -errno value
1341  */
1342 
1343 static int
1344 etm_resp_q_enq(fmd_hdl_t *hdl, etm_resp_q_ele_t *rqep)
1345 {
1346 	etm_resp_q_ele_t	*newp;	/* ptr to new resp q ele */
1347 
1348 	if (etm_resp_q_cur_len >= etm_resp_q_max_len) {
1349 		fmd_hdl_debug(hdl, "warning: enq to full responder queue\n");
1350 		etm_stats.etm_enq_drop_resp_q.fmds_value.ui64++;
1351 		return (-E2BIG);
1352 	}
1353 
1354 	newp = fmd_hdl_zalloc(hdl, sizeof (*newp), FMD_SLEEP);
1355 	(void) memcpy(newp, rqep, sizeof (*newp));
1356 	newp->rqe_nextp = NULL;
1357 
1358 	if (etm_resp_q_cur_len == 0) {
1359 		etm_resp_q_head = newp;
1360 	} else {
1361 		etm_resp_q_tail->rqe_nextp = newp;
1362 	}
1363 	etm_resp_q_tail = newp;
1364 	etm_resp_q_cur_len++;
1365 	etm_stats.etm_resp_q_cur_len.fmds_value.ui64 = etm_resp_q_cur_len;
1366 
1367 	return (1);
1368 
1369 } /* etm_resp_q_enq() */
1370 
1371 static int
1372 etm_resp_q_deq(fmd_hdl_t *hdl, etm_resp_q_ele_t *rqep)
1373 {
1374 	etm_resp_q_ele_t	*oldp;	/* ptr to old resp q ele */
1375 
1376 	if (etm_resp_q_cur_len == 0) {
1377 		fmd_hdl_debug(hdl, "warning: deq from empty responder queue\n");
1378 		etm_stats.etm_deq_drop_resp_q.fmds_value.ui64++;
1379 		return (-ENOENT);
1380 	}
1381 
1382 	(void) memcpy(rqep, etm_resp_q_head, sizeof (*rqep));
1383 	rqep->rqe_nextp = NULL;
1384 
1385 	oldp = etm_resp_q_head;
1386 	etm_resp_q_head = etm_resp_q_head->rqe_nextp;
1387 	fmd_hdl_free(hdl, oldp, sizeof (*oldp));
1388 
1389 	etm_resp_q_cur_len--;
1390 	etm_stats.etm_resp_q_cur_len.fmds_value.ui64 = etm_resp_q_cur_len;
1391 	if (etm_resp_q_cur_len == 0) {
1392 		etm_resp_q_tail = NULL;
1393 	}
1394 
1395 	return (1);
1396 
1397 } /* etm_resp_q_deq() */
1398 
1399 /*
1400  * etm_maybe_enq_response - check the given message header to see
1401  *				whether a response has been requested,
1402  *				if so then enqueue the given connection
1403  *				and header for later transport by the
1404  *				responder thread as an ETM response msg,
1405  *				return 0 for nop, >0 success, or -errno value
1406  */
1407 
1408 static ssize_t
1409 etm_maybe_enq_response(fmd_hdl_t *hdl, etm_xport_conn_t conn,
1410     void *hdrp, uint32_t hdr_sz, int32_t resp_code)
1411 {
1412 	ssize_t			rv;		/* ret val */
1413 	etm_proto_v1_pp_t	*ppp;		/* protocol preamble ptr */
1414 	uint8_t			orig_msg_type;	/* orig hdr's message type */
1415 	uint32_t		orig_timeout;	/* orig hdr's timeout */
1416 	etm_resp_q_ele_t	rqe;		/* responder queue ele */
1417 
1418 	ppp = hdrp;
1419 	orig_msg_type = ppp->pp_msg_type;
1420 	orig_timeout = ppp->pp_timeout;
1421 
1422 	/* bail out now if no response is to be sent */
1423 
1424 	if (orig_timeout == ETM_PROTO_V1_TIMEOUT_NONE) {
1425 		return (0);
1426 	} /* if a nop */
1427 
1428 	if ((orig_msg_type != ETM_MSG_TYPE_FMA_EVENT) &&
1429 	    (orig_msg_type != ETM_MSG_TYPE_ALERT) &&
1430 	    (orig_msg_type != ETM_MSG_TYPE_CONTROL)) {
1431 		fmd_hdl_debug(hdl, "warning: bad msg type 0x%x\n",
1432 		    orig_msg_type);
1433 		return (-EINVAL);
1434 	} /* if inappropriate hdr for a response msg */
1435 
1436 	/*
1437 	 * enqueue the msg hdr and nudge the responder thread
1438 	 * if the responder queue was previously empty
1439 	 */
1440 
1441 	rqe.rqe_conn = conn;
1442 	rqe.rqe_hdrp = hdrp;
1443 	rqe.rqe_hdr_sz = hdr_sz;
1444 	rqe.rqe_resp_code = resp_code;
1445 
1446 	(void) pthread_mutex_lock(&etm_resp_q_lock);
1447 	rv = etm_resp_q_enq(hdl, &rqe);
1448 	if (etm_resp_q_cur_len == 1)
1449 		(void) pthread_cond_signal(&etm_resp_q_cv);
1450 	(void) pthread_mutex_unlock(&etm_resp_q_lock);
1451 
1452 	return (rv);
1453 
1454 } /* etm_maybe_enq_response() */
1455 
1456 /*
1457  * Design_Note:	We rely on the fact that all message types have
1458  *		a common protocol preamble; if this fact should
1459  *		ever change it may break the code below. We also
1460  *		rely on the fact that FMA_EVENT and CONTROL headers
1461  *		returned by etm_hdr_read() will be sized large enough
1462  *		to reuse them as RESPONSE headers if the remote endpt
1463  *		asked for a response via the pp_timeout field.
1464  */
1465 
1466 /*
1467  * etm_send_response - use the given message header and response code
1468  *			to construct an appropriate response message,
1469  *			and send it back on the given connection,
1470  *			return >0 for success, or -errno value
1471  */
1472 
1473 static ssize_t
1474 etm_send_response(fmd_hdl_t *hdl, etm_xport_conn_t conn,
1475     void *hdrp, int32_t resp_code)
1476 {
1477 	ssize_t			rv;		/* ret val */
1478 	etm_proto_v1_pp_t	*ppp;		/* protocol preamble ptr */
1479 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
1480 	uint8_t			resp_body[4];	/* response body if needed */
1481 	uint8_t			*resp_msg;	/* response hdr+body */
1482 	size_t			hdr_sz;		/* sizeof response hdr */
1483 	uint8_t			orig_msg_type;	/* orig hdr's message type */
1484 
1485 	ppp = hdrp;
1486 	orig_msg_type = ppp->pp_msg_type;
1487 
1488 	if (etm_debug_lvl >= 2) {
1489 		etm_show_time(hdl, "ante resp send");
1490 	}
1491 
1492 	/* reuse the given header as a response header */
1493 
1494 	resp_hdrp = hdrp;
1495 	resp_hdrp->resp_code = resp_code;
1496 	resp_hdrp->resp_len = 0;		/* default is empty body */
1497 
1498 	if ((orig_msg_type == ETM_MSG_TYPE_CONTROL) &&
1499 	    (ppp->pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ)) {
1500 		resp_body[0] = ETM_PROTO_V2;
1501 		resp_body[1] = ETM_PROTO_V3;
1502 		resp_body[2] = 0;
1503 		resp_hdrp->resp_len = 3;
1504 	} /* if should send our/negotiated proto ver in resp body */
1505 
1506 	/* respond with the proto ver that was negotiated */
1507 
1508 	resp_hdrp->resp_pp.pp_proto_ver = etm_resp_ver;
1509 	resp_hdrp->resp_pp.pp_msg_type = ETM_MSG_TYPE_RESPONSE;
1510 	resp_hdrp->resp_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
1511 
1512 	/*
1513 	 * send the whole response msg in one write, header and body;
1514 	 * avoid the alloc-and-copy if we can reuse the hdr as the msg,
1515 	 * ie, if the body is empty. update the response stats.
1516 	 */
1517 
1518 	hdr_sz = sizeof (etm_proto_v1_resp_hdr_t);
1519 
1520 	resp_msg = hdrp;
1521 	if (resp_hdrp->resp_len > 0) {
1522 		resp_msg = fmd_hdl_zalloc(hdl, hdr_sz + resp_hdrp->resp_len,
1523 		    FMD_SLEEP);
1524 		(void) memcpy(resp_msg, resp_hdrp, hdr_sz);
1525 		(void) memcpy(resp_msg + hdr_sz, resp_body,
1526 		    resp_hdrp->resp_len);
1527 	}
1528 
1529 	(void) pthread_mutex_lock(&etm_write_lock);
1530 	rv = etm_io_op(hdl, "bad io write on resp msg", conn,
1531 	    resp_msg, hdr_sz + resp_hdrp->resp_len, ETM_IO_OP_WR);
1532 	(void) pthread_mutex_unlock(&etm_write_lock);
1533 	if (rv < 0) {
1534 		goto func_ret;
1535 	}
1536 
1537 	etm_stats.etm_wr_hdr_response.fmds_value.ui64++;
1538 	etm_stats.etm_wr_body_response.fmds_value.ui64++;
1539 
1540 	fmd_hdl_debug(hdl, "info: sent V%u RESPONSE msg to xport "
1541 	    "xid 0x%x code %d len %u\n",
1542 	    (unsigned int)resp_hdrp->resp_pp.pp_proto_ver,
1543 	    resp_hdrp->resp_pp.pp_xid, resp_hdrp->resp_code,
1544 	    resp_hdrp->resp_len);
1545 func_ret:
1546 
1547 	if (resp_hdrp->resp_len > 0) {
1548 		fmd_hdl_free(hdl, resp_msg, hdr_sz + resp_hdrp->resp_len);
1549 	}
1550 	if (etm_debug_lvl >= 2) {
1551 		etm_show_time(hdl, "post resp send");
1552 	}
1553 	return (rv);
1554 
1555 } /* etm_send_response() */
1556 
1557 /*
1558  * etm_handle_new_conn - receive an ETM message sent from the other end via
1559  *			the given open connection, pull out any FMA events
1560  *			and post them to the local FMD (or handle any ETM
1561  *			control or response msg); when done, close the
1562  *			connection
1563  */
1564 
1565 static void
1566 etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
1567 {
1568 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
1569 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1570 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
1571 	etm_proto_v3_sa_hdr_t	*sa_hdrp;	/* for ALERT msg */
1572 	int32_t			resp_code;	/* response code */
1573 	ssize_t			enq_rv;		/* resp_q enqueue status */
1574 	size_t			hdr_sz;		/* sizeof header */
1575 	uint8_t			*body_buf;	/* msg body buffer */
1576 	uint32_t		body_sz;	/* sizeof body_buf */
1577 	uint32_t		ev_cnt;		/* count of FMA events */
1578 	uint8_t			*bp;		/* byte ptr within body_buf */
1579 	nvlist_t		*evp;		/* ptr to unpacked FMA event */
1580 	char			*class;		/* FMA event class */
1581 	ssize_t			i, n;		/* gen use */
1582 
1583 	if (etm_debug_lvl >= 2) {
1584 		etm_show_time(hdl, "ante conn handle");
1585 	}
1586 	fmd_hdl_debug(hdl, "info: handling new conn %p\n", conn);
1587 
1588 	ev_hdrp = NULL;
1589 	ctl_hdrp = NULL;
1590 	resp_hdrp = NULL;
1591 	sa_hdrp = NULL;
1592 	body_buf = NULL;
1593 	class = NULL;
1594 	evp = NULL;
1595 	resp_code = 0;	/* default is success */
1596 	enq_rv = 0;	/* default is nop, ie, did not enqueue */
1597 
1598 	/* read a network decoded message header from the connection */
1599 
1600 	if ((ev_hdrp = etm_hdr_read(hdl, conn, &hdr_sz)) == NULL) {
1601 		/* errno assumed set by above call */
1602 		fmd_hdl_debug(hdl, "error: FMA event dropped: "
1603 		    "bad hdr read errno %d\n", errno);
1604 		etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1605 		goto func_ret;
1606 	}
1607 
1608 	/*
1609 	 * handle the message based on its preamble pp_msg_type
1610 	 * which is known to be valid from etm_hdr_read() checks
1611 	 */
1612 
1613 	if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
1614 
1615 		fmd_hdl_debug(hdl, "info: rcvd FMA_EVENT msg from xport\n");
1616 
1617 		/* allocate buf large enough for whole body / all FMA events */
1618 
1619 		body_sz = 0;
1620 		for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) {
1621 			body_sz += ev_hdrp->ev_lens[i];
1622 		} /* for summing sizes of all FMA events */
1623 		if (i > etm_stats.etm_rd_max_ev_per_msg.fmds_value.ui64)
1624 			etm_stats.etm_rd_max_ev_per_msg.fmds_value.ui64 = i;
1625 		ev_cnt = i;
1626 
1627 		if (etm_debug_lvl >= 1) {
1628 			fmd_hdl_debug(hdl, "info: event lengths %u sum %u\n",
1629 			    ev_cnt, body_sz);
1630 		}
1631 
1632 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1633 
1634 		/* read all the FMA events at once */
1635 
1636 		if ((n = etm_io_op(hdl, "FMA event dropped: "
1637 		    "bad io read on event bodies", conn, body_buf, body_sz,
1638 		    ETM_IO_OP_RD)) < 0) {
1639 			etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1640 			goto func_ret;
1641 		}
1642 
1643 		etm_stats.etm_rd_xport_bytes.fmds_value.ui64 += body_sz;
1644 		etm_stats.etm_rd_body_fmaevent.fmds_value.ui64 += ev_cnt;
1645 
1646 		/*
1647 		 * now that we've read the entire ETM msg from the conn,
1648 		 * which avoids later ETM protocol framing errors if we didn't,
1649 		 * check for dup msg/xid against last good FMD posting,
1650 		 * if a dup then resend response but skip repost to FMD
1651 		 */
1652 
1653 		if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_ev) {
1654 			enq_rv = etm_maybe_enq_response(hdl, conn,
1655 			    ev_hdrp, hdr_sz, 0);
1656 			fmd_hdl_debug(hdl, "info: skipping dup FMA event post "
1657 			    "xid 0x%x\n", etm_xid_posted_ev);
1658 			etm_stats.etm_rd_dup_fmaevent.fmds_value.ui64++;
1659 			goto func_ret;
1660 		}
1661 
1662 		/* unpack each FMA event and post it to FMD */
1663 
1664 		bp = body_buf;
1665 		for (i = 0; i < ev_cnt; i++) {
1666 			if ((n = nvlist_unpack((char *)bp,
1667 			    ev_hdrp->ev_lens[i], &evp, 0)) != 0) {
1668 				resp_code = (-n);
1669 				enq_rv = etm_maybe_enq_response(hdl, conn,
1670 				    ev_hdrp, hdr_sz, resp_code);
1671 				fmd_hdl_error(hdl, "error: FMA event dropped: "
1672 				    "bad event body unpack errno %d\n", n);
1673 				if (etm_debug_lvl >= 2) {
1674 					fmd_hdl_debug(hdl, "info: FMA event "
1675 					    "hexdump %d bytes:\n",
1676 					    ev_hdrp->ev_lens[i]);
1677 					etm_hexdump(hdl, bp,
1678 					    ev_hdrp->ev_lens[i]);
1679 				}
1680 				etm_stats.etm_os_nvlist_unpack_fail.fmds_value.
1681 				    ui64++;
1682 				etm_stats.etm_rd_drop_fmaevent.fmds_value.
1683 				    ui64++;
1684 				bp += ev_hdrp->ev_lens[i];
1685 				continue;
1686 			}
1687 			if (etm_debug_lvl >= 1) {
1688 				(void) nvlist_lookup_string(evp, FM_CLASS,
1689 				    &class);
1690 				if (class == NULL) {
1691 					class = "NULL";
1692 				}
1693 				fmd_hdl_debug(hdl, "info: FMA event %p "
1694 				    "class %s\n", evp, class);
1695 			}
1696 			resp_code = etm_post_to_fmd(hdl, evp);
1697 			if (resp_code >= 0) {
1698 				etm_xid_posted_ev = ev_hdrp->ev_pp.pp_xid;
1699 			}
1700 			evp = NULL;
1701 			enq_rv = etm_maybe_enq_response(hdl, conn,
1702 			    ev_hdrp, hdr_sz, resp_code);
1703 			bp += ev_hdrp->ev_lens[i];
1704 		} /* foreach FMA event in the body buffer */
1705 
1706 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
1707 
1708 		ctl_hdrp = (void*)ev_hdrp;
1709 
1710 		fmd_hdl_debug(hdl, "info: rcvd CONTROL msg from xport\n");
1711 		if (etm_debug_lvl >= 1) {
1712 			fmd_hdl_debug(hdl, "info: ctl sel %d xid 0x%x\n",
1713 			    (int)ctl_hdrp->ctl_pp.pp_sub_type,
1714 			    ctl_hdrp->ctl_pp.pp_xid);
1715 		}
1716 
1717 		/*
1718 		 * if we have a VER_NEGOT_REQ read the body and validate
1719 		 * the protocol version set contained therein,
1720 		 * otherwise we have a PING_REQ (which has no body)
1721 		 * and we [also] fall thru to the code which sends a
1722 		 * response msg if the pp_timeout field requested one
1723 		 */
1724 
1725 		if (ctl_hdrp->ctl_pp.pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ) {
1726 
1727 			body_sz = ctl_hdrp->ctl_len;
1728 			body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1729 
1730 			if ((n = etm_io_op(hdl, "bad io read on ctl body",
1731 			    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
1732 				goto func_ret;
1733 			}
1734 
1735 			/* complain if version set completely incompatible */
1736 
1737 			for (i = 0; i < body_sz; i++) {
1738 				if ((body_buf[i] == ETM_PROTO_V1) ||
1739 				    (body_buf[i] == ETM_PROTO_V2) ||
1740 				    (body_buf[i] == ETM_PROTO_V3)) {
1741 					break;
1742 				}
1743 			}
1744 			if (i >= body_sz) {
1745 				etm_stats.etm_ver_bad.fmds_value.ui64++;
1746 				resp_code = (-EPROTO);
1747 			}
1748 
1749 		} /* if got version set request */
1750 
1751 		etm_stats.etm_rd_body_control.fmds_value.ui64++;
1752 
1753 		enq_rv = etm_maybe_enq_response(hdl, conn,
1754 		    ctl_hdrp, hdr_sz, resp_code);
1755 
1756 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
1757 
1758 		resp_hdrp = (void*)ev_hdrp;
1759 
1760 		fmd_hdl_debug(hdl, "info: rcvd RESPONSE msg from xport\n");
1761 		if (etm_debug_lvl >= 1) {
1762 			fmd_hdl_debug(hdl, "info: resp xid 0x%x\n",
1763 			    (int)resp_hdrp->resp_pp.pp_xid);
1764 		}
1765 
1766 		body_sz = resp_hdrp->resp_len;
1767 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1768 
1769 		if ((n = etm_io_op(hdl, "bad io read on resp len",
1770 		    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
1771 			goto func_ret;
1772 		}
1773 
1774 		etm_stats.etm_rd_body_response.fmds_value.ui64++;
1775 
1776 		/*
1777 		 * look up the xid to interpret the response body
1778 		 *
1779 		 * ping is a nop; for ver negot confirm that a supported
1780 		 * protocol version was negotiated and remember which one
1781 		 */
1782 
1783 		if ((resp_hdrp->resp_pp.pp_xid != etm_xid_ping) &&
1784 		    (resp_hdrp->resp_pp.pp_xid != etm_xid_ver_negot)) {
1785 			etm_stats.etm_xid_bad.fmds_value.ui64++;
1786 			goto func_ret;
1787 		}
1788 
1789 		if (resp_hdrp->resp_pp.pp_xid == etm_xid_ver_negot) {
1790 			if ((body_buf[0] < ETM_PROTO_V1) ||
1791 			    (body_buf[0] > ETM_PROTO_V3)) {
1792 				etm_stats.etm_ver_bad.fmds_value.ui64++;
1793 				goto func_ret;
1794 			}
1795 			etm_resp_ver = body_buf[0];
1796 		} /* if have resp to last req to negotiate proto ver */
1797 
1798 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_ALERT) {
1799 
1800 		sa_hdrp = (void*)ev_hdrp;
1801 
1802 		fmd_hdl_debug(hdl, "info: rcvd ALERT msg from xport\n");
1803 		if (etm_debug_lvl >= 1) {
1804 			fmd_hdl_debug(hdl, "info: sa sel %d xid 0x%x\n",
1805 			    (int)sa_hdrp->sa_pp.pp_sub_type,
1806 			    sa_hdrp->sa_pp.pp_xid);
1807 		}
1808 
1809 		body_sz = sa_hdrp->sa_len;
1810 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1811 
1812 		if ((n = etm_io_op(hdl, "bad io read on sa body",
1813 		    conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
1814 			goto func_ret;
1815 		}
1816 
1817 		etm_stats.etm_rd_body_alert.fmds_value.ui64++;
1818 
1819 		/*
1820 		 * now that we've read the entire ETM msg from the conn,
1821 		 * which avoids later ETM protocol framing errors if we didn't,
1822 		 * check for dup msg/xid against last good syslog posting,
1823 		 * if a dup then resend response but skip repost to syslog
1824 		 */
1825 
1826 		if (sa_hdrp->sa_pp.pp_xid == etm_xid_posted_sa) {
1827 			enq_rv = etm_maybe_enq_response(hdl, conn,
1828 			    sa_hdrp, hdr_sz, 0);
1829 			fmd_hdl_debug(hdl, "info: skipping dup ALERT post "
1830 			    "xid 0x%x\n", etm_xid_posted_sa);
1831 			etm_stats.etm_rd_dup_alert.fmds_value.ui64++;
1832 			goto func_ret;
1833 		}
1834 
1835 		resp_code = etm_post_to_syslog(hdl, sa_hdrp->sa_priority,
1836 		    body_sz, body_buf);
1837 		if (resp_code >= 0) {
1838 			etm_xid_posted_sa = sa_hdrp->sa_pp.pp_xid;
1839 		}
1840 		enq_rv = etm_maybe_enq_response(hdl, conn,
1841 		    sa_hdrp, hdr_sz, resp_code);
1842 	} /* whether we have a FMA_EVENT, CONTROL, RESPONSE or ALERT msg */
1843 
1844 func_ret:
1845 
1846 	if (etm_debug_lvl >= 2) {
1847 		etm_show_time(hdl, "post conn handle");
1848 	}
1849 
1850 	/*
1851 	 * if no responder ele was enqueued, close the conn now
1852 	 * and free the ETM msg hdr; the ETM msg body is not needed
1853 	 * by the responder thread and should always be freed here
1854 	 */
1855 
1856 	if (enq_rv <= 0) {
1857 		(void) etm_conn_close(hdl, "bad conn close after msg recv",
1858 		    conn);
1859 		if (ev_hdrp != NULL) {
1860 			fmd_hdl_free(hdl, ev_hdrp, hdr_sz);
1861 		}
1862 	}
1863 	if (body_buf != NULL) {
1864 		fmd_hdl_free(hdl, body_buf, body_sz);
1865 	}
1866 } /* etm_handle_new_conn() */
1867 
1868 /*
1869  * etm_server - loop forever accepting new connections
1870  *		using the given FMD handle,
1871  *		handling any ETM msgs sent from the other side
1872  *		via each such connection
1873  */
1874 
1875 static void
1876 etm_server(void *arg)
1877 {
1878 	etm_xport_conn_t	conn;		/* connection handle */
1879 	ssize_t			n;		/* gen use */
1880 	fmd_hdl_t		*hdl;		/* FMD handle */
1881 
1882 	hdl = arg;
1883 
1884 	fmd_hdl_debug(hdl, "info: connection server starting\n");
1885 
1886 	while (!etm_is_dying) {
1887 
1888 		if ((conn = etm_xport_accept(hdl, NULL)) == NULL) {
1889 			/* errno assumed set by above call */
1890 			n = errno;
1891 			if (etm_is_dying) {
1892 				break;
1893 			}
1894 			fmd_hdl_debug(hdl,
1895 			    "error: bad conn accept errno %d\n", n);
1896 			etm_stats.etm_xport_accept_fail.fmds_value.ui64++;
1897 			/* avoid spinning CPU */
1898 			(void) etm_sleep(ETM_SLEEP_SLOW);
1899 			continue;
1900 		}
1901 
1902 		/* handle the new message/connection, closing it when done */
1903 
1904 		etm_handle_new_conn(hdl, conn);
1905 
1906 	} /* while accepting new connections until ETM dies */
1907 
1908 	/* ETM is dying (probably due to "fmadm unload etm") */
1909 
1910 	fmd_hdl_debug(hdl, "info: connection server is dying\n");
1911 
1912 } /* etm_server() */
1913 
1914 /*
1915  * etm_responder - loop forever waiting for new responder queue elements
1916  *		to be enqueued, for each one constructing and sending
1917  *		an ETM response msg to the other side, and closing its
1918  *		associated connection when appropriate
1919  *
1920  *	this thread exists to ensure that the etm_server() thread
1921  *	never pends indefinitely waiting on the xport write lock, and is
1922  *	hence always available to accept new connections and handle
1923  *	incoming messages
1924  *
1925  *	this design relies on the fact that each connection accepted and
1926  *	returned by the ETM xport layer is unique, and each can be closed
1927  *	independently of the others while multiple connections are
1928  *	outstanding
1929  */
1930 
1931 static void
1932 etm_responder(void *arg)
1933 {
1934 	ssize_t			n;		/* gen use */
1935 	fmd_hdl_t		*hdl;		/* FMD handle */
1936 	etm_resp_q_ele_t	rqe;		/* responder queue ele */
1937 
1938 	hdl = arg;
1939 
1940 	fmd_hdl_debug(hdl, "info: responder server starting\n");
1941 
1942 	while (!etm_is_dying) {
1943 
1944 		(void) pthread_mutex_lock(&etm_resp_q_lock);
1945 
1946 		while (etm_resp_q_cur_len == 0) {
1947 			(void) pthread_cond_wait(&etm_resp_q_cv,
1948 			    &etm_resp_q_lock);
1949 			if (etm_is_dying) {
1950 				(void) pthread_mutex_unlock(&etm_resp_q_lock);
1951 				goto func_ret;
1952 			}
1953 		} /* while the responder queue is empty, wait to be nudged */
1954 
1955 		/*
1956 		 * for every responder ele that has been enqueued,
1957 		 * dequeue and send it as an ETM response msg,
1958 		 * closing its associated conn and freeing its hdr
1959 		 *
1960 		 * enter the queue draining loop holding the responder
1961 		 * queue lock, but do not hold the lock indefinitely
1962 		 * (the actual send may pend us indefinitely),
1963 		 * so that other threads will never pend for long
1964 		 * trying to enqueue a new element
1965 		 */
1966 
1967 		while (etm_resp_q_cur_len > 0) {
1968 
1969 			(void) etm_resp_q_deq(hdl, &rqe);
1970 			(void) pthread_mutex_unlock(&etm_resp_q_lock);
1971 
1972 			if ((n = etm_send_response(hdl, rqe.rqe_conn,
1973 			    rqe.rqe_hdrp, rqe.rqe_resp_code)) < 0) {
1974 				fmd_hdl_error(hdl, "error: bad resp send "
1975 				    "errno %d\n", (-n));
1976 			}
1977 
1978 			(void) etm_conn_close(hdl, "bad conn close after resp",
1979 			    rqe.rqe_conn);
1980 			fmd_hdl_free(hdl, rqe.rqe_hdrp, rqe.rqe_hdr_sz);
1981 
1982 			if (etm_is_dying) {
1983 				goto func_ret;
1984 			}
1985 			(void) pthread_mutex_lock(&etm_resp_q_lock);
1986 
1987 		} /* while draining the responder queue */
1988 
1989 		(void) pthread_mutex_unlock(&etm_resp_q_lock);
1990 
1991 	} /* while awaiting and sending resp msgs until ETM dies */
1992 
1993 func_ret:
1994 
1995 	/* ETM is dying (probably due to "fmadm unload etm") */
1996 
1997 	fmd_hdl_debug(hdl, "info: responder server is dying\n");
1998 
1999 	(void) pthread_mutex_lock(&etm_resp_q_lock);
2000 	if (etm_resp_q_cur_len > 0) {
2001 		fmd_hdl_error(hdl, "warning: %d response msgs dropped\n",
2002 		    (int)etm_resp_q_cur_len);
2003 		while (etm_resp_q_cur_len > 0) {
2004 			(void) etm_resp_q_deq(hdl, &rqe);
2005 			(void) etm_conn_close(hdl, "bad conn close after deq",
2006 			    rqe.rqe_conn);
2007 			fmd_hdl_free(hdl, rqe.rqe_hdrp, rqe.rqe_hdr_sz);
2008 		}
2009 	}
2010 	(void) pthread_mutex_unlock(&etm_resp_q_lock);
2011 
2012 } /* etm_responder() */
2013 
2014 static void *
2015 etm_init_alloc(size_t size)
2016 {
2017 	return (fmd_hdl_alloc(init_hdl, size, FMD_SLEEP));
2018 }
2019 
2020 static void
2021 etm_init_free(void *addr, size_t size)
2022 {
2023 	fmd_hdl_free(init_hdl, addr, size);
2024 }
2025 
2026 /*
2027  * -------------------------- FMD entry points -------------------------------
2028  */
2029 
2030 /*
2031  * _fmd_init - initialize the transport for use by ETM and start the
2032  *		server daemon to accept new connections to us
2033  *
2034  *		FMD will read our *.conf and subscribe us to FMA events
2035  */
2036 
2037 void
2038 _fmd_init(fmd_hdl_t *hdl)
2039 {
2040 	struct timeval		tmv;		/* timeval */
2041 	ssize_t			n;		/* gen use */
2042 	ldom_hdl_t		*lhp;		/* ldom pointer */
2043 	const struct facility	*fp;		/* syslog facility matching */
2044 	char			*facname;	/* syslog facility property */
2045 
2046 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
2047 		return; /* invalid data in configuration file */
2048 	}
2049 
2050 	fmd_hdl_debug(hdl, "info: module initializing\n");
2051 
2052 	init_hdl = hdl;
2053 	lhp = ldom_init(etm_init_alloc, etm_init_free);
2054 
2055 	/*
2056 	 * Do not load this module if it is runing on a guest ldom.
2057 	 */
2058 	if (ldom_major_version(lhp) == 1 && ldom_on_service(lhp) == 0) {
2059 		fmd_hdl_debug(hdl, "info: module unregistering\n");
2060 		ldom_fini(lhp);
2061 		fmd_hdl_unregister(hdl);
2062 		return;
2063 	} else {
2064 		ldom_fini(lhp);
2065 	}
2066 
2067 	/* setup statistics and properties from FMD */
2068 
2069 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
2070 	    sizeof (etm_stats) / sizeof (fmd_stat_t), (fmd_stat_t *)&etm_stats);
2071 
2072 	etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
2073 	etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl,
2074 	    ETM_PROP_NM_DEBUG_MAX_EV_CNT);
2075 	fmd_hdl_debug(hdl, "info: etm_debug_lvl %d "
2076 	    "etm_debug_max_ev_cnt %d\n", etm_debug_lvl, etm_debug_max_ev_cnt);
2077 
2078 	etm_resp_q_max_len = fmd_prop_get_int32(hdl,
2079 	    ETM_PROP_NM_MAX_RESP_Q_LEN);
2080 	etm_stats.etm_resp_q_max_len.fmds_value.ui64 = etm_resp_q_max_len;
2081 
2082 	/* obtain an FMD transport handle so we can post FMA events later */
2083 
2084 	etm_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
2085 
2086 	/* encourage protocol transaction id to be unique per module load */
2087 
2088 	(void) gettimeofday(&tmv, NULL);
2089 	etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) |
2090 	    ((unsigned long)tmv.tv_usec >> 10));
2091 
2092 	/* init the ETM transport */
2093 
2094 	if ((n = etm_xport_init(hdl)) != 0) {
2095 		fmd_hdl_error(hdl, "error: bad xport init errno %d\n", (-n));
2096 		fmd_hdl_unregister(hdl);
2097 		return;
2098 	}
2099 
2100 	/*
2101 	 * Cache any properties we use every time we receive an alert.
2102 	 */
2103 	syslog_file = fmd_prop_get_int32(hdl, ETM_PROP_NM_SYSLOGD);
2104 	syslog_cons = fmd_prop_get_int32(hdl, ETM_PROP_NM_CONSOLE);
2105 
2106 	if (syslog_file && (syslog_logfd = open("/dev/conslog",
2107 	    O_WRONLY | O_NOCTTY)) == -1) {
2108 		fmd_hdl_error(hdl, "error: failed to open /dev/conslog");
2109 		syslog_file = 0;
2110 	}
2111 
2112 	if (syslog_cons && (syslog_msgfd = open("/dev/sysmsg",
2113 	    O_WRONLY | O_NOCTTY)) == -1) {
2114 		fmd_hdl_error(hdl, "error: failed to open /dev/sysmsg");
2115 		syslog_cons = 0;
2116 	}
2117 
2118 	if (syslog_file) {
2119 		/*
2120 		 * Look up the value of the "facility" property and use it to
2121 		 * determine * what syslog LOG_* facility value we use to
2122 		 * fill in our log_ctl_t.
2123 		 */
2124 		facname = fmd_prop_get_string(hdl, ETM_PROP_NM_FACILITY);
2125 
2126 		for (fp = syslog_facs; fp->fac_name != NULL; fp++) {
2127 			if (strcmp(fp->fac_name, facname) == 0)
2128 				break;
2129 		}
2130 
2131 		if (fp->fac_name == NULL) {
2132 			fmd_hdl_error(hdl, "error: invalid 'facility'"
2133 			    " setting: %s\n", facname);
2134 			syslog_file = 0;
2135 		} else {
2136 			syslog_facility = fp->fac_value;
2137 			syslog_ctl.flags = SL_CONSOLE | SL_LOGONLY;
2138 		}
2139 
2140 		fmd_prop_free_string(hdl, facname);
2141 	}
2142 
2143 	/*
2144 	 * start the message responder and the connection acceptance server;
2145 	 * request protocol version be negotiated after waiting a second
2146 	 * for the receiver to be ready to start handshaking
2147 	 */
2148 
2149 	etm_resp_tid = fmd_thr_create(hdl, etm_responder, hdl);
2150 	etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl);
2151 
2152 	(void) etm_sleep(ETM_SLEEP_QUIK);
2153 	etm_req_ver_negot(hdl);
2154 
2155 	fmd_hdl_debug(hdl, "info: module initialized ok\n");
2156 
2157 } /* _fmd_init() */
2158 
2159 /*
2160  * etm_recv - receive an FMA event from FMD and transport it
2161  *		to the remote endpoint
2162  */
2163 
2164 /*ARGSUSED*/
2165 void
2166 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
2167 {
2168 	etm_xport_addr_t	*addrv;	/* vector of transport addresses */
2169 	etm_xport_conn_t	conn;	/* connection handle */
2170 	etm_proto_v1_ev_hdr_t	*hdrp;	/* for FMA_EVENT msg */
2171 	ssize_t			i, n;	/* gen use */
2172 	size_t			sz;	/* header size */
2173 	size_t			buflen;	/* size of packed FMA event */
2174 	uint8_t			*buf;	/* tmp buffer for packed FMA event */
2175 
2176 	buflen = 0;
2177 	if ((n = nvlist_size(evp, &buflen, NV_ENCODE_XDR)) != 0) {
2178 		fmd_hdl_error(hdl, "error: FMA event dropped: "
2179 		    "event size errno %d class %s\n", n, class);
2180 		etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++;
2181 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2182 		return;
2183 	}
2184 
2185 	fmd_hdl_debug(hdl, "info: rcvd event %p from FMD\n", evp);
2186 	fmd_hdl_debug(hdl, "info: cnt %llu class %s\n",
2187 	    etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64, class);
2188 
2189 	etm_stats.etm_rd_fmd_bytes.fmds_value.ui64 += buflen;
2190 	etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64++;
2191 
2192 	/*
2193 	 * if the debug limit has been set, avoid excessive traffic,
2194 	 * for example, an infinite cycle using loopback nodes
2195 	 */
2196 
2197 	if ((etm_debug_max_ev_cnt >= 0) &&
2198 	    (etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64 >
2199 	    etm_debug_max_ev_cnt)) {
2200 		fmd_hdl_debug(hdl, "warning: FMA event dropped: "
2201 		    "event %p cnt %llu > debug max %d\n", evp,
2202 		    etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64,
2203 		    etm_debug_max_ev_cnt);
2204 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2205 		return;
2206 	}
2207 
2208 	/* allocate a buffer for the FMA event and nvlist pack it */
2209 
2210 	buf = fmd_hdl_zalloc(hdl, buflen, FMD_SLEEP);
2211 
2212 	if ((n = nvlist_pack(evp, (char **)&buf, &buflen,
2213 	    NV_ENCODE_XDR, 0)) != 0) {
2214 		fmd_hdl_error(hdl, "error: FMA event dropped: "
2215 		    "event pack errno %d class %s\n", n, class);
2216 		etm_stats.etm_os_nvlist_pack_fail.fmds_value.ui64++;
2217 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2218 		fmd_hdl_free(hdl, buf, buflen);
2219 		return;
2220 	}
2221 
2222 	/* get vector of dst addrs and send the FMA event to each one */
2223 
2224 	if ((addrv = etm_xport_get_ev_addrv(hdl, evp)) == NULL) {
2225 		fmd_hdl_error(hdl, "error: FMA event dropped: "
2226 		    "bad event dst addrs errno %d\n", errno);
2227 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
2228 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2229 		fmd_hdl_free(hdl, buf, buflen);
2230 		return;
2231 	}
2232 
2233 	for (i = 0; addrv[i] != NULL; i++) {
2234 
2235 		/* open a new connection to this dst addr */
2236 
2237 		if ((n = etm_conn_open(hdl, "FMA event dropped: "
2238 		    "bad conn open on new ev", addrv[i], &conn)) < 0) {
2239 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2240 			continue;
2241 		}
2242 
2243 		(void) pthread_mutex_lock(&etm_write_lock);
2244 
2245 		/* write the ETM message header */
2246 
2247 		if ((hdrp = etm_hdr_write(hdl, conn, evp, NV_ENCODE_XDR,
2248 		    &sz)) == NULL) {
2249 			(void) pthread_mutex_unlock(&etm_write_lock);
2250 			fmd_hdl_error(hdl, "error: FMA event dropped: "
2251 			    "bad hdr write errno %d\n", errno);
2252 			(void) etm_conn_close(hdl,
2253 			    "bad conn close per bad hdr wr", conn);
2254 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2255 			continue;
2256 		}
2257 
2258 		fmd_hdl_free(hdl, hdrp, sz);	/* header not needed */
2259 		etm_stats.etm_wr_hdr_fmaevent.fmds_value.ui64++;
2260 		fmd_hdl_debug(hdl, "info: hdr xport write ok for event %p\n",
2261 		    evp);
2262 
2263 		/* write the ETM message body, ie, the packed nvlist */
2264 
2265 		if ((n = etm_io_op(hdl, "FMA event dropped: "
2266 		    "bad io write on event", conn,
2267 		    buf, buflen, ETM_IO_OP_WR)) < 0) {
2268 			(void) pthread_mutex_unlock(&etm_write_lock);
2269 			(void) etm_conn_close(hdl,
2270 			    "bad conn close per bad body wr", conn);
2271 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
2272 			continue;
2273 		}
2274 
2275 		(void) pthread_mutex_unlock(&etm_write_lock);
2276 
2277 		etm_stats.etm_wr_body_fmaevent.fmds_value.ui64++;
2278 		etm_stats.etm_wr_xport_bytes.fmds_value.ui64 += buflen;
2279 		fmd_hdl_debug(hdl, "info: body xport write ok for event %p\n",
2280 		    evp);
2281 
2282 		/* close the connection */
2283 
2284 		(void) etm_conn_close(hdl, "bad conn close after event send",
2285 		    conn);
2286 	} /* foreach dst addr in the vector */
2287 
2288 	etm_xport_free_addrv(hdl, addrv);
2289 	fmd_hdl_free(hdl, buf, buflen);
2290 
2291 } /* etm_recv() */
2292 
2293 /*
2294  * _fmd_fini - stop the server daemon and teardown the transport
2295  */
2296 
2297 void
2298 _fmd_fini(fmd_hdl_t *hdl)
2299 {
2300 	ssize_t	n;	/* gen use */
2301 
2302 	fmd_hdl_debug(hdl, "info: module finalizing\n");
2303 
2304 	/* kill the connection server and responder ; wait for them to die */
2305 
2306 	etm_is_dying = 1;
2307 
2308 	if (etm_svr_tid != NULL) {
2309 		fmd_thr_signal(hdl, etm_svr_tid);
2310 		fmd_thr_destroy(hdl, etm_svr_tid);
2311 		etm_svr_tid = NULL;
2312 	} /* if server thread was successfully created */
2313 
2314 	if (etm_resp_tid != NULL) {
2315 		fmd_thr_signal(hdl, etm_resp_tid);
2316 		fmd_thr_destroy(hdl, etm_resp_tid);
2317 		etm_resp_tid = NULL;
2318 	} /* if responder thread was successfully created */
2319 
2320 	/* teardown the transport and cleanup syslogging */
2321 
2322 	if ((n = etm_xport_fini(hdl)) != 0) {
2323 		fmd_hdl_error(hdl, "warning: xport fini errno %d\n", (-n));
2324 	}
2325 	if (etm_fmd_xprt != NULL) {
2326 		fmd_xprt_close(hdl, etm_fmd_xprt);
2327 	}
2328 
2329 	if (syslog_logfd != -1) {
2330 		(void) close(syslog_logfd);
2331 	}
2332 	if (syslog_msgfd != -1) {
2333 		(void) close(syslog_msgfd);
2334 	}
2335 
2336 	fmd_hdl_debug(hdl, "info: module finalized ok\n");
2337 
2338 } /* _fmd_fini() */
2339