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