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 25*eda14cbcSMatt Macy /* 26*eda14cbcSMatt Macy * Fault Management Architecture (FMA) Resource and Protocol Support 27*eda14cbcSMatt Macy * 28*eda14cbcSMatt Macy * The routines contained herein provide services to support kernel subsystems 29*eda14cbcSMatt Macy * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089). 30*eda14cbcSMatt Macy * 31*eda14cbcSMatt Macy * Name-Value Pair Lists 32*eda14cbcSMatt Macy * 33*eda14cbcSMatt Macy * The embodiment of an FMA protocol element (event, fmri or authority) is a 34*eda14cbcSMatt Macy * name-value pair list (nvlist_t). FMA-specific nvlist constructor and 35*eda14cbcSMatt Macy * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used 36*eda14cbcSMatt Macy * to create an nvpair list using custom allocators. Callers may choose to 37*eda14cbcSMatt Macy * allocate either from the kernel memory allocator, or from a preallocated 38*eda14cbcSMatt Macy * buffer, useful in constrained contexts like high-level interrupt routines. 39*eda14cbcSMatt Macy * 40*eda14cbcSMatt Macy * Protocol Event and FMRI Construction 41*eda14cbcSMatt Macy * 42*eda14cbcSMatt Macy * Convenience routines are provided to construct nvlist events according to 43*eda14cbcSMatt Macy * the FMA Event Protocol and Naming Schema specification for ereports and 44*eda14cbcSMatt Macy * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes. 45*eda14cbcSMatt Macy * 46*eda14cbcSMatt Macy * ENA Manipulation 47*eda14cbcSMatt Macy * 48*eda14cbcSMatt Macy * Routines to generate ENA formats 0, 1 and 2 are available as well as 49*eda14cbcSMatt Macy * routines to increment formats 1 and 2. Individual fields within the 50*eda14cbcSMatt Macy * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(), 51*eda14cbcSMatt Macy * fm_ena_format_get() and fm_ena_gen_get(). 52*eda14cbcSMatt Macy */ 53*eda14cbcSMatt Macy 54*eda14cbcSMatt Macy #include <sys/types.h> 55*eda14cbcSMatt Macy #include <sys/time.h> 56*eda14cbcSMatt Macy #include <sys/list.h> 57*eda14cbcSMatt Macy #include <sys/nvpair.h> 58*eda14cbcSMatt Macy #include <sys/cmn_err.h> 59*eda14cbcSMatt Macy #include <sys/sysmacros.h> 60*eda14cbcSMatt Macy #include <sys/sunddi.h> 61*eda14cbcSMatt Macy #include <sys/systeminfo.h> 62*eda14cbcSMatt Macy #include <sys/fm/util.h> 63*eda14cbcSMatt Macy #include <sys/fm/protocol.h> 64*eda14cbcSMatt Macy #include <sys/kstat.h> 65*eda14cbcSMatt Macy #include <sys/zfs_context.h> 66*eda14cbcSMatt Macy #ifdef _KERNEL 67*eda14cbcSMatt Macy #include <sys/atomic.h> 68*eda14cbcSMatt Macy #include <sys/condvar.h> 69*eda14cbcSMatt Macy #include <sys/console.h> 70*eda14cbcSMatt Macy #include <sys/time.h> 71*eda14cbcSMatt Macy #include <sys/zfs_ioctl.h> 72*eda14cbcSMatt Macy 73*eda14cbcSMatt Macy int zfs_zevent_len_max = 0; 74*eda14cbcSMatt Macy int zfs_zevent_cols = 80; 75*eda14cbcSMatt Macy int zfs_zevent_console = 0; 76*eda14cbcSMatt Macy 77*eda14cbcSMatt Macy static int zevent_len_cur = 0; 78*eda14cbcSMatt Macy static int zevent_waiters = 0; 79*eda14cbcSMatt Macy static int zevent_flags = 0; 80*eda14cbcSMatt Macy 81*eda14cbcSMatt Macy /* Num events rate limited since the last time zfs_zevent_next() was called */ 82*eda14cbcSMatt Macy static uint64_t ratelimit_dropped = 0; 83*eda14cbcSMatt Macy 84*eda14cbcSMatt Macy /* 85*eda14cbcSMatt Macy * The EID (Event IDentifier) is used to uniquely tag a zevent when it is 86*eda14cbcSMatt Macy * posted. The posted EIDs are monotonically increasing but not persistent. 87*eda14cbcSMatt Macy * They will be reset to the initial value (1) each time the kernel module is 88*eda14cbcSMatt Macy * loaded. 89*eda14cbcSMatt Macy */ 90*eda14cbcSMatt Macy static uint64_t zevent_eid = 0; 91*eda14cbcSMatt Macy 92*eda14cbcSMatt Macy static kmutex_t zevent_lock; 93*eda14cbcSMatt Macy static list_t zevent_list; 94*eda14cbcSMatt Macy static kcondvar_t zevent_cv; 95*eda14cbcSMatt Macy #endif /* _KERNEL */ 96*eda14cbcSMatt Macy 97*eda14cbcSMatt Macy 98*eda14cbcSMatt Macy /* 99*eda14cbcSMatt Macy * Common fault management kstats to record event generation failures 100*eda14cbcSMatt Macy */ 101*eda14cbcSMatt Macy 102*eda14cbcSMatt Macy struct erpt_kstat { 103*eda14cbcSMatt Macy kstat_named_t erpt_dropped; /* num erpts dropped on post */ 104*eda14cbcSMatt Macy kstat_named_t erpt_set_failed; /* num erpt set failures */ 105*eda14cbcSMatt Macy kstat_named_t fmri_set_failed; /* num fmri set failures */ 106*eda14cbcSMatt Macy kstat_named_t payload_set_failed; /* num payload set failures */ 107*eda14cbcSMatt Macy }; 108*eda14cbcSMatt Macy 109*eda14cbcSMatt Macy static struct erpt_kstat erpt_kstat_data = { 110*eda14cbcSMatt Macy { "erpt-dropped", KSTAT_DATA_UINT64 }, 111*eda14cbcSMatt Macy { "erpt-set-failed", KSTAT_DATA_UINT64 }, 112*eda14cbcSMatt Macy { "fmri-set-failed", KSTAT_DATA_UINT64 }, 113*eda14cbcSMatt Macy { "payload-set-failed", KSTAT_DATA_UINT64 } 114*eda14cbcSMatt Macy }; 115*eda14cbcSMatt Macy 116*eda14cbcSMatt Macy kstat_t *fm_ksp; 117*eda14cbcSMatt Macy 118*eda14cbcSMatt Macy #ifdef _KERNEL 119*eda14cbcSMatt Macy 120*eda14cbcSMatt Macy /* 121*eda14cbcSMatt Macy * Formatting utility function for fm_nvprintr. We attempt to wrap chunks of 122*eda14cbcSMatt Macy * output so they aren't split across console lines, and return the end column. 123*eda14cbcSMatt Macy */ 124*eda14cbcSMatt Macy /*PRINTFLIKE4*/ 125*eda14cbcSMatt Macy static int 126*eda14cbcSMatt Macy fm_printf(int depth, int c, int cols, const char *format, ...) 127*eda14cbcSMatt Macy { 128*eda14cbcSMatt Macy va_list ap; 129*eda14cbcSMatt Macy int width; 130*eda14cbcSMatt Macy char c1; 131*eda14cbcSMatt Macy 132*eda14cbcSMatt Macy va_start(ap, format); 133*eda14cbcSMatt Macy width = vsnprintf(&c1, sizeof (c1), format, ap); 134*eda14cbcSMatt Macy va_end(ap); 135*eda14cbcSMatt Macy 136*eda14cbcSMatt Macy if (c + width >= cols) { 137*eda14cbcSMatt Macy console_printf("\n"); 138*eda14cbcSMatt Macy c = 0; 139*eda14cbcSMatt Macy if (format[0] != ' ' && depth > 0) { 140*eda14cbcSMatt Macy console_printf(" "); 141*eda14cbcSMatt Macy c++; 142*eda14cbcSMatt Macy } 143*eda14cbcSMatt Macy } 144*eda14cbcSMatt Macy 145*eda14cbcSMatt Macy va_start(ap, format); 146*eda14cbcSMatt Macy console_vprintf(format, ap); 147*eda14cbcSMatt Macy va_end(ap); 148*eda14cbcSMatt Macy 149*eda14cbcSMatt Macy return ((c + width) % cols); 150*eda14cbcSMatt Macy } 151*eda14cbcSMatt Macy 152*eda14cbcSMatt Macy /* 153*eda14cbcSMatt Macy * Recursively print an nvlist in the specified column width and return the 154*eda14cbcSMatt Macy * column we end up in. This function is called recursively by fm_nvprint(), 155*eda14cbcSMatt Macy * below. We generically format the entire nvpair using hexadecimal 156*eda14cbcSMatt Macy * integers and strings, and elide any integer arrays. Arrays are basically 157*eda14cbcSMatt Macy * used for cache dumps right now, so we suppress them so as not to overwhelm 158*eda14cbcSMatt Macy * the amount of console output we produce at panic time. This can be further 159*eda14cbcSMatt Macy * enhanced as FMA technology grows based upon the needs of consumers. All 160*eda14cbcSMatt Macy * FMA telemetry is logged using the dump device transport, so the console 161*eda14cbcSMatt Macy * output serves only as a fallback in case this procedure is unsuccessful. 162*eda14cbcSMatt Macy */ 163*eda14cbcSMatt Macy static int 164*eda14cbcSMatt Macy fm_nvprintr(nvlist_t *nvl, int d, int c, int cols) 165*eda14cbcSMatt Macy { 166*eda14cbcSMatt Macy nvpair_t *nvp; 167*eda14cbcSMatt Macy 168*eda14cbcSMatt Macy for (nvp = nvlist_next_nvpair(nvl, NULL); 169*eda14cbcSMatt Macy nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { 170*eda14cbcSMatt Macy 171*eda14cbcSMatt Macy data_type_t type = nvpair_type(nvp); 172*eda14cbcSMatt Macy const char *name = nvpair_name(nvp); 173*eda14cbcSMatt Macy 174*eda14cbcSMatt Macy boolean_t b; 175*eda14cbcSMatt Macy uint8_t i8; 176*eda14cbcSMatt Macy uint16_t i16; 177*eda14cbcSMatt Macy uint32_t i32; 178*eda14cbcSMatt Macy uint64_t i64; 179*eda14cbcSMatt Macy char *str; 180*eda14cbcSMatt Macy nvlist_t *cnv; 181*eda14cbcSMatt Macy 182*eda14cbcSMatt Macy if (strcmp(name, FM_CLASS) == 0) 183*eda14cbcSMatt Macy continue; /* already printed by caller */ 184*eda14cbcSMatt Macy 185*eda14cbcSMatt Macy c = fm_printf(d, c, cols, " %s=", name); 186*eda14cbcSMatt Macy 187*eda14cbcSMatt Macy switch (type) { 188*eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN: 189*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, " 1"); 190*eda14cbcSMatt Macy break; 191*eda14cbcSMatt Macy 192*eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 193*eda14cbcSMatt Macy (void) nvpair_value_boolean_value(nvp, &b); 194*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, b ? "1" : "0"); 195*eda14cbcSMatt Macy break; 196*eda14cbcSMatt Macy 197*eda14cbcSMatt Macy case DATA_TYPE_BYTE: 198*eda14cbcSMatt Macy (void) nvpair_value_byte(nvp, &i8); 199*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i8); 200*eda14cbcSMatt Macy break; 201*eda14cbcSMatt Macy 202*eda14cbcSMatt Macy case DATA_TYPE_INT8: 203*eda14cbcSMatt Macy (void) nvpair_value_int8(nvp, (void *)&i8); 204*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i8); 205*eda14cbcSMatt Macy break; 206*eda14cbcSMatt Macy 207*eda14cbcSMatt Macy case DATA_TYPE_UINT8: 208*eda14cbcSMatt Macy (void) nvpair_value_uint8(nvp, &i8); 209*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i8); 210*eda14cbcSMatt Macy break; 211*eda14cbcSMatt Macy 212*eda14cbcSMatt Macy case DATA_TYPE_INT16: 213*eda14cbcSMatt Macy (void) nvpair_value_int16(nvp, (void *)&i16); 214*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i16); 215*eda14cbcSMatt Macy break; 216*eda14cbcSMatt Macy 217*eda14cbcSMatt Macy case DATA_TYPE_UINT16: 218*eda14cbcSMatt Macy (void) nvpair_value_uint16(nvp, &i16); 219*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i16); 220*eda14cbcSMatt Macy break; 221*eda14cbcSMatt Macy 222*eda14cbcSMatt Macy case DATA_TYPE_INT32: 223*eda14cbcSMatt Macy (void) nvpair_value_int32(nvp, (void *)&i32); 224*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i32); 225*eda14cbcSMatt Macy break; 226*eda14cbcSMatt Macy 227*eda14cbcSMatt Macy case DATA_TYPE_UINT32: 228*eda14cbcSMatt Macy (void) nvpair_value_uint32(nvp, &i32); 229*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%x", i32); 230*eda14cbcSMatt Macy break; 231*eda14cbcSMatt Macy 232*eda14cbcSMatt Macy case DATA_TYPE_INT64: 233*eda14cbcSMatt Macy (void) nvpair_value_int64(nvp, (void *)&i64); 234*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx", 235*eda14cbcSMatt Macy (u_longlong_t)i64); 236*eda14cbcSMatt Macy break; 237*eda14cbcSMatt Macy 238*eda14cbcSMatt Macy case DATA_TYPE_UINT64: 239*eda14cbcSMatt Macy (void) nvpair_value_uint64(nvp, &i64); 240*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx", 241*eda14cbcSMatt Macy (u_longlong_t)i64); 242*eda14cbcSMatt Macy break; 243*eda14cbcSMatt Macy 244*eda14cbcSMatt Macy case DATA_TYPE_HRTIME: 245*eda14cbcSMatt Macy (void) nvpair_value_hrtime(nvp, (void *)&i64); 246*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx", 247*eda14cbcSMatt Macy (u_longlong_t)i64); 248*eda14cbcSMatt Macy break; 249*eda14cbcSMatt Macy 250*eda14cbcSMatt Macy case DATA_TYPE_STRING: 251*eda14cbcSMatt Macy (void) nvpair_value_string(nvp, &str); 252*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "\"%s\"", 253*eda14cbcSMatt Macy str ? str : "<NULL>"); 254*eda14cbcSMatt Macy break; 255*eda14cbcSMatt Macy 256*eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 257*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "["); 258*eda14cbcSMatt Macy (void) nvpair_value_nvlist(nvp, &cnv); 259*eda14cbcSMatt Macy c = fm_nvprintr(cnv, d + 1, c, cols); 260*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, " ]"); 261*eda14cbcSMatt Macy break; 262*eda14cbcSMatt Macy 263*eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: { 264*eda14cbcSMatt Macy nvlist_t **val; 265*eda14cbcSMatt Macy uint_t i, nelem; 266*eda14cbcSMatt Macy 267*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "["); 268*eda14cbcSMatt Macy (void) nvpair_value_nvlist_array(nvp, &val, &nelem); 269*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) { 270*eda14cbcSMatt Macy c = fm_nvprintr(val[i], d + 1, c, cols); 271*eda14cbcSMatt Macy } 272*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, " ]"); 273*eda14cbcSMatt Macy } 274*eda14cbcSMatt Macy break; 275*eda14cbcSMatt Macy 276*eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: { 277*eda14cbcSMatt Macy int8_t *val; 278*eda14cbcSMatt Macy uint_t i, nelem; 279*eda14cbcSMatt Macy 280*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 281*eda14cbcSMatt Macy (void) nvpair_value_int8_array(nvp, &val, &nelem); 282*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 283*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 284*eda14cbcSMatt Macy (u_longlong_t)val[i]); 285*eda14cbcSMatt Macy 286*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 287*eda14cbcSMatt Macy break; 288*eda14cbcSMatt Macy } 289*eda14cbcSMatt Macy 290*eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: { 291*eda14cbcSMatt Macy uint8_t *val; 292*eda14cbcSMatt Macy uint_t i, nelem; 293*eda14cbcSMatt Macy 294*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 295*eda14cbcSMatt Macy (void) nvpair_value_uint8_array(nvp, &val, &nelem); 296*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 297*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 298*eda14cbcSMatt Macy (u_longlong_t)val[i]); 299*eda14cbcSMatt Macy 300*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 301*eda14cbcSMatt Macy break; 302*eda14cbcSMatt Macy } 303*eda14cbcSMatt Macy 304*eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: { 305*eda14cbcSMatt Macy int16_t *val; 306*eda14cbcSMatt Macy uint_t i, nelem; 307*eda14cbcSMatt Macy 308*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 309*eda14cbcSMatt Macy (void) nvpair_value_int16_array(nvp, &val, &nelem); 310*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 311*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 312*eda14cbcSMatt Macy (u_longlong_t)val[i]); 313*eda14cbcSMatt Macy 314*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 315*eda14cbcSMatt Macy break; 316*eda14cbcSMatt Macy } 317*eda14cbcSMatt Macy 318*eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: { 319*eda14cbcSMatt Macy uint16_t *val; 320*eda14cbcSMatt Macy uint_t i, nelem; 321*eda14cbcSMatt Macy 322*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 323*eda14cbcSMatt Macy (void) nvpair_value_uint16_array(nvp, &val, &nelem); 324*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 325*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 326*eda14cbcSMatt Macy (u_longlong_t)val[i]); 327*eda14cbcSMatt Macy 328*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 329*eda14cbcSMatt Macy break; 330*eda14cbcSMatt Macy } 331*eda14cbcSMatt Macy 332*eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: { 333*eda14cbcSMatt Macy int32_t *val; 334*eda14cbcSMatt Macy uint_t i, nelem; 335*eda14cbcSMatt Macy 336*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 337*eda14cbcSMatt Macy (void) nvpair_value_int32_array(nvp, &val, &nelem); 338*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 339*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 340*eda14cbcSMatt Macy (u_longlong_t)val[i]); 341*eda14cbcSMatt Macy 342*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 343*eda14cbcSMatt Macy break; 344*eda14cbcSMatt Macy } 345*eda14cbcSMatt Macy 346*eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: { 347*eda14cbcSMatt Macy uint32_t *val; 348*eda14cbcSMatt Macy uint_t i, nelem; 349*eda14cbcSMatt Macy 350*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 351*eda14cbcSMatt Macy (void) nvpair_value_uint32_array(nvp, &val, &nelem); 352*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 353*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 354*eda14cbcSMatt Macy (u_longlong_t)val[i]); 355*eda14cbcSMatt Macy 356*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 357*eda14cbcSMatt Macy break; 358*eda14cbcSMatt Macy } 359*eda14cbcSMatt Macy 360*eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: { 361*eda14cbcSMatt Macy int64_t *val; 362*eda14cbcSMatt Macy uint_t i, nelem; 363*eda14cbcSMatt Macy 364*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 365*eda14cbcSMatt Macy (void) nvpair_value_int64_array(nvp, &val, &nelem); 366*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 367*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 368*eda14cbcSMatt Macy (u_longlong_t)val[i]); 369*eda14cbcSMatt Macy 370*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 371*eda14cbcSMatt Macy break; 372*eda14cbcSMatt Macy } 373*eda14cbcSMatt Macy 374*eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: { 375*eda14cbcSMatt Macy uint64_t *val; 376*eda14cbcSMatt Macy uint_t i, nelem; 377*eda14cbcSMatt Macy 378*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[ "); 379*eda14cbcSMatt Macy (void) nvpair_value_uint64_array(nvp, &val, &nelem); 380*eda14cbcSMatt Macy for (i = 0; i < nelem; i++) 381*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "0x%llx ", 382*eda14cbcSMatt Macy (u_longlong_t)val[i]); 383*eda14cbcSMatt Macy 384*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "]"); 385*eda14cbcSMatt Macy break; 386*eda14cbcSMatt Macy } 387*eda14cbcSMatt Macy 388*eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 389*eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 390*eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 391*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "[...]"); 392*eda14cbcSMatt Macy break; 393*eda14cbcSMatt Macy 394*eda14cbcSMatt Macy case DATA_TYPE_UNKNOWN: 395*eda14cbcSMatt Macy case DATA_TYPE_DONTCARE: 396*eda14cbcSMatt Macy c = fm_printf(d + 1, c, cols, "<unknown>"); 397*eda14cbcSMatt Macy break; 398*eda14cbcSMatt Macy } 399*eda14cbcSMatt Macy } 400*eda14cbcSMatt Macy 401*eda14cbcSMatt Macy return (c); 402*eda14cbcSMatt Macy } 403*eda14cbcSMatt Macy 404*eda14cbcSMatt Macy void 405*eda14cbcSMatt Macy fm_nvprint(nvlist_t *nvl) 406*eda14cbcSMatt Macy { 407*eda14cbcSMatt Macy char *class; 408*eda14cbcSMatt Macy int c = 0; 409*eda14cbcSMatt Macy 410*eda14cbcSMatt Macy console_printf("\n"); 411*eda14cbcSMatt Macy 412*eda14cbcSMatt Macy if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0) 413*eda14cbcSMatt Macy c = fm_printf(0, c, zfs_zevent_cols, "%s", class); 414*eda14cbcSMatt Macy 415*eda14cbcSMatt Macy if (fm_nvprintr(nvl, 0, c, zfs_zevent_cols) != 0) 416*eda14cbcSMatt Macy console_printf("\n"); 417*eda14cbcSMatt Macy 418*eda14cbcSMatt Macy console_printf("\n"); 419*eda14cbcSMatt Macy } 420*eda14cbcSMatt Macy 421*eda14cbcSMatt Macy static zevent_t * 422*eda14cbcSMatt Macy zfs_zevent_alloc(void) 423*eda14cbcSMatt Macy { 424*eda14cbcSMatt Macy zevent_t *ev; 425*eda14cbcSMatt Macy 426*eda14cbcSMatt Macy ev = kmem_zalloc(sizeof (zevent_t), KM_SLEEP); 427*eda14cbcSMatt Macy 428*eda14cbcSMatt Macy list_create(&ev->ev_ze_list, sizeof (zfs_zevent_t), 429*eda14cbcSMatt Macy offsetof(zfs_zevent_t, ze_node)); 430*eda14cbcSMatt Macy list_link_init(&ev->ev_node); 431*eda14cbcSMatt Macy 432*eda14cbcSMatt Macy return (ev); 433*eda14cbcSMatt Macy } 434*eda14cbcSMatt Macy 435*eda14cbcSMatt Macy static void 436*eda14cbcSMatt Macy zfs_zevent_free(zevent_t *ev) 437*eda14cbcSMatt Macy { 438*eda14cbcSMatt Macy /* Run provided cleanup callback */ 439*eda14cbcSMatt Macy ev->ev_cb(ev->ev_nvl, ev->ev_detector); 440*eda14cbcSMatt Macy 441*eda14cbcSMatt Macy list_destroy(&ev->ev_ze_list); 442*eda14cbcSMatt Macy kmem_free(ev, sizeof (zevent_t)); 443*eda14cbcSMatt Macy } 444*eda14cbcSMatt Macy 445*eda14cbcSMatt Macy static void 446*eda14cbcSMatt Macy zfs_zevent_drain(zevent_t *ev) 447*eda14cbcSMatt Macy { 448*eda14cbcSMatt Macy zfs_zevent_t *ze; 449*eda14cbcSMatt Macy 450*eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&zevent_lock)); 451*eda14cbcSMatt Macy list_remove(&zevent_list, ev); 452*eda14cbcSMatt Macy 453*eda14cbcSMatt Macy /* Remove references to this event in all private file data */ 454*eda14cbcSMatt Macy while ((ze = list_head(&ev->ev_ze_list)) != NULL) { 455*eda14cbcSMatt Macy list_remove(&ev->ev_ze_list, ze); 456*eda14cbcSMatt Macy ze->ze_zevent = NULL; 457*eda14cbcSMatt Macy ze->ze_dropped++; 458*eda14cbcSMatt Macy } 459*eda14cbcSMatt Macy 460*eda14cbcSMatt Macy zfs_zevent_free(ev); 461*eda14cbcSMatt Macy } 462*eda14cbcSMatt Macy 463*eda14cbcSMatt Macy void 464*eda14cbcSMatt Macy zfs_zevent_drain_all(int *count) 465*eda14cbcSMatt Macy { 466*eda14cbcSMatt Macy zevent_t *ev; 467*eda14cbcSMatt Macy 468*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 469*eda14cbcSMatt Macy while ((ev = list_head(&zevent_list)) != NULL) 470*eda14cbcSMatt Macy zfs_zevent_drain(ev); 471*eda14cbcSMatt Macy 472*eda14cbcSMatt Macy *count = zevent_len_cur; 473*eda14cbcSMatt Macy zevent_len_cur = 0; 474*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 475*eda14cbcSMatt Macy } 476*eda14cbcSMatt Macy 477*eda14cbcSMatt Macy /* 478*eda14cbcSMatt Macy * New zevents are inserted at the head. If the maximum queue 479*eda14cbcSMatt Macy * length is exceeded a zevent will be drained from the tail. 480*eda14cbcSMatt Macy * As part of this any user space processes which currently have 481*eda14cbcSMatt Macy * a reference to this zevent_t in their private data will have 482*eda14cbcSMatt Macy * this reference set to NULL. 483*eda14cbcSMatt Macy */ 484*eda14cbcSMatt Macy static void 485*eda14cbcSMatt Macy zfs_zevent_insert(zevent_t *ev) 486*eda14cbcSMatt Macy { 487*eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&zevent_lock)); 488*eda14cbcSMatt Macy list_insert_head(&zevent_list, ev); 489*eda14cbcSMatt Macy 490*eda14cbcSMatt Macy if (zevent_len_cur >= zfs_zevent_len_max) 491*eda14cbcSMatt Macy zfs_zevent_drain(list_tail(&zevent_list)); 492*eda14cbcSMatt Macy else 493*eda14cbcSMatt Macy zevent_len_cur++; 494*eda14cbcSMatt Macy } 495*eda14cbcSMatt Macy 496*eda14cbcSMatt Macy /* 497*eda14cbcSMatt Macy * Post a zevent. The cb will be called when nvl and detector are no longer 498*eda14cbcSMatt Macy * needed, i.e.: 499*eda14cbcSMatt Macy * - An error happened and a zevent can't be posted. In this case, cb is called 500*eda14cbcSMatt Macy * before zfs_zevent_post() returns. 501*eda14cbcSMatt Macy * - The event is being drained and freed. 502*eda14cbcSMatt Macy */ 503*eda14cbcSMatt Macy int 504*eda14cbcSMatt Macy zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb) 505*eda14cbcSMatt Macy { 506*eda14cbcSMatt Macy inode_timespec_t tv; 507*eda14cbcSMatt Macy int64_t tv_array[2]; 508*eda14cbcSMatt Macy uint64_t eid; 509*eda14cbcSMatt Macy size_t nvl_size = 0; 510*eda14cbcSMatt Macy zevent_t *ev; 511*eda14cbcSMatt Macy int error; 512*eda14cbcSMatt Macy 513*eda14cbcSMatt Macy ASSERT(cb != NULL); 514*eda14cbcSMatt Macy 515*eda14cbcSMatt Macy gethrestime(&tv); 516*eda14cbcSMatt Macy tv_array[0] = tv.tv_sec; 517*eda14cbcSMatt Macy tv_array[1] = tv.tv_nsec; 518*eda14cbcSMatt Macy 519*eda14cbcSMatt Macy error = nvlist_add_int64_array(nvl, FM_EREPORT_TIME, tv_array, 2); 520*eda14cbcSMatt Macy if (error) { 521*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 522*eda14cbcSMatt Macy goto out; 523*eda14cbcSMatt Macy } 524*eda14cbcSMatt Macy 525*eda14cbcSMatt Macy eid = atomic_inc_64_nv(&zevent_eid); 526*eda14cbcSMatt Macy error = nvlist_add_uint64(nvl, FM_EREPORT_EID, eid); 527*eda14cbcSMatt Macy if (error) { 528*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 529*eda14cbcSMatt Macy goto out; 530*eda14cbcSMatt Macy } 531*eda14cbcSMatt Macy 532*eda14cbcSMatt Macy error = nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE); 533*eda14cbcSMatt Macy if (error) { 534*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64); 535*eda14cbcSMatt Macy goto out; 536*eda14cbcSMatt Macy } 537*eda14cbcSMatt Macy 538*eda14cbcSMatt Macy if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) { 539*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64); 540*eda14cbcSMatt Macy error = EOVERFLOW; 541*eda14cbcSMatt Macy goto out; 542*eda14cbcSMatt Macy } 543*eda14cbcSMatt Macy 544*eda14cbcSMatt Macy if (zfs_zevent_console) 545*eda14cbcSMatt Macy fm_nvprint(nvl); 546*eda14cbcSMatt Macy 547*eda14cbcSMatt Macy ev = zfs_zevent_alloc(); 548*eda14cbcSMatt Macy if (ev == NULL) { 549*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64); 550*eda14cbcSMatt Macy error = ENOMEM; 551*eda14cbcSMatt Macy goto out; 552*eda14cbcSMatt Macy } 553*eda14cbcSMatt Macy 554*eda14cbcSMatt Macy ev->ev_nvl = nvl; 555*eda14cbcSMatt Macy ev->ev_detector = detector; 556*eda14cbcSMatt Macy ev->ev_cb = cb; 557*eda14cbcSMatt Macy ev->ev_eid = eid; 558*eda14cbcSMatt Macy 559*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 560*eda14cbcSMatt Macy zfs_zevent_insert(ev); 561*eda14cbcSMatt Macy cv_broadcast(&zevent_cv); 562*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 563*eda14cbcSMatt Macy 564*eda14cbcSMatt Macy out: 565*eda14cbcSMatt Macy if (error) 566*eda14cbcSMatt Macy cb(nvl, detector); 567*eda14cbcSMatt Macy 568*eda14cbcSMatt Macy return (error); 569*eda14cbcSMatt Macy } 570*eda14cbcSMatt Macy 571*eda14cbcSMatt Macy static int 572*eda14cbcSMatt Macy zfs_zevent_minor_to_state(minor_t minor, zfs_zevent_t **ze) 573*eda14cbcSMatt Macy { 574*eda14cbcSMatt Macy *ze = zfsdev_get_state(minor, ZST_ZEVENT); 575*eda14cbcSMatt Macy if (*ze == NULL) 576*eda14cbcSMatt Macy return (SET_ERROR(EBADF)); 577*eda14cbcSMatt Macy 578*eda14cbcSMatt Macy return (0); 579*eda14cbcSMatt Macy } 580*eda14cbcSMatt Macy 581*eda14cbcSMatt Macy int 582*eda14cbcSMatt Macy zfs_zevent_fd_hold(int fd, minor_t *minorp, zfs_zevent_t **ze) 583*eda14cbcSMatt Macy { 584*eda14cbcSMatt Macy int error; 585*eda14cbcSMatt Macy 586*eda14cbcSMatt Macy error = zfsdev_getminor(fd, minorp); 587*eda14cbcSMatt Macy if (error == 0) 588*eda14cbcSMatt Macy error = zfs_zevent_minor_to_state(*minorp, ze); 589*eda14cbcSMatt Macy 590*eda14cbcSMatt Macy if (error) 591*eda14cbcSMatt Macy zfs_zevent_fd_rele(fd); 592*eda14cbcSMatt Macy 593*eda14cbcSMatt Macy return (error); 594*eda14cbcSMatt Macy } 595*eda14cbcSMatt Macy 596*eda14cbcSMatt Macy void 597*eda14cbcSMatt Macy zfs_zevent_fd_rele(int fd) 598*eda14cbcSMatt Macy { 599*eda14cbcSMatt Macy zfs_file_put(fd); 600*eda14cbcSMatt Macy } 601*eda14cbcSMatt Macy 602*eda14cbcSMatt Macy /* 603*eda14cbcSMatt Macy * Get the next zevent in the stream and place a copy in 'event'. This 604*eda14cbcSMatt Macy * may fail with ENOMEM if the encoded nvlist size exceeds the passed 605*eda14cbcSMatt Macy * 'event_size'. In this case the stream pointer is not advanced and 606*eda14cbcSMatt Macy * and 'event_size' is set to the minimum required buffer size. 607*eda14cbcSMatt Macy */ 608*eda14cbcSMatt Macy int 609*eda14cbcSMatt Macy zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *event_size, 610*eda14cbcSMatt Macy uint64_t *dropped) 611*eda14cbcSMatt Macy { 612*eda14cbcSMatt Macy zevent_t *ev; 613*eda14cbcSMatt Macy size_t size; 614*eda14cbcSMatt Macy int error = 0; 615*eda14cbcSMatt Macy 616*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 617*eda14cbcSMatt Macy if (ze->ze_zevent == NULL) { 618*eda14cbcSMatt Macy /* New stream start at the beginning/tail */ 619*eda14cbcSMatt Macy ev = list_tail(&zevent_list); 620*eda14cbcSMatt Macy if (ev == NULL) { 621*eda14cbcSMatt Macy error = ENOENT; 622*eda14cbcSMatt Macy goto out; 623*eda14cbcSMatt Macy } 624*eda14cbcSMatt Macy } else { 625*eda14cbcSMatt Macy /* 626*eda14cbcSMatt Macy * Existing stream continue with the next element and remove 627*eda14cbcSMatt Macy * ourselves from the wait queue for the previous element 628*eda14cbcSMatt Macy */ 629*eda14cbcSMatt Macy ev = list_prev(&zevent_list, ze->ze_zevent); 630*eda14cbcSMatt Macy if (ev == NULL) { 631*eda14cbcSMatt Macy error = ENOENT; 632*eda14cbcSMatt Macy goto out; 633*eda14cbcSMatt Macy } 634*eda14cbcSMatt Macy } 635*eda14cbcSMatt Macy 636*eda14cbcSMatt Macy VERIFY(nvlist_size(ev->ev_nvl, &size, NV_ENCODE_NATIVE) == 0); 637*eda14cbcSMatt Macy if (size > *event_size) { 638*eda14cbcSMatt Macy *event_size = size; 639*eda14cbcSMatt Macy error = ENOMEM; 640*eda14cbcSMatt Macy goto out; 641*eda14cbcSMatt Macy } 642*eda14cbcSMatt Macy 643*eda14cbcSMatt Macy if (ze->ze_zevent) 644*eda14cbcSMatt Macy list_remove(&ze->ze_zevent->ev_ze_list, ze); 645*eda14cbcSMatt Macy 646*eda14cbcSMatt Macy ze->ze_zevent = ev; 647*eda14cbcSMatt Macy list_insert_head(&ev->ev_ze_list, ze); 648*eda14cbcSMatt Macy (void) nvlist_dup(ev->ev_nvl, event, KM_SLEEP); 649*eda14cbcSMatt Macy *dropped = ze->ze_dropped; 650*eda14cbcSMatt Macy 651*eda14cbcSMatt Macy #ifdef _KERNEL 652*eda14cbcSMatt Macy /* Include events dropped due to rate limiting */ 653*eda14cbcSMatt Macy *dropped += ratelimit_dropped; 654*eda14cbcSMatt Macy ratelimit_dropped = 0; 655*eda14cbcSMatt Macy #endif 656*eda14cbcSMatt Macy ze->ze_dropped = 0; 657*eda14cbcSMatt Macy out: 658*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 659*eda14cbcSMatt Macy 660*eda14cbcSMatt Macy return (error); 661*eda14cbcSMatt Macy } 662*eda14cbcSMatt Macy 663*eda14cbcSMatt Macy /* 664*eda14cbcSMatt Macy * Wait in an interruptible state for any new events. 665*eda14cbcSMatt Macy */ 666*eda14cbcSMatt Macy int 667*eda14cbcSMatt Macy zfs_zevent_wait(zfs_zevent_t *ze) 668*eda14cbcSMatt Macy { 669*eda14cbcSMatt Macy int error = EAGAIN; 670*eda14cbcSMatt Macy 671*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 672*eda14cbcSMatt Macy zevent_waiters++; 673*eda14cbcSMatt Macy 674*eda14cbcSMatt Macy while (error == EAGAIN) { 675*eda14cbcSMatt Macy if (zevent_flags & ZEVENT_SHUTDOWN) { 676*eda14cbcSMatt Macy error = SET_ERROR(ESHUTDOWN); 677*eda14cbcSMatt Macy break; 678*eda14cbcSMatt Macy } 679*eda14cbcSMatt Macy 680*eda14cbcSMatt Macy error = cv_wait_sig(&zevent_cv, &zevent_lock); 681*eda14cbcSMatt Macy if (signal_pending(current)) { 682*eda14cbcSMatt Macy error = SET_ERROR(EINTR); 683*eda14cbcSMatt Macy break; 684*eda14cbcSMatt Macy } else if (!list_is_empty(&zevent_list)) { 685*eda14cbcSMatt Macy error = 0; 686*eda14cbcSMatt Macy continue; 687*eda14cbcSMatt Macy } else { 688*eda14cbcSMatt Macy error = EAGAIN; 689*eda14cbcSMatt Macy } 690*eda14cbcSMatt Macy } 691*eda14cbcSMatt Macy 692*eda14cbcSMatt Macy zevent_waiters--; 693*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 694*eda14cbcSMatt Macy 695*eda14cbcSMatt Macy return (error); 696*eda14cbcSMatt Macy } 697*eda14cbcSMatt Macy 698*eda14cbcSMatt Macy /* 699*eda14cbcSMatt Macy * The caller may seek to a specific EID by passing that EID. If the EID 700*eda14cbcSMatt Macy * is still available in the posted list of events the cursor is positioned 701*eda14cbcSMatt Macy * there. Otherwise ENOENT is returned and the cursor is not moved. 702*eda14cbcSMatt Macy * 703*eda14cbcSMatt Macy * There are two reserved EIDs which may be passed and will never fail. 704*eda14cbcSMatt Macy * ZEVENT_SEEK_START positions the cursor at the start of the list, and 705*eda14cbcSMatt Macy * ZEVENT_SEEK_END positions the cursor at the end of the list. 706*eda14cbcSMatt Macy */ 707*eda14cbcSMatt Macy int 708*eda14cbcSMatt Macy zfs_zevent_seek(zfs_zevent_t *ze, uint64_t eid) 709*eda14cbcSMatt Macy { 710*eda14cbcSMatt Macy zevent_t *ev; 711*eda14cbcSMatt Macy int error = 0; 712*eda14cbcSMatt Macy 713*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 714*eda14cbcSMatt Macy 715*eda14cbcSMatt Macy if (eid == ZEVENT_SEEK_START) { 716*eda14cbcSMatt Macy if (ze->ze_zevent) 717*eda14cbcSMatt Macy list_remove(&ze->ze_zevent->ev_ze_list, ze); 718*eda14cbcSMatt Macy 719*eda14cbcSMatt Macy ze->ze_zevent = NULL; 720*eda14cbcSMatt Macy goto out; 721*eda14cbcSMatt Macy } 722*eda14cbcSMatt Macy 723*eda14cbcSMatt Macy if (eid == ZEVENT_SEEK_END) { 724*eda14cbcSMatt Macy if (ze->ze_zevent) 725*eda14cbcSMatt Macy list_remove(&ze->ze_zevent->ev_ze_list, ze); 726*eda14cbcSMatt Macy 727*eda14cbcSMatt Macy ev = list_head(&zevent_list); 728*eda14cbcSMatt Macy if (ev) { 729*eda14cbcSMatt Macy ze->ze_zevent = ev; 730*eda14cbcSMatt Macy list_insert_head(&ev->ev_ze_list, ze); 731*eda14cbcSMatt Macy } else { 732*eda14cbcSMatt Macy ze->ze_zevent = NULL; 733*eda14cbcSMatt Macy } 734*eda14cbcSMatt Macy 735*eda14cbcSMatt Macy goto out; 736*eda14cbcSMatt Macy } 737*eda14cbcSMatt Macy 738*eda14cbcSMatt Macy for (ev = list_tail(&zevent_list); ev != NULL; 739*eda14cbcSMatt Macy ev = list_prev(&zevent_list, ev)) { 740*eda14cbcSMatt Macy if (ev->ev_eid == eid) { 741*eda14cbcSMatt Macy if (ze->ze_zevent) 742*eda14cbcSMatt Macy list_remove(&ze->ze_zevent->ev_ze_list, ze); 743*eda14cbcSMatt Macy 744*eda14cbcSMatt Macy ze->ze_zevent = ev; 745*eda14cbcSMatt Macy list_insert_head(&ev->ev_ze_list, ze); 746*eda14cbcSMatt Macy break; 747*eda14cbcSMatt Macy } 748*eda14cbcSMatt Macy } 749*eda14cbcSMatt Macy 750*eda14cbcSMatt Macy if (ev == NULL) 751*eda14cbcSMatt Macy error = ENOENT; 752*eda14cbcSMatt Macy 753*eda14cbcSMatt Macy out: 754*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 755*eda14cbcSMatt Macy 756*eda14cbcSMatt Macy return (error); 757*eda14cbcSMatt Macy } 758*eda14cbcSMatt Macy 759*eda14cbcSMatt Macy void 760*eda14cbcSMatt Macy zfs_zevent_init(zfs_zevent_t **zep) 761*eda14cbcSMatt Macy { 762*eda14cbcSMatt Macy zfs_zevent_t *ze; 763*eda14cbcSMatt Macy 764*eda14cbcSMatt Macy ze = *zep = kmem_zalloc(sizeof (zfs_zevent_t), KM_SLEEP); 765*eda14cbcSMatt Macy list_link_init(&ze->ze_node); 766*eda14cbcSMatt Macy } 767*eda14cbcSMatt Macy 768*eda14cbcSMatt Macy void 769*eda14cbcSMatt Macy zfs_zevent_destroy(zfs_zevent_t *ze) 770*eda14cbcSMatt Macy { 771*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 772*eda14cbcSMatt Macy if (ze->ze_zevent) 773*eda14cbcSMatt Macy list_remove(&ze->ze_zevent->ev_ze_list, ze); 774*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 775*eda14cbcSMatt Macy 776*eda14cbcSMatt Macy kmem_free(ze, sizeof (zfs_zevent_t)); 777*eda14cbcSMatt Macy } 778*eda14cbcSMatt Macy #endif /* _KERNEL */ 779*eda14cbcSMatt Macy 780*eda14cbcSMatt Macy /* 781*eda14cbcSMatt Macy * Wrappers for FM nvlist allocators 782*eda14cbcSMatt Macy */ 783*eda14cbcSMatt Macy /* ARGSUSED */ 784*eda14cbcSMatt Macy static void * 785*eda14cbcSMatt Macy i_fm_alloc(nv_alloc_t *nva, size_t size) 786*eda14cbcSMatt Macy { 787*eda14cbcSMatt Macy return (kmem_zalloc(size, KM_SLEEP)); 788*eda14cbcSMatt Macy } 789*eda14cbcSMatt Macy 790*eda14cbcSMatt Macy /* ARGSUSED */ 791*eda14cbcSMatt Macy static void 792*eda14cbcSMatt Macy i_fm_free(nv_alloc_t *nva, void *buf, size_t size) 793*eda14cbcSMatt Macy { 794*eda14cbcSMatt Macy kmem_free(buf, size); 795*eda14cbcSMatt Macy } 796*eda14cbcSMatt Macy 797*eda14cbcSMatt Macy const nv_alloc_ops_t fm_mem_alloc_ops = { 798*eda14cbcSMatt Macy .nv_ao_init = NULL, 799*eda14cbcSMatt Macy .nv_ao_fini = NULL, 800*eda14cbcSMatt Macy .nv_ao_alloc = i_fm_alloc, 801*eda14cbcSMatt Macy .nv_ao_free = i_fm_free, 802*eda14cbcSMatt Macy .nv_ao_reset = NULL 803*eda14cbcSMatt Macy }; 804*eda14cbcSMatt Macy 805*eda14cbcSMatt Macy /* 806*eda14cbcSMatt Macy * Create and initialize a new nv_alloc_t for a fixed buffer, buf. A pointer 807*eda14cbcSMatt Macy * to the newly allocated nv_alloc_t structure is returned upon success or NULL 808*eda14cbcSMatt Macy * is returned to indicate that the nv_alloc structure could not be created. 809*eda14cbcSMatt Macy */ 810*eda14cbcSMatt Macy nv_alloc_t * 811*eda14cbcSMatt Macy fm_nva_xcreate(char *buf, size_t bufsz) 812*eda14cbcSMatt Macy { 813*eda14cbcSMatt Macy nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP); 814*eda14cbcSMatt Macy 815*eda14cbcSMatt Macy if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) { 816*eda14cbcSMatt Macy kmem_free(nvhdl, sizeof (nv_alloc_t)); 817*eda14cbcSMatt Macy return (NULL); 818*eda14cbcSMatt Macy } 819*eda14cbcSMatt Macy 820*eda14cbcSMatt Macy return (nvhdl); 821*eda14cbcSMatt Macy } 822*eda14cbcSMatt Macy 823*eda14cbcSMatt Macy /* 824*eda14cbcSMatt Macy * Destroy a previously allocated nv_alloc structure. The fixed buffer 825*eda14cbcSMatt Macy * associated with nva must be freed by the caller. 826*eda14cbcSMatt Macy */ 827*eda14cbcSMatt Macy void 828*eda14cbcSMatt Macy fm_nva_xdestroy(nv_alloc_t *nva) 829*eda14cbcSMatt Macy { 830*eda14cbcSMatt Macy nv_alloc_fini(nva); 831*eda14cbcSMatt Macy kmem_free(nva, sizeof (nv_alloc_t)); 832*eda14cbcSMatt Macy } 833*eda14cbcSMatt Macy 834*eda14cbcSMatt Macy /* 835*eda14cbcSMatt Macy * Create a new nv list. A pointer to a new nv list structure is returned 836*eda14cbcSMatt Macy * upon success or NULL is returned to indicate that the structure could 837*eda14cbcSMatt Macy * not be created. The newly created nv list is created and managed by the 838*eda14cbcSMatt Macy * operations installed in nva. If nva is NULL, the default FMA nva 839*eda14cbcSMatt Macy * operations are installed and used. 840*eda14cbcSMatt Macy * 841*eda14cbcSMatt Macy * When called from the kernel and nva == NULL, this function must be called 842*eda14cbcSMatt Macy * from passive kernel context with no locks held that can prevent a 843*eda14cbcSMatt Macy * sleeping memory allocation from occurring. Otherwise, this function may 844*eda14cbcSMatt Macy * be called from other kernel contexts as long a valid nva created via 845*eda14cbcSMatt Macy * fm_nva_create() is supplied. 846*eda14cbcSMatt Macy */ 847*eda14cbcSMatt Macy nvlist_t * 848*eda14cbcSMatt Macy fm_nvlist_create(nv_alloc_t *nva) 849*eda14cbcSMatt Macy { 850*eda14cbcSMatt Macy int hdl_alloced = 0; 851*eda14cbcSMatt Macy nvlist_t *nvl; 852*eda14cbcSMatt Macy nv_alloc_t *nvhdl; 853*eda14cbcSMatt Macy 854*eda14cbcSMatt Macy if (nva == NULL) { 855*eda14cbcSMatt Macy nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP); 856*eda14cbcSMatt Macy 857*eda14cbcSMatt Macy if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) { 858*eda14cbcSMatt Macy kmem_free(nvhdl, sizeof (nv_alloc_t)); 859*eda14cbcSMatt Macy return (NULL); 860*eda14cbcSMatt Macy } 861*eda14cbcSMatt Macy hdl_alloced = 1; 862*eda14cbcSMatt Macy } else { 863*eda14cbcSMatt Macy nvhdl = nva; 864*eda14cbcSMatt Macy } 865*eda14cbcSMatt Macy 866*eda14cbcSMatt Macy if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) { 867*eda14cbcSMatt Macy if (hdl_alloced) { 868*eda14cbcSMatt Macy nv_alloc_fini(nvhdl); 869*eda14cbcSMatt Macy kmem_free(nvhdl, sizeof (nv_alloc_t)); 870*eda14cbcSMatt Macy } 871*eda14cbcSMatt Macy return (NULL); 872*eda14cbcSMatt Macy } 873*eda14cbcSMatt Macy 874*eda14cbcSMatt Macy return (nvl); 875*eda14cbcSMatt Macy } 876*eda14cbcSMatt Macy 877*eda14cbcSMatt Macy /* 878*eda14cbcSMatt Macy * Destroy a previously allocated nvlist structure. flag indicates whether 879*eda14cbcSMatt Macy * or not the associated nva structure should be freed (FM_NVA_FREE) or 880*eda14cbcSMatt Macy * retained (FM_NVA_RETAIN). Retaining the nv alloc structure allows 881*eda14cbcSMatt Macy * it to be re-used for future nvlist creation operations. 882*eda14cbcSMatt Macy */ 883*eda14cbcSMatt Macy void 884*eda14cbcSMatt Macy fm_nvlist_destroy(nvlist_t *nvl, int flag) 885*eda14cbcSMatt Macy { 886*eda14cbcSMatt Macy nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl); 887*eda14cbcSMatt Macy 888*eda14cbcSMatt Macy nvlist_free(nvl); 889*eda14cbcSMatt Macy 890*eda14cbcSMatt Macy if (nva != NULL) { 891*eda14cbcSMatt Macy if (flag == FM_NVA_FREE) 892*eda14cbcSMatt Macy fm_nva_xdestroy(nva); 893*eda14cbcSMatt Macy } 894*eda14cbcSMatt Macy } 895*eda14cbcSMatt Macy 896*eda14cbcSMatt Macy int 897*eda14cbcSMatt Macy i_fm_payload_set(nvlist_t *payload, const char *name, va_list ap) 898*eda14cbcSMatt Macy { 899*eda14cbcSMatt Macy int nelem, ret = 0; 900*eda14cbcSMatt Macy data_type_t type; 901*eda14cbcSMatt Macy 902*eda14cbcSMatt Macy while (ret == 0 && name != NULL) { 903*eda14cbcSMatt Macy type = va_arg(ap, data_type_t); 904*eda14cbcSMatt Macy switch (type) { 905*eda14cbcSMatt Macy case DATA_TYPE_BYTE: 906*eda14cbcSMatt Macy ret = nvlist_add_byte(payload, name, 907*eda14cbcSMatt Macy va_arg(ap, uint_t)); 908*eda14cbcSMatt Macy break; 909*eda14cbcSMatt Macy case DATA_TYPE_BYTE_ARRAY: 910*eda14cbcSMatt Macy nelem = va_arg(ap, int); 911*eda14cbcSMatt Macy ret = nvlist_add_byte_array(payload, name, 912*eda14cbcSMatt Macy va_arg(ap, uchar_t *), nelem); 913*eda14cbcSMatt Macy break; 914*eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_VALUE: 915*eda14cbcSMatt Macy ret = nvlist_add_boolean_value(payload, name, 916*eda14cbcSMatt Macy va_arg(ap, boolean_t)); 917*eda14cbcSMatt Macy break; 918*eda14cbcSMatt Macy case DATA_TYPE_BOOLEAN_ARRAY: 919*eda14cbcSMatt Macy nelem = va_arg(ap, int); 920*eda14cbcSMatt Macy ret = nvlist_add_boolean_array(payload, name, 921*eda14cbcSMatt Macy va_arg(ap, boolean_t *), nelem); 922*eda14cbcSMatt Macy break; 923*eda14cbcSMatt Macy case DATA_TYPE_INT8: 924*eda14cbcSMatt Macy ret = nvlist_add_int8(payload, name, 925*eda14cbcSMatt Macy va_arg(ap, int)); 926*eda14cbcSMatt Macy break; 927*eda14cbcSMatt Macy case DATA_TYPE_INT8_ARRAY: 928*eda14cbcSMatt Macy nelem = va_arg(ap, int); 929*eda14cbcSMatt Macy ret = nvlist_add_int8_array(payload, name, 930*eda14cbcSMatt Macy va_arg(ap, int8_t *), nelem); 931*eda14cbcSMatt Macy break; 932*eda14cbcSMatt Macy case DATA_TYPE_UINT8: 933*eda14cbcSMatt Macy ret = nvlist_add_uint8(payload, name, 934*eda14cbcSMatt Macy va_arg(ap, uint_t)); 935*eda14cbcSMatt Macy break; 936*eda14cbcSMatt Macy case DATA_TYPE_UINT8_ARRAY: 937*eda14cbcSMatt Macy nelem = va_arg(ap, int); 938*eda14cbcSMatt Macy ret = nvlist_add_uint8_array(payload, name, 939*eda14cbcSMatt Macy va_arg(ap, uint8_t *), nelem); 940*eda14cbcSMatt Macy break; 941*eda14cbcSMatt Macy case DATA_TYPE_INT16: 942*eda14cbcSMatt Macy ret = nvlist_add_int16(payload, name, 943*eda14cbcSMatt Macy va_arg(ap, int)); 944*eda14cbcSMatt Macy break; 945*eda14cbcSMatt Macy case DATA_TYPE_INT16_ARRAY: 946*eda14cbcSMatt Macy nelem = va_arg(ap, int); 947*eda14cbcSMatt Macy ret = nvlist_add_int16_array(payload, name, 948*eda14cbcSMatt Macy va_arg(ap, int16_t *), nelem); 949*eda14cbcSMatt Macy break; 950*eda14cbcSMatt Macy case DATA_TYPE_UINT16: 951*eda14cbcSMatt Macy ret = nvlist_add_uint16(payload, name, 952*eda14cbcSMatt Macy va_arg(ap, uint_t)); 953*eda14cbcSMatt Macy break; 954*eda14cbcSMatt Macy case DATA_TYPE_UINT16_ARRAY: 955*eda14cbcSMatt Macy nelem = va_arg(ap, int); 956*eda14cbcSMatt Macy ret = nvlist_add_uint16_array(payload, name, 957*eda14cbcSMatt Macy va_arg(ap, uint16_t *), nelem); 958*eda14cbcSMatt Macy break; 959*eda14cbcSMatt Macy case DATA_TYPE_INT32: 960*eda14cbcSMatt Macy ret = nvlist_add_int32(payload, name, 961*eda14cbcSMatt Macy va_arg(ap, int32_t)); 962*eda14cbcSMatt Macy break; 963*eda14cbcSMatt Macy case DATA_TYPE_INT32_ARRAY: 964*eda14cbcSMatt Macy nelem = va_arg(ap, int); 965*eda14cbcSMatt Macy ret = nvlist_add_int32_array(payload, name, 966*eda14cbcSMatt Macy va_arg(ap, int32_t *), nelem); 967*eda14cbcSMatt Macy break; 968*eda14cbcSMatt Macy case DATA_TYPE_UINT32: 969*eda14cbcSMatt Macy ret = nvlist_add_uint32(payload, name, 970*eda14cbcSMatt Macy va_arg(ap, uint32_t)); 971*eda14cbcSMatt Macy break; 972*eda14cbcSMatt Macy case DATA_TYPE_UINT32_ARRAY: 973*eda14cbcSMatt Macy nelem = va_arg(ap, int); 974*eda14cbcSMatt Macy ret = nvlist_add_uint32_array(payload, name, 975*eda14cbcSMatt Macy va_arg(ap, uint32_t *), nelem); 976*eda14cbcSMatt Macy break; 977*eda14cbcSMatt Macy case DATA_TYPE_INT64: 978*eda14cbcSMatt Macy ret = nvlist_add_int64(payload, name, 979*eda14cbcSMatt Macy va_arg(ap, int64_t)); 980*eda14cbcSMatt Macy break; 981*eda14cbcSMatt Macy case DATA_TYPE_INT64_ARRAY: 982*eda14cbcSMatt Macy nelem = va_arg(ap, int); 983*eda14cbcSMatt Macy ret = nvlist_add_int64_array(payload, name, 984*eda14cbcSMatt Macy va_arg(ap, int64_t *), nelem); 985*eda14cbcSMatt Macy break; 986*eda14cbcSMatt Macy case DATA_TYPE_UINT64: 987*eda14cbcSMatt Macy ret = nvlist_add_uint64(payload, name, 988*eda14cbcSMatt Macy va_arg(ap, uint64_t)); 989*eda14cbcSMatt Macy break; 990*eda14cbcSMatt Macy case DATA_TYPE_UINT64_ARRAY: 991*eda14cbcSMatt Macy nelem = va_arg(ap, int); 992*eda14cbcSMatt Macy ret = nvlist_add_uint64_array(payload, name, 993*eda14cbcSMatt Macy va_arg(ap, uint64_t *), nelem); 994*eda14cbcSMatt Macy break; 995*eda14cbcSMatt Macy case DATA_TYPE_STRING: 996*eda14cbcSMatt Macy ret = nvlist_add_string(payload, name, 997*eda14cbcSMatt Macy va_arg(ap, char *)); 998*eda14cbcSMatt Macy break; 999*eda14cbcSMatt Macy case DATA_TYPE_STRING_ARRAY: 1000*eda14cbcSMatt Macy nelem = va_arg(ap, int); 1001*eda14cbcSMatt Macy ret = nvlist_add_string_array(payload, name, 1002*eda14cbcSMatt Macy va_arg(ap, char **), nelem); 1003*eda14cbcSMatt Macy break; 1004*eda14cbcSMatt Macy case DATA_TYPE_NVLIST: 1005*eda14cbcSMatt Macy ret = nvlist_add_nvlist(payload, name, 1006*eda14cbcSMatt Macy va_arg(ap, nvlist_t *)); 1007*eda14cbcSMatt Macy break; 1008*eda14cbcSMatt Macy case DATA_TYPE_NVLIST_ARRAY: 1009*eda14cbcSMatt Macy nelem = va_arg(ap, int); 1010*eda14cbcSMatt Macy ret = nvlist_add_nvlist_array(payload, name, 1011*eda14cbcSMatt Macy va_arg(ap, nvlist_t **), nelem); 1012*eda14cbcSMatt Macy break; 1013*eda14cbcSMatt Macy default: 1014*eda14cbcSMatt Macy ret = EINVAL; 1015*eda14cbcSMatt Macy } 1016*eda14cbcSMatt Macy 1017*eda14cbcSMatt Macy name = va_arg(ap, char *); 1018*eda14cbcSMatt Macy } 1019*eda14cbcSMatt Macy return (ret); 1020*eda14cbcSMatt Macy } 1021*eda14cbcSMatt Macy 1022*eda14cbcSMatt Macy void 1023*eda14cbcSMatt Macy fm_payload_set(nvlist_t *payload, ...) 1024*eda14cbcSMatt Macy { 1025*eda14cbcSMatt Macy int ret; 1026*eda14cbcSMatt Macy const char *name; 1027*eda14cbcSMatt Macy va_list ap; 1028*eda14cbcSMatt Macy 1029*eda14cbcSMatt Macy va_start(ap, payload); 1030*eda14cbcSMatt Macy name = va_arg(ap, char *); 1031*eda14cbcSMatt Macy ret = i_fm_payload_set(payload, name, ap); 1032*eda14cbcSMatt Macy va_end(ap); 1033*eda14cbcSMatt Macy 1034*eda14cbcSMatt Macy if (ret) 1035*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.payload_set_failed.value.ui64); 1036*eda14cbcSMatt Macy } 1037*eda14cbcSMatt Macy 1038*eda14cbcSMatt Macy /* 1039*eda14cbcSMatt Macy * Set-up and validate the members of an ereport event according to: 1040*eda14cbcSMatt Macy * 1041*eda14cbcSMatt Macy * Member name Type Value 1042*eda14cbcSMatt Macy * ==================================================== 1043*eda14cbcSMatt Macy * class string ereport 1044*eda14cbcSMatt Macy * version uint8_t 0 1045*eda14cbcSMatt Macy * ena uint64_t <ena> 1046*eda14cbcSMatt Macy * detector nvlist_t <detector> 1047*eda14cbcSMatt Macy * ereport-payload nvlist_t <var args> 1048*eda14cbcSMatt Macy * 1049*eda14cbcSMatt Macy * We don't actually add a 'version' member to the payload. Really, 1050*eda14cbcSMatt Macy * the version quoted to us by our caller is that of the category 1 1051*eda14cbcSMatt Macy * "ereport" event class (and we require FM_EREPORT_VERS0) but 1052*eda14cbcSMatt Macy * the payload version of the actual leaf class event under construction 1053*eda14cbcSMatt Macy * may be something else. Callers should supply a version in the varargs, 1054*eda14cbcSMatt Macy * or (better) we could take two version arguments - one for the 1055*eda14cbcSMatt Macy * ereport category 1 classification (expect FM_EREPORT_VERS0) and one 1056*eda14cbcSMatt Macy * for the leaf class. 1057*eda14cbcSMatt Macy */ 1058*eda14cbcSMatt Macy void 1059*eda14cbcSMatt Macy fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class, 1060*eda14cbcSMatt Macy uint64_t ena, const nvlist_t *detector, ...) 1061*eda14cbcSMatt Macy { 1062*eda14cbcSMatt Macy char ereport_class[FM_MAX_CLASS]; 1063*eda14cbcSMatt Macy const char *name; 1064*eda14cbcSMatt Macy va_list ap; 1065*eda14cbcSMatt Macy int ret; 1066*eda14cbcSMatt Macy 1067*eda14cbcSMatt Macy if (version != FM_EREPORT_VERS0) { 1068*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 1069*eda14cbcSMatt Macy return; 1070*eda14cbcSMatt Macy } 1071*eda14cbcSMatt Macy 1072*eda14cbcSMatt Macy (void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s", 1073*eda14cbcSMatt Macy FM_EREPORT_CLASS, erpt_class); 1074*eda14cbcSMatt Macy if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) { 1075*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 1076*eda14cbcSMatt Macy return; 1077*eda14cbcSMatt Macy } 1078*eda14cbcSMatt Macy 1079*eda14cbcSMatt Macy if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) { 1080*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 1081*eda14cbcSMatt Macy } 1082*eda14cbcSMatt Macy 1083*eda14cbcSMatt Macy if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR, 1084*eda14cbcSMatt Macy (nvlist_t *)detector) != 0) { 1085*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 1086*eda14cbcSMatt Macy } 1087*eda14cbcSMatt Macy 1088*eda14cbcSMatt Macy va_start(ap, detector); 1089*eda14cbcSMatt Macy name = va_arg(ap, const char *); 1090*eda14cbcSMatt Macy ret = i_fm_payload_set(ereport, name, ap); 1091*eda14cbcSMatt Macy va_end(ap); 1092*eda14cbcSMatt Macy 1093*eda14cbcSMatt Macy if (ret) 1094*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64); 1095*eda14cbcSMatt Macy } 1096*eda14cbcSMatt Macy 1097*eda14cbcSMatt Macy /* 1098*eda14cbcSMatt Macy * Set-up and validate the members of an hc fmri according to; 1099*eda14cbcSMatt Macy * 1100*eda14cbcSMatt Macy * Member name Type Value 1101*eda14cbcSMatt Macy * =================================================== 1102*eda14cbcSMatt Macy * version uint8_t 0 1103*eda14cbcSMatt Macy * auth nvlist_t <auth> 1104*eda14cbcSMatt Macy * hc-name string <name> 1105*eda14cbcSMatt Macy * hc-id string <id> 1106*eda14cbcSMatt Macy * 1107*eda14cbcSMatt Macy * Note that auth and hc-id are optional members. 1108*eda14cbcSMatt Macy */ 1109*eda14cbcSMatt Macy 1110*eda14cbcSMatt Macy #define HC_MAXPAIRS 20 1111*eda14cbcSMatt Macy #define HC_MAXNAMELEN 50 1112*eda14cbcSMatt Macy 1113*eda14cbcSMatt Macy static int 1114*eda14cbcSMatt Macy fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth) 1115*eda14cbcSMatt Macy { 1116*eda14cbcSMatt Macy if (version != FM_HC_SCHEME_VERSION) { 1117*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1118*eda14cbcSMatt Macy return (0); 1119*eda14cbcSMatt Macy } 1120*eda14cbcSMatt Macy 1121*eda14cbcSMatt Macy if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 || 1122*eda14cbcSMatt Macy nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) { 1123*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1124*eda14cbcSMatt Macy return (0); 1125*eda14cbcSMatt Macy } 1126*eda14cbcSMatt Macy 1127*eda14cbcSMatt Macy if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 1128*eda14cbcSMatt Macy (nvlist_t *)auth) != 0) { 1129*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1130*eda14cbcSMatt Macy return (0); 1131*eda14cbcSMatt Macy } 1132*eda14cbcSMatt Macy 1133*eda14cbcSMatt Macy return (1); 1134*eda14cbcSMatt Macy } 1135*eda14cbcSMatt Macy 1136*eda14cbcSMatt Macy void 1137*eda14cbcSMatt Macy fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth, 1138*eda14cbcSMatt Macy nvlist_t *snvl, int npairs, ...) 1139*eda14cbcSMatt Macy { 1140*eda14cbcSMatt Macy nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); 1141*eda14cbcSMatt Macy nvlist_t *pairs[HC_MAXPAIRS]; 1142*eda14cbcSMatt Macy va_list ap; 1143*eda14cbcSMatt Macy int i; 1144*eda14cbcSMatt Macy 1145*eda14cbcSMatt Macy if (!fm_fmri_hc_set_common(fmri, version, auth)) 1146*eda14cbcSMatt Macy return; 1147*eda14cbcSMatt Macy 1148*eda14cbcSMatt Macy npairs = MIN(npairs, HC_MAXPAIRS); 1149*eda14cbcSMatt Macy 1150*eda14cbcSMatt Macy va_start(ap, npairs); 1151*eda14cbcSMatt Macy for (i = 0; i < npairs; i++) { 1152*eda14cbcSMatt Macy const char *name = va_arg(ap, const char *); 1153*eda14cbcSMatt Macy uint32_t id = va_arg(ap, uint32_t); 1154*eda14cbcSMatt Macy char idstr[11]; 1155*eda14cbcSMatt Macy 1156*eda14cbcSMatt Macy (void) snprintf(idstr, sizeof (idstr), "%u", id); 1157*eda14cbcSMatt Macy 1158*eda14cbcSMatt Macy pairs[i] = fm_nvlist_create(nva); 1159*eda14cbcSMatt Macy if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || 1160*eda14cbcSMatt Macy nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { 1161*eda14cbcSMatt Macy atomic_inc_64( 1162*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1163*eda14cbcSMatt Macy } 1164*eda14cbcSMatt Macy } 1165*eda14cbcSMatt Macy va_end(ap); 1166*eda14cbcSMatt Macy 1167*eda14cbcSMatt Macy if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0) 1168*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1169*eda14cbcSMatt Macy 1170*eda14cbcSMatt Macy for (i = 0; i < npairs; i++) 1171*eda14cbcSMatt Macy fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); 1172*eda14cbcSMatt Macy 1173*eda14cbcSMatt Macy if (snvl != NULL) { 1174*eda14cbcSMatt Macy if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { 1175*eda14cbcSMatt Macy atomic_inc_64( 1176*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1177*eda14cbcSMatt Macy } 1178*eda14cbcSMatt Macy } 1179*eda14cbcSMatt Macy } 1180*eda14cbcSMatt Macy 1181*eda14cbcSMatt Macy void 1182*eda14cbcSMatt Macy fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth, 1183*eda14cbcSMatt Macy nvlist_t *snvl, nvlist_t *bboard, int npairs, ...) 1184*eda14cbcSMatt Macy { 1185*eda14cbcSMatt Macy nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); 1186*eda14cbcSMatt Macy nvlist_t *pairs[HC_MAXPAIRS]; 1187*eda14cbcSMatt Macy nvlist_t **hcl; 1188*eda14cbcSMatt Macy uint_t n; 1189*eda14cbcSMatt Macy int i, j; 1190*eda14cbcSMatt Macy va_list ap; 1191*eda14cbcSMatt Macy char *hcname, *hcid; 1192*eda14cbcSMatt Macy 1193*eda14cbcSMatt Macy if (!fm_fmri_hc_set_common(fmri, version, auth)) 1194*eda14cbcSMatt Macy return; 1195*eda14cbcSMatt Macy 1196*eda14cbcSMatt Macy /* 1197*eda14cbcSMatt Macy * copy the bboard nvpairs to the pairs array 1198*eda14cbcSMatt Macy */ 1199*eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n) 1200*eda14cbcSMatt Macy != 0) { 1201*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1202*eda14cbcSMatt Macy return; 1203*eda14cbcSMatt Macy } 1204*eda14cbcSMatt Macy 1205*eda14cbcSMatt Macy for (i = 0; i < n; i++) { 1206*eda14cbcSMatt Macy if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, 1207*eda14cbcSMatt Macy &hcname) != 0) { 1208*eda14cbcSMatt Macy atomic_inc_64( 1209*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1210*eda14cbcSMatt Macy return; 1211*eda14cbcSMatt Macy } 1212*eda14cbcSMatt Macy if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) { 1213*eda14cbcSMatt Macy atomic_inc_64( 1214*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1215*eda14cbcSMatt Macy return; 1216*eda14cbcSMatt Macy } 1217*eda14cbcSMatt Macy 1218*eda14cbcSMatt Macy pairs[i] = fm_nvlist_create(nva); 1219*eda14cbcSMatt Macy if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 || 1220*eda14cbcSMatt Macy nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) { 1221*eda14cbcSMatt Macy for (j = 0; j <= i; j++) { 1222*eda14cbcSMatt Macy if (pairs[j] != NULL) 1223*eda14cbcSMatt Macy fm_nvlist_destroy(pairs[j], 1224*eda14cbcSMatt Macy FM_NVA_RETAIN); 1225*eda14cbcSMatt Macy } 1226*eda14cbcSMatt Macy atomic_inc_64( 1227*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1228*eda14cbcSMatt Macy return; 1229*eda14cbcSMatt Macy } 1230*eda14cbcSMatt Macy } 1231*eda14cbcSMatt Macy 1232*eda14cbcSMatt Macy /* 1233*eda14cbcSMatt Macy * create the pairs from passed in pairs 1234*eda14cbcSMatt Macy */ 1235*eda14cbcSMatt Macy npairs = MIN(npairs, HC_MAXPAIRS); 1236*eda14cbcSMatt Macy 1237*eda14cbcSMatt Macy va_start(ap, npairs); 1238*eda14cbcSMatt Macy for (i = n; i < npairs + n; i++) { 1239*eda14cbcSMatt Macy const char *name = va_arg(ap, const char *); 1240*eda14cbcSMatt Macy uint32_t id = va_arg(ap, uint32_t); 1241*eda14cbcSMatt Macy char idstr[11]; 1242*eda14cbcSMatt Macy (void) snprintf(idstr, sizeof (idstr), "%u", id); 1243*eda14cbcSMatt Macy pairs[i] = fm_nvlist_create(nva); 1244*eda14cbcSMatt Macy if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || 1245*eda14cbcSMatt Macy nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { 1246*eda14cbcSMatt Macy for (j = 0; j <= i; j++) { 1247*eda14cbcSMatt Macy if (pairs[j] != NULL) 1248*eda14cbcSMatt Macy fm_nvlist_destroy(pairs[j], 1249*eda14cbcSMatt Macy FM_NVA_RETAIN); 1250*eda14cbcSMatt Macy } 1251*eda14cbcSMatt Macy atomic_inc_64( 1252*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1253*eda14cbcSMatt Macy return; 1254*eda14cbcSMatt Macy } 1255*eda14cbcSMatt Macy } 1256*eda14cbcSMatt Macy va_end(ap); 1257*eda14cbcSMatt Macy 1258*eda14cbcSMatt Macy /* 1259*eda14cbcSMatt Macy * Create the fmri hc list 1260*eda14cbcSMatt Macy */ 1261*eda14cbcSMatt Macy if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, 1262*eda14cbcSMatt Macy npairs + n) != 0) { 1263*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1264*eda14cbcSMatt Macy return; 1265*eda14cbcSMatt Macy } 1266*eda14cbcSMatt Macy 1267*eda14cbcSMatt Macy for (i = 0; i < npairs + n; i++) { 1268*eda14cbcSMatt Macy fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); 1269*eda14cbcSMatt Macy } 1270*eda14cbcSMatt Macy 1271*eda14cbcSMatt Macy if (snvl != NULL) { 1272*eda14cbcSMatt Macy if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { 1273*eda14cbcSMatt Macy atomic_inc_64( 1274*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1275*eda14cbcSMatt Macy return; 1276*eda14cbcSMatt Macy } 1277*eda14cbcSMatt Macy } 1278*eda14cbcSMatt Macy } 1279*eda14cbcSMatt Macy 1280*eda14cbcSMatt Macy /* 1281*eda14cbcSMatt Macy * Set-up and validate the members of an dev fmri according to: 1282*eda14cbcSMatt Macy * 1283*eda14cbcSMatt Macy * Member name Type Value 1284*eda14cbcSMatt Macy * ==================================================== 1285*eda14cbcSMatt Macy * version uint8_t 0 1286*eda14cbcSMatt Macy * auth nvlist_t <auth> 1287*eda14cbcSMatt Macy * devpath string <devpath> 1288*eda14cbcSMatt Macy * [devid] string <devid> 1289*eda14cbcSMatt Macy * [target-port-l0id] string <target-port-lun0-id> 1290*eda14cbcSMatt Macy * 1291*eda14cbcSMatt Macy * Note that auth and devid are optional members. 1292*eda14cbcSMatt Macy */ 1293*eda14cbcSMatt Macy void 1294*eda14cbcSMatt Macy fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth, 1295*eda14cbcSMatt Macy const char *devpath, const char *devid, const char *tpl0) 1296*eda14cbcSMatt Macy { 1297*eda14cbcSMatt Macy int err = 0; 1298*eda14cbcSMatt Macy 1299*eda14cbcSMatt Macy if (version != DEV_SCHEME_VERSION0) { 1300*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1301*eda14cbcSMatt Macy return; 1302*eda14cbcSMatt Macy } 1303*eda14cbcSMatt Macy 1304*eda14cbcSMatt Macy err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version); 1305*eda14cbcSMatt Macy err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 1306*eda14cbcSMatt Macy 1307*eda14cbcSMatt Macy if (auth != NULL) { 1308*eda14cbcSMatt Macy err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY, 1309*eda14cbcSMatt Macy (nvlist_t *)auth); 1310*eda14cbcSMatt Macy } 1311*eda14cbcSMatt Macy 1312*eda14cbcSMatt Macy err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath); 1313*eda14cbcSMatt Macy 1314*eda14cbcSMatt Macy if (devid != NULL) 1315*eda14cbcSMatt Macy err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid); 1316*eda14cbcSMatt Macy 1317*eda14cbcSMatt Macy if (tpl0 != NULL) 1318*eda14cbcSMatt Macy err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0); 1319*eda14cbcSMatt Macy 1320*eda14cbcSMatt Macy if (err) 1321*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1322*eda14cbcSMatt Macy 1323*eda14cbcSMatt Macy } 1324*eda14cbcSMatt Macy 1325*eda14cbcSMatt Macy /* 1326*eda14cbcSMatt Macy * Set-up and validate the members of an cpu fmri according to: 1327*eda14cbcSMatt Macy * 1328*eda14cbcSMatt Macy * Member name Type Value 1329*eda14cbcSMatt Macy * ==================================================== 1330*eda14cbcSMatt Macy * version uint8_t 0 1331*eda14cbcSMatt Macy * auth nvlist_t <auth> 1332*eda14cbcSMatt Macy * cpuid uint32_t <cpu_id> 1333*eda14cbcSMatt Macy * cpumask uint8_t <cpu_mask> 1334*eda14cbcSMatt Macy * serial uint64_t <serial_id> 1335*eda14cbcSMatt Macy * 1336*eda14cbcSMatt Macy * Note that auth, cpumask, serial are optional members. 1337*eda14cbcSMatt Macy * 1338*eda14cbcSMatt Macy */ 1339*eda14cbcSMatt Macy void 1340*eda14cbcSMatt Macy fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth, 1341*eda14cbcSMatt Macy uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp) 1342*eda14cbcSMatt Macy { 1343*eda14cbcSMatt Macy uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64; 1344*eda14cbcSMatt Macy 1345*eda14cbcSMatt Macy if (version < CPU_SCHEME_VERSION1) { 1346*eda14cbcSMatt Macy atomic_inc_64(failedp); 1347*eda14cbcSMatt Macy return; 1348*eda14cbcSMatt Macy } 1349*eda14cbcSMatt Macy 1350*eda14cbcSMatt Macy if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) { 1351*eda14cbcSMatt Macy atomic_inc_64(failedp); 1352*eda14cbcSMatt Macy return; 1353*eda14cbcSMatt Macy } 1354*eda14cbcSMatt Macy 1355*eda14cbcSMatt Macy if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME, 1356*eda14cbcSMatt Macy FM_FMRI_SCHEME_CPU) != 0) { 1357*eda14cbcSMatt Macy atomic_inc_64(failedp); 1358*eda14cbcSMatt Macy return; 1359*eda14cbcSMatt Macy } 1360*eda14cbcSMatt Macy 1361*eda14cbcSMatt Macy if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, 1362*eda14cbcSMatt Macy (nvlist_t *)auth) != 0) 1363*eda14cbcSMatt Macy atomic_inc_64(failedp); 1364*eda14cbcSMatt Macy 1365*eda14cbcSMatt Macy if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) 1366*eda14cbcSMatt Macy atomic_inc_64(failedp); 1367*eda14cbcSMatt Macy 1368*eda14cbcSMatt Macy if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, 1369*eda14cbcSMatt Macy *cpu_maskp) != 0) 1370*eda14cbcSMatt Macy atomic_inc_64(failedp); 1371*eda14cbcSMatt Macy 1372*eda14cbcSMatt Macy if (serial_idp == NULL || nvlist_add_string(fmri_cpu, 1373*eda14cbcSMatt Macy FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0) 1374*eda14cbcSMatt Macy atomic_inc_64(failedp); 1375*eda14cbcSMatt Macy } 1376*eda14cbcSMatt Macy 1377*eda14cbcSMatt Macy /* 1378*eda14cbcSMatt Macy * Set-up and validate the members of a mem according to: 1379*eda14cbcSMatt Macy * 1380*eda14cbcSMatt Macy * Member name Type Value 1381*eda14cbcSMatt Macy * ==================================================== 1382*eda14cbcSMatt Macy * version uint8_t 0 1383*eda14cbcSMatt Macy * auth nvlist_t <auth> [optional] 1384*eda14cbcSMatt Macy * unum string <unum> 1385*eda14cbcSMatt Macy * serial string <serial> [optional*] 1386*eda14cbcSMatt Macy * offset uint64_t <offset> [optional] 1387*eda14cbcSMatt Macy * 1388*eda14cbcSMatt Macy * * serial is required if offset is present 1389*eda14cbcSMatt Macy */ 1390*eda14cbcSMatt Macy void 1391*eda14cbcSMatt Macy fm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth, 1392*eda14cbcSMatt Macy const char *unum, const char *serial, uint64_t offset) 1393*eda14cbcSMatt Macy { 1394*eda14cbcSMatt Macy if (version != MEM_SCHEME_VERSION0) { 1395*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1396*eda14cbcSMatt Macy return; 1397*eda14cbcSMatt Macy } 1398*eda14cbcSMatt Macy 1399*eda14cbcSMatt Macy if (!serial && (offset != (uint64_t)-1)) { 1400*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1401*eda14cbcSMatt Macy return; 1402*eda14cbcSMatt Macy } 1403*eda14cbcSMatt Macy 1404*eda14cbcSMatt Macy if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) { 1405*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1406*eda14cbcSMatt Macy return; 1407*eda14cbcSMatt Macy } 1408*eda14cbcSMatt Macy 1409*eda14cbcSMatt Macy if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) { 1410*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1411*eda14cbcSMatt Macy return; 1412*eda14cbcSMatt Macy } 1413*eda14cbcSMatt Macy 1414*eda14cbcSMatt Macy if (auth != NULL) { 1415*eda14cbcSMatt Macy if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 1416*eda14cbcSMatt Macy (nvlist_t *)auth) != 0) { 1417*eda14cbcSMatt Macy atomic_inc_64( 1418*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1419*eda14cbcSMatt Macy } 1420*eda14cbcSMatt Macy } 1421*eda14cbcSMatt Macy 1422*eda14cbcSMatt Macy if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) { 1423*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1424*eda14cbcSMatt Macy } 1425*eda14cbcSMatt Macy 1426*eda14cbcSMatt Macy if (serial != NULL) { 1427*eda14cbcSMatt Macy if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID, 1428*eda14cbcSMatt Macy (char **)&serial, 1) != 0) { 1429*eda14cbcSMatt Macy atomic_inc_64( 1430*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1431*eda14cbcSMatt Macy } 1432*eda14cbcSMatt Macy if (offset != (uint64_t)-1 && nvlist_add_uint64(fmri, 1433*eda14cbcSMatt Macy FM_FMRI_MEM_OFFSET, offset) != 0) { 1434*eda14cbcSMatt Macy atomic_inc_64( 1435*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1436*eda14cbcSMatt Macy } 1437*eda14cbcSMatt Macy } 1438*eda14cbcSMatt Macy } 1439*eda14cbcSMatt Macy 1440*eda14cbcSMatt Macy void 1441*eda14cbcSMatt Macy fm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid, 1442*eda14cbcSMatt Macy uint64_t vdev_guid) 1443*eda14cbcSMatt Macy { 1444*eda14cbcSMatt Macy if (version != ZFS_SCHEME_VERSION0) { 1445*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1446*eda14cbcSMatt Macy return; 1447*eda14cbcSMatt Macy } 1448*eda14cbcSMatt Macy 1449*eda14cbcSMatt Macy if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) { 1450*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1451*eda14cbcSMatt Macy return; 1452*eda14cbcSMatt Macy } 1453*eda14cbcSMatt Macy 1454*eda14cbcSMatt Macy if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) { 1455*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1456*eda14cbcSMatt Macy return; 1457*eda14cbcSMatt Macy } 1458*eda14cbcSMatt Macy 1459*eda14cbcSMatt Macy if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) { 1460*eda14cbcSMatt Macy atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64); 1461*eda14cbcSMatt Macy } 1462*eda14cbcSMatt Macy 1463*eda14cbcSMatt Macy if (vdev_guid != 0) { 1464*eda14cbcSMatt Macy if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) { 1465*eda14cbcSMatt Macy atomic_inc_64( 1466*eda14cbcSMatt Macy &erpt_kstat_data.fmri_set_failed.value.ui64); 1467*eda14cbcSMatt Macy } 1468*eda14cbcSMatt Macy } 1469*eda14cbcSMatt Macy } 1470*eda14cbcSMatt Macy 1471*eda14cbcSMatt Macy uint64_t 1472*eda14cbcSMatt Macy fm_ena_increment(uint64_t ena) 1473*eda14cbcSMatt Macy { 1474*eda14cbcSMatt Macy uint64_t new_ena; 1475*eda14cbcSMatt Macy 1476*eda14cbcSMatt Macy switch (ENA_FORMAT(ena)) { 1477*eda14cbcSMatt Macy case FM_ENA_FMT1: 1478*eda14cbcSMatt Macy new_ena = ena + (1 << ENA_FMT1_GEN_SHFT); 1479*eda14cbcSMatt Macy break; 1480*eda14cbcSMatt Macy case FM_ENA_FMT2: 1481*eda14cbcSMatt Macy new_ena = ena + (1 << ENA_FMT2_GEN_SHFT); 1482*eda14cbcSMatt Macy break; 1483*eda14cbcSMatt Macy default: 1484*eda14cbcSMatt Macy new_ena = 0; 1485*eda14cbcSMatt Macy } 1486*eda14cbcSMatt Macy 1487*eda14cbcSMatt Macy return (new_ena); 1488*eda14cbcSMatt Macy } 1489*eda14cbcSMatt Macy 1490*eda14cbcSMatt Macy uint64_t 1491*eda14cbcSMatt Macy fm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format) 1492*eda14cbcSMatt Macy { 1493*eda14cbcSMatt Macy uint64_t ena = 0; 1494*eda14cbcSMatt Macy 1495*eda14cbcSMatt Macy switch (format) { 1496*eda14cbcSMatt Macy case FM_ENA_FMT1: 1497*eda14cbcSMatt Macy if (timestamp) { 1498*eda14cbcSMatt Macy ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1499*eda14cbcSMatt Macy ((cpuid << ENA_FMT1_CPUID_SHFT) & 1500*eda14cbcSMatt Macy ENA_FMT1_CPUID_MASK) | 1501*eda14cbcSMatt Macy ((timestamp << ENA_FMT1_TIME_SHFT) & 1502*eda14cbcSMatt Macy ENA_FMT1_TIME_MASK)); 1503*eda14cbcSMatt Macy } else { 1504*eda14cbcSMatt Macy ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1505*eda14cbcSMatt Macy ((cpuid << ENA_FMT1_CPUID_SHFT) & 1506*eda14cbcSMatt Macy ENA_FMT1_CPUID_MASK) | 1507*eda14cbcSMatt Macy ((gethrtime() << ENA_FMT1_TIME_SHFT) & 1508*eda14cbcSMatt Macy ENA_FMT1_TIME_MASK)); 1509*eda14cbcSMatt Macy } 1510*eda14cbcSMatt Macy break; 1511*eda14cbcSMatt Macy case FM_ENA_FMT2: 1512*eda14cbcSMatt Macy ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1513*eda14cbcSMatt Macy ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK)); 1514*eda14cbcSMatt Macy break; 1515*eda14cbcSMatt Macy default: 1516*eda14cbcSMatt Macy break; 1517*eda14cbcSMatt Macy } 1518*eda14cbcSMatt Macy 1519*eda14cbcSMatt Macy return (ena); 1520*eda14cbcSMatt Macy } 1521*eda14cbcSMatt Macy 1522*eda14cbcSMatt Macy uint64_t 1523*eda14cbcSMatt Macy fm_ena_generate(uint64_t timestamp, uchar_t format) 1524*eda14cbcSMatt Macy { 1525*eda14cbcSMatt Macy uint64_t ena; 1526*eda14cbcSMatt Macy 1527*eda14cbcSMatt Macy kpreempt_disable(); 1528*eda14cbcSMatt Macy ena = fm_ena_generate_cpu(timestamp, getcpuid(), format); 1529*eda14cbcSMatt Macy kpreempt_enable(); 1530*eda14cbcSMatt Macy 1531*eda14cbcSMatt Macy return (ena); 1532*eda14cbcSMatt Macy } 1533*eda14cbcSMatt Macy 1534*eda14cbcSMatt Macy uint64_t 1535*eda14cbcSMatt Macy fm_ena_generation_get(uint64_t ena) 1536*eda14cbcSMatt Macy { 1537*eda14cbcSMatt Macy uint64_t gen; 1538*eda14cbcSMatt Macy 1539*eda14cbcSMatt Macy switch (ENA_FORMAT(ena)) { 1540*eda14cbcSMatt Macy case FM_ENA_FMT1: 1541*eda14cbcSMatt Macy gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT; 1542*eda14cbcSMatt Macy break; 1543*eda14cbcSMatt Macy case FM_ENA_FMT2: 1544*eda14cbcSMatt Macy gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT; 1545*eda14cbcSMatt Macy break; 1546*eda14cbcSMatt Macy default: 1547*eda14cbcSMatt Macy gen = 0; 1548*eda14cbcSMatt Macy break; 1549*eda14cbcSMatt Macy } 1550*eda14cbcSMatt Macy 1551*eda14cbcSMatt Macy return (gen); 1552*eda14cbcSMatt Macy } 1553*eda14cbcSMatt Macy 1554*eda14cbcSMatt Macy uchar_t 1555*eda14cbcSMatt Macy fm_ena_format_get(uint64_t ena) 1556*eda14cbcSMatt Macy { 1557*eda14cbcSMatt Macy 1558*eda14cbcSMatt Macy return (ENA_FORMAT(ena)); 1559*eda14cbcSMatt Macy } 1560*eda14cbcSMatt Macy 1561*eda14cbcSMatt Macy uint64_t 1562*eda14cbcSMatt Macy fm_ena_id_get(uint64_t ena) 1563*eda14cbcSMatt Macy { 1564*eda14cbcSMatt Macy uint64_t id; 1565*eda14cbcSMatt Macy 1566*eda14cbcSMatt Macy switch (ENA_FORMAT(ena)) { 1567*eda14cbcSMatt Macy case FM_ENA_FMT1: 1568*eda14cbcSMatt Macy id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT; 1569*eda14cbcSMatt Macy break; 1570*eda14cbcSMatt Macy case FM_ENA_FMT2: 1571*eda14cbcSMatt Macy id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT; 1572*eda14cbcSMatt Macy break; 1573*eda14cbcSMatt Macy default: 1574*eda14cbcSMatt Macy id = 0; 1575*eda14cbcSMatt Macy } 1576*eda14cbcSMatt Macy 1577*eda14cbcSMatt Macy return (id); 1578*eda14cbcSMatt Macy } 1579*eda14cbcSMatt Macy 1580*eda14cbcSMatt Macy uint64_t 1581*eda14cbcSMatt Macy fm_ena_time_get(uint64_t ena) 1582*eda14cbcSMatt Macy { 1583*eda14cbcSMatt Macy uint64_t time; 1584*eda14cbcSMatt Macy 1585*eda14cbcSMatt Macy switch (ENA_FORMAT(ena)) { 1586*eda14cbcSMatt Macy case FM_ENA_FMT1: 1587*eda14cbcSMatt Macy time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT; 1588*eda14cbcSMatt Macy break; 1589*eda14cbcSMatt Macy case FM_ENA_FMT2: 1590*eda14cbcSMatt Macy time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT; 1591*eda14cbcSMatt Macy break; 1592*eda14cbcSMatt Macy default: 1593*eda14cbcSMatt Macy time = 0; 1594*eda14cbcSMatt Macy } 1595*eda14cbcSMatt Macy 1596*eda14cbcSMatt Macy return (time); 1597*eda14cbcSMatt Macy } 1598*eda14cbcSMatt Macy 1599*eda14cbcSMatt Macy #ifdef _KERNEL 1600*eda14cbcSMatt Macy /* 1601*eda14cbcSMatt Macy * Helper function to increment ereport dropped count. Used by the event 1602*eda14cbcSMatt Macy * rate limiting code to give feedback to the user about how many events were 1603*eda14cbcSMatt Macy * rate limited by including them in the 'dropped' count. 1604*eda14cbcSMatt Macy */ 1605*eda14cbcSMatt Macy void 1606*eda14cbcSMatt Macy fm_erpt_dropped_increment(void) 1607*eda14cbcSMatt Macy { 1608*eda14cbcSMatt Macy atomic_inc_64(&ratelimit_dropped); 1609*eda14cbcSMatt Macy } 1610*eda14cbcSMatt Macy 1611*eda14cbcSMatt Macy void 1612*eda14cbcSMatt Macy fm_init(void) 1613*eda14cbcSMatt Macy { 1614*eda14cbcSMatt Macy zevent_len_cur = 0; 1615*eda14cbcSMatt Macy zevent_flags = 0; 1616*eda14cbcSMatt Macy 1617*eda14cbcSMatt Macy if (zfs_zevent_len_max == 0) 1618*eda14cbcSMatt Macy zfs_zevent_len_max = ERPT_MAX_ERRS * MAX(max_ncpus, 4); 1619*eda14cbcSMatt Macy 1620*eda14cbcSMatt Macy /* Initialize zevent allocation and generation kstats */ 1621*eda14cbcSMatt Macy fm_ksp = kstat_create("zfs", 0, "fm", "misc", KSTAT_TYPE_NAMED, 1622*eda14cbcSMatt Macy sizeof (struct erpt_kstat) / sizeof (kstat_named_t), 1623*eda14cbcSMatt Macy KSTAT_FLAG_VIRTUAL); 1624*eda14cbcSMatt Macy 1625*eda14cbcSMatt Macy if (fm_ksp != NULL) { 1626*eda14cbcSMatt Macy fm_ksp->ks_data = &erpt_kstat_data; 1627*eda14cbcSMatt Macy kstat_install(fm_ksp); 1628*eda14cbcSMatt Macy } else { 1629*eda14cbcSMatt Macy cmn_err(CE_NOTE, "failed to create fm/misc kstat\n"); 1630*eda14cbcSMatt Macy } 1631*eda14cbcSMatt Macy 1632*eda14cbcSMatt Macy mutex_init(&zevent_lock, NULL, MUTEX_DEFAULT, NULL); 1633*eda14cbcSMatt Macy list_create(&zevent_list, sizeof (zevent_t), 1634*eda14cbcSMatt Macy offsetof(zevent_t, ev_node)); 1635*eda14cbcSMatt Macy cv_init(&zevent_cv, NULL, CV_DEFAULT, NULL); 1636*eda14cbcSMatt Macy } 1637*eda14cbcSMatt Macy 1638*eda14cbcSMatt Macy void 1639*eda14cbcSMatt Macy fm_fini(void) 1640*eda14cbcSMatt Macy { 1641*eda14cbcSMatt Macy int count; 1642*eda14cbcSMatt Macy 1643*eda14cbcSMatt Macy zfs_zevent_drain_all(&count); 1644*eda14cbcSMatt Macy 1645*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 1646*eda14cbcSMatt Macy cv_broadcast(&zevent_cv); 1647*eda14cbcSMatt Macy 1648*eda14cbcSMatt Macy zevent_flags |= ZEVENT_SHUTDOWN; 1649*eda14cbcSMatt Macy while (zevent_waiters > 0) { 1650*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 1651*eda14cbcSMatt Macy schedule(); 1652*eda14cbcSMatt Macy mutex_enter(&zevent_lock); 1653*eda14cbcSMatt Macy } 1654*eda14cbcSMatt Macy mutex_exit(&zevent_lock); 1655*eda14cbcSMatt Macy 1656*eda14cbcSMatt Macy cv_destroy(&zevent_cv); 1657*eda14cbcSMatt Macy list_destroy(&zevent_list); 1658*eda14cbcSMatt Macy mutex_destroy(&zevent_lock); 1659*eda14cbcSMatt Macy 1660*eda14cbcSMatt Macy if (fm_ksp != NULL) { 1661*eda14cbcSMatt Macy kstat_delete(fm_ksp); 1662*eda14cbcSMatt Macy fm_ksp = NULL; 1663*eda14cbcSMatt Macy } 1664*eda14cbcSMatt Macy } 1665*eda14cbcSMatt Macy #endif /* _KERNEL */ 1666*eda14cbcSMatt Macy 1667*eda14cbcSMatt Macy ZFS_MODULE_PARAM(zfs_zevent, zfs_zevent_, len_max, INT, ZMOD_RW, 1668*eda14cbcSMatt Macy "Max event queue length"); 1669*eda14cbcSMatt Macy 1670*eda14cbcSMatt Macy ZFS_MODULE_PARAM(zfs_zevent, zfs_zevent_, cols, INT, ZMOD_RW, 1671*eda14cbcSMatt Macy "Max event column width"); 1672*eda14cbcSMatt Macy 1673*eda14cbcSMatt Macy ZFS_MODULE_PARAM(zfs_zevent, zfs_zevent_, console, INT, ZMOD_RW, 1674*eda14cbcSMatt Macy "Log events to the console"); 1675