Home | History | Annotate | Line # | Download | only in os
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
     23  */
     24 
     25 /*
     26  * Fault Management Architecture (FMA) Resource and Protocol Support
     27  *
     28  * The routines contained herein provide services to support kernel subsystems
     29  * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089).
     30  *
     31  * Name-Value Pair Lists
     32  *
     33  * The embodiment of an FMA protocol element (event, fmri or authority) is a
     34  * name-value pair list (nvlist_t).  FMA-specific nvlist construtor and
     35  * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used
     36  * to create an nvpair list using custom allocators.  Callers may choose to
     37  * allocate either from the kernel memory allocator, or from a preallocated
     38  * buffer, useful in constrained contexts like high-level interrupt routines.
     39  *
     40  * Protocol Event and FMRI Construction
     41  *
     42  * Convenience routines are provided to construct nvlist events according to
     43  * the FMA Event Protocol and Naming Schema specification for ereports and
     44  * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes.
     45  *
     46  * ENA Manipulation
     47  *
     48  * Routines to generate ENA formats 0, 1 and 2 are available as well as
     49  * routines to increment formats 1 and 2.  Individual fields within the
     50  * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(),
     51  * fm_ena_format_get() and fm_ena_gen_get().
     52  */
     53 
     54 #include <sys/types.h>
     55 #include <sys/time.h>
     56 #include <sys/sysevent.h>
     57 #include <sys/nvpair.h>
     58 #include <sys/cmn_err.h>
     59 #include <sys/cpuvar.h>
     60 #include <sys/sysmacros.h>
     61 #include <sys/systm.h>
     62 #include <sys/compress.h>
     63 #include <sys/cpuvar.h>
     64 #include <sys/kobj.h>
     65 #include <sys/kstat.h>
     66 #include <sys/processor.h>
     67 #ifdef __NetBSD__
     68 #include <sys/atomic.h>
     69 #include <sys/cpu.h>
     70 #else
     71 #include <sys/pcpu.h>
     72 #endif
     73 #include <sys/sunddi.h>
     74 #include <sys/systeminfo.h>
     75 #include <sys/sysevent/eventdefs.h>
     76 #include <sys/fm/util.h>
     77 #include <sys/fm/protocol.h>
     78 
     79 /*
     80  * URL and SUNW-MSG-ID value to display for fm_panic(), defined below.  These
     81  * values must be kept in sync with the FMA source code in usr/src/cmd/fm.
     82  */
     83 static const char *fm_url = "http://www.sun.com/msg";
     84 static const char *fm_msgid = "SUNOS-8000-0G";
     85 static char *volatile fm_panicstr = NULL;
     86 
     87 #ifdef illumos
     88 errorq_t *ereport_errorq;
     89 #endif
     90 void *ereport_dumpbuf;
     91 size_t ereport_dumplen;
     92 
     93 static uint_t ereport_chanlen = ERPT_EVCH_MAX;
     94 static evchan_t *ereport_chan = NULL;
     95 static ulong_t ereport_qlen = 0;
     96 static size_t ereport_size = 0;
     97 static int ereport_cols = 80;
     98 
     99 extern void fastreboot_disable_highpil(void);
    100 
    101 /*
    102  * Common fault management kstats to record ereport generation
    103  * failures
    104  */
    105 
    106 struct erpt_kstat {
    107 	kstat_named_t	erpt_dropped;		/* num erpts dropped on post */
    108 	kstat_named_t	erpt_set_failed;	/* num erpt set failures */
    109 	kstat_named_t	fmri_set_failed;	/* num fmri set failures */
    110 	kstat_named_t	payload_set_failed;	/* num payload set failures */
    111 };
    112 
    113 static struct erpt_kstat erpt_kstat_data = {
    114 	{ "erpt-dropped", KSTAT_DATA_UINT64 },
    115 	{ "erpt-set-failed", KSTAT_DATA_UINT64 },
    116 	{ "fmri-set-failed", KSTAT_DATA_UINT64 },
    117 	{ "payload-set-failed", KSTAT_DATA_UINT64 }
    118 };
    119 
    120 #ifdef illumos
    121 /*ARGSUSED*/
    122 static void
    123 fm_drain(void *private, void *data, errorq_elem_t *eep)
    124 {
    125 	nvlist_t *nvl = errorq_elem_nvl(ereport_errorq, eep);
    126 
    127 	if (!panicstr)
    128 		(void) fm_ereport_post(nvl, EVCH_TRYHARD);
    129 	else
    130 		fm_nvprint(nvl);
    131 }
    132 #endif
    133 
    134 void
    135 fm_init(void)
    136 {
    137 	kstat_t *ksp;
    138 
    139 #ifdef illumos
    140 	(void) sysevent_evc_bind(FM_ERROR_CHAN,
    141 	    &ereport_chan, EVCH_CREAT | EVCH_HOLD_PEND);
    142 
    143 	(void) sysevent_evc_control(ereport_chan,
    144 	    EVCH_SET_CHAN_LEN, &ereport_chanlen);
    145 #endif
    146 
    147 	if (ereport_qlen == 0)
    148 		ereport_qlen = ERPT_MAX_ERRS * MAX(max_ncpus, 4);
    149 
    150 	if (ereport_size == 0)
    151 		ereport_size = ERPT_DATA_SZ;
    152 
    153 #ifdef illumos
    154 	ereport_errorq = errorq_nvcreate("fm_ereport_queue",
    155 	    (errorq_func_t)fm_drain, NULL, ereport_qlen, ereport_size,
    156 	    FM_ERR_PIL, ERRORQ_VITAL);
    157 	if (ereport_errorq == NULL)
    158 		panic("failed to create required ereport error queue");
    159 #endif
    160 
    161 	ereport_dumpbuf = kmem_alloc(ereport_size, KM_SLEEP);
    162 	ereport_dumplen = ereport_size;
    163 
    164 	/* Initialize ereport allocation and generation kstats */
    165 	ksp = kstat_create("unix", 0, "fm", "misc", KSTAT_TYPE_NAMED,
    166 	    sizeof (struct erpt_kstat) / sizeof (kstat_named_t),
    167 	    KSTAT_FLAG_VIRTUAL);
    168 
    169 	if (ksp != NULL) {
    170 		ksp->ks_data = &erpt_kstat_data;
    171 		kstat_install(ksp);
    172 	} else {
    173 		cmn_err(CE_NOTE, "failed to create fm/misc kstat\n");
    174 
    175 	}
    176 }
    177 
    178 #ifdef illumos
    179 /*
    180  * Formatting utility function for fm_nvprintr.  We attempt to wrap chunks of
    181  * output so they aren't split across console lines, and return the end column.
    182  */
    183 /*PRINTFLIKE4*/
    184 static int
    185 fm_printf(int depth, int c, int cols, const char *format, ...)
    186 {
    187 	va_list ap;
    188 	int width;
    189 	char c1;
    190 
    191 	va_start(ap, format);
    192 	width = vsnprintf(&c1, sizeof (c1), format, ap);
    193 	va_end(ap);
    194 
    195 	if (c + width >= cols) {
    196 		console_printf("\n\r");
    197 		c = 0;
    198 		if (format[0] != ' ' && depth > 0) {
    199 			console_printf(" ");
    200 			c++;
    201 		}
    202 	}
    203 
    204 	va_start(ap, format);
    205 	console_vprintf(format, ap);
    206 	va_end(ap);
    207 
    208 	return ((c + width) % cols);
    209 }
    210 
    211 /*
    212  * Recursively print a nvlist in the specified column width and return the
    213  * column we end up in.  This function is called recursively by fm_nvprint(),
    214  * below.  We generically format the entire nvpair using hexadecimal
    215  * integers and strings, and elide any integer arrays.  Arrays are basically
    216  * used for cache dumps right now, so we suppress them so as not to overwhelm
    217  * the amount of console output we produce at panic time.  This can be further
    218  * enhanced as FMA technology grows based upon the needs of consumers.  All
    219  * FMA telemetry is logged using the dump device transport, so the console
    220  * output serves only as a fallback in case this procedure is unsuccessful.
    221  */
    222 static int
    223 fm_nvprintr(nvlist_t *nvl, int d, int c, int cols)
    224 {
    225 	nvpair_t *nvp;
    226 
    227 	for (nvp = nvlist_next_nvpair(nvl, NULL);
    228 	    nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
    229 
    230 		data_type_t type = nvpair_type(nvp);
    231 		const char *name = nvpair_name(nvp);
    232 
    233 		boolean_t b;
    234 		uint8_t i8;
    235 		uint16_t i16;
    236 		uint32_t i32;
    237 		uint64_t i64;
    238 		char *str;
    239 		nvlist_t *cnv;
    240 
    241 		if (strcmp(name, FM_CLASS) == 0)
    242 			continue; /* already printed by caller */
    243 
    244 		c = fm_printf(d, c, cols, " %s=", name);
    245 
    246 		switch (type) {
    247 		case DATA_TYPE_BOOLEAN:
    248 			c = fm_printf(d + 1, c, cols, " 1");
    249 			break;
    250 
    251 		case DATA_TYPE_BOOLEAN_VALUE:
    252 			(void) nvpair_value_boolean_value(nvp, &b);
    253 			c = fm_printf(d + 1, c, cols, b ? "1" : "0");
    254 			break;
    255 
    256 		case DATA_TYPE_BYTE:
    257 			(void) nvpair_value_byte(nvp, &i8);
    258 			c = fm_printf(d + 1, c, cols, "%x", i8);
    259 			break;
    260 
    261 		case DATA_TYPE_INT8:
    262 			(void) nvpair_value_int8(nvp, (void *)&i8);
    263 			c = fm_printf(d + 1, c, cols, "%x", i8);
    264 			break;
    265 
    266 		case DATA_TYPE_UINT8:
    267 			(void) nvpair_value_uint8(nvp, &i8);
    268 			c = fm_printf(d + 1, c, cols, "%x", i8);
    269 			break;
    270 
    271 		case DATA_TYPE_INT16:
    272 			(void) nvpair_value_int16(nvp, (void *)&i16);
    273 			c = fm_printf(d + 1, c, cols, "%x", i16);
    274 			break;
    275 
    276 		case DATA_TYPE_UINT16:
    277 			(void) nvpair_value_uint16(nvp, &i16);
    278 			c = fm_printf(d + 1, c, cols, "%x", i16);
    279 			break;
    280 
    281 		case DATA_TYPE_INT32:
    282 			(void) nvpair_value_int32(nvp, (void *)&i32);
    283 			c = fm_printf(d + 1, c, cols, "%x", i32);
    284 			break;
    285 
    286 		case DATA_TYPE_UINT32:
    287 			(void) nvpair_value_uint32(nvp, &i32);
    288 			c = fm_printf(d + 1, c, cols, "%x", i32);
    289 			break;
    290 
    291 		case DATA_TYPE_INT64:
    292 			(void) nvpair_value_int64(nvp, (void *)&i64);
    293 			c = fm_printf(d + 1, c, cols, "%llx",
    294 			    (u_longlong_t)i64);
    295 			break;
    296 
    297 		case DATA_TYPE_UINT64:
    298 			(void) nvpair_value_uint64(nvp, &i64);
    299 			c = fm_printf(d + 1, c, cols, "%llx",
    300 			    (u_longlong_t)i64);
    301 			break;
    302 
    303 		case DATA_TYPE_HRTIME:
    304 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
    305 			c = fm_printf(d + 1, c, cols, "%llx",
    306 			    (u_longlong_t)i64);
    307 			break;
    308 
    309 		case DATA_TYPE_STRING:
    310 			(void) nvpair_value_string(nvp, &str);
    311 			c = fm_printf(d + 1, c, cols, "\"%s\"",
    312 			    str ? str : "<NULL>");
    313 			break;
    314 
    315 		case DATA_TYPE_NVLIST:
    316 			c = fm_printf(d + 1, c, cols, "[");
    317 			(void) nvpair_value_nvlist(nvp, &cnv);
    318 			c = fm_nvprintr(cnv, d + 1, c, cols);
    319 			c = fm_printf(d + 1, c, cols, " ]");
    320 			break;
    321 
    322 		case DATA_TYPE_NVLIST_ARRAY: {
    323 			nvlist_t **val;
    324 			uint_t i, nelem;
    325 
    326 			c = fm_printf(d + 1, c, cols, "[");
    327 			(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
    328 			for (i = 0; i < nelem; i++) {
    329 				c = fm_nvprintr(val[i], d + 1, c, cols);
    330 			}
    331 			c = fm_printf(d + 1, c, cols, " ]");
    332 			}
    333 			break;
    334 
    335 		case DATA_TYPE_BOOLEAN_ARRAY:
    336 		case DATA_TYPE_BYTE_ARRAY:
    337 		case DATA_TYPE_INT8_ARRAY:
    338 		case DATA_TYPE_UINT8_ARRAY:
    339 		case DATA_TYPE_INT16_ARRAY:
    340 		case DATA_TYPE_UINT16_ARRAY:
    341 		case DATA_TYPE_INT32_ARRAY:
    342 		case DATA_TYPE_UINT32_ARRAY:
    343 		case DATA_TYPE_INT64_ARRAY:
    344 		case DATA_TYPE_UINT64_ARRAY:
    345 		case DATA_TYPE_STRING_ARRAY:
    346 			c = fm_printf(d + 1, c, cols, "[...]");
    347 			break;
    348 		case DATA_TYPE_UNKNOWN:
    349 			c = fm_printf(d + 1, c, cols, "<unknown>");
    350 			break;
    351 		}
    352 	}
    353 
    354 	return (c);
    355 }
    356 
    357 void
    358 fm_nvprint(nvlist_t *nvl)
    359 {
    360 	char *class;
    361 	int c = 0;
    362 
    363 	console_printf("\r");
    364 
    365 	if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0)
    366 		c = fm_printf(0, c, ereport_cols, "%s", class);
    367 
    368 	if (fm_nvprintr(nvl, 0, c, ereport_cols) != 0)
    369 		console_printf("\n");
    370 
    371 	console_printf("\n");
    372 }
    373 
    374 /*
    375  * Wrapper for panic() that first produces an FMA-style message for admins.
    376  * Normally such messages are generated by fmd(1M)'s syslog-msgs agent: this
    377  * is the one exception to that rule and the only error that gets messaged.
    378  * This function is intended for use by subsystems that have detected a fatal
    379  * error and enqueued appropriate ereports and wish to then force a panic.
    380  */
    381 /*PRINTFLIKE1*/
    382 void
    383 fm_panic(const char *format, ...)
    384 {
    385 	va_list ap;
    386 
    387 	(void) atomic_cas_ptr((void *)&fm_panicstr, NULL, (void *)format);
    388 #if defined(__i386) || defined(__amd64)
    389 	fastreboot_disable_highpil();
    390 #endif /* __i386 || __amd64 */
    391 	va_start(ap, format);
    392 	vpanic(format, ap);
    393 	va_end(ap);
    394 }
    395 
    396 /*
    397  * Simply tell the caller if fm_panicstr is set, ie. an fma event has
    398  * caused the panic. If so, something other than the default panic
    399  * diagnosis method will diagnose the cause of the panic.
    400  */
    401 int
    402 is_fm_panic()
    403 {
    404 	if (fm_panicstr)
    405 		return (1);
    406 	else
    407 		return (0);
    408 }
    409 
    410 /*
    411  * Print any appropriate FMA banner message before the panic message.  This
    412  * function is called by panicsys() and prints the message for fm_panic().
    413  * We print the message here so that it comes after the system is quiesced.
    414  * A one-line summary is recorded in the log only (cmn_err(9F) with "!" prefix).
    415  * The rest of the message is for the console only and not needed in the log,
    416  * so it is printed using console_printf().  We break it up into multiple
    417  * chunks so as to avoid overflowing any small legacy prom_printf() buffers.
    418  */
    419 void
    420 fm_banner(void)
    421 {
    422 	timespec_t tod;
    423 	hrtime_t now;
    424 
    425 	if (!fm_panicstr)
    426 		return; /* panic was not initiated by fm_panic(); do nothing */
    427 
    428 	if (panicstr) {
    429 		tod = panic_hrestime;
    430 		now = panic_hrtime;
    431 	} else {
    432 		gethrestime(&tod);
    433 		now = gethrtime_waitfree();
    434 	}
    435 
    436 	cmn_err(CE_NOTE, "!SUNW-MSG-ID: %s, "
    437 	    "TYPE: Error, VER: 1, SEVERITY: Major\n", fm_msgid);
    438 
    439 	console_printf(
    440 "\n\rSUNW-MSG-ID: %s, TYPE: Error, VER: 1, SEVERITY: Major\n"
    441 "EVENT-TIME: 0x%lx.0x%lx (0x%llx)\n",
    442 	    fm_msgid, tod.tv_sec, tod.tv_nsec, (u_longlong_t)now);
    443 
    444 	console_printf(
    445 "PLATFORM: %s, CSN: -, HOSTNAME: %s\n"
    446 "SOURCE: %s, REV: %s %s\n",
    447 	    platform, utsname.nodename, utsname.sysname,
    448 	    utsname.release, utsname.version);
    449 
    450 	console_printf(
    451 "DESC: Errors have been detected that require a reboot to ensure system\n"
    452 "integrity.  See %s/%s for more information.\n",
    453 	    fm_url, fm_msgid);
    454 
    455 	console_printf(
    456 "AUTO-RESPONSE: Solaris will attempt to save and diagnose the error telemetry\n"
    457 "IMPACT: The system will sync files, save a crash dump if needed, and reboot\n"
    458 "REC-ACTION: Save the error summary below in case telemetry cannot be saved\n");
    459 
    460 	console_printf("\n");
    461 }
    462 
    463 /*
    464  * Utility function to write all of the pending ereports to the dump device.
    465  * This function is called at either normal reboot or panic time, and simply
    466  * iterates over the in-transit messages in the ereport sysevent channel.
    467  */
    468 void
    469 fm_ereport_dump(void)
    470 {
    471 	evchanq_t *chq;
    472 	sysevent_t *sep;
    473 	erpt_dump_t ed;
    474 
    475 	timespec_t tod;
    476 	hrtime_t now;
    477 	char *buf;
    478 	size_t len;
    479 
    480 	if (panicstr) {
    481 		tod = panic_hrestime;
    482 		now = panic_hrtime;
    483 	} else {
    484 		if (ereport_errorq != NULL)
    485 			errorq_drain(ereport_errorq);
    486 		gethrestime(&tod);
    487 		now = gethrtime_waitfree();
    488 	}
    489 
    490 	/*
    491 	 * In the panic case, sysevent_evc_walk_init() will return NULL.
    492 	 */
    493 	if ((chq = sysevent_evc_walk_init(ereport_chan, NULL)) == NULL &&
    494 	    !panicstr)
    495 		return; /* event channel isn't initialized yet */
    496 
    497 	while ((sep = sysevent_evc_walk_step(chq)) != NULL) {
    498 		if ((buf = sysevent_evc_event_attr(sep, &len)) == NULL)
    499 			break;
    500 
    501 		ed.ed_magic = ERPT_MAGIC;
    502 		ed.ed_chksum = checksum32(buf, len);
    503 		ed.ed_size = (uint32_t)len;
    504 		ed.ed_pad = 0;
    505 		ed.ed_hrt_nsec = SE_TIME(sep);
    506 		ed.ed_hrt_base = now;
    507 		ed.ed_tod_base.sec = tod.tv_sec;
    508 		ed.ed_tod_base.nsec = tod.tv_nsec;
    509 
    510 		dumpvp_write(&ed, sizeof (ed));
    511 		dumpvp_write(buf, len);
    512 	}
    513 
    514 	sysevent_evc_walk_fini(chq);
    515 }
    516 #endif
    517 
    518 /*
    519  * Post an error report (ereport) to the sysevent error channel.  The error
    520  * channel must be established with a prior call to sysevent_evc_create()
    521  * before publication may occur.
    522  */
    523 void
    524 fm_ereport_post(nvlist_t *ereport, int evc_flag)
    525 {
    526 	size_t nvl_size = 0;
    527 	evchan_t *error_chan;
    528 	sysevent_id_t eid;
    529 
    530 	(void) nvlist_size(ereport, &nvl_size, NV_ENCODE_NATIVE);
    531 	if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) {
    532 		atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
    533 		return;
    534 	}
    535 
    536 #ifdef illumos
    537 	if (sysevent_evc_bind(FM_ERROR_CHAN, &error_chan,
    538 	    EVCH_CREAT|EVCH_HOLD_PEND) != 0) {
    539 		atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
    540 		return;
    541 	}
    542 
    543 	if (sysevent_evc_publish(error_chan, EC_FM, ESC_FM_ERROR,
    544 	    SUNW_VENDOR, FM_PUB, ereport, evc_flag) != 0) {
    545 		atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
    546 		(void) sysevent_evc_unbind(error_chan);
    547 		return;
    548 	}
    549 	(void) sysevent_evc_unbind(error_chan);
    550 #else
    551 	(void) ddi_log_sysevent(NULL, SUNW_VENDOR, EC_DEV_STATUS,
    552 	    ESC_DEV_DLE, ereport, &eid, DDI_SLEEP);
    553 #endif
    554 }
    555 
    556 /*
    557  * Wrapppers for FM nvlist allocators
    558  */
    559 /* ARGSUSED */
    560 static void *
    561 i_fm_alloc(nv_alloc_t *nva, size_t size)
    562 {
    563 	return (kmem_zalloc(size, KM_SLEEP));
    564 }
    565 
    566 /* ARGSUSED */
    567 static void
    568 i_fm_free(nv_alloc_t *nva, void *buf, size_t size)
    569 {
    570 	kmem_free(buf, size);
    571 }
    572 
    573 const nv_alloc_ops_t fm_mem_alloc_ops = {
    574 	NULL,
    575 	NULL,
    576 	i_fm_alloc,
    577 	i_fm_free,
    578 	NULL
    579 };
    580 
    581 /*
    582  * Create and initialize a new nv_alloc_t for a fixed buffer, buf.  A pointer
    583  * to the newly allocated nv_alloc_t structure is returned upon success or NULL
    584  * is returned to indicate that the nv_alloc structure could not be created.
    585  */
    586 nv_alloc_t *
    587 fm_nva_xcreate(char *buf, size_t bufsz)
    588 {
    589 	nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
    590 
    591 	if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) {
    592 		kmem_free(nvhdl, sizeof (nv_alloc_t));
    593 		return (NULL);
    594 	}
    595 
    596 	return (nvhdl);
    597 }
    598 
    599 /*
    600  * Destroy a previously allocated nv_alloc structure.  The fixed buffer
    601  * associated with nva must be freed by the caller.
    602  */
    603 void
    604 fm_nva_xdestroy(nv_alloc_t *nva)
    605 {
    606 	nv_alloc_fini(nva);
    607 	kmem_free(nva, sizeof (nv_alloc_t));
    608 }
    609 
    610 /*
    611  * Create a new nv list.  A pointer to a new nv list structure is returned
    612  * upon success or NULL is returned to indicate that the structure could
    613  * not be created.  The newly created nv list is created and managed by the
    614  * operations installed in nva.   If nva is NULL, the default FMA nva
    615  * operations are installed and used.
    616  *
    617  * When called from the kernel and nva == NULL, this function must be called
    618  * from passive kernel context with no locks held that can prevent a
    619  * sleeping memory allocation from occurring.  Otherwise, this function may
    620  * be called from other kernel contexts as long a valid nva created via
    621  * fm_nva_create() is supplied.
    622  */
    623 nvlist_t *
    624 fm_nvlist_create(nv_alloc_t *nva)
    625 {
    626 	int hdl_alloced = 0;
    627 	nvlist_t *nvl;
    628 	nv_alloc_t *nvhdl;
    629 
    630 	if (nva == NULL) {
    631 		nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP);
    632 
    633 		if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) {
    634 			kmem_free(nvhdl, sizeof (nv_alloc_t));
    635 			return (NULL);
    636 		}
    637 		hdl_alloced = 1;
    638 	} else {
    639 		nvhdl = nva;
    640 	}
    641 
    642 	if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) {
    643 		if (hdl_alloced) {
    644 			nv_alloc_fini(nvhdl);
    645 			kmem_free(nvhdl, sizeof (nv_alloc_t));
    646 		}
    647 		return (NULL);
    648 	}
    649 
    650 	return (nvl);
    651 }
    652 
    653 /*
    654  * Destroy a previously allocated nvlist structure.  flag indicates whether
    655  * or not the associated nva structure should be freed (FM_NVA_FREE) or
    656  * retained (FM_NVA_RETAIN).  Retaining the nv alloc structure allows
    657  * it to be re-used for future nvlist creation operations.
    658  */
    659 void
    660 fm_nvlist_destroy(nvlist_t *nvl, int flag)
    661 {
    662 	nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl);
    663 
    664 	nvlist_free(nvl);
    665 
    666 	if (nva != NULL) {
    667 		if (flag == FM_NVA_FREE)
    668 			fm_nva_xdestroy(nva);
    669 	}
    670 }
    671 
    672 int
    673 i_fm_payload_set(nvlist_t *payload, const char *name, va_list ap)
    674 {
    675 	int nelem, ret = 0;
    676 	data_type_t type;
    677 
    678 	while (ret == 0 && name != NULL) {
    679 		type = va_arg(ap, data_type_t);
    680 		switch (type) {
    681 		case DATA_TYPE_BYTE:
    682 			ret = nvlist_add_byte(payload, name,
    683 			    va_arg(ap, uint_t));
    684 			break;
    685 		case DATA_TYPE_BYTE_ARRAY:
    686 			nelem = va_arg(ap, int);
    687 			ret = nvlist_add_byte_array(payload, name,
    688 			    va_arg(ap, uchar_t *), nelem);
    689 			break;
    690 		case DATA_TYPE_BOOLEAN_VALUE:
    691 			ret = nvlist_add_boolean_value(payload, name,
    692 			    va_arg(ap, boolean_t));
    693 			break;
    694 		case DATA_TYPE_BOOLEAN_ARRAY:
    695 			nelem = va_arg(ap, int);
    696 			ret = nvlist_add_boolean_array(payload, name,
    697 			    va_arg(ap, boolean_t *), nelem);
    698 			break;
    699 		case DATA_TYPE_INT8:
    700 			ret = nvlist_add_int8(payload, name,
    701 			    va_arg(ap, int));
    702 			break;
    703 		case DATA_TYPE_INT8_ARRAY:
    704 			nelem = va_arg(ap, int);
    705 			ret = nvlist_add_int8_array(payload, name,
    706 			    va_arg(ap, int8_t *), nelem);
    707 			break;
    708 		case DATA_TYPE_UINT8:
    709 			ret = nvlist_add_uint8(payload, name,
    710 			    va_arg(ap, uint_t));
    711 			break;
    712 		case DATA_TYPE_UINT8_ARRAY:
    713 			nelem = va_arg(ap, int);
    714 			ret = nvlist_add_uint8_array(payload, name,
    715 			    va_arg(ap, uint8_t *), nelem);
    716 			break;
    717 		case DATA_TYPE_INT16:
    718 			ret = nvlist_add_int16(payload, name,
    719 			    va_arg(ap, int));
    720 			break;
    721 		case DATA_TYPE_INT16_ARRAY:
    722 			nelem = va_arg(ap, int);
    723 			ret = nvlist_add_int16_array(payload, name,
    724 			    va_arg(ap, int16_t *), nelem);
    725 			break;
    726 		case DATA_TYPE_UINT16:
    727 			ret = nvlist_add_uint16(payload, name,
    728 			    va_arg(ap, uint_t));
    729 			break;
    730 		case DATA_TYPE_UINT16_ARRAY:
    731 			nelem = va_arg(ap, int);
    732 			ret = nvlist_add_uint16_array(payload, name,
    733 			    va_arg(ap, uint16_t *), nelem);
    734 			break;
    735 		case DATA_TYPE_INT32:
    736 			ret = nvlist_add_int32(payload, name,
    737 			    va_arg(ap, int32_t));
    738 			break;
    739 		case DATA_TYPE_INT32_ARRAY:
    740 			nelem = va_arg(ap, int);
    741 			ret = nvlist_add_int32_array(payload, name,
    742 			    va_arg(ap, int32_t *), nelem);
    743 			break;
    744 		case DATA_TYPE_UINT32:
    745 			ret = nvlist_add_uint32(payload, name,
    746 			    va_arg(ap, uint32_t));
    747 			break;
    748 		case DATA_TYPE_UINT32_ARRAY:
    749 			nelem = va_arg(ap, int);
    750 			ret = nvlist_add_uint32_array(payload, name,
    751 			    va_arg(ap, uint32_t *), nelem);
    752 			break;
    753 		case DATA_TYPE_INT64:
    754 			ret = nvlist_add_int64(payload, name,
    755 			    va_arg(ap, int64_t));
    756 			break;
    757 		case DATA_TYPE_INT64_ARRAY:
    758 			nelem = va_arg(ap, int);
    759 			ret = nvlist_add_int64_array(payload, name,
    760 			    va_arg(ap, int64_t *), nelem);
    761 			break;
    762 		case DATA_TYPE_UINT64:
    763 			ret = nvlist_add_uint64(payload, name,
    764 			    va_arg(ap, uint64_t));
    765 			break;
    766 		case DATA_TYPE_UINT64_ARRAY:
    767 			nelem = va_arg(ap, int);
    768 			ret = nvlist_add_uint64_array(payload, name,
    769 			    va_arg(ap, uint64_t *), nelem);
    770 			break;
    771 		case DATA_TYPE_STRING:
    772 			ret = nvlist_add_string(payload, name,
    773 			    va_arg(ap, char *));
    774 			break;
    775 		case DATA_TYPE_STRING_ARRAY:
    776 			nelem = va_arg(ap, int);
    777 			ret = nvlist_add_string_array(payload, name,
    778 			    va_arg(ap, char **), nelem);
    779 			break;
    780 		case DATA_TYPE_NVLIST:
    781 			ret = nvlist_add_nvlist(payload, name,
    782 			    va_arg(ap, nvlist_t *));
    783 			break;
    784 		case DATA_TYPE_NVLIST_ARRAY:
    785 			nelem = va_arg(ap, int);
    786 			ret = nvlist_add_nvlist_array(payload, name,
    787 			    va_arg(ap, nvlist_t **), nelem);
    788 			break;
    789 		default:
    790 			ret = EINVAL;
    791 		}
    792 
    793 		name = va_arg(ap, char *);
    794 	}
    795 	return (ret);
    796 }
    797 
    798 void
    799 fm_payload_set(nvlist_t *payload, ...)
    800 {
    801 	int ret;
    802 	const char *name;
    803 	va_list ap;
    804 
    805 	va_start(ap, payload);
    806 	name = va_arg(ap, char *);
    807 	ret = i_fm_payload_set(payload, name, ap);
    808 	va_end(ap);
    809 
    810 	if (ret)
    811 		atomic_inc_64(&erpt_kstat_data.payload_set_failed.value.ui64);
    812 }
    813 
    814 /*
    815  * Set-up and validate the members of an ereport event according to:
    816  *
    817  *	Member name		Type		Value
    818  *	====================================================
    819  *	class			string		ereport
    820  *	version			uint8_t		0
    821  *	ena			uint64_t	<ena>
    822  *	detector		nvlist_t	<detector>
    823  *	ereport-payload		nvlist_t	<var args>
    824  *
    825  * We don't actually add a 'version' member to the payload.  Really,
    826  * the version quoted to us by our caller is that of the category 1
    827  * "ereport" event class (and we require FM_EREPORT_VERS0) but
    828  * the payload version of the actual leaf class event under construction
    829  * may be something else.  Callers should supply a version in the varargs,
    830  * or (better) we could take two version arguments - one for the
    831  * ereport category 1 classification (expect FM_EREPORT_VERS0) and one
    832  * for the leaf class.
    833  */
    834 void
    835 fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
    836     uint64_t ena, const nvlist_t *detector, ...)
    837 {
    838 	char ereport_class[FM_MAX_CLASS];
    839 	const char *name;
    840 	va_list ap;
    841 	int ret;
    842 
    843 	if (version != FM_EREPORT_VERS0) {
    844 		atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
    845 		return;
    846 	}
    847 
    848 	(void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s",
    849 	    FM_EREPORT_CLASS, erpt_class);
    850 	if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) {
    851 		atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
    852 		return;
    853 	}
    854 
    855 	if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) {
    856 		atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
    857 	}
    858 
    859 	if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR,
    860 	    (nvlist_t *)detector) != 0) {
    861 		atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
    862 	}
    863 
    864 	va_start(ap, detector);
    865 	name = va_arg(ap, const char *);
    866 	ret = i_fm_payload_set(ereport, name, ap);
    867 	va_end(ap);
    868 
    869 	if (ret)
    870 		atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
    871 }
    872 
    873 /*
    874  * Set-up and validate the members of an hc fmri according to;
    875  *
    876  *	Member name		Type		Value
    877  *	===================================================
    878  *	version			uint8_t		0
    879  *	auth			nvlist_t	<auth>
    880  *	hc-name			string		<name>
    881  *	hc-id			string		<id>
    882  *
    883  * Note that auth and hc-id are optional members.
    884  */
    885 
    886 #define	HC_MAXPAIRS	20
    887 #define	HC_MAXNAMELEN	50
    888 
    889 static int
    890 fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth)
    891 {
    892 	if (version != FM_HC_SCHEME_VERSION) {
    893 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    894 		return (0);
    895 	}
    896 
    897 	if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 ||
    898 	    nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) {
    899 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    900 		return (0);
    901 	}
    902 
    903 	if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
    904 	    (nvlist_t *)auth) != 0) {
    905 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    906 		return (0);
    907 	}
    908 
    909 	return (1);
    910 }
    911 
    912 void
    913 fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
    914     nvlist_t *snvl, int npairs, ...)
    915 {
    916 	nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
    917 	nvlist_t *pairs[HC_MAXPAIRS];
    918 	va_list ap;
    919 	int i;
    920 
    921 	if (!fm_fmri_hc_set_common(fmri, version, auth))
    922 		return;
    923 
    924 	npairs = MIN(npairs, HC_MAXPAIRS);
    925 
    926 	va_start(ap, npairs);
    927 	for (i = 0; i < npairs; i++) {
    928 		const char *name = va_arg(ap, const char *);
    929 		uint32_t id = va_arg(ap, uint32_t);
    930 		char idstr[11];
    931 
    932 		(void) snprintf(idstr, sizeof (idstr), "%u", id);
    933 
    934 		pairs[i] = fm_nvlist_create(nva);
    935 		if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
    936 		    nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
    937 			atomic_inc_64(
    938 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
    939 		}
    940 	}
    941 	va_end(ap);
    942 
    943 	if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0)
    944 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    945 
    946 	for (i = 0; i < npairs; i++)
    947 		fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
    948 
    949 	if (snvl != NULL) {
    950 		if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
    951 			atomic_inc_64(
    952 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
    953 		}
    954 	}
    955 }
    956 
    957 /*
    958  * Set-up and validate the members of an dev fmri according to:
    959  *
    960  *	Member name		Type		Value
    961  *	====================================================
    962  *	version			uint8_t		0
    963  *	auth			nvlist_t	<auth>
    964  *	devpath			string		<devpath>
    965  *	[devid]			string		<devid>
    966  *	[target-port-l0id]	string		<target-port-lun0-id>
    967  *
    968  * Note that auth and devid are optional members.
    969  */
    970 void
    971 fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
    972     const char *devpath, const char *devid, const char *tpl0)
    973 {
    974 	int err = 0;
    975 
    976 	if (version != DEV_SCHEME_VERSION0) {
    977 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    978 		return;
    979 	}
    980 
    981 	err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version);
    982 	err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV);
    983 
    984 	if (auth != NULL) {
    985 		err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY,
    986 		    (nvlist_t *)auth);
    987 	}
    988 
    989 	err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath);
    990 
    991 	if (devid != NULL)
    992 		err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid);
    993 
    994 	if (tpl0 != NULL)
    995 		err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0);
    996 
    997 	if (err)
    998 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
    999 
   1000 }
   1001 
   1002 /*
   1003  * Set-up and validate the members of an cpu fmri according to:
   1004  *
   1005  *	Member name		Type		Value
   1006  *	====================================================
   1007  *	version			uint8_t		0
   1008  *	auth			nvlist_t	<auth>
   1009  *	cpuid			uint32_t	<cpu_id>
   1010  *	cpumask			uint8_t		<cpu_mask>
   1011  *	serial			uint64_t	<serial_id>
   1012  *
   1013  * Note that auth, cpumask, serial are optional members.
   1014  *
   1015  */
   1016 void
   1017 fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
   1018     uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp)
   1019 {
   1020 	uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
   1021 
   1022 	if (version < CPU_SCHEME_VERSION1) {
   1023 		atomic_inc_64(failedp);
   1024 		return;
   1025 	}
   1026 
   1027 	if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
   1028 		atomic_inc_64(failedp);
   1029 		return;
   1030 	}
   1031 
   1032 	if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
   1033 	    FM_FMRI_SCHEME_CPU) != 0) {
   1034 		atomic_inc_64(failedp);
   1035 		return;
   1036 	}
   1037 
   1038 	if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
   1039 	    (nvlist_t *)auth) != 0)
   1040 		atomic_inc_64(failedp);
   1041 
   1042 	if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
   1043 		atomic_inc_64(failedp);
   1044 
   1045 	if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
   1046 	    *cpu_maskp) != 0)
   1047 		atomic_inc_64(failedp);
   1048 
   1049 	if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
   1050 	    FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
   1051 			atomic_inc_64(failedp);
   1052 }
   1053 
   1054 /*
   1055  * Set-up and validate the members of a mem according to:
   1056  *
   1057  *	Member name		Type		Value
   1058  *	====================================================
   1059  *	version			uint8_t		0
   1060  *	auth			nvlist_t	<auth>		[optional]
   1061  *	unum			string		<unum>
   1062  *	serial			string		<serial>	[optional*]
   1063  *	offset			uint64_t	<offset>	[optional]
   1064  *
   1065  *	* serial is required if offset is present
   1066  */
   1067 void
   1068 fm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth,
   1069     const char *unum, const char *serial, uint64_t offset)
   1070 {
   1071 	if (version != MEM_SCHEME_VERSION0) {
   1072 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1073 		return;
   1074 	}
   1075 
   1076 	if (!serial && (offset != (uint64_t)-1)) {
   1077 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1078 		return;
   1079 	}
   1080 
   1081 	if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
   1082 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1083 		return;
   1084 	}
   1085 
   1086 	if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) {
   1087 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1088 		return;
   1089 	}
   1090 
   1091 	if (auth != NULL) {
   1092 		if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
   1093 		    (nvlist_t *)auth) != 0) {
   1094 			atomic_inc_64(
   1095 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1096 		}
   1097 	}
   1098 
   1099 	if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) {
   1100 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1101 	}
   1102 
   1103 	if (serial != NULL) {
   1104 		if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
   1105 		    (char **)&serial, 1) != 0) {
   1106 			atomic_inc_64(
   1107 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1108 		}
   1109 		if (offset != (uint64_t)-1 && nvlist_add_uint64(fmri,
   1110 		    FM_FMRI_MEM_OFFSET, offset) != 0) {
   1111 			atomic_inc_64(
   1112 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1113 		}
   1114 	}
   1115 }
   1116 
   1117 void
   1118 fm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid,
   1119     uint64_t vdev_guid)
   1120 {
   1121 	if (version != ZFS_SCHEME_VERSION0) {
   1122 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1123 		return;
   1124 	}
   1125 
   1126 	if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
   1127 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1128 		return;
   1129 	}
   1130 
   1131 	if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) {
   1132 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1133 		return;
   1134 	}
   1135 
   1136 	if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) {
   1137 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1138 	}
   1139 
   1140 	if (vdev_guid != 0) {
   1141 		if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) {
   1142 			atomic_inc_64(
   1143 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1144 		}
   1145 	}
   1146 }
   1147 
   1148 uint64_t
   1149 fm_ena_increment(uint64_t ena)
   1150 {
   1151 	uint64_t new_ena;
   1152 
   1153 	switch (ENA_FORMAT(ena)) {
   1154 	case FM_ENA_FMT1:
   1155 		new_ena = ena + (1 << ENA_FMT1_GEN_SHFT);
   1156 		break;
   1157 	case FM_ENA_FMT2:
   1158 		new_ena = ena + (1 << ENA_FMT2_GEN_SHFT);
   1159 		break;
   1160 	default:
   1161 		new_ena = 0;
   1162 	}
   1163 
   1164 	return (new_ena);
   1165 }
   1166 
   1167 uint64_t
   1168 fm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format)
   1169 {
   1170 	uint64_t ena = 0;
   1171 
   1172 	switch (format) {
   1173 	case FM_ENA_FMT1:
   1174 		if (timestamp) {
   1175 			ena = (uint64_t)((format & ENA_FORMAT_MASK) |
   1176 			    ((cpuid << ENA_FMT1_CPUID_SHFT) &
   1177 			    ENA_FMT1_CPUID_MASK) |
   1178 			    ((timestamp << ENA_FMT1_TIME_SHFT) &
   1179 			    ENA_FMT1_TIME_MASK));
   1180 		} else {
   1181 			ena = (uint64_t)((format & ENA_FORMAT_MASK) |
   1182 			    ((cpuid << ENA_FMT1_CPUID_SHFT) &
   1183 			    ENA_FMT1_CPUID_MASK) |
   1184 			    ((gethrtime_waitfree() << ENA_FMT1_TIME_SHFT) &
   1185 			    ENA_FMT1_TIME_MASK));
   1186 		}
   1187 		break;
   1188 	case FM_ENA_FMT2:
   1189 		ena = (uint64_t)((format & ENA_FORMAT_MASK) |
   1190 		    ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK));
   1191 		break;
   1192 	default:
   1193 		break;
   1194 	}
   1195 
   1196 	return (ena);
   1197 }
   1198 
   1199 uint64_t
   1200 fm_ena_generate(uint64_t timestamp, uchar_t format)
   1201 {
   1202 #ifdef __NetBSD__
   1203 	return (fm_ena_generate_cpu(timestamp, cpu_index(curcpu()), format));
   1204 #else
   1205 	return (fm_ena_generate_cpu(timestamp, PCPU_GET(cpuid), format));
   1206 #endif
   1207 }
   1208 
   1209 uint64_t
   1210 fm_ena_generation_get(uint64_t ena)
   1211 {
   1212 	uint64_t gen;
   1213 
   1214 	switch (ENA_FORMAT(ena)) {
   1215 	case FM_ENA_FMT1:
   1216 		gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT;
   1217 		break;
   1218 	case FM_ENA_FMT2:
   1219 		gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT;
   1220 		break;
   1221 	default:
   1222 		gen = 0;
   1223 		break;
   1224 	}
   1225 
   1226 	return (gen);
   1227 }
   1228 
   1229 uchar_t
   1230 fm_ena_format_get(uint64_t ena)
   1231 {
   1232 
   1233 	return (ENA_FORMAT(ena));
   1234 }
   1235 
   1236 uint64_t
   1237 fm_ena_id_get(uint64_t ena)
   1238 {
   1239 	uint64_t id;
   1240 
   1241 	switch (ENA_FORMAT(ena)) {
   1242 	case FM_ENA_FMT1:
   1243 		id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT;
   1244 		break;
   1245 	case FM_ENA_FMT2:
   1246 		id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT;
   1247 		break;
   1248 	default:
   1249 		id = 0;
   1250 	}
   1251 
   1252 	return (id);
   1253 }
   1254 
   1255 uint64_t
   1256 fm_ena_time_get(uint64_t ena)
   1257 {
   1258 	uint64_t time;
   1259 
   1260 	switch (ENA_FORMAT(ena)) {
   1261 	case FM_ENA_FMT1:
   1262 		time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT;
   1263 		break;
   1264 	case FM_ENA_FMT2:
   1265 		time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT;
   1266 		break;
   1267 	default:
   1268 		time = 0;
   1269 	}
   1270 
   1271 	return (time);
   1272 }
   1273 
   1274 #ifdef illumos
   1275 /*
   1276  * Convert a getpcstack() trace to symbolic name+offset, and add the resulting
   1277  * string array to a Fault Management ereport as FM_EREPORT_PAYLOAD_NAME_STACK.
   1278  */
   1279 void
   1280 fm_payload_stack_add(nvlist_t *payload, const pc_t *stack, int depth)
   1281 {
   1282 	int i;
   1283 	char *sym;
   1284 	ulong_t off;
   1285 	char *stkpp[FM_STK_DEPTH];
   1286 	char buf[FM_STK_DEPTH * FM_SYM_SZ];
   1287 	char *stkp = buf;
   1288 
   1289 	for (i = 0; i < depth && i != FM_STK_DEPTH; i++, stkp += FM_SYM_SZ) {
   1290 		if ((sym = kobj_getsymname(stack[i], &off)) != NULL)
   1291 			(void) snprintf(stkp, FM_SYM_SZ, "%s+%lx", sym, off);
   1292 		else
   1293 			(void) snprintf(stkp, FM_SYM_SZ, "%lx", (long)stack[i]);
   1294 		stkpp[i] = stkp;
   1295 	}
   1296 
   1297 	fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_STACK,
   1298 	    DATA_TYPE_STRING_ARRAY, depth, stkpp, NULL);
   1299 }
   1300 #endif
   1301 
   1302 #ifdef illumos
   1303 void
   1304 print_msg_hwerr(ctid_t ct_id, proc_t *p)
   1305 {
   1306 	uprintf("Killed process %d (%s) in contract id %d "
   1307 	    "due to hardware error\n", p->p_pid, p->p_user.u_comm, ct_id);
   1308 }
   1309 #endif
   1310 
   1311 void
   1312 fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
   1313     nvlist_t *snvl, nvlist_t *bboard, int npairs, ...)
   1314 {
   1315 	nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri);
   1316 	nvlist_t *pairs[HC_MAXPAIRS];
   1317 	nvlist_t **hcl;
   1318 	uint_t n;
   1319 	int i, j;
   1320 	va_list ap;
   1321 	char *hcname, *hcid;
   1322 
   1323 	if (!fm_fmri_hc_set_common(fmri, version, auth))
   1324 		return;
   1325 
   1326 	/*
   1327 	 * copy the bboard nvpairs to the pairs array
   1328 	 */
   1329 	if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n)
   1330 	    != 0) {
   1331 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1332 		return;
   1333 	}
   1334 
   1335 	for (i = 0; i < n; i++) {
   1336 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
   1337 		    &hcname) != 0) {
   1338 			atomic_inc_64(
   1339 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1340 			return;
   1341 		}
   1342 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) {
   1343 			atomic_inc_64(
   1344 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1345 			return;
   1346 		}
   1347 
   1348 		pairs[i] = fm_nvlist_create(nva);
   1349 		if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 ||
   1350 		    nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) {
   1351 			for (j = 0; j <= i; j++) {
   1352 				if (pairs[j] != NULL)
   1353 					fm_nvlist_destroy(pairs[j],
   1354 					    FM_NVA_RETAIN);
   1355 			}
   1356 			atomic_inc_64(
   1357 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1358 			return;
   1359 		}
   1360 	}
   1361 
   1362 	/*
   1363 	 * create the pairs from passed in pairs
   1364 	 */
   1365 	npairs = MIN(npairs, HC_MAXPAIRS);
   1366 
   1367 	va_start(ap, npairs);
   1368 	for (i = n; i < npairs + n; i++) {
   1369 		const char *name = va_arg(ap, const char *);
   1370 		uint32_t id = va_arg(ap, uint32_t);
   1371 		char idstr[11];
   1372 		(void) snprintf(idstr, sizeof (idstr), "%u", id);
   1373 		pairs[i] = fm_nvlist_create(nva);
   1374 		if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
   1375 		    nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
   1376 			for (j = 0; j <= i; j++) {
   1377 				if (pairs[j] != NULL)
   1378 					fm_nvlist_destroy(pairs[j],
   1379 					    FM_NVA_RETAIN);
   1380 			}
   1381 			atomic_inc_64(
   1382 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1383 			return;
   1384 		}
   1385 	}
   1386 	va_end(ap);
   1387 
   1388 	/*
   1389 	 * Create the fmri hc list
   1390 	 */
   1391 	if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs,
   1392 	    npairs + n) != 0) {
   1393 		atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
   1394 		return;
   1395 	}
   1396 
   1397 	for (i = 0; i < npairs + n; i++) {
   1398 			fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
   1399 	}
   1400 
   1401 	if (snvl != NULL) {
   1402 		if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
   1403 			atomic_inc_64(
   1404 			    &erpt_kstat_data.fmri_set_failed.value.ui64);
   1405 			return;
   1406 		}
   1407 	}
   1408 }
   1409