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