xref: /freebsd-src/sys/contrib/openzfs/cmd/zed/agents/fmd_api.c (revision eda14cbc264d6969b02f2b1994cef11148e914f1)
1*eda14cbcSMatt Macy /*
2*eda14cbcSMatt Macy  * CDDL HEADER START
3*eda14cbcSMatt Macy  *
4*eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5*eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6*eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7*eda14cbcSMatt Macy  *
8*eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*eda14cbcSMatt Macy  * or http://www.opensolaris.org/os/licensing.
10*eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11*eda14cbcSMatt Macy  * and limitations under the License.
12*eda14cbcSMatt Macy  *
13*eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14*eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16*eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17*eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18*eda14cbcSMatt Macy  *
19*eda14cbcSMatt Macy  * CDDL HEADER END
20*eda14cbcSMatt Macy  */
21*eda14cbcSMatt Macy /*
22*eda14cbcSMatt Macy  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23*eda14cbcSMatt Macy  *
24*eda14cbcSMatt Macy  * Copyright (c) 2016, Intel Corporation.
25*eda14cbcSMatt Macy  */
26*eda14cbcSMatt Macy 
27*eda14cbcSMatt Macy /*
28*eda14cbcSMatt Macy  * This file implements the minimal FMD module API required to support the
29*eda14cbcSMatt Macy  * fault logic modules in ZED. This support includes module registration,
30*eda14cbcSMatt Macy  * memory allocation, module property accessors, basic case management,
31*eda14cbcSMatt Macy  * one-shot timers and SERD engines.
32*eda14cbcSMatt Macy  *
33*eda14cbcSMatt Macy  * In the ZED runtime, the modules are called from a single thread so no
34*eda14cbcSMatt Macy  * locking is required in this emulated FMD environment.
35*eda14cbcSMatt Macy  */
36*eda14cbcSMatt Macy 
37*eda14cbcSMatt Macy #include <sys/types.h>
38*eda14cbcSMatt Macy #include <sys/fm/protocol.h>
39*eda14cbcSMatt Macy #include <uuid/uuid.h>
40*eda14cbcSMatt Macy #include <signal.h>
41*eda14cbcSMatt Macy #include <strings.h>
42*eda14cbcSMatt Macy #include <time.h>
43*eda14cbcSMatt Macy 
44*eda14cbcSMatt Macy #include "fmd_api.h"
45*eda14cbcSMatt Macy #include "fmd_serd.h"
46*eda14cbcSMatt Macy 
47*eda14cbcSMatt Macy #include "zfs_agents.h"
48*eda14cbcSMatt Macy #include "../zed_log.h"
49*eda14cbcSMatt Macy 
50*eda14cbcSMatt Macy typedef struct fmd_modstat {
51*eda14cbcSMatt Macy 	fmd_stat_t	ms_accepted;	/* total events accepted by module */
52*eda14cbcSMatt Macy 	fmd_stat_t	ms_caseopen;	/* cases currently open */
53*eda14cbcSMatt Macy 	fmd_stat_t	ms_casesolved;	/* total cases solved by module */
54*eda14cbcSMatt Macy 	fmd_stat_t	ms_caseclosed;	/* total cases closed by module */
55*eda14cbcSMatt Macy } fmd_modstat_t;
56*eda14cbcSMatt Macy 
57*eda14cbcSMatt Macy typedef struct fmd_module {
58*eda14cbcSMatt Macy 	const char	*mod_name;	/* basename of module (ro) */
59*eda14cbcSMatt Macy 	const fmd_hdl_info_t *mod_info;	/* module info registered with handle */
60*eda14cbcSMatt Macy 	void		*mod_spec;	/* fmd_hdl_get/setspecific data value */
61*eda14cbcSMatt Macy 	fmd_stat_t	*mod_ustat;	/* module specific custom stats */
62*eda14cbcSMatt Macy 	uint_t		mod_ustat_cnt;	/* count of ustat stats */
63*eda14cbcSMatt Macy 	fmd_modstat_t	mod_stats;	/* fmd built-in per-module statistics */
64*eda14cbcSMatt Macy 	fmd_serd_hash_t	mod_serds;	/* hash of serd engs owned by module */
65*eda14cbcSMatt Macy 	char		*mod_vers;	/* a copy of module version string */
66*eda14cbcSMatt Macy } fmd_module_t;
67*eda14cbcSMatt Macy 
68*eda14cbcSMatt Macy /*
69*eda14cbcSMatt Macy  * ZED has two FMD hardwired module instances
70*eda14cbcSMatt Macy  */
71*eda14cbcSMatt Macy fmd_module_t	zfs_retire_module;
72*eda14cbcSMatt Macy fmd_module_t	zfs_diagnosis_module;
73*eda14cbcSMatt Macy 
74*eda14cbcSMatt Macy /*
75*eda14cbcSMatt Macy  * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
76*eda14cbcSMatt Macy  */
77*eda14cbcSMatt Macy 
78*eda14cbcSMatt Macy #ifdef DEBUG
79*eda14cbcSMatt Macy const char *
80*eda14cbcSMatt Macy _umem_debug_init(void)
81*eda14cbcSMatt Macy {
82*eda14cbcSMatt Macy 	return ("default,verbose"); /* $UMEM_DEBUG setting */
83*eda14cbcSMatt Macy }
84*eda14cbcSMatt Macy 
85*eda14cbcSMatt Macy const char *
86*eda14cbcSMatt Macy _umem_logging_init(void)
87*eda14cbcSMatt Macy {
88*eda14cbcSMatt Macy 	return ("fail,contents"); /* $UMEM_LOGGING setting */
89*eda14cbcSMatt Macy }
90*eda14cbcSMatt Macy #endif
91*eda14cbcSMatt Macy 
92*eda14cbcSMatt Macy /*
93*eda14cbcSMatt Macy  * Register a module with fmd and finish module initialization.
94*eda14cbcSMatt Macy  * Returns an integer indicating whether it succeeded (zero) or
95*eda14cbcSMatt Macy  * failed (non-zero).
96*eda14cbcSMatt Macy  */
97*eda14cbcSMatt Macy int
98*eda14cbcSMatt Macy fmd_hdl_register(fmd_hdl_t *hdl, int version, const fmd_hdl_info_t *mip)
99*eda14cbcSMatt Macy {
100*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
101*eda14cbcSMatt Macy 
102*eda14cbcSMatt Macy 	mp->mod_info = mip;
103*eda14cbcSMatt Macy 	mp->mod_name = mip->fmdi_desc + 4;	/* drop 'ZFS ' prefix */
104*eda14cbcSMatt Macy 	mp->mod_spec = NULL;
105*eda14cbcSMatt Macy 
106*eda14cbcSMatt Macy 	/* bare minimum module stats */
107*eda14cbcSMatt Macy 	(void) strcpy(mp->mod_stats.ms_accepted.fmds_name, "fmd.accepted");
108*eda14cbcSMatt Macy 	(void) strcpy(mp->mod_stats.ms_caseopen.fmds_name, "fmd.caseopen");
109*eda14cbcSMatt Macy 	(void) strcpy(mp->mod_stats.ms_casesolved.fmds_name, "fmd.casesolved");
110*eda14cbcSMatt Macy 	(void) strcpy(mp->mod_stats.ms_caseclosed.fmds_name, "fmd.caseclosed");
111*eda14cbcSMatt Macy 
112*eda14cbcSMatt Macy 	fmd_serd_hash_create(&mp->mod_serds);
113*eda14cbcSMatt Macy 
114*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "register module");
115*eda14cbcSMatt Macy 
116*eda14cbcSMatt Macy 	return (0);
117*eda14cbcSMatt Macy }
118*eda14cbcSMatt Macy 
119*eda14cbcSMatt Macy void
120*eda14cbcSMatt Macy fmd_hdl_unregister(fmd_hdl_t *hdl)
121*eda14cbcSMatt Macy {
122*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
123*eda14cbcSMatt Macy 	fmd_modstat_t *msp = &mp->mod_stats;
124*eda14cbcSMatt Macy 	const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
125*eda14cbcSMatt Macy 
126*eda14cbcSMatt Macy 	/* dump generic module stats */
127*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "%s: %llu", msp->ms_accepted.fmds_name,
128*eda14cbcSMatt Macy 	    msp->ms_accepted.fmds_value.ui64);
129*eda14cbcSMatt Macy 	if (ops->fmdo_close != NULL) {
130*eda14cbcSMatt Macy 		fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseopen.fmds_name,
131*eda14cbcSMatt Macy 		    msp->ms_caseopen.fmds_value.ui64);
132*eda14cbcSMatt Macy 		fmd_hdl_debug(hdl, "%s: %llu", msp->ms_casesolved.fmds_name,
133*eda14cbcSMatt Macy 		    msp->ms_casesolved.fmds_value.ui64);
134*eda14cbcSMatt Macy 		fmd_hdl_debug(hdl, "%s: %llu", msp->ms_caseclosed.fmds_name,
135*eda14cbcSMatt Macy 		    msp->ms_caseclosed.fmds_value.ui64);
136*eda14cbcSMatt Macy 	}
137*eda14cbcSMatt Macy 
138*eda14cbcSMatt Macy 	/* dump module specific stats */
139*eda14cbcSMatt Macy 	if (mp->mod_ustat != NULL) {
140*eda14cbcSMatt Macy 		int i;
141*eda14cbcSMatt Macy 
142*eda14cbcSMatt Macy 		for (i = 0; i < mp->mod_ustat_cnt; i++) {
143*eda14cbcSMatt Macy 			fmd_hdl_debug(hdl, "%s: %llu",
144*eda14cbcSMatt Macy 			    mp->mod_ustat[i].fmds_name,
145*eda14cbcSMatt Macy 			    mp->mod_ustat[i].fmds_value.ui64);
146*eda14cbcSMatt Macy 		}
147*eda14cbcSMatt Macy 	}
148*eda14cbcSMatt Macy 
149*eda14cbcSMatt Macy 	fmd_serd_hash_destroy(&mp->mod_serds);
150*eda14cbcSMatt Macy 
151*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "unregister module");
152*eda14cbcSMatt Macy }
153*eda14cbcSMatt Macy 
154*eda14cbcSMatt Macy /*
155*eda14cbcSMatt Macy  * fmd_hdl_setspecific() is used to associate a data pointer with
156*eda14cbcSMatt Macy  * the specified handle for the duration of the module's lifetime.
157*eda14cbcSMatt Macy  * This pointer can be retrieved using fmd_hdl_getspecific().
158*eda14cbcSMatt Macy  */
159*eda14cbcSMatt Macy void
160*eda14cbcSMatt Macy fmd_hdl_setspecific(fmd_hdl_t *hdl, void *spec)
161*eda14cbcSMatt Macy {
162*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
163*eda14cbcSMatt Macy 
164*eda14cbcSMatt Macy 	mp->mod_spec = spec;
165*eda14cbcSMatt Macy }
166*eda14cbcSMatt Macy 
167*eda14cbcSMatt Macy /*
168*eda14cbcSMatt Macy  * Return the module-specific data pointer previously associated
169*eda14cbcSMatt Macy  * with the handle using fmd_hdl_setspecific().
170*eda14cbcSMatt Macy  */
171*eda14cbcSMatt Macy void *
172*eda14cbcSMatt Macy fmd_hdl_getspecific(fmd_hdl_t *hdl)
173*eda14cbcSMatt Macy {
174*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
175*eda14cbcSMatt Macy 
176*eda14cbcSMatt Macy 	return (mp->mod_spec);
177*eda14cbcSMatt Macy }
178*eda14cbcSMatt Macy 
179*eda14cbcSMatt Macy void *
180*eda14cbcSMatt Macy fmd_hdl_alloc(fmd_hdl_t *hdl, size_t size, int flags)
181*eda14cbcSMatt Macy {
182*eda14cbcSMatt Macy 	return (umem_alloc(size, flags));
183*eda14cbcSMatt Macy }
184*eda14cbcSMatt Macy 
185*eda14cbcSMatt Macy void *
186*eda14cbcSMatt Macy fmd_hdl_zalloc(fmd_hdl_t *hdl, size_t size, int flags)
187*eda14cbcSMatt Macy {
188*eda14cbcSMatt Macy 	return (umem_zalloc(size, flags));
189*eda14cbcSMatt Macy }
190*eda14cbcSMatt Macy 
191*eda14cbcSMatt Macy void
192*eda14cbcSMatt Macy fmd_hdl_free(fmd_hdl_t *hdl, void *data, size_t size)
193*eda14cbcSMatt Macy {
194*eda14cbcSMatt Macy 	umem_free(data, size);
195*eda14cbcSMatt Macy }
196*eda14cbcSMatt Macy 
197*eda14cbcSMatt Macy /*
198*eda14cbcSMatt Macy  * Record a module debug message using the specified format.
199*eda14cbcSMatt Macy  */
200*eda14cbcSMatt Macy void
201*eda14cbcSMatt Macy fmd_hdl_debug(fmd_hdl_t *hdl, const char *format, ...)
202*eda14cbcSMatt Macy {
203*eda14cbcSMatt Macy 	char message[256];
204*eda14cbcSMatt Macy 	va_list vargs;
205*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
206*eda14cbcSMatt Macy 
207*eda14cbcSMatt Macy 	va_start(vargs, format);
208*eda14cbcSMatt Macy 	(void) vsnprintf(message, sizeof (message), format, vargs);
209*eda14cbcSMatt Macy 	va_end(vargs);
210*eda14cbcSMatt Macy 
211*eda14cbcSMatt Macy 	/* prefix message with module name */
212*eda14cbcSMatt Macy 	zed_log_msg(LOG_INFO, "%s: %s", mp->mod_name, message);
213*eda14cbcSMatt Macy }
214*eda14cbcSMatt Macy 
215*eda14cbcSMatt Macy /* Property Retrieval */
216*eda14cbcSMatt Macy 
217*eda14cbcSMatt Macy int32_t
218*eda14cbcSMatt Macy fmd_prop_get_int32(fmd_hdl_t *hdl, const char *name)
219*eda14cbcSMatt Macy {
220*eda14cbcSMatt Macy 	/*
221*eda14cbcSMatt Macy 	 * These can be looked up in mp->modinfo->fmdi_props
222*eda14cbcSMatt Macy 	 * For now we just hard code for phase 2. In the
223*eda14cbcSMatt Macy 	 * future, there can be a ZED based override.
224*eda14cbcSMatt Macy 	 */
225*eda14cbcSMatt Macy 	if (strcmp(name, "spare_on_remove") == 0)
226*eda14cbcSMatt Macy 		return (1);
227*eda14cbcSMatt Macy 
228*eda14cbcSMatt Macy 	if (strcmp(name, "io_N") == 0 || strcmp(name, "checksum_N") == 0)
229*eda14cbcSMatt Macy 		return (10);	/* N = 10 events */
230*eda14cbcSMatt Macy 
231*eda14cbcSMatt Macy 	return (0);
232*eda14cbcSMatt Macy }
233*eda14cbcSMatt Macy 
234*eda14cbcSMatt Macy int64_t
235*eda14cbcSMatt Macy fmd_prop_get_int64(fmd_hdl_t *hdl, const char *name)
236*eda14cbcSMatt Macy {
237*eda14cbcSMatt Macy 	/*
238*eda14cbcSMatt Macy 	 * These can be looked up in mp->modinfo->fmdi_props
239*eda14cbcSMatt Macy 	 * For now we just hard code for phase 2. In the
240*eda14cbcSMatt Macy 	 * future, there can be a ZED based override.
241*eda14cbcSMatt Macy 	 */
242*eda14cbcSMatt Macy 	if (strcmp(name, "remove_timeout") == 0)
243*eda14cbcSMatt Macy 		return (15ULL * 1000ULL * 1000ULL * 1000ULL);	/* 15 sec */
244*eda14cbcSMatt Macy 
245*eda14cbcSMatt Macy 	if (strcmp(name, "io_T") == 0 || strcmp(name, "checksum_T") == 0)
246*eda14cbcSMatt Macy 		return (1000ULL * 1000ULL * 1000ULL * 600ULL);	/* 10 min */
247*eda14cbcSMatt Macy 
248*eda14cbcSMatt Macy 	return (0);
249*eda14cbcSMatt Macy }
250*eda14cbcSMatt Macy 
251*eda14cbcSMatt Macy /* FMD Statistics */
252*eda14cbcSMatt Macy 
253*eda14cbcSMatt Macy fmd_stat_t *
254*eda14cbcSMatt Macy fmd_stat_create(fmd_hdl_t *hdl, uint_t flags, uint_t nstats, fmd_stat_t *statv)
255*eda14cbcSMatt Macy {
256*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
257*eda14cbcSMatt Macy 
258*eda14cbcSMatt Macy 	if (flags == FMD_STAT_NOALLOC) {
259*eda14cbcSMatt Macy 		mp->mod_ustat = statv;
260*eda14cbcSMatt Macy 		mp->mod_ustat_cnt = nstats;
261*eda14cbcSMatt Macy 	}
262*eda14cbcSMatt Macy 
263*eda14cbcSMatt Macy 	return (statv);
264*eda14cbcSMatt Macy }
265*eda14cbcSMatt Macy 
266*eda14cbcSMatt Macy /* Case Management */
267*eda14cbcSMatt Macy 
268*eda14cbcSMatt Macy fmd_case_t *
269*eda14cbcSMatt Macy fmd_case_open(fmd_hdl_t *hdl, void *data)
270*eda14cbcSMatt Macy {
271*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
272*eda14cbcSMatt Macy 	uuid_t uuid;
273*eda14cbcSMatt Macy 
274*eda14cbcSMatt Macy 	fmd_case_t *cp;
275*eda14cbcSMatt Macy 
276*eda14cbcSMatt Macy 	cp = fmd_hdl_zalloc(hdl, sizeof (fmd_case_t), FMD_SLEEP);
277*eda14cbcSMatt Macy 	cp->ci_mod = hdl;
278*eda14cbcSMatt Macy 	cp->ci_state = FMD_CASE_UNSOLVED;
279*eda14cbcSMatt Macy 	cp->ci_flags = FMD_CF_DIRTY;
280*eda14cbcSMatt Macy 	cp->ci_data = data;
281*eda14cbcSMatt Macy 	cp->ci_bufptr = NULL;
282*eda14cbcSMatt Macy 	cp->ci_bufsiz = 0;
283*eda14cbcSMatt Macy 
284*eda14cbcSMatt Macy 	uuid_generate(uuid);
285*eda14cbcSMatt Macy 	uuid_unparse(uuid, cp->ci_uuid);
286*eda14cbcSMatt Macy 
287*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "case opened (%s)", cp->ci_uuid);
288*eda14cbcSMatt Macy 	mp->mod_stats.ms_caseopen.fmds_value.ui64++;
289*eda14cbcSMatt Macy 
290*eda14cbcSMatt Macy 	return (cp);
291*eda14cbcSMatt Macy }
292*eda14cbcSMatt Macy 
293*eda14cbcSMatt Macy void
294*eda14cbcSMatt Macy fmd_case_solve(fmd_hdl_t *hdl, fmd_case_t *cp)
295*eda14cbcSMatt Macy {
296*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
297*eda14cbcSMatt Macy 
298*eda14cbcSMatt Macy 	/*
299*eda14cbcSMatt Macy 	 * For ZED, the event was already sent from fmd_case_add_suspect()
300*eda14cbcSMatt Macy 	 */
301*eda14cbcSMatt Macy 
302*eda14cbcSMatt Macy 	if (cp->ci_state >= FMD_CASE_SOLVED)
303*eda14cbcSMatt Macy 		fmd_hdl_debug(hdl, "case is already solved or closed");
304*eda14cbcSMatt Macy 
305*eda14cbcSMatt Macy 	cp->ci_state = FMD_CASE_SOLVED;
306*eda14cbcSMatt Macy 
307*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "case solved (%s)", cp->ci_uuid);
308*eda14cbcSMatt Macy 	mp->mod_stats.ms_casesolved.fmds_value.ui64++;
309*eda14cbcSMatt Macy }
310*eda14cbcSMatt Macy 
311*eda14cbcSMatt Macy void
312*eda14cbcSMatt Macy fmd_case_close(fmd_hdl_t *hdl, fmd_case_t *cp)
313*eda14cbcSMatt Macy {
314*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
315*eda14cbcSMatt Macy 	const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
316*eda14cbcSMatt Macy 
317*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "case closed (%s)", cp->ci_uuid);
318*eda14cbcSMatt Macy 
319*eda14cbcSMatt Macy 	if (ops->fmdo_close != NULL)
320*eda14cbcSMatt Macy 		ops->fmdo_close(hdl, cp);
321*eda14cbcSMatt Macy 
322*eda14cbcSMatt Macy 	mp->mod_stats.ms_caseopen.fmds_value.ui64--;
323*eda14cbcSMatt Macy 	mp->mod_stats.ms_caseclosed.fmds_value.ui64++;
324*eda14cbcSMatt Macy 
325*eda14cbcSMatt Macy 	if (cp->ci_bufptr != NULL && cp->ci_bufsiz > 0)
326*eda14cbcSMatt Macy 		fmd_hdl_free(hdl, cp->ci_bufptr, cp->ci_bufsiz);
327*eda14cbcSMatt Macy 
328*eda14cbcSMatt Macy 	fmd_hdl_free(hdl, cp, sizeof (fmd_case_t));
329*eda14cbcSMatt Macy }
330*eda14cbcSMatt Macy 
331*eda14cbcSMatt Macy void
332*eda14cbcSMatt Macy fmd_case_uuresolved(fmd_hdl_t *hdl, const char *uuid)
333*eda14cbcSMatt Macy {
334*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "case resolved by uuid (%s)", uuid);
335*eda14cbcSMatt Macy }
336*eda14cbcSMatt Macy 
337*eda14cbcSMatt Macy int
338*eda14cbcSMatt Macy fmd_case_solved(fmd_hdl_t *hdl, fmd_case_t *cp)
339*eda14cbcSMatt Macy {
340*eda14cbcSMatt Macy 	return ((cp->ci_state >= FMD_CASE_SOLVED) ? FMD_B_TRUE : FMD_B_FALSE);
341*eda14cbcSMatt Macy }
342*eda14cbcSMatt Macy 
343*eda14cbcSMatt Macy void
344*eda14cbcSMatt Macy fmd_case_add_ereport(fmd_hdl_t *hdl, fmd_case_t *cp, fmd_event_t *ep)
345*eda14cbcSMatt Macy {
346*eda14cbcSMatt Macy }
347*eda14cbcSMatt Macy 
348*eda14cbcSMatt Macy static void
349*eda14cbcSMatt Macy zed_log_fault(nvlist_t *nvl, const char *uuid, const char *code)
350*eda14cbcSMatt Macy {
351*eda14cbcSMatt Macy 	nvlist_t *rsrc;
352*eda14cbcSMatt Macy 	char *strval;
353*eda14cbcSMatt Macy 	uint64_t guid;
354*eda14cbcSMatt Macy 	uint8_t byte;
355*eda14cbcSMatt Macy 
356*eda14cbcSMatt Macy 	zed_log_msg(LOG_INFO, "\nzed_fault_event:");
357*eda14cbcSMatt Macy 
358*eda14cbcSMatt Macy 	if (uuid != NULL)
359*eda14cbcSMatt Macy 		zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_UUID, uuid);
360*eda14cbcSMatt Macy 	if (nvlist_lookup_string(nvl, FM_CLASS, &strval) == 0)
361*eda14cbcSMatt Macy 		zed_log_msg(LOG_INFO, "\t%s: %s", FM_CLASS, strval);
362*eda14cbcSMatt Macy 	if (code != NULL)
363*eda14cbcSMatt Macy 		zed_log_msg(LOG_INFO, "\t%s: %s", FM_SUSPECT_DIAG_CODE, code);
364*eda14cbcSMatt Macy 	if (nvlist_lookup_uint8(nvl, FM_FAULT_CERTAINTY, &byte) == 0)
365*eda14cbcSMatt Macy 		zed_log_msg(LOG_INFO, "\t%s: %llu", FM_FAULT_CERTAINTY, byte);
366*eda14cbcSMatt Macy 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0) {
367*eda14cbcSMatt Macy 		if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &strval) == 0)
368*eda14cbcSMatt Macy 			zed_log_msg(LOG_INFO, "\t%s: %s", FM_FMRI_SCHEME,
369*eda14cbcSMatt Macy 			    strval);
370*eda14cbcSMatt Macy 		if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_POOL, &guid) == 0)
371*eda14cbcSMatt Macy 			zed_log_msg(LOG_INFO, "\t%s: %llu", FM_FMRI_ZFS_POOL,
372*eda14cbcSMatt Macy 			    guid);
373*eda14cbcSMatt Macy 		if (nvlist_lookup_uint64(rsrc, FM_FMRI_ZFS_VDEV, &guid) == 0)
374*eda14cbcSMatt Macy 			zed_log_msg(LOG_INFO, "\t%s: %llu \n", FM_FMRI_ZFS_VDEV,
375*eda14cbcSMatt Macy 			    guid);
376*eda14cbcSMatt Macy 	}
377*eda14cbcSMatt Macy }
378*eda14cbcSMatt Macy 
379*eda14cbcSMatt Macy static const char *
380*eda14cbcSMatt Macy fmd_fault_mkcode(nvlist_t *fault)
381*eda14cbcSMatt Macy {
382*eda14cbcSMatt Macy 	char *class, *code = "-";
383*eda14cbcSMatt Macy 
384*eda14cbcSMatt Macy 	/*
385*eda14cbcSMatt Macy 	 * Note: message codes come from: openzfs/usr/src/cmd/fm/dicts/ZFS.po
386*eda14cbcSMatt Macy 	 */
387*eda14cbcSMatt Macy 	if (nvlist_lookup_string(fault, FM_CLASS, &class) == 0) {
388*eda14cbcSMatt Macy 		if (strcmp(class, "fault.fs.zfs.vdev.io") == 0)
389*eda14cbcSMatt Macy 			code = "ZFS-8000-FD";
390*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.vdev.checksum") == 0)
391*eda14cbcSMatt Macy 			code = "ZFS-8000-GH";
392*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.io_failure_wait") == 0)
393*eda14cbcSMatt Macy 			code = "ZFS-8000-HC";
394*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.io_failure_continue") == 0)
395*eda14cbcSMatt Macy 			code = "ZFS-8000-JQ";
396*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.log_replay") == 0)
397*eda14cbcSMatt Macy 			code = "ZFS-8000-K4";
398*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.pool") == 0)
399*eda14cbcSMatt Macy 			code = "ZFS-8000-CS";
400*eda14cbcSMatt Macy 		else if (strcmp(class, "fault.fs.zfs.device") == 0)
401*eda14cbcSMatt Macy 			code = "ZFS-8000-D3";
402*eda14cbcSMatt Macy 
403*eda14cbcSMatt Macy 	}
404*eda14cbcSMatt Macy 	return (code);
405*eda14cbcSMatt Macy }
406*eda14cbcSMatt Macy 
407*eda14cbcSMatt Macy void
408*eda14cbcSMatt Macy fmd_case_add_suspect(fmd_hdl_t *hdl, fmd_case_t *cp, nvlist_t *fault)
409*eda14cbcSMatt Macy {
410*eda14cbcSMatt Macy 	nvlist_t *nvl;
411*eda14cbcSMatt Macy 	const char *code = fmd_fault_mkcode(fault);
412*eda14cbcSMatt Macy 	int64_t tod[2];
413*eda14cbcSMatt Macy 	int err = 0;
414*eda14cbcSMatt Macy 
415*eda14cbcSMatt Macy 	/*
416*eda14cbcSMatt Macy 	 * payload derived from fmd_protocol_list()
417*eda14cbcSMatt Macy 	 */
418*eda14cbcSMatt Macy 
419*eda14cbcSMatt Macy 	(void) gettimeofday(&cp->ci_tv, NULL);
420*eda14cbcSMatt Macy 	tod[0] = cp->ci_tv.tv_sec;
421*eda14cbcSMatt Macy 	tod[1] = cp->ci_tv.tv_usec;
422*eda14cbcSMatt Macy 
423*eda14cbcSMatt Macy 	nvl = fmd_nvl_alloc(hdl, FMD_SLEEP);
424*eda14cbcSMatt Macy 
425*eda14cbcSMatt Macy 	err |= nvlist_add_uint8(nvl, FM_VERSION, FM_SUSPECT_VERSION);
426*eda14cbcSMatt Macy 	err |= nvlist_add_string(nvl, FM_CLASS, FM_LIST_SUSPECT_CLASS);
427*eda14cbcSMatt Macy 	err |= nvlist_add_string(nvl, FM_SUSPECT_UUID, cp->ci_uuid);
428*eda14cbcSMatt Macy 	err |= nvlist_add_string(nvl, FM_SUSPECT_DIAG_CODE, code);
429*eda14cbcSMatt Macy 	err |= nvlist_add_int64_array(nvl, FM_SUSPECT_DIAG_TIME, tod, 2);
430*eda14cbcSMatt Macy 	err |= nvlist_add_uint32(nvl, FM_SUSPECT_FAULT_SZ, 1);
431*eda14cbcSMatt Macy 	err |= nvlist_add_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &fault, 1);
432*eda14cbcSMatt Macy 
433*eda14cbcSMatt Macy 	if (err)
434*eda14cbcSMatt Macy 		zed_log_die("failed to populate nvlist");
435*eda14cbcSMatt Macy 
436*eda14cbcSMatt Macy 	zed_log_fault(fault, cp->ci_uuid, code);
437*eda14cbcSMatt Macy 	zfs_agent_post_event(FM_LIST_SUSPECT_CLASS, NULL, nvl);
438*eda14cbcSMatt Macy 
439*eda14cbcSMatt Macy 	nvlist_free(nvl);
440*eda14cbcSMatt Macy 	nvlist_free(fault);
441*eda14cbcSMatt Macy }
442*eda14cbcSMatt Macy 
443*eda14cbcSMatt Macy void
444*eda14cbcSMatt Macy fmd_case_setspecific(fmd_hdl_t *hdl, fmd_case_t *cp, void *data)
445*eda14cbcSMatt Macy {
446*eda14cbcSMatt Macy 	cp->ci_data = data;
447*eda14cbcSMatt Macy }
448*eda14cbcSMatt Macy 
449*eda14cbcSMatt Macy void *
450*eda14cbcSMatt Macy fmd_case_getspecific(fmd_hdl_t *hdl, fmd_case_t *cp)
451*eda14cbcSMatt Macy {
452*eda14cbcSMatt Macy 	return (cp->ci_data);
453*eda14cbcSMatt Macy }
454*eda14cbcSMatt Macy 
455*eda14cbcSMatt Macy void
456*eda14cbcSMatt Macy fmd_buf_create(fmd_hdl_t *hdl, fmd_case_t *cp, const char *name, size_t size)
457*eda14cbcSMatt Macy {
458*eda14cbcSMatt Macy 	assert(strcmp(name, "data") == 0);
459*eda14cbcSMatt Macy 	assert(cp->ci_bufptr == NULL);
460*eda14cbcSMatt Macy 	assert(size < (1024 * 1024));
461*eda14cbcSMatt Macy 
462*eda14cbcSMatt Macy 	cp->ci_bufptr = fmd_hdl_alloc(hdl, size, FMD_SLEEP);
463*eda14cbcSMatt Macy 	cp->ci_bufsiz = size;
464*eda14cbcSMatt Macy }
465*eda14cbcSMatt Macy 
466*eda14cbcSMatt Macy void
467*eda14cbcSMatt Macy fmd_buf_read(fmd_hdl_t *hdl, fmd_case_t *cp,
468*eda14cbcSMatt Macy     const char *name, void *buf, size_t size)
469*eda14cbcSMatt Macy {
470*eda14cbcSMatt Macy 	assert(strcmp(name, "data") == 0);
471*eda14cbcSMatt Macy 	assert(cp->ci_bufptr != NULL);
472*eda14cbcSMatt Macy 	assert(size <= cp->ci_bufsiz);
473*eda14cbcSMatt Macy 
474*eda14cbcSMatt Macy 	bcopy(cp->ci_bufptr, buf, size);
475*eda14cbcSMatt Macy }
476*eda14cbcSMatt Macy 
477*eda14cbcSMatt Macy void
478*eda14cbcSMatt Macy fmd_buf_write(fmd_hdl_t *hdl, fmd_case_t *cp,
479*eda14cbcSMatt Macy     const char *name, const void *buf, size_t size)
480*eda14cbcSMatt Macy {
481*eda14cbcSMatt Macy 	assert(strcmp(name, "data") == 0);
482*eda14cbcSMatt Macy 	assert(cp->ci_bufptr != NULL);
483*eda14cbcSMatt Macy 	assert(cp->ci_bufsiz >= size);
484*eda14cbcSMatt Macy 
485*eda14cbcSMatt Macy 	bcopy(buf, cp->ci_bufptr, size);
486*eda14cbcSMatt Macy }
487*eda14cbcSMatt Macy 
488*eda14cbcSMatt Macy /* SERD Engines */
489*eda14cbcSMatt Macy 
490*eda14cbcSMatt Macy void
491*eda14cbcSMatt Macy fmd_serd_create(fmd_hdl_t *hdl, const char *name, uint_t n, hrtime_t t)
492*eda14cbcSMatt Macy {
493*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
494*eda14cbcSMatt Macy 
495*eda14cbcSMatt Macy 	if (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL) {
496*eda14cbcSMatt Macy 		zed_log_msg(LOG_ERR, "failed to create SERD engine '%s': "
497*eda14cbcSMatt Macy 		    " name already exists", name);
498*eda14cbcSMatt Macy 		return;
499*eda14cbcSMatt Macy 	}
500*eda14cbcSMatt Macy 
501*eda14cbcSMatt Macy 	(void) fmd_serd_eng_insert(&mp->mod_serds, name, n, t);
502*eda14cbcSMatt Macy }
503*eda14cbcSMatt Macy 
504*eda14cbcSMatt Macy void
505*eda14cbcSMatt Macy fmd_serd_destroy(fmd_hdl_t *hdl, const char *name)
506*eda14cbcSMatt Macy {
507*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
508*eda14cbcSMatt Macy 
509*eda14cbcSMatt Macy 	fmd_serd_eng_delete(&mp->mod_serds, name);
510*eda14cbcSMatt Macy 
511*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "serd_destroy %s", name);
512*eda14cbcSMatt Macy }
513*eda14cbcSMatt Macy 
514*eda14cbcSMatt Macy int
515*eda14cbcSMatt Macy fmd_serd_exists(fmd_hdl_t *hdl, const char *name)
516*eda14cbcSMatt Macy {
517*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
518*eda14cbcSMatt Macy 
519*eda14cbcSMatt Macy 	return (fmd_serd_eng_lookup(&mp->mod_serds, name) != NULL);
520*eda14cbcSMatt Macy }
521*eda14cbcSMatt Macy 
522*eda14cbcSMatt Macy void
523*eda14cbcSMatt Macy fmd_serd_reset(fmd_hdl_t *hdl, const char *name)
524*eda14cbcSMatt Macy {
525*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
526*eda14cbcSMatt Macy 	fmd_serd_eng_t *sgp;
527*eda14cbcSMatt Macy 
528*eda14cbcSMatt Macy 	if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
529*eda14cbcSMatt Macy 		zed_log_msg(LOG_ERR, "serd engine '%s' does not exist", name);
530*eda14cbcSMatt Macy 		return;
531*eda14cbcSMatt Macy 	}
532*eda14cbcSMatt Macy 
533*eda14cbcSMatt Macy 	fmd_serd_eng_reset(sgp);
534*eda14cbcSMatt Macy 
535*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "serd_reset %s", name);
536*eda14cbcSMatt Macy }
537*eda14cbcSMatt Macy 
538*eda14cbcSMatt Macy int
539*eda14cbcSMatt Macy fmd_serd_record(fmd_hdl_t *hdl, const char *name, fmd_event_t *ep)
540*eda14cbcSMatt Macy {
541*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
542*eda14cbcSMatt Macy 	fmd_serd_eng_t *sgp;
543*eda14cbcSMatt Macy 	int err;
544*eda14cbcSMatt Macy 
545*eda14cbcSMatt Macy 	if ((sgp = fmd_serd_eng_lookup(&mp->mod_serds, name)) == NULL) {
546*eda14cbcSMatt Macy 		zed_log_msg(LOG_ERR, "failed to add record to SERD engine '%s'",
547*eda14cbcSMatt Macy 		    name);
548*eda14cbcSMatt Macy 		return (FMD_B_FALSE);
549*eda14cbcSMatt Macy 	}
550*eda14cbcSMatt Macy 	err = fmd_serd_eng_record(sgp, ep->ev_hrt);
551*eda14cbcSMatt Macy 
552*eda14cbcSMatt Macy 	return (err);
553*eda14cbcSMatt Macy }
554*eda14cbcSMatt Macy 
555*eda14cbcSMatt Macy /* FMD Timers */
556*eda14cbcSMatt Macy 
557*eda14cbcSMatt Macy static void
558*eda14cbcSMatt Macy _timer_notify(union sigval sv)
559*eda14cbcSMatt Macy {
560*eda14cbcSMatt Macy 	fmd_timer_t *ftp = sv.sival_ptr;
561*eda14cbcSMatt Macy 	fmd_hdl_t *hdl = ftp->ft_hdl;
562*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
563*eda14cbcSMatt Macy 	const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
564*eda14cbcSMatt Macy 	struct itimerspec its;
565*eda14cbcSMatt Macy 
566*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "timer fired (%p)", ftp->ft_tid);
567*eda14cbcSMatt Macy 
568*eda14cbcSMatt Macy 	/* disarm the timer */
569*eda14cbcSMatt Macy 	bzero(&its, sizeof (struct itimerspec));
570*eda14cbcSMatt Macy 	timer_settime(ftp->ft_tid, 0, &its, NULL);
571*eda14cbcSMatt Macy 
572*eda14cbcSMatt Macy 	/* Note that the fmdo_timeout can remove this timer */
573*eda14cbcSMatt Macy 	if (ops->fmdo_timeout != NULL)
574*eda14cbcSMatt Macy 		ops->fmdo_timeout(hdl, ftp, ftp->ft_arg);
575*eda14cbcSMatt Macy }
576*eda14cbcSMatt Macy 
577*eda14cbcSMatt Macy /*
578*eda14cbcSMatt Macy  * Install a new timer which will fire at least delta nanoseconds after the
579*eda14cbcSMatt Macy  * current time. After the timeout has expired, the module's fmdo_timeout
580*eda14cbcSMatt Macy  * entry point is called.
581*eda14cbcSMatt Macy  */
582*eda14cbcSMatt Macy fmd_timer_t *
583*eda14cbcSMatt Macy fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta)
584*eda14cbcSMatt Macy {
585*eda14cbcSMatt Macy 	struct sigevent sev;
586*eda14cbcSMatt Macy 	struct itimerspec its;
587*eda14cbcSMatt Macy 	fmd_timer_t *ftp;
588*eda14cbcSMatt Macy 
589*eda14cbcSMatt Macy 	ftp = fmd_hdl_alloc(hdl, sizeof (fmd_timer_t), FMD_SLEEP);
590*eda14cbcSMatt Macy 	ftp->ft_arg = arg;
591*eda14cbcSMatt Macy 	ftp->ft_hdl = hdl;
592*eda14cbcSMatt Macy 
593*eda14cbcSMatt Macy 	its.it_value.tv_sec = delta / 1000000000;
594*eda14cbcSMatt Macy 	its.it_value.tv_nsec = delta % 1000000000;
595*eda14cbcSMatt Macy 	its.it_interval.tv_sec = its.it_value.tv_sec;
596*eda14cbcSMatt Macy 	its.it_interval.tv_nsec = its.it_value.tv_nsec;
597*eda14cbcSMatt Macy 
598*eda14cbcSMatt Macy 	sev.sigev_notify = SIGEV_THREAD;
599*eda14cbcSMatt Macy 	sev.sigev_notify_function = _timer_notify;
600*eda14cbcSMatt Macy 	sev.sigev_notify_attributes = NULL;
601*eda14cbcSMatt Macy 	sev.sigev_value.sival_ptr = ftp;
602*eda14cbcSMatt Macy 
603*eda14cbcSMatt Macy 	timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid);
604*eda14cbcSMatt Macy 	timer_settime(ftp->ft_tid, 0, &its, NULL);
605*eda14cbcSMatt Macy 
606*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "installing timer for %d secs (%p)",
607*eda14cbcSMatt Macy 	    (int)its.it_value.tv_sec, ftp->ft_tid);
608*eda14cbcSMatt Macy 
609*eda14cbcSMatt Macy 	return (ftp);
610*eda14cbcSMatt Macy }
611*eda14cbcSMatt Macy 
612*eda14cbcSMatt Macy void
613*eda14cbcSMatt Macy fmd_timer_remove(fmd_hdl_t *hdl, fmd_timer_t *ftp)
614*eda14cbcSMatt Macy {
615*eda14cbcSMatt Macy 	fmd_hdl_debug(hdl, "removing timer (%p)", ftp->ft_tid);
616*eda14cbcSMatt Macy 
617*eda14cbcSMatt Macy 	timer_delete(ftp->ft_tid);
618*eda14cbcSMatt Macy 
619*eda14cbcSMatt Macy 	fmd_hdl_free(hdl, ftp, sizeof (fmd_timer_t));
620*eda14cbcSMatt Macy }
621*eda14cbcSMatt Macy 
622*eda14cbcSMatt Macy /* Name-Value Pair Lists */
623*eda14cbcSMatt Macy 
624*eda14cbcSMatt Macy nvlist_t *
625*eda14cbcSMatt Macy fmd_nvl_create_fault(fmd_hdl_t *hdl, const char *class, uint8_t certainty,
626*eda14cbcSMatt Macy     nvlist_t *asru, nvlist_t *fru, nvlist_t *resource)
627*eda14cbcSMatt Macy {
628*eda14cbcSMatt Macy 	nvlist_t *nvl;
629*eda14cbcSMatt Macy 	int err = 0;
630*eda14cbcSMatt Macy 
631*eda14cbcSMatt Macy 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
632*eda14cbcSMatt Macy 		zed_log_die("failed to xalloc fault nvlist");
633*eda14cbcSMatt Macy 
634*eda14cbcSMatt Macy 	err |= nvlist_add_uint8(nvl, FM_VERSION, FM_FAULT_VERSION);
635*eda14cbcSMatt Macy 	err |= nvlist_add_string(nvl, FM_CLASS, class);
636*eda14cbcSMatt Macy 	err |= nvlist_add_uint8(nvl, FM_FAULT_CERTAINTY, certainty);
637*eda14cbcSMatt Macy 
638*eda14cbcSMatt Macy 	if (asru != NULL)
639*eda14cbcSMatt Macy 		err |= nvlist_add_nvlist(nvl, FM_FAULT_ASRU, asru);
640*eda14cbcSMatt Macy 	if (fru != NULL)
641*eda14cbcSMatt Macy 		err |= nvlist_add_nvlist(nvl, FM_FAULT_FRU, fru);
642*eda14cbcSMatt Macy 	if (resource != NULL)
643*eda14cbcSMatt Macy 		err |= nvlist_add_nvlist(nvl, FM_FAULT_RESOURCE, resource);
644*eda14cbcSMatt Macy 
645*eda14cbcSMatt Macy 	if (err)
646*eda14cbcSMatt Macy 		zed_log_die("failed to populate nvlist: %s\n", strerror(err));
647*eda14cbcSMatt Macy 
648*eda14cbcSMatt Macy 	return (nvl);
649*eda14cbcSMatt Macy }
650*eda14cbcSMatt Macy 
651*eda14cbcSMatt Macy /*
652*eda14cbcSMatt Macy  * sourced from fmd_string.c
653*eda14cbcSMatt Macy  */
654*eda14cbcSMatt Macy static int
655*eda14cbcSMatt Macy fmd_strmatch(const char *s, const char *p)
656*eda14cbcSMatt Macy {
657*eda14cbcSMatt Macy 	char c;
658*eda14cbcSMatt Macy 
659*eda14cbcSMatt Macy 	if (p == NULL)
660*eda14cbcSMatt Macy 		return (0);
661*eda14cbcSMatt Macy 
662*eda14cbcSMatt Macy 	if (s == NULL)
663*eda14cbcSMatt Macy 		s = ""; /* treat NULL string as the empty string */
664*eda14cbcSMatt Macy 
665*eda14cbcSMatt Macy 	do {
666*eda14cbcSMatt Macy 		if ((c = *p++) == '\0')
667*eda14cbcSMatt Macy 			return (*s == '\0');
668*eda14cbcSMatt Macy 
669*eda14cbcSMatt Macy 		if (c == '*') {
670*eda14cbcSMatt Macy 			while (*p == '*')
671*eda14cbcSMatt Macy 				p++; /* consecutive *'s can be collapsed */
672*eda14cbcSMatt Macy 
673*eda14cbcSMatt Macy 			if (*p == '\0')
674*eda14cbcSMatt Macy 				return (1);
675*eda14cbcSMatt Macy 
676*eda14cbcSMatt Macy 			while (*s != '\0') {
677*eda14cbcSMatt Macy 				if (fmd_strmatch(s++, p) != 0)
678*eda14cbcSMatt Macy 					return (1);
679*eda14cbcSMatt Macy 			}
680*eda14cbcSMatt Macy 
681*eda14cbcSMatt Macy 			return (0);
682*eda14cbcSMatt Macy 		}
683*eda14cbcSMatt Macy 	} while (c == *s++);
684*eda14cbcSMatt Macy 
685*eda14cbcSMatt Macy 	return (0);
686*eda14cbcSMatt Macy }
687*eda14cbcSMatt Macy 
688*eda14cbcSMatt Macy int
689*eda14cbcSMatt Macy fmd_nvl_class_match(fmd_hdl_t *hdl, nvlist_t *nvl, const char *pattern)
690*eda14cbcSMatt Macy {
691*eda14cbcSMatt Macy 	char *class;
692*eda14cbcSMatt Macy 
693*eda14cbcSMatt Macy 	return (nvl != NULL &&
694*eda14cbcSMatt Macy 	    nvlist_lookup_string(nvl, FM_CLASS, &class) == 0 &&
695*eda14cbcSMatt Macy 	    fmd_strmatch(class, pattern));
696*eda14cbcSMatt Macy }
697*eda14cbcSMatt Macy 
698*eda14cbcSMatt Macy nvlist_t *
699*eda14cbcSMatt Macy fmd_nvl_alloc(fmd_hdl_t *hdl, int flags)
700*eda14cbcSMatt Macy {
701*eda14cbcSMatt Macy 	nvlist_t *nvl = NULL;
702*eda14cbcSMatt Macy 
703*eda14cbcSMatt Macy 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
704*eda14cbcSMatt Macy 		return (NULL);
705*eda14cbcSMatt Macy 
706*eda14cbcSMatt Macy 	return (nvl);
707*eda14cbcSMatt Macy }
708*eda14cbcSMatt Macy 
709*eda14cbcSMatt Macy 
710*eda14cbcSMatt Macy /*
711*eda14cbcSMatt Macy  * ZED Agent specific APIs
712*eda14cbcSMatt Macy  */
713*eda14cbcSMatt Macy 
714*eda14cbcSMatt Macy fmd_hdl_t *
715*eda14cbcSMatt Macy fmd_module_hdl(const char *name)
716*eda14cbcSMatt Macy {
717*eda14cbcSMatt Macy 	if (strcmp(name, "zfs-retire") == 0)
718*eda14cbcSMatt Macy 		return ((fmd_hdl_t *)&zfs_retire_module);
719*eda14cbcSMatt Macy 	if (strcmp(name, "zfs-diagnosis") == 0)
720*eda14cbcSMatt Macy 		return ((fmd_hdl_t *)&zfs_diagnosis_module);
721*eda14cbcSMatt Macy 
722*eda14cbcSMatt Macy 	return (NULL);
723*eda14cbcSMatt Macy }
724*eda14cbcSMatt Macy 
725*eda14cbcSMatt Macy boolean_t
726*eda14cbcSMatt Macy fmd_module_initialized(fmd_hdl_t *hdl)
727*eda14cbcSMatt Macy {
728*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
729*eda14cbcSMatt Macy 
730*eda14cbcSMatt Macy 	return (mp->mod_info != NULL);
731*eda14cbcSMatt Macy }
732*eda14cbcSMatt Macy 
733*eda14cbcSMatt Macy /*
734*eda14cbcSMatt Macy  * fmd_module_recv is called for each event that is received by
735*eda14cbcSMatt Macy  * the fault manager that has a class that matches one of the
736*eda14cbcSMatt Macy  * module's subscriptions.
737*eda14cbcSMatt Macy  */
738*eda14cbcSMatt Macy void
739*eda14cbcSMatt Macy fmd_module_recv(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class)
740*eda14cbcSMatt Macy {
741*eda14cbcSMatt Macy 	fmd_module_t *mp = (fmd_module_t *)hdl;
742*eda14cbcSMatt Macy 	const fmd_hdl_ops_t *ops = mp->mod_info->fmdi_ops;
743*eda14cbcSMatt Macy 	fmd_event_t faux_event = {0};
744*eda14cbcSMatt Macy 	int64_t *tv;
745*eda14cbcSMatt Macy 	uint_t n;
746*eda14cbcSMatt Macy 
747*eda14cbcSMatt Macy 	/*
748*eda14cbcSMatt Macy 	 * Will need to normalized this if we persistently store the case data
749*eda14cbcSMatt Macy 	 */
750*eda14cbcSMatt Macy 	if (nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0)
751*eda14cbcSMatt Macy 		faux_event.ev_hrt = tv[0] * NANOSEC + tv[1];
752*eda14cbcSMatt Macy 	else
753*eda14cbcSMatt Macy 		faux_event.ev_hrt = 0;
754*eda14cbcSMatt Macy 
755*eda14cbcSMatt Macy 	ops->fmdo_recv(hdl, &faux_event, nvl, class);
756*eda14cbcSMatt Macy 
757*eda14cbcSMatt Macy 	mp->mod_stats.ms_accepted.fmds_value.ui64++;
758*eda14cbcSMatt Macy 
759*eda14cbcSMatt Macy 	/* TBD - should we initiate fm_module_gc() periodically? */
760*eda14cbcSMatt Macy }
761