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