xref: /titanic_50/usr/src/cmd/fm/modules/sun4v/etm/etm.c (revision 66f9d5cb3cc0652e2d9d1366fb950efbe4ca2f24)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*
29  * etm.c	FMA Event Transport Module implementation, a plugin of FMD
30  *		for sun4v/Ontario
31  *
32  * plugin for sending/receiving FMA events to/from service processor
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * --------------------------------- includes --------------------------------
39  */
40 
41 #include <sys/fm/protocol.h>
42 #include <sys/sysevent/eventdefs.h>
43 #include <sys/fm/util.h>
44 #include <netinet/in.h>
45 #include <fm/fmd_api.h>
46 #include <libsysevent.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 };
84 
85 static const fmd_prop_t fmd_props[] = {
86 	{ ETM_PROP_NM_XPORT_ADDRS,	FMD_TYPE_STRING, "" },
87 	{ ETM_PROP_NM_DEBUG_LVL,	FMD_TYPE_INT32, "0" },
88 	{ ETM_PROP_NM_DEBUG_MAX_EV_CNT,	FMD_TYPE_INT32, "-1" },
89 	{ NULL, 0, NULL }
90 };
91 
92 static const fmd_hdl_info_t fmd_info = {
93 	"FMA Event Transport Module", "1.0", &fmd_ops, fmd_props
94 };
95 
96 /*
97  * ----------------------- private consts and defns --------------------------
98  */
99 
100 /* misc buffer for variable sized protocol header fields */
101 
102 #define	ETM_MISC_BUF_SZ	(4 * 1024)
103 
104 /* try limit for IO operations w/ capped exp backoff sleep on retry */
105 
106 /*
107  * Design_Note:	ETM will potentially retry forever IO operations that the
108  *		transport fails with EAGAIN (aka EWOULDBLOCK) rather than
109  *		giving up after some number of seconds. This avoids
110  *		dropping FMA events while the service processor is down,
111  *		but at the risk of pending fmdo_recv() forever and
112  *		overflowing FMD's event queue for ETM.
113  *		A future TBD enhancement would be to always recv
114  *		and send each ETM msg in a single read/write() to reduce
115  *		the risk of failure between ETM msg hdr and body,
116  *		assuming the MTU_SZ is large enough.
117  */
118 
119 #define	ETM_TRY_MAX_CNT		(MAXINT - 1)
120 #define	ETM_TRY_BACKOFF_RATE	(4)
121 #define	ETM_TRY_BACKOFF_CAP	(60)
122 
123 /* amount to increment protocol transaction id on each new send */
124 
125 #define	ETM_XID_INC	(2)
126 
127 /*
128  * ---------------------------- global data ----------------------------------
129  */
130 
131 static int
132 etm_debug_lvl = 0;	/* debug level: 0 is off, 1 is on, 2 is more, etc */
133 
134 static int
135 etm_debug_max_ev_cnt = -1; /* max allowed event count for debugging */
136 
137 static pthread_t
138 etm_svr_tid = NULL;	/* thread id of connection acceptance server */
139 
140 static volatile int
141 etm_is_dying = 0;	/* bool for dying (killing self) */
142 
143 static uint32_t
144 etm_xid_cur = 0;	/* current transaction id for sends */
145 
146 static uint32_t
147 etm_xid_ping = 0;	/* xid of last CONTROL msg sent requesting ping */
148 
149 static uint32_t
150 etm_xid_ver_negot = 0;	/* xid of last CONTROL msg sent requesting ver negot */
151 
152 static uint32_t
153 etm_xid_posted_ev = 0;	/* xid of last FMA_EVENT msg/event posted OK to FMD */
154 
155 static uint8_t
156 etm_resp_ver = ETM_PROTO_V1; /* proto ver [negotiated] for msg sends */
157 
158 static struct stats {
159 
160 	/* ETM msg counters */
161 
162 	fmd_stat_t etm_rd_hdr_fmaevent;
163 	fmd_stat_t etm_rd_hdr_control;
164 	fmd_stat_t etm_rd_hdr_response;
165 	fmd_stat_t etm_rd_body_fmaevent;
166 	fmd_stat_t etm_rd_body_control;
167 	fmd_stat_t etm_rd_body_response;
168 	fmd_stat_t etm_wr_hdr_fmaevent;
169 	fmd_stat_t etm_wr_hdr_control;
170 	fmd_stat_t etm_wr_hdr_response;
171 	fmd_stat_t etm_wr_body_fmaevent;
172 	fmd_stat_t etm_wr_body_control;
173 	fmd_stat_t etm_wr_body_response;
174 
175 	/* ETM byte counters */
176 
177 	fmd_stat_t etm_wr_fmd_bytes;
178 	fmd_stat_t etm_rd_fmd_bytes;
179 	fmd_stat_t etm_wr_xport_bytes;
180 	fmd_stat_t etm_rd_xport_bytes;
181 
182 	fmd_stat_t etm_magic_drop_bytes;
183 
184 	/* ETM [dropped] FMA event counters */
185 
186 	fmd_stat_t etm_rd_fmd_fmaevent;
187 	fmd_stat_t etm_wr_fmd_fmaevent;
188 
189 	fmd_stat_t etm_rd_drop_fmaevent;
190 	fmd_stat_t etm_wr_drop_fmaevent;
191 
192 	fmd_stat_t etm_rd_dup_fmaevent;
193 	fmd_stat_t etm_wr_dup_fmaevent;
194 
195 	/* ETM protocol failures */
196 
197 	fmd_stat_t etm_magic_bad;
198 	fmd_stat_t etm_ver_bad;
199 	fmd_stat_t etm_msgtype_bad;
200 	fmd_stat_t etm_subtype_bad;
201 	fmd_stat_t etm_xid_bad;
202 	fmd_stat_t etm_fmaeventlen_bad;
203 	fmd_stat_t etm_respcode_bad;
204 	fmd_stat_t etm_timeout_bad;
205 	fmd_stat_t etm_evlens_bad;
206 
207 	/* IO operation failures */
208 
209 	fmd_stat_t etm_xport_wr_fail;
210 	fmd_stat_t etm_xport_rd_fail;
211 	fmd_stat_t etm_xport_pk_fail;
212 
213 	/* IO operation retries */
214 
215 	fmd_stat_t etm_xport_wr_retry;
216 	fmd_stat_t etm_xport_rd_retry;
217 	fmd_stat_t etm_xport_pk_retry;
218 
219 	/* system and library failures */
220 
221 	fmd_stat_t etm_os_sysevent_publish_fail;
222 	fmd_stat_t etm_os_sysevent_bind_fail;
223 	fmd_stat_t etm_os_nvlist_pack_fail;
224 	fmd_stat_t etm_os_nvlist_unpack_fail;
225 	fmd_stat_t etm_os_nvlist_size_fail;
226 	fmd_stat_t etm_os_pthread_create_fail;
227 
228 	/* xport API failures */
229 
230 	fmd_stat_t etm_xport_get_ev_addrv_fail;
231 	fmd_stat_t etm_xport_open_fail;
232 	fmd_stat_t etm_xport_close_fail;
233 	fmd_stat_t etm_xport_accept_fail;
234 	fmd_stat_t etm_xport_open_retry;
235 
236 	/* FMD entry point bad arguments */
237 
238 	fmd_stat_t etm_fmd_recv_badargs;
239 	fmd_stat_t etm_fmd_init_badargs;
240 	fmd_stat_t etm_fmd_fini_badargs;
241 
242 } etm_stats = {
243 
244 	/* ETM msg counters */
245 
246 	{ "etm_rd_hdr_fmaevent", FMD_TYPE_UINT64,
247 		"ETM fmaevent msg headers rcvd from xport" },
248 	{ "etm_rd_hdr_control", FMD_TYPE_UINT64,
249 		"ETM control msg headers rcvd from xport" },
250 	{ "etm_rd_hdr_response", FMD_TYPE_UINT64,
251 		"ETM response msg headers rcvd from xport" },
252 	{ "etm_rd_body_fmaevent", FMD_TYPE_UINT64,
253 		"ETM fmaevent msg bodies rcvd from xport" },
254 	{ "etm_rd_body_control", FMD_TYPE_UINT64,
255 		"ETM control msg bodies rcvd from xport" },
256 	{ "etm_rd_body_response", FMD_TYPE_UINT64,
257 		"ETM response msg bodies rcvd from xport" },
258 	{ "etm_wr_hdr_fmaevent", FMD_TYPE_UINT64,
259 		"ETM fmaevent msg headers sent to xport" },
260 	{ "etm_wr_hdr_control", FMD_TYPE_UINT64,
261 		"ETM control msg headers sent to xport" },
262 	{ "etm_wr_hdr_response", FMD_TYPE_UINT64,
263 		"ETM response msg headers sent to xport" },
264 	{ "etm_wr_body_fmaevent", FMD_TYPE_UINT64,
265 		"ETM fmaevent msg bodies sent to xport" },
266 	{ "etm_wr_body_control", FMD_TYPE_UINT64,
267 		"ETM control msg bodies sent to xport" },
268 	{ "etm_wr_body_response", FMD_TYPE_UINT64,
269 		"ETM response msg bodies sent to xport" },
270 
271 	/* ETM byte counters */
272 
273 	{ "etm_wr_fmd_bytes", FMD_TYPE_UINT64,
274 		"bytes of FMA events sent to FMD" },
275 	{ "etm_rd_fmd_bytes", FMD_TYPE_UINT64,
276 		"bytes of FMA events rcvd from FMD" },
277 	{ "etm_wr_xport_bytes", FMD_TYPE_UINT64,
278 		"bytes of FMA events sent to xport" },
279 	{ "etm_rd_xport_bytes", FMD_TYPE_UINT64,
280 		"bytes of FMA events rcvd from xport" },
281 
282 	{ "etm_magic_drop_bytes", FMD_TYPE_UINT64,
283 		"bytes dropped from xport pre magic num" },
284 
285 	/* ETM [dropped] FMA event counters */
286 
287 	{ "etm_rd_fmd_fmaevent", FMD_TYPE_UINT64,
288 		"FMA events rcvd from FMD" },
289 	{ "etm_wr_fmd_fmaevent", FMD_TYPE_UINT64,
290 		"FMA events sent to FMD" },
291 
292 	{ "etm_rd_drop_fmaevent", FMD_TYPE_UINT64,
293 		"dropped FMA events from xport" },
294 	{ "etm_wr_drop_fmaevent", FMD_TYPE_UINT64,
295 		"dropped FMA events to xport" },
296 
297 	{ "etm_rd_dup_fmaevent", FMD_TYPE_UINT64,
298 	    "duplicate FMA events from xport" },
299 	{ "etm_wr_dup_fmaevent", FMD_TYPE_UINT64,
300 	    "duplicate FMA events to xport" },
301 
302 	/* ETM protocol failures */
303 
304 	{ "etm_magic_bad", FMD_TYPE_UINT64,
305 		"ETM msgs w/ invalid magic num" },
306 	{ "etm_ver_bad", FMD_TYPE_UINT64,
307 		"ETM msgs w/ invalid protocol version" },
308 	{ "etm_msgtype_bad", FMD_TYPE_UINT64,
309 		"ETM msgs w/ invalid message type" },
310 	{ "etm_subtype_bad", FMD_TYPE_UINT64,
311 		"ETM msgs w/ invalid sub type" },
312 	{ "etm_xid_bad", FMD_TYPE_UINT64,
313 		"ETM msgs w/ unmatched xid" },
314 	{ "etm_fmaeventlen_bad", FMD_TYPE_UINT64,
315 		"ETM msgs w/ invalid FMA event length" },
316 	{ "etm_respcode_bad", FMD_TYPE_UINT64,
317 		"ETM msgs w/ invalid response code" },
318 	{ "etm_timeout_bad", FMD_TYPE_UINT64,
319 		"ETM msgs w/ invalid timeout value" },
320 	{ "etm_evlens_bad", FMD_TYPE_UINT64,
321 		"ETM msgs w/ too many event lengths" },
322 
323 	/* IO operation failures */
324 
325 	{ "etm_xport_wr_fail", FMD_TYPE_UINT64,
326 		"xport write failures" },
327 	{ "etm_xport_rd_fail", FMD_TYPE_UINT64,
328 		"xport read failures" },
329 	{ "etm_xport_pk_fail", FMD_TYPE_UINT64,
330 		"xport peek failures" },
331 
332 	/* IO operation retries */
333 
334 	{ "etm_xport_wr_retry", FMD_TYPE_UINT64,
335 		"xport write retries" },
336 	{ "etm_xport_rd_retry", FMD_TYPE_UINT64,
337 		"xport read retries" },
338 	{ "etm_xport_pk_retry", FMD_TYPE_UINT64,
339 		"xport peek retries" },
340 
341 	/* system and library failures */
342 
343 	{ "etm_os_sysevent_publish_fail", FMD_TYPE_UINT64,
344 		"sysevent_evc_publish failures" },
345 	{ "etm_os_sysevent_bind_fail", FMD_TYPE_UINT64,
346 		"sysevent_evc_bind failures" },
347 	{ "etm_os_nvlist_pack_fail", FMD_TYPE_UINT64,
348 		"nvlist_pack failures" },
349 	{ "etm_os_nvlist_unpack_fail", FMD_TYPE_UINT64,
350 		"nvlist_unpack failures" },
351 	{ "etm_os_nvlist_size_fail", FMD_TYPE_UINT64,
352 		"nvlist_size failures" },
353 	{ "etm_os_pthread_create_fail", FMD_TYPE_UINT64,
354 		"pthread_create failures" },
355 
356 	/* transport API failures */
357 
358 	{ "etm_xport_get_ev_addrv_fail", FMD_TYPE_UINT64,
359 		"xport get event addrv API failures" },
360 	{ "etm_xport_open_fail", FMD_TYPE_UINT64,
361 		"xport open API failures" },
362 	{ "etm_xport_close_fail", FMD_TYPE_UINT64,
363 		"xport close API failures" },
364 	{ "etm_xport_accept_fail", FMD_TYPE_UINT64,
365 		"xport accept API failures" },
366 	{ "etm_xport_open_retry", FMD_TYPE_UINT64,
367 		"xport open API retries" },
368 
369 	/* FMD entry point bad arguments */
370 
371 	{ "etm_fmd_recv_badargs", FMD_TYPE_UINT64,
372 		"bad arguments from fmd_recv entry point" },
373 	{ "etm_fmd_init_badargs", FMD_TYPE_UINT64,
374 		"bad arguments from fmd_init entry point" },
375 	{ "etm_fmd_fini_badargs", FMD_TYPE_UINT64,
376 		"bad arguments from fmd_fini entry point" }
377 };
378 
379 /*
380  * -------------------------- support functions ------------------------------
381  */
382 
383 /*
384  * Design_Note:	Each failure worth reporting to FMD should be done using
385  *		a single call to fmd_hdl_error() as it logs an FMA event
386  *		for each call. Also be aware that all the fmd_hdl_*()
387  *		format strings currently use platform specific *printf()
388  *		routines; so "%p" under Solaris does not prepend "0x" to
389  *		the outputted hex digits, while Linux and VxWorks do.
390  */
391 
392 /*
393  * etm_show_time - display the current time of day (for debugging) using
394  *		the given FMD module handle and annotation string
395  */
396 
397 static void
398 etm_show_time(fmd_hdl_t *hdl, char *note_str)
399 {
400 	struct timeval		tmv;		/* timeval */
401 
402 	(void) gettimeofday(&tmv, NULL);
403 	fmd_hdl_debug(hdl, "info: %s: cur Unix Epoch time %d.%06d\n",
404 	    note_str, tmv.tv_sec, tmv.tv_usec);
405 
406 } /* etm_show_time() */
407 
408 /*
409  * etm_hexdump - hexdump the given buffer (for debugging) using
410  *		the given FMD module handle
411  */
412 
413 static void
414 etm_hexdump(fmd_hdl_t *hdl, void *buf, size_t byte_cnt)
415 {
416 	uint8_t		*bp;		/* byte ptr */
417 	int		i, j;		/* index */
418 	char		cb[80];		/* char buf */
419 	unsigned int	n;		/* a byte of data for sprintf() */
420 
421 	bp = buf;
422 	j = 0;
423 
424 	/*
425 	 * Design_Note:	fmd_hdl_debug() auto adds a newline if missing;
426 	 *		hence cb exists to accumulate a longer string.
427 	 */
428 
429 	for (i = 1; i <= byte_cnt; i++) {
430 		n = *bp++;
431 		(void) sprintf(&cb[j], "%2.2x ", n);
432 		j += 3;
433 		/* add a newline every 16 bytes or at the buffer's end */
434 		if (((i % 16) == 0) || (i >= byte_cnt)) {
435 			cb[j-1] = '\0';
436 			fmd_hdl_debug(hdl, "%s\n", cb);
437 			j = 0;
438 		}
439 	} /* for each byte in the buffer */
440 
441 } /* etm_hexdump() */
442 
443 /*
444  * etm_sleep - sleep the caller for the given number of seconds,
445  *		return 0 or -errno value
446  *
447  * Design_Note:	To avoid interfering with FMD's signal mask (SIGALRM)
448  *		do not use [Solaris] sleep(3C) and instead use
449  *		pthread_cond_wait() or nanosleep(), both of which
450  *		are POSIX spec-ed to leave signal masks alone.
451  *		This is needed for Solaris and Linux (domain and SP).
452  */
453 
454 static int
455 etm_sleep(unsigned sleep_sec)
456 {
457 	struct timespec	tms;	/* for nanosleep() */
458 
459 	tms.tv_sec = sleep_sec;
460 	tms.tv_nsec = 0;
461 
462 	if (nanosleep(&tms, NULL) < 0) {
463 		/* errno assumed set by above call */
464 		return (-errno);
465 	}
466 	return (0);
467 
468 } /* etm_sleep() */
469 
470 /*
471  * etm_conn_open - open a connection to the given transport address,
472  *		return 0 and the opened connection handle
473  *		or -errno value
474  *
475  * caveats:	the err_substr is used in failure cases for calling
476  *		fmd_hdl_error()
477  */
478 
479 static int
480 etm_conn_open(fmd_hdl_t *hdl, char *err_substr,
481 		etm_xport_addr_t addr, etm_xport_conn_t *connp)
482 {
483 	etm_xport_conn_t	conn;	/* connection to return */
484 	int			nev;	/* -errno value */
485 
486 	if ((conn = etm_xport_open(hdl, addr)) == NULL) {
487 		nev = (-errno);
488 		fmd_hdl_error(hdl, "error: %s: errno %d\n",
489 					err_substr, errno);
490 		etm_stats.etm_xport_open_fail.fmds_value.ui64++;
491 		return (nev);
492 	} else {
493 		*connp = conn;
494 		return (0);
495 	}
496 } /* etm_conn_open() */
497 
498 /*
499  * etm_conn_close - close the given connection,
500  *		return 0 or -errno value
501  *
502  * caveats:	the err_substr is used in failure cases for calling
503  *		fmd_hdl_error()
504  */
505 
506 static int
507 etm_conn_close(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn)
508 {
509 	int	nev;	/* -errno value */
510 
511 	if (etm_xport_close(hdl, conn) == NULL) {
512 		nev = (-errno);
513 		fmd_hdl_error(hdl, "warning: %s: errno %d\n",
514 					err_substr, errno);
515 		etm_stats.etm_xport_close_fail.fmds_value.ui64++;
516 		return (nev);
517 	} else {
518 		return (0);
519 	}
520 } /* etm_conn_close() */
521 
522 /*
523  * etm_io_op - perform an IO operation on the given connection
524  *		with the given buffer,
525  *		accommodating MTU size and retrying op if needed,
526  *		return how many bytes actually done by the op
527  *		or -errno value
528  *
529  * caveats:	the err_substr is used in failure cases for calling
530  *		fmd_hdl_error()
531  */
532 
533 static ssize_t
534 etm_io_op(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn,
535 				void *buf, size_t byte_cnt, int io_op)
536 {
537 	ssize_t		rv;		/* ret val / byte count */
538 	ssize_t		n;		/* gen use */
539 	uint8_t		*datap;		/* ptr to data */
540 	size_t		mtu_sz;		/* MTU size in bytes */
541 	int		(*io_func_ptr)(fmd_hdl_t *, etm_xport_conn_t,
542 							void *, size_t);
543 	size_t		io_sz;		/* byte count for io_func_ptr */
544 	int		try_cnt;	/* number of tries done */
545 	int		sleep_sec;	/* exp backoff sleep period in sec */
546 	int		sleep_rv;	/* ret val from sleeping */
547 	fmd_stat_t	io_retry_stat;	/* IO retry stat to update */
548 	fmd_stat_t	io_fail_stat;	/* IO failure stat to update */
549 
550 	if ((conn == NULL) || (buf == NULL)) {
551 		return (-EINVAL);
552 	}
553 	switch (io_op) {
554 		case ETM_IO_OP_RD:
555 			io_func_ptr = etm_xport_read;
556 			io_retry_stat = etm_stats.etm_xport_rd_retry;
557 			io_fail_stat = etm_stats.etm_xport_rd_fail;
558 			break;
559 		case ETM_IO_OP_WR:
560 			io_func_ptr = etm_xport_write;
561 			io_retry_stat = etm_stats.etm_xport_wr_retry;
562 			io_fail_stat = etm_stats.etm_xport_wr_fail;
563 			break;
564 		case ETM_IO_OP_PK:
565 			io_func_ptr = etm_xport_peek;
566 			io_retry_stat = etm_stats.etm_xport_pk_retry;
567 			io_fail_stat = etm_stats.etm_xport_pk_fail;
568 			break;
569 		default:
570 			return (-EINVAL);
571 	}
572 	if (byte_cnt == 0) {
573 		return (byte_cnt);	/* nop */
574 	}
575 
576 	/* obtain [current] MTU size */
577 
578 	if ((n = etm_xport_get_opt(hdl, conn, ETM_XPORT_OPT_MTU_SZ)) < 0) {
579 		mtu_sz = ETM_XPORT_MTU_SZ_DEF;
580 	} else {
581 		mtu_sz = n;
582 	}
583 
584 	/* loop until all IO done, try limit exceeded, or real failure */
585 
586 	rv = 0;
587 	datap = buf;
588 	while (rv < byte_cnt) {
589 		io_sz = MIN((byte_cnt - rv), mtu_sz);
590 		try_cnt = 0;
591 		sleep_sec = 0;
592 
593 		/* when give up, return -errno value even if partly done */
594 
595 		while ((n = (*io_func_ptr)(hdl, conn, datap, io_sz)) ==
596 								(-EAGAIN)) {
597 			try_cnt++;
598 			if (try_cnt > ETM_TRY_MAX_CNT) {
599 				rv = n;
600 				goto func_ret;
601 			}
602 			if (etm_is_dying) {
603 				rv = (-EINTR);
604 				goto func_ret;
605 			}
606 			if ((sleep_rv = etm_sleep(sleep_sec)) < 0) {
607 				rv = sleep_rv;
608 				goto func_ret;
609 			}
610 			sleep_sec = ((sleep_sec == 0) ? 1 :
611 					(sleep_sec * ETM_TRY_BACKOFF_RATE));
612 			sleep_sec = MIN(sleep_sec, ETM_TRY_BACKOFF_CAP);
613 			io_retry_stat.fmds_value.ui64++;
614 			if (etm_debug_lvl >= 1) {
615 				fmd_hdl_debug(hdl, "info: retrying io op %d "
616 						"due to EAGAIN\n", io_op);
617 			}
618 		} /* while trying the io operation */
619 
620 		if (etm_is_dying) {
621 			rv = (-EINTR);
622 			goto func_ret;
623 		}
624 		if (n < 0) {
625 			rv = n;
626 			goto func_ret;
627 		}
628 		/* avoid spinning CPU when given 0 bytes but no error */
629 		if (n == 0) {
630 			if ((sleep_rv = etm_sleep(ETM_SLEEP_QUIK)) < 0) {
631 				rv = sleep_rv;
632 				goto func_ret;
633 			}
634 		}
635 		rv += n;
636 		datap += n;
637 	} /* while still have more data */
638 
639 func_ret:
640 
641 	if (rv < 0) {
642 		io_fail_stat.fmds_value.ui64++;
643 		fmd_hdl_error(hdl, "error: %s: errno %d\n",
644 					err_substr, (int)(-rv));
645 	}
646 	if (etm_debug_lvl >= 3) {
647 		fmd_hdl_debug(hdl, "info: io op %d ret %d of %d\n",
648 					io_op, (int)rv, (int)byte_cnt);
649 	}
650 	return (rv);
651 
652 } /* etm_io_op() */
653 
654 /*
655  * etm_magic_read - read the magic number of an ETM message header
656  *		from the given connection into the given buffer,
657  *		return 0 or -errno value
658  *
659  * Design_Note:	This routine is intended to help protect ETM from protocol
660  *		framing errors as might be caused by an SP reset / crash in
661  *		the middle of an ETM message send; the connection will be
662  *		read from for as many bytes as needed until the magic number
663  *		is found using a sliding buffer for comparisons.
664  */
665 
666 static int
667 etm_magic_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, uint32_t *magic_ptr)
668 {
669 	int		rv;		/* ret val */
670 	uint32_t	magic_num;	/* magic number */
671 	int		byte_cnt;	/* count of bytes read */
672 	uint8_t		buf5[4+1];	/* sliding input buffer */
673 	int		i, j;		/* indices into buf5 */
674 	ssize_t		n;		/* gen use */
675 	uint8_t		drop_buf[1024];	/* dropped bytes buffer */
676 
677 	rv = 0;		/* assume success */
678 	magic_num = 0;
679 	byte_cnt = 0;
680 	j = 0;
681 
682 	/* magic number bytes are sent in network (big endian) order */
683 
684 	while (magic_num != ETM_PROTO_MAGIC_NUM) {
685 		if ((n = etm_io_op(hdl, "bad io read on magic",
686 				conn, &buf5[j], 1, ETM_IO_OP_RD)) < 0) {
687 			rv = n;
688 			goto func_ret;
689 		}
690 		byte_cnt++;
691 		j = MIN((j + 1), sizeof (magic_num));
692 		if (byte_cnt < sizeof (magic_num)) {
693 			continue;
694 		}
695 
696 		if (byte_cnt > sizeof (magic_num)) {
697 			etm_stats.etm_magic_drop_bytes.fmds_value.ui64++;
698 			i = MIN(byte_cnt - j - 1, sizeof (drop_buf) - 1);
699 			drop_buf[i] = buf5[0];
700 			for (i = 0; i < j; i++) {
701 				buf5[i] = buf5[i+1];
702 			} /* for sliding the buffer contents */
703 		}
704 		(void) memcpy(&magic_num, &buf5[0], sizeof (magic_num));
705 		magic_num = ntohl(magic_num);
706 	} /* for reading bytes until find magic number */
707 
708 func_ret:
709 
710 	if (byte_cnt != sizeof (magic_num)) {
711 		fmd_hdl_error(hdl, "warning: bad proto frame "
712 				"implies corrupt/lost msg(s)\n");
713 	}
714 	if ((byte_cnt > sizeof (magic_num)) && (etm_debug_lvl >= 2)) {
715 		i = MIN(byte_cnt - sizeof (magic_num), sizeof (drop_buf));
716 		fmd_hdl_debug(hdl, "info: magic drop hexdump "
717 				"first %d of %d bytes:\n",
718 				i, byte_cnt - sizeof (magic_num));
719 		etm_hexdump(hdl, drop_buf, i);
720 	}
721 
722 	if (rv == 0) {
723 		*magic_ptr = magic_num;
724 	}
725 	return (rv);
726 
727 } /* etm_magic_read() */
728 
729 /*
730  * etm_hdr_read - allocate, read, and validate a [variable sized]
731  *		ETM message header from the given connection,
732  *		return the allocated ETM message header
733  *		(which is guaranteed to be large enough to reuse as a
734  *		RESPONSE msg hdr) and its size
735  *		or NULL and set errno on failure
736  */
737 
738 static void *
739 etm_hdr_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, size_t *szp)
740 {
741 	uint8_t			*hdrp;		/* ptr to header to return */
742 	size_t			hdr_sz;		/* sizeof *hdrp */
743 	etm_proto_v1_pp_t	pp; 		/* protocol preamble */
744 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
745 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
746 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
747 	uint32_t		*lenp;		/* ptr to FMA event length */
748 	ssize_t			i, n;		/* gen use */
749 	uint8_t	misc_buf[ETM_MISC_BUF_SZ];	/* for var sized hdrs */
750 	int			dummy_int;	/* dummy var to appease lint */
751 
752 	hdrp = NULL; hdr_sz = 0;
753 
754 	/* read the magic number which starts the protocol preamble */
755 
756 	if ((n = etm_magic_read(hdl, conn, &pp.pp_magic_num)) < 0) {
757 		errno = (-n);
758 		etm_stats.etm_magic_bad.fmds_value.ui64++;
759 		return (NULL);
760 	}
761 
762 	/* read the rest of the protocol preamble all at once */
763 
764 	if ((n = etm_io_op(hdl, "bad io read on preamble",
765 				conn, &pp.pp_proto_ver,
766 				sizeof (pp) - sizeof (pp.pp_magic_num),
767 				ETM_IO_OP_RD)) < 0) {
768 		errno = (-n);
769 		return (NULL);
770 	}
771 
772 	/*
773 	 * Design_Note:	The magic number was already network decoded; but
774 	 *		some other preamble fields also need to be decoded,
775 	 *		specifically pp_xid and pp_timeout. The rest of the
776 	 *		preamble fields are byte sized and hence need no
777 	 *		decoding.
778 	 */
779 
780 	pp.pp_xid = ntohl(pp.pp_xid);
781 	pp.pp_timeout = ntohl(pp.pp_timeout);
782 
783 	/* sanity check the header as best we can */
784 
785 	if ((pp.pp_proto_ver < ETM_PROTO_V1) ||
786 	    (pp.pp_proto_ver > ETM_PROTO_V2)) {
787 		fmd_hdl_error(hdl, "error: bad proto ver %d\n",
788 					(int)pp.pp_proto_ver);
789 		errno = EPROTO;
790 		etm_stats.etm_ver_bad.fmds_value.ui64++;
791 		return (NULL);
792 	}
793 
794 	dummy_int = pp.pp_msg_type;
795 	if ((dummy_int <= ETM_MSG_TYPE_TOO_LOW) ||
796 	    (dummy_int >= ETM_MSG_TYPE_TOO_BIG)) {
797 		fmd_hdl_error(hdl, "error: bad msg type %d", dummy_int);
798 		errno = EBADMSG;
799 		etm_stats.etm_msgtype_bad.fmds_value.ui64++;
800 		return (NULL);
801 	}
802 
803 	/* handle [var sized] hdrs for FMA_EVENT, CONTROL, RESPONSE msgs */
804 
805 	if (pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
806 
807 		ev_hdrp = (void*)&misc_buf[0];
808 		hdr_sz = sizeof (*ev_hdrp);
809 		(void) memcpy(&ev_hdrp->ev_pp, &pp, sizeof (pp));
810 
811 		/* sanity check the header's timeout */
812 
813 		if ((ev_hdrp->ev_pp.pp_proto_ver == ETM_PROTO_V1) &&
814 		    (ev_hdrp->ev_pp.pp_timeout != ETM_PROTO_V1_TIMEOUT_NONE)) {
815 			errno = ETIME;
816 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
817 			return (NULL);
818 		}
819 
820 		/* get all FMA event lengths from the header */
821 
822 		lenp = (uint32_t *)&ev_hdrp->ev_lens[0]; lenp--;
823 		i = -1;	/* cnt of length entries preceding 0 */
824 		do {
825 			i++; lenp++;
826 			if ((sizeof (*ev_hdrp) + (i * sizeof (*lenp))) >=
827 							ETM_MISC_BUF_SZ) {
828 				errno = E2BIG;	/* ridiculous size */
829 				etm_stats.etm_evlens_bad.fmds_value.ui64++;
830 				return (NULL);
831 			}
832 			if ((n = etm_io_op(hdl, "bad io read on event len",
833 						conn, lenp, sizeof (*lenp),
834 						ETM_IO_OP_RD)) < 0) {
835 				errno = (-n);
836 				return (NULL);
837 			}
838 			*lenp = ntohl(*lenp);
839 
840 		} while (*lenp != 0);
841 		i += 0; /* first len already counted by sizeof(ev_hdr) */
842 		hdr_sz += (i * sizeof (*lenp));
843 
844 		etm_stats.etm_rd_hdr_fmaevent.fmds_value.ui64++;
845 
846 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
847 
848 		ctl_hdrp = (void*)&misc_buf[0];
849 		hdr_sz = sizeof (*ctl_hdrp);
850 		(void) memcpy(&ctl_hdrp->ctl_pp, &pp, sizeof (pp));
851 
852 		/* sanity check the header's sub type (control selector) */
853 
854 		if ((ctl_hdrp->ctl_pp.pp_sub_type <= ETM_CTL_SEL_TOO_LOW) ||
855 		    (ctl_hdrp->ctl_pp.pp_sub_type >= ETM_CTL_SEL_TOO_BIG)) {
856 			fmd_hdl_error(hdl, "error: bad ctl sub type %d\n",
857 					(int)ctl_hdrp->ctl_pp.pp_sub_type);
858 			errno = EBADMSG;
859 			etm_stats.etm_subtype_bad.fmds_value.ui64++;
860 			return (NULL);
861 		}
862 
863 		/* get the control length */
864 
865 		if ((n = etm_io_op(hdl, "bad io read on ctl len",
866 					conn, &ctl_hdrp->ctl_len,
867 					sizeof (ctl_hdrp->ctl_len),
868 					ETM_IO_OP_RD)) < 0) {
869 			errno = (-n);
870 			return (NULL);
871 		}
872 
873 		ctl_hdrp->ctl_len = ntohl(ctl_hdrp->ctl_len);
874 
875 		etm_stats.etm_rd_hdr_control.fmds_value.ui64++;
876 
877 	} else if (pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
878 
879 		resp_hdrp = (void*)&misc_buf[0];
880 		hdr_sz = sizeof (*resp_hdrp);
881 		(void) memcpy(&resp_hdrp->resp_pp, &pp, sizeof (pp));
882 
883 		/* sanity check the header's timeout */
884 
885 		if (resp_hdrp->resp_pp.pp_timeout !=
886 						ETM_PROTO_V1_TIMEOUT_NONE) {
887 			errno = ETIME;
888 			etm_stats.etm_timeout_bad.fmds_value.ui64++;
889 			return (NULL);
890 		}
891 
892 		/* get the response code and length */
893 
894 		if ((n = etm_io_op(hdl, "bad io read on resp code+len",
895 					conn, &resp_hdrp->resp_code,
896 					sizeof (resp_hdrp->resp_code) +
897 					sizeof (resp_hdrp->resp_len),
898 					ETM_IO_OP_RD)) < 0) {
899 			errno = (-n);
900 			return (NULL);
901 		}
902 
903 		resp_hdrp->resp_code = ntohl(resp_hdrp->resp_code);
904 		resp_hdrp->resp_len = ntohl(resp_hdrp->resp_len);
905 
906 		etm_stats.etm_rd_hdr_response.fmds_value.ui64++;
907 
908 	} /* whether we have FMA_EVENT, CONTROL, RESPONSE msg */
909 
910 	/*
911 	 * choose a header size that allows hdr reuse for RESPONSE msgs,
912 	 * allocate and populate the message header, and
913 	 * return alloc size to caller for later free of hdrp
914 	 */
915 
916 	hdr_sz = MAX(hdr_sz, sizeof (*resp_hdrp));
917 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
918 	(void) memcpy(hdrp, misc_buf, hdr_sz);
919 
920 	if (etm_debug_lvl >= 3) {
921 		fmd_hdl_debug(hdl, "info: msg hdr hexdump %d bytes:\n",
922 								hdr_sz);
923 		etm_hexdump(hdl, hdrp, hdr_sz);
924 	}
925 	*szp = hdr_sz;
926 	return (hdrp);
927 
928 } /* etm_hdr_read() */
929 
930 /*
931  * etm_hdr_write - create and write a [variable sized] ETM message header
932  *		to the given connection appropriate for the given FMA event
933  *		and type of nvlist encoding,
934  *		return the allocated ETM message header and its size
935  *		or NULL and set errno on failure
936  */
937 
938 static void*
939 etm_hdr_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, nvlist_t *evp,
940 						int encoding, size_t *szp)
941 {
942 	etm_proto_v1_ev_hdr_t	*hdrp;		/* for FMA_EVENT msg */
943 	size_t			hdr_sz;		/* sizeof *hdrp */
944 	uint32_t		*lenp;		/* ptr to FMA event length */
945 	size_t			evsz;		/* packed FMA event size */
946 	ssize_t			n;		/* gen use */
947 
948 	/* allocate and populate the message header for 1 FMA event */
949 
950 	hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0]));
951 
952 	hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP);
953 
954 	/*
955 	 * Design_Note: Although the ETM protocol supports it, we do not (yet)
956 	 *		want responses/ACKs on FMA events that we send. All
957 	 *		such messages are sent with ETM_PROTO_V1_TIMEOUT_NONE.
958 	 */
959 
960 	hdrp->ev_pp.pp_magic_num = ETM_PROTO_MAGIC_NUM;
961 	hdrp->ev_pp.pp_magic_num = htonl(hdrp->ev_pp.pp_magic_num);
962 	hdrp->ev_pp.pp_proto_ver = ETM_PROTO_V1;
963 	hdrp->ev_pp.pp_msg_type = ETM_MSG_TYPE_FMA_EVENT;
964 	hdrp->ev_pp.pp_sub_type = 0;
965 	hdrp->ev_pp.pp_rsvd_pad = 0;
966 	hdrp->ev_pp.pp_xid = etm_xid_cur;
967 	hdrp->ev_pp.pp_xid = htonl(hdrp->ev_pp.pp_xid);
968 	etm_xid_cur += ETM_XID_INC;
969 	hdrp->ev_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
970 	hdrp->ev_pp.pp_timeout = htonl(hdrp->ev_pp.pp_timeout);
971 
972 	lenp = &hdrp->ev_lens[0];
973 
974 	if ((n = nvlist_size(evp, &evsz, encoding)) != 0) {
975 		errno = n;
976 		fmd_hdl_free(hdl, hdrp, hdr_sz);
977 		etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++;
978 		return (NULL);
979 	}
980 
981 	/* indicate 1 FMA event, network encode its length, and 0-terminate */
982 
983 	*lenp = evsz; *lenp = htonl(*lenp); lenp++;
984 	*lenp = 0; *lenp = htonl(*lenp); lenp++;
985 
986 	/*
987 	 * write the network encoded header to the transport, and
988 	 * return alloc size to caller for later free
989 	 */
990 
991 	if ((n = etm_io_op(hdl, "bad io write on event hdr",
992 				conn, hdrp, hdr_sz, ETM_IO_OP_WR)) < 0) {
993 		errno = (-n);
994 		fmd_hdl_free(hdl, hdrp, hdr_sz);
995 		return (NULL);
996 	}
997 
998 	*szp = hdr_sz;
999 	return (hdrp);
1000 
1001 } /* etm_hdr_write() */
1002 
1003 /*
1004  * etm_post_to_fmd - post the given FMA event to FMD
1005  *			[via sysevent or via a FMD transport API call ],
1006  *			return 0 or -errno value
1007  *
1008  * Design_Note:	This routine exists to ease future porting to both
1009  *		FMA Phase 2 FMD as well as porting to Linux which lacks
1010  *		a native sysevent.
1011  */
1012 
1013 static int
1014 etm_post_to_fmd(fmd_hdl_t *hdl, nvlist_t *evp)
1015 {
1016 	int			rv;		/* ret val */
1017 	evchan_t		*scp;		/* sysevent channel ptr */
1018 	ssize_t			n;		/* gen use */
1019 
1020 	rv = 0; /* default success */
1021 
1022 	scp = NULL;
1023 
1024 	if (etm_debug_lvl >= 2) {
1025 		etm_show_time(hdl, "ante ev post");
1026 	}
1027 	if ((n = sysevent_evc_bind(FM_ERROR_CHAN, &scp,
1028 				EVCH_CREAT | EVCH_HOLD_PEND)) != 0) {
1029 		rv = (-n);
1030 		fmd_hdl_error(hdl, "error: FMA event dropped: "
1031 				"sysevent bind errno %d\n", n);
1032 		etm_stats.etm_os_sysevent_bind_fail.fmds_value.ui64++;
1033 		etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1034 		goto func_ret;
1035 	}
1036 
1037 	if ((n = sysevent_evc_publish(scp, EC_FM, ESC_FM_ERROR, "com.sun",
1038 				getexecname(), evp, EVCH_SLEEP)) != 0) {
1039 		rv = (-n);
1040 		fmd_hdl_error(hdl, "error: FMA event dropped: "
1041 				"sysevent publish errno %d\n", n);
1042 		etm_stats.etm_os_sysevent_publish_fail.fmds_value.ui64++;
1043 		etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1044 		goto func_ret;
1045 	}
1046 
1047 func_ret:
1048 
1049 	if (scp != NULL) {
1050 		sysevent_evc_unbind(scp);
1051 	}
1052 	if (rv == 0) {
1053 		etm_stats.etm_wr_fmd_fmaevent.fmds_value.ui64++;
1054 		(void) nvlist_size(evp, (size_t *)&n, NV_ENCODE_XDR);
1055 		etm_stats.etm_wr_fmd_bytes.fmds_value.ui64 += n;
1056 		if (etm_debug_lvl >= 1) {
1057 			fmd_hdl_debug(hdl, "info: event %p post ok to FMD\n",
1058 								evp);
1059 		}
1060 	}
1061 	if (etm_debug_lvl >= 2) {
1062 		etm_show_time(hdl, "post ev post");
1063 	}
1064 	return (rv);
1065 
1066 } /* etm_post_to_fmd() */
1067 
1068 /*
1069  * etm_req_ver_negot - send an ETM control message to the other end requesting
1070  *			that the ETM protocol version be negotiated/set
1071  */
1072 
1073 static void
1074 etm_req_ver_negot(fmd_hdl_t *hdl)
1075 {
1076 	etm_xport_addr_t	*addrv;		/* default dst addr(s) */
1077 	etm_xport_conn_t	conn;		/* connection to other end */
1078 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1079 	size_t			hdr_sz;		/* sizeof header */
1080 	uint8_t			*body_buf;	/* msg body buffer */
1081 	uint32_t		body_sz;	/* sizeof *body_buf */
1082 	ssize_t			i;		/* gen use */
1083 
1084 	/* populate an ETM control msg to send */
1085 
1086 	hdr_sz = sizeof (*ctl_hdrp);
1087 	body_sz = (2 + 1);		/* version bytes plus null byte */
1088 
1089 	ctl_hdrp = fmd_hdl_zalloc(hdl, hdr_sz + body_sz, FMD_SLEEP);
1090 
1091 	ctl_hdrp->ctl_pp.pp_magic_num = htonl(ETM_PROTO_MAGIC_NUM);
1092 	ctl_hdrp->ctl_pp.pp_proto_ver = ETM_PROTO_V1;
1093 	ctl_hdrp->ctl_pp.pp_msg_type = ETM_MSG_TYPE_CONTROL;
1094 	ctl_hdrp->ctl_pp.pp_sub_type = ETM_CTL_SEL_VER_NEGOT_REQ;
1095 	ctl_hdrp->ctl_pp.pp_rsvd_pad = 0;
1096 	etm_xid_ver_negot = etm_xid_cur;
1097 	etm_xid_cur += ETM_XID_INC;
1098 	ctl_hdrp->ctl_pp.pp_xid = htonl(etm_xid_ver_negot);
1099 	ctl_hdrp->ctl_pp.pp_timeout = htonl(ETM_PROTO_V1_TIMEOUT_FOREVER);
1100 	ctl_hdrp->ctl_len = htonl(body_sz);
1101 
1102 	body_buf = (void*)&ctl_hdrp->ctl_len;
1103 	body_buf += sizeof (ctl_hdrp->ctl_len);
1104 	*body_buf++ = ETM_PROTO_V2;
1105 	*body_buf++ = ETM_PROTO_V1;
1106 	*body_buf++ = '\0';
1107 
1108 	/*
1109 	 * open and close a connection to send the ETM control msg
1110 	 * to any/all of the default dst addrs
1111 	 */
1112 
1113 	if ((addrv = etm_xport_get_ev_addrv(hdl, NULL)) == NULL) {
1114 		fmd_hdl_error(hdl,
1115 			"error: bad ctl dst addrs errno %d\n", errno);
1116 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
1117 		goto func_ret;
1118 	}
1119 
1120 	for (i = 0; addrv[i] != NULL; i++) {
1121 
1122 		if (etm_conn_open(hdl, "bad conn open during ver negot",
1123 					addrv[i], &conn) < 0) {
1124 			continue;
1125 		}
1126 		if (etm_io_op(hdl, "bad io write on ctl hdr+body",
1127 					conn, ctl_hdrp, hdr_sz + body_sz,
1128 					ETM_IO_OP_WR) >= 0) {
1129 			etm_stats.etm_wr_hdr_control.fmds_value.ui64++;
1130 			etm_stats.etm_wr_body_control.fmds_value.ui64++;
1131 		}
1132 		(void) etm_conn_close(hdl, "bad conn close during ver negot",
1133 									conn);
1134 
1135 	} /* foreach dst addr */
1136 
1137 func_ret:
1138 
1139 	if (addrv != NULL) {
1140 		etm_xport_free_addrv(hdl, addrv);
1141 	}
1142 	fmd_hdl_free(hdl, ctl_hdrp, hdr_sz + body_sz);
1143 
1144 } /* etm_req_ver_negot() */
1145 
1146 /*
1147  * Design_Note:	We rely on the fact that all message types have
1148  *		a common protocol preamble; if this fact should
1149  *		ever change it may break the code below. We also
1150  *		rely on the fact that FMA_EVENT and CONTROL headers
1151  *		returned will be sized large enough to reuse them
1152  *		as RESPONSE headers if the remote endpt asked
1153  *		for a response via the pp_timeout field.
1154  */
1155 
1156 /*
1157  * etm_maybe_send_response - check the given message header to see
1158  *				whether a response has been requested,
1159  *				if so then send an appropriate response
1160  *				back on the given connection using the
1161  *				given response code,
1162  *				return 0 or -errno value
1163  */
1164 
1165 static ssize_t
1166 etm_maybe_send_response(fmd_hdl_t *hdl, etm_xport_conn_t conn,
1167     void *hdrp, int32_t resp_code)
1168 {
1169 	ssize_t			rv;		/* ret val */
1170 	etm_proto_v1_pp_t	*ppp;		/* protocol preamble ptr */
1171 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
1172 	uint8_t			resp_body[4];	/* response body if needed */
1173 	uint8_t			*resp_msg;	/* response hdr+body */
1174 	size_t			hdr_sz;		/* sizeof response hdr */
1175 	uint8_t			orig_msg_type;	/* orig hdr's message type */
1176 	uint32_t		orig_timeout;	/* orig hdr's timeout */
1177 	ssize_t			n;		/* gen use */
1178 
1179 	rv = 0;		/* default is success */
1180 	ppp = hdrp;
1181 	orig_msg_type = ppp->pp_msg_type;
1182 	orig_timeout = ppp->pp_timeout;
1183 
1184 	/* bail out now if no response is to be sent */
1185 
1186 	if (orig_timeout == ETM_PROTO_V1_TIMEOUT_NONE) {
1187 		return (0);
1188 	} /* if a nop */
1189 
1190 	if ((orig_msg_type != ETM_MSG_TYPE_FMA_EVENT) &&
1191 	    (orig_msg_type != ETM_MSG_TYPE_CONTROL)) {
1192 		return (-EINVAL);
1193 	} /* if inappropriate hdr for a response msg */
1194 
1195 	/* reuse the given header as a response header */
1196 
1197 	if (etm_debug_lvl >= 2) {
1198 		etm_show_time(hdl, "ante resp send");
1199 	}
1200 
1201 	resp_hdrp = hdrp;
1202 	resp_hdrp->resp_code = resp_code;
1203 	resp_hdrp->resp_len = 0;		/* default is empty body */
1204 
1205 	if ((orig_msg_type == ETM_MSG_TYPE_CONTROL) &&
1206 	    (ppp->pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ)) {
1207 		resp_body[0] = ETM_PROTO_V2;
1208 		resp_hdrp->resp_len = 1;
1209 	} /* if should send our/negotiated proto ver in resp body */
1210 
1211 	/* respond with the proto ver that was negotiated */
1212 
1213 	resp_hdrp->resp_pp.pp_proto_ver = etm_resp_ver;
1214 	resp_hdrp->resp_pp.pp_msg_type = ETM_MSG_TYPE_RESPONSE;
1215 	resp_hdrp->resp_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE;
1216 
1217 	/*
1218 	 * send the whole response msg in one write, header and body;
1219 	 * avoid the alloc-and-copy if we can reuse the hdr as the msg,
1220 	 * ie, if the body is empty
1221 	 *
1222 	 * update stats and note the xid associated with last ACKed FMA_EVENT
1223 	 * known to be successfully posted to FMD to aid duplicate filtering
1224 	 */
1225 
1226 	hdr_sz = sizeof (etm_proto_v1_resp_hdr_t);
1227 
1228 	resp_msg = hdrp;
1229 	if (resp_hdrp->resp_len > 0) {
1230 		resp_msg = fmd_hdl_zalloc(hdl, hdr_sz + resp_hdrp->resp_len,
1231 		    FMD_SLEEP);
1232 		(void) memcpy(resp_msg, resp_hdrp, hdr_sz);
1233 		(void) memcpy(resp_msg + hdr_sz, resp_body,
1234 		    resp_hdrp->resp_len);
1235 	}
1236 
1237 	if ((n = etm_io_op(hdl, "bad io write on resp msg", conn,
1238 	    resp_msg, hdr_sz + resp_hdrp->resp_len, ETM_IO_OP_WR)) < 0) {
1239 		rv = n;
1240 		goto func_ret;
1241 	}
1242 
1243 	etm_stats.etm_wr_hdr_response.fmds_value.ui64++;
1244 	etm_stats.etm_wr_body_response.fmds_value.ui64++;
1245 
1246 	if ((orig_msg_type == ETM_MSG_TYPE_FMA_EVENT) &&
1247 	    (resp_code >= 0)) {
1248 		etm_xid_posted_ev = resp_hdrp->resp_pp.pp_xid;
1249 	}
1250 
1251 	fmd_hdl_debug(hdl, "info: sent V%u RESPONSE msg to xport "
1252 	    "xid 0x%x code %d len %u\n",
1253 	    (unsigned int)resp_hdrp->resp_pp.pp_proto_ver,
1254 	    resp_hdrp->resp_pp.pp_xid, resp_hdrp->resp_code,
1255 	    resp_hdrp->resp_len);
1256 func_ret:
1257 
1258 	if (resp_hdrp->resp_len > 0) {
1259 		fmd_hdl_free(hdl, resp_msg, hdr_sz + resp_hdrp->resp_len);
1260 	}
1261 	if (etm_debug_lvl >= 2) {
1262 		etm_show_time(hdl, "post resp send");
1263 	}
1264 	return (rv);
1265 
1266 } /* etm_maybe_send_response() */
1267 
1268 /*
1269  * etm_handle_new_conn - receive an ETM message sent from the other end via
1270  *			the given open connection, pull out any FMA events
1271  *			and post them to the local FMD (or handle any ETM
1272  *			control or response msg); when done, close the
1273  *			connection
1274  */
1275 
1276 static void
1277 etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn)
1278 {
1279 	etm_proto_v1_ev_hdr_t	*ev_hdrp;	/* for FMA_EVENT msg */
1280 	etm_proto_v1_ctl_hdr_t	*ctl_hdrp;	/* for CONTROL msg */
1281 	etm_proto_v1_resp_hdr_t *resp_hdrp;	/* for RESPONSE msg */
1282 	int32_t			resp_code;	/* response code */
1283 	size_t			hdr_sz;		/* sizeof header */
1284 	uint8_t			*body_buf;	/* msg body buffer */
1285 	uint32_t		body_sz;	/* sizeof body_buf */
1286 	uint32_t		ev_cnt;		/* count of FMA events */
1287 	uint8_t			*bp;		/* byte ptr within body_buf */
1288 	nvlist_t		*evp;		/* ptr to unpacked FMA event */
1289 	char			*class;		/* FMA event class */
1290 	ssize_t			i, n;		/* gen use */
1291 
1292 	if (etm_debug_lvl >= 2) {
1293 		etm_show_time(hdl, "ante conn handle");
1294 	}
1295 	fmd_hdl_debug(hdl, "info: handling new conn %p\n", conn);
1296 
1297 	ev_hdrp = NULL;
1298 	ctl_hdrp = NULL;
1299 	resp_hdrp = NULL;
1300 	body_buf = NULL;
1301 	class = NULL;
1302 	evp = NULL;
1303 	resp_code = 0;	/* default is success */
1304 
1305 	/* read a network decoded message header from the connection */
1306 
1307 	if ((ev_hdrp = etm_hdr_read(hdl, conn, &hdr_sz)) == NULL) {
1308 		/* errno assumed set by above call */
1309 		fmd_hdl_error(hdl, "error: FMA event dropped: "
1310 					"bad hdr read errno %d\n", errno);
1311 		etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1312 		goto func_ret;
1313 	}
1314 
1315 	/*
1316 	 * handle the message based on its preamble pp_msg_type
1317 	 * which is known to be valid from etm_hdr_read() checks
1318 	 */
1319 
1320 	if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) {
1321 
1322 		fmd_hdl_debug(hdl, "info: rcvd FMA_EVENT msg from xport\n");
1323 
1324 		/* allocate buf large enough for whole body / all FMA events */
1325 
1326 		body_sz = 0;
1327 		for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) {
1328 			body_sz += ev_hdrp->ev_lens[i];
1329 		} /* for summing sizes of all FMA events */
1330 		ev_cnt = i;
1331 
1332 		if (etm_debug_lvl >= 1) {
1333 			fmd_hdl_debug(hdl, "info: event lengths %u sum %u\n",
1334 			    ev_cnt, body_sz);
1335 		}
1336 
1337 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1338 
1339 		/* read all the FMA events at once */
1340 
1341 		if ((n = etm_io_op(hdl, "FMA event dropped: "
1342 					"bad io read on event bodies",
1343 					conn, body_buf, body_sz,
1344 					ETM_IO_OP_RD)) < 0) {
1345 			etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++;
1346 			goto func_ret;
1347 		}
1348 
1349 		etm_stats.etm_rd_xport_bytes.fmds_value.ui64 += body_sz;
1350 		etm_stats.etm_rd_body_fmaevent.fmds_value.ui64 += ev_cnt;
1351 
1352 		/*
1353 		 * check for dup msg/xid against last good response sent,
1354 		 * if a dup then resend response but skip repost to FMD
1355 		 */
1356 
1357 		if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_ev) {
1358 			(void) etm_maybe_send_response(hdl, conn, ev_hdrp, 0);
1359 			fmd_hdl_debug(hdl, "info: skipping dup FMA event post "
1360 			    "xid 0x%x\n", etm_xid_posted_ev);
1361 			etm_stats.etm_rd_dup_fmaevent.fmds_value.ui64++;
1362 			goto func_ret;
1363 		}
1364 
1365 		/* unpack each FMA event and post it to FMD */
1366 
1367 		bp = body_buf;
1368 		for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) {
1369 			if ((n = nvlist_unpack((char *)bp,
1370 					ev_hdrp->ev_lens[i], &evp, 0)) != 0) {
1371 				resp_code = (-n);
1372 				(void) etm_maybe_send_response(hdl, conn,
1373 				    ev_hdrp, resp_code);
1374 				fmd_hdl_error(hdl, "error: FMA event dropped: "
1375 						"bad event body unpack "
1376 						"errno %d\n", n);
1377 				if (etm_debug_lvl >= 2) {
1378 					fmd_hdl_debug(hdl, "info: FMA event "
1379 						"hexdump %d bytes:\n",
1380 						ev_hdrp->ev_lens[i]);
1381 					etm_hexdump(hdl, bp,
1382 						ev_hdrp->ev_lens[i]);
1383 				}
1384 				etm_stats.etm_os_nvlist_unpack_fail.fmds_value.
1385 					ui64++;
1386 				etm_stats.etm_rd_drop_fmaevent.fmds_value.
1387 					ui64++;
1388 				bp += ev_hdrp->ev_lens[i];
1389 				continue;
1390 			}
1391 			if (etm_debug_lvl >= 1) {
1392 				(void) nvlist_lookup_string(evp, FM_CLASS,
1393 								&class);
1394 				if (class == NULL) {
1395 					class = "NULL";
1396 				}
1397 				fmd_hdl_debug(hdl, "info: FMA event %p "
1398 						"class %s\n", evp, class);
1399 			}
1400 			resp_code = etm_post_to_fmd(hdl, evp);
1401 			(void) etm_maybe_send_response(hdl, conn,
1402 							ev_hdrp, resp_code);
1403 			nvlist_free(evp);
1404 			bp += ev_hdrp->ev_lens[i];
1405 		} /* foreach FMA event in the body buffer */
1406 
1407 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) {
1408 
1409 		ctl_hdrp = (void*)ev_hdrp;
1410 
1411 		fmd_hdl_debug(hdl, "info: rcvd CONTROL msg from xport\n");
1412 		if (etm_debug_lvl >= 1) {
1413 			fmd_hdl_debug(hdl, "info: ctl sel %d xid 0x%x\n",
1414 					(int)ctl_hdrp->ctl_pp.pp_sub_type,
1415 					ctl_hdrp->ctl_pp.pp_xid);
1416 		}
1417 
1418 		/*
1419 		 * if we have a VER_NEGOT_REQ read the body and validate
1420 		 * the protocol version set contained therein,
1421 		 * otherwise we have a PING_REQ (which has no body)
1422 		 * and we [also] fall thru to the code which sends a
1423 		 * response msg if the pp_timeout field requested one
1424 		 */
1425 
1426 		if (ctl_hdrp->ctl_pp.pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ) {
1427 
1428 			body_sz = ctl_hdrp->ctl_len;
1429 			body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1430 
1431 			if ((n = etm_io_op(hdl, "bad io read on ctl body",
1432 						conn, body_buf, body_sz,
1433 						ETM_IO_OP_RD)) < 0) {
1434 				goto func_ret;
1435 			}
1436 
1437 			/* complain if version set completely incompatible */
1438 
1439 			for (i = 0; i < body_sz; i++) {
1440 				if ((body_buf[i] == ETM_PROTO_V1) ||
1441 				    (body_buf[i] == ETM_PROTO_V2)) {
1442 					break;
1443 				}
1444 			}
1445 			if (i >= body_sz) {
1446 				etm_stats.etm_ver_bad.fmds_value.ui64++;
1447 				resp_code = (-EPROTO);
1448 			}
1449 
1450 		} /* if got version set request */
1451 
1452 		etm_stats.etm_rd_body_control.fmds_value.ui64++;
1453 
1454 		(void) etm_maybe_send_response(hdl, conn, ctl_hdrp, resp_code);
1455 
1456 	} else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) {
1457 
1458 		resp_hdrp = (void*)ev_hdrp;
1459 
1460 		fmd_hdl_debug(hdl, "info: rcvd RESPONSE msg from xport\n");
1461 		if (etm_debug_lvl >= 1) {
1462 			fmd_hdl_debug(hdl, "info: resp xid 0x%x\n",
1463 					(int)resp_hdrp->resp_pp.pp_xid);
1464 		}
1465 
1466 		body_sz = resp_hdrp->resp_len;
1467 		body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP);
1468 
1469 		if ((n = etm_io_op(hdl, "bad io read on resp len",
1470 				conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) {
1471 			goto func_ret;
1472 		}
1473 
1474 		etm_stats.etm_rd_body_response.fmds_value.ui64++;
1475 
1476 		/*
1477 		 * look up the xid to interpret the response body
1478 		 *
1479 		 * ping is a nop; for ver negot confirm that a supported
1480 		 * protocol version was negotiated and remember which one
1481 		 */
1482 
1483 		if ((resp_hdrp->resp_pp.pp_xid != etm_xid_ping) &&
1484 		    (resp_hdrp->resp_pp.pp_xid != etm_xid_ver_negot)) {
1485 			etm_stats.etm_xid_bad.fmds_value.ui64++;
1486 			goto func_ret;
1487 		}
1488 
1489 		if (resp_hdrp->resp_pp.pp_xid == etm_xid_ver_negot) {
1490 			if ((body_buf[0] < ETM_PROTO_V1) ||
1491 			    (body_buf[0] > ETM_PROTO_V2)) {
1492 				etm_stats.etm_ver_bad.fmds_value.ui64++;
1493 				goto func_ret;
1494 			}
1495 			etm_resp_ver = body_buf[0];
1496 		} /* if have resp to last req to negotiate proto ver */
1497 
1498 	} /* whether we have a FMA_EVENT, CONTROL, or RESPONSE msg */
1499 
1500 func_ret:
1501 
1502 	(void) etm_conn_close(hdl, "bad conn close after msg recv", conn);
1503 
1504 	if (etm_debug_lvl >= 2) {
1505 		etm_show_time(hdl, "post conn handle");
1506 	}
1507 	if (ev_hdrp != NULL) {
1508 		fmd_hdl_free(hdl, ev_hdrp, hdr_sz);
1509 	}
1510 	if (body_buf != NULL) {
1511 		fmd_hdl_free(hdl, body_buf, body_sz);
1512 	}
1513 } /* etm_handle_new_conn() */
1514 
1515 /*
1516  * etm_server - loop forever accepting new connections
1517  *		using the given FMD handle,
1518  *		handling any ETM msgs sent from the other side
1519  *		via each such connection
1520  */
1521 
1522 static void
1523 etm_server(void *arg)
1524 {
1525 	etm_xport_conn_t	conn;		/* connection handle */
1526 	ssize_t			n;		/* gen use */
1527 	fmd_hdl_t		*hdl;		/* FMD handle */
1528 
1529 	hdl = arg;
1530 
1531 	fmd_hdl_debug(hdl, "info: connection server starting\n");
1532 
1533 	while (!etm_is_dying) {
1534 		if ((conn = etm_xport_accept(hdl, NULL)) == NULL) {
1535 			/* errno assumed set by above call */
1536 			n = errno;
1537 			if (etm_is_dying) {
1538 				break;
1539 			}
1540 			fmd_hdl_debug(hdl,
1541 				"error: bad conn accept errno %d\n", n);
1542 			etm_stats.etm_xport_accept_fail.fmds_value.ui64++;
1543 			/* avoid spinning CPU */
1544 			(void) etm_sleep(ETM_SLEEP_SLOW);
1545 			continue;
1546 		}
1547 
1548 		/*
1549 		 * Design_Note: etm_handle_new_conn() will close the
1550 		 *		accepted connection when done. In early designs
1551 		 *		etm_handle_new_conn() was spawned as a
1552 		 *		separate thread via pthread_create();
1553 		 *		however fmd_thr_create() constrains thread
1554 		 *		creation to prevent spawned threads from
1555 		 *		spawning others (ie, no grandchildren).
1556 		 *		Hence etm_handle_new_conn() is now called
1557 		 *		as a simple function [w/ multiple args].
1558 		 */
1559 
1560 		etm_handle_new_conn(hdl, conn);
1561 
1562 	} /* while accepting new connections until ETM dies */
1563 
1564 	/* ETM is dying (probably due to "fmadm unload etm") */
1565 
1566 	if (etm_debug_lvl >= 1) {
1567 		fmd_hdl_debug(hdl, "info: connection server is dying\n");
1568 	}
1569 } /* etm_server() */
1570 
1571 /*
1572  * -------------------------- FMD entry points -------------------------------
1573  */
1574 
1575 /*
1576  * _fmd_init - initialize the transport for use by ETM and start the
1577  *		server daemon to accept new connections to us
1578  *
1579  *		FMD will read our *.conf and subscribe us to FMA events
1580  */
1581 
1582 void
1583 _fmd_init(fmd_hdl_t *hdl)
1584 {
1585 	struct timeval		tmv;		/* timeval */
1586 	ssize_t			n;		/* gen use */
1587 
1588 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) {
1589 		return; /* invalid data in configuration file */
1590 	}
1591 
1592 	fmd_hdl_debug(hdl, "info: module initializing\n");
1593 
1594 	/* setup statistics and properties from FMD */
1595 
1596 	(void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
1597 				sizeof (etm_stats) / sizeof (fmd_stat_t),
1598 				(fmd_stat_t *)&etm_stats);
1599 
1600 	etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
1601 	etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl,
1602 						ETM_PROP_NM_DEBUG_MAX_EV_CNT);
1603 	fmd_hdl_debug(hdl, "info: etm_debug_lvl %d "
1604 			"etm_debug_max_ev_cnt %d\n",
1605 			etm_debug_lvl, etm_debug_max_ev_cnt);
1606 
1607 	/* encourage protocol transaction id to be unique per module load */
1608 
1609 	(void) gettimeofday(&tmv, NULL);
1610 	etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) |
1611 	    ((unsigned long)tmv.tv_usec >> 10));
1612 
1613 	/*
1614 	 * init the transport,
1615 	 * start the connection acceptance server, and
1616 	 * request protocol version be negotiated
1617 	 */
1618 
1619 	if ((n = etm_xport_init(hdl)) != 0) {
1620 		fmd_hdl_error(hdl, "error: bad xport init errno %d\n", (-n));
1621 		fmd_hdl_unregister(hdl);
1622 		return;
1623 	}
1624 
1625 	etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl);
1626 	etm_req_ver_negot(hdl);
1627 
1628 	fmd_hdl_debug(hdl, "info: module initialized ok\n");
1629 
1630 } /* _fmd_init() */
1631 
1632 /*
1633  * etm_recv - receive an FMA event from FMD and transport it
1634  *		to the remote endpoint
1635  */
1636 
1637 /*ARGSUSED*/
1638 void
1639 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class)
1640 {
1641 	etm_xport_addr_t	*addrv;	/* vector of transport addresses */
1642 	etm_xport_conn_t	conn;	/* connection handle */
1643 	etm_proto_v1_ev_hdr_t	*hdrp;	/* for FMA_EVENT msg */
1644 	ssize_t			i, n;	/* gen use */
1645 	size_t			sz;	/* header size */
1646 	size_t			buflen;	/* size of packed FMA event */
1647 	uint8_t			*buf;	/* tmp buffer for packed FMA event */
1648 
1649 	buflen = 0;
1650 	(void) nvlist_size(evp, &buflen, NV_ENCODE_XDR);
1651 	etm_stats.etm_rd_fmd_bytes.fmds_value.ui64 += buflen;
1652 	etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64++;
1653 
1654 	fmd_hdl_debug(hdl, "info: rcvd event %p from FMD\n", evp);
1655 	fmd_hdl_debug(hdl, "info: cnt %llu class %s\n",
1656 		etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64, class);
1657 
1658 	/*
1659 	 * if the debug limit has been set, avoid excessive traffic,
1660 	 * for example, an infinite cycle using loopback nodes
1661 	 */
1662 
1663 	if ((etm_debug_max_ev_cnt >= 0) &&
1664 		(etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64 >
1665 						etm_debug_max_ev_cnt)) {
1666 		fmd_hdl_debug(hdl, "warning: FMA event dropped: "
1667 			"event %p cnt %llu > debug max %d\n", evp,
1668 			etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64,
1669 			etm_debug_max_ev_cnt);
1670 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1671 		return;
1672 	}
1673 
1674 	/* allocate a buffer for the FMA event and nvlist pack it */
1675 
1676 	buf = fmd_hdl_zalloc(hdl, buflen, FMD_SLEEP);
1677 
1678 	if ((n = nvlist_pack(evp, (char **)&buf, &buflen,
1679 					NV_ENCODE_XDR, 0)) != 0) {
1680 		fmd_hdl_error(hdl, "error: FMA event dropped: "
1681 				"event pack errno %d\n", n);
1682 		etm_stats.etm_os_nvlist_pack_fail.fmds_value.ui64++;
1683 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1684 		fmd_hdl_free(hdl, buf, buflen);
1685 		return;
1686 	}
1687 
1688 	/* get vector of dst addrs and send the FMA event to each one */
1689 
1690 	if ((addrv = etm_xport_get_ev_addrv(hdl, evp)) == NULL) {
1691 		fmd_hdl_error(hdl, "error: FMA event dropped: "
1692 				"bad event dst addrs errno %d\n", errno);
1693 		etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++;
1694 		etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1695 		fmd_hdl_free(hdl, buf, buflen);
1696 		return;
1697 	}
1698 
1699 	for (i = 0; addrv[i] != NULL; i++) {
1700 
1701 		/* open a new connection to this dst addr */
1702 
1703 		if ((n = etm_conn_open(hdl, "FMA event dropped: "
1704 				"bad conn open on new ev",
1705 				addrv[i], &conn)) < 0) {
1706 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1707 			continue;
1708 		}
1709 
1710 		/* write the ETM message header */
1711 
1712 		if ((hdrp = etm_hdr_write(hdl, conn, evp, NV_ENCODE_XDR,
1713 							&sz)) == NULL) {
1714 			fmd_hdl_error(hdl, "error: FMA event dropped: "
1715 					"bad hdr write errno %d\n", errno);
1716 			(void) etm_conn_close(hdl,
1717 				"bad conn close per bad hdr wr", conn);
1718 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1719 			continue;
1720 		}
1721 
1722 		fmd_hdl_free(hdl, hdrp, sz);	/* header not needed */
1723 		etm_stats.etm_wr_hdr_fmaevent.fmds_value.ui64++;
1724 		fmd_hdl_debug(hdl, "info: hdr xport write ok for event %p\n",
1725 								evp);
1726 
1727 		/* write the ETM message body, ie, the packed nvlist */
1728 
1729 		if ((n = etm_io_op(hdl, "FMA event dropped: "
1730 					"bad io write on event", conn,
1731 					buf, buflen, ETM_IO_OP_WR)) < 0) {
1732 			(void) etm_conn_close(hdl,
1733 				"bad conn close per bad body wr", conn);
1734 			etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++;
1735 			continue;
1736 		}
1737 
1738 		etm_stats.etm_wr_body_fmaevent.fmds_value.ui64++;
1739 		etm_stats.etm_wr_xport_bytes.fmds_value.ui64 += buflen;
1740 		fmd_hdl_debug(hdl, "info: body xport write ok for event %p\n",
1741 								evp);
1742 
1743 		/* close the connection */
1744 
1745 		(void) etm_conn_close(hdl, "bad conn close after event send",
1746 									conn);
1747 	} /* foreach dst addr in the vector */
1748 
1749 	etm_xport_free_addrv(hdl, addrv);
1750 	fmd_hdl_free(hdl, buf, buflen);
1751 
1752 } /* etm_recv() */
1753 
1754 /*
1755  * _fmd_fini - stop the server daemon and teardown the transport
1756  */
1757 
1758 void
1759 _fmd_fini(fmd_hdl_t *hdl)
1760 {
1761 	ssize_t	n;	/* gen use */
1762 
1763 	fmd_hdl_debug(hdl, "info: module finializing\n");
1764 
1765 	/* kill the connection server ; wait for it to die */
1766 
1767 	etm_is_dying = 1;
1768 
1769 	if (etm_svr_tid != NULL) {
1770 		fmd_thr_signal(hdl, etm_svr_tid);
1771 		fmd_thr_destroy(hdl, etm_svr_tid);
1772 		etm_svr_tid = NULL;
1773 	} /* if server thread was successfully created */
1774 
1775 	/* teardown the transport */
1776 
1777 	if ((n = etm_xport_fini(hdl)) != 0) {
1778 		fmd_hdl_error(hdl, "warning: xport fini errno %d\n", (-n));
1779 	}
1780 
1781 	fmd_hdl_debug(hdl, "info: module finalized ok\n");
1782 
1783 } /* _fmd_fini() */
1784