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