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