fm.c revision 219089
1219089Spjd/* 2219089Spjd * CDDL HEADER START 3219089Spjd * 4219089Spjd * The contents of this file are subject to the terms of the 5219089Spjd * Common Development and Distribution License (the "License"). 6219089Spjd * You may not use this file except in compliance with the License. 7219089Spjd * 8219089Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9219089Spjd * or http://www.opensolaris.org/os/licensing. 10219089Spjd * See the License for the specific language governing permissions 11219089Spjd * and limitations under the License. 12219089Spjd * 13219089Spjd * When distributing Covered Code, include this CDDL HEADER in each 14219089Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15219089Spjd * If applicable, add the following below this CDDL HEADER, with the 16219089Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17219089Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18219089Spjd * 19219089Spjd * CDDL HEADER END 20219089Spjd */ 21219089Spjd/* 22219089Spjd * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 23219089Spjd */ 24219089Spjd 25219089Spjd/* 26219089Spjd * Fault Management Architecture (FMA) Resource and Protocol Support 27219089Spjd * 28219089Spjd * The routines contained herein provide services to support kernel subsystems 29219089Spjd * in publishing fault management telemetry (see PSARC 2002/412 and 2003/089). 30219089Spjd * 31219089Spjd * Name-Value Pair Lists 32219089Spjd * 33219089Spjd * The embodiment of an FMA protocol element (event, fmri or authority) is a 34219089Spjd * name-value pair list (nvlist_t). FMA-specific nvlist construtor and 35219089Spjd * destructor functions, fm_nvlist_create() and fm_nvlist_destroy(), are used 36219089Spjd * to create an nvpair list using custom allocators. Callers may choose to 37219089Spjd * allocate either from the kernel memory allocator, or from a preallocated 38219089Spjd * buffer, useful in constrained contexts like high-level interrupt routines. 39219089Spjd * 40219089Spjd * Protocol Event and FMRI Construction 41219089Spjd * 42219089Spjd * Convenience routines are provided to construct nvlist events according to 43219089Spjd * the FMA Event Protocol and Naming Schema specification for ereports and 44219089Spjd * FMRIs for the dev, cpu, hc, mem, legacy hc and de schemes. 45219089Spjd * 46219089Spjd * ENA Manipulation 47219089Spjd * 48219089Spjd * Routines to generate ENA formats 0, 1 and 2 are available as well as 49219089Spjd * routines to increment formats 1 and 2. Individual fields within the 50219089Spjd * ENA are extractable via fm_ena_time_get(), fm_ena_id_get(), 51219089Spjd * fm_ena_format_get() and fm_ena_gen_get(). 52219089Spjd */ 53219089Spjd 54219089Spjd#include <sys/types.h> 55219089Spjd#include <sys/time.h> 56219089Spjd#include <sys/sysevent.h> 57219089Spjd#include <sys/nvpair.h> 58219089Spjd#include <sys/cmn_err.h> 59219089Spjd#include <sys/cpuvar.h> 60219089Spjd#include <sys/sysmacros.h> 61219089Spjd#include <sys/systm.h> 62219089Spjd#include <sys/compress.h> 63219089Spjd#include <sys/cpuvar.h> 64219089Spjd#include <sys/kobj.h> 65219089Spjd#include <sys/kstat.h> 66219089Spjd#include <sys/processor.h> 67219089Spjd#include <sys/pcpu.h> 68219089Spjd#include <sys/sunddi.h> 69219089Spjd#include <sys/systeminfo.h> 70219089Spjd#include <sys/sysevent/eventdefs.h> 71219089Spjd#include <sys/fm/util.h> 72219089Spjd#include <sys/fm/protocol.h> 73219089Spjd 74219089Spjd/* 75219089Spjd * URL and SUNW-MSG-ID value to display for fm_panic(), defined below. These 76219089Spjd * values must be kept in sync with the FMA source code in usr/src/cmd/fm. 77219089Spjd */ 78219089Spjdstatic const char *fm_url = "http://www.sun.com/msg"; 79219089Spjdstatic const char *fm_msgid = "SUNOS-8000-0G"; 80219089Spjdstatic char *volatile fm_panicstr = NULL; 81219089Spjd 82219089Spjd#ifdef sun 83219089Spjderrorq_t *ereport_errorq; 84219089Spjd#endif 85219089Spjdvoid *ereport_dumpbuf; 86219089Spjdsize_t ereport_dumplen; 87219089Spjd 88219089Spjdstatic uint_t ereport_chanlen = ERPT_EVCH_MAX; 89219089Spjdstatic evchan_t *ereport_chan = NULL; 90219089Spjdstatic ulong_t ereport_qlen = 0; 91219089Spjdstatic size_t ereport_size = 0; 92219089Spjdstatic int ereport_cols = 80; 93219089Spjd 94219089Spjdextern void fastreboot_disable_highpil(void); 95219089Spjd 96219089Spjd/* 97219089Spjd * Common fault management kstats to record ereport generation 98219089Spjd * failures 99219089Spjd */ 100219089Spjd 101219089Spjdstruct erpt_kstat { 102219089Spjd kstat_named_t erpt_dropped; /* num erpts dropped on post */ 103219089Spjd kstat_named_t erpt_set_failed; /* num erpt set failures */ 104219089Spjd kstat_named_t fmri_set_failed; /* num fmri set failures */ 105219089Spjd kstat_named_t payload_set_failed; /* num payload set failures */ 106219089Spjd}; 107219089Spjd 108219089Spjdstatic struct erpt_kstat erpt_kstat_data = { 109219089Spjd { "erpt-dropped", KSTAT_DATA_UINT64 }, 110219089Spjd { "erpt-set-failed", KSTAT_DATA_UINT64 }, 111219089Spjd { "fmri-set-failed", KSTAT_DATA_UINT64 }, 112219089Spjd { "payload-set-failed", KSTAT_DATA_UINT64 } 113219089Spjd}; 114219089Spjd 115219089Spjd#ifdef sun 116219089Spjd/*ARGSUSED*/ 117219089Spjdstatic void 118219089Spjdfm_drain(void *private, void *data, errorq_elem_t *eep) 119219089Spjd{ 120219089Spjd nvlist_t *nvl = errorq_elem_nvl(ereport_errorq, eep); 121219089Spjd 122219089Spjd if (!panicstr) 123219089Spjd (void) fm_ereport_post(nvl, EVCH_TRYHARD); 124219089Spjd else 125219089Spjd fm_nvprint(nvl); 126219089Spjd} 127219089Spjd#endif 128219089Spjd 129219089Spjdvoid 130219089Spjdfm_init(void) 131219089Spjd{ 132219089Spjd kstat_t *ksp; 133219089Spjd 134219089Spjd#ifdef sun 135219089Spjd (void) sysevent_evc_bind(FM_ERROR_CHAN, 136219089Spjd &ereport_chan, EVCH_CREAT | EVCH_HOLD_PEND); 137219089Spjd 138219089Spjd (void) sysevent_evc_control(ereport_chan, 139219089Spjd EVCH_SET_CHAN_LEN, &ereport_chanlen); 140219089Spjd#endif 141219089Spjd 142219089Spjd if (ereport_qlen == 0) 143219089Spjd ereport_qlen = ERPT_MAX_ERRS * MAX(max_ncpus, 4); 144219089Spjd 145219089Spjd if (ereport_size == 0) 146219089Spjd ereport_size = ERPT_DATA_SZ; 147219089Spjd 148219089Spjd#ifdef sun 149219089Spjd ereport_errorq = errorq_nvcreate("fm_ereport_queue", 150219089Spjd (errorq_func_t)fm_drain, NULL, ereport_qlen, ereport_size, 151219089Spjd FM_ERR_PIL, ERRORQ_VITAL); 152219089Spjd if (ereport_errorq == NULL) 153219089Spjd panic("failed to create required ereport error queue"); 154219089Spjd#endif 155219089Spjd 156219089Spjd ereport_dumpbuf = kmem_alloc(ereport_size, KM_SLEEP); 157219089Spjd ereport_dumplen = ereport_size; 158219089Spjd 159219089Spjd /* Initialize ereport allocation and generation kstats */ 160219089Spjd ksp = kstat_create("unix", 0, "fm", "misc", KSTAT_TYPE_NAMED, 161219089Spjd sizeof (struct erpt_kstat) / sizeof (kstat_named_t), 162219089Spjd KSTAT_FLAG_VIRTUAL); 163219089Spjd 164219089Spjd if (ksp != NULL) { 165219089Spjd ksp->ks_data = &erpt_kstat_data; 166219089Spjd kstat_install(ksp); 167219089Spjd } else { 168219089Spjd cmn_err(CE_NOTE, "failed to create fm/misc kstat\n"); 169219089Spjd 170219089Spjd } 171219089Spjd} 172219089Spjd 173219089Spjd#ifdef sun 174219089Spjd/* 175219089Spjd * Formatting utility function for fm_nvprintr. We attempt to wrap chunks of 176219089Spjd * output so they aren't split across console lines, and return the end column. 177219089Spjd */ 178219089Spjd/*PRINTFLIKE4*/ 179219089Spjdstatic int 180219089Spjdfm_printf(int depth, int c, int cols, const char *format, ...) 181219089Spjd{ 182219089Spjd va_list ap; 183219089Spjd int width; 184219089Spjd char c1; 185219089Spjd 186219089Spjd va_start(ap, format); 187219089Spjd width = vsnprintf(&c1, sizeof (c1), format, ap); 188219089Spjd va_end(ap); 189219089Spjd 190219089Spjd if (c + width >= cols) { 191219089Spjd console_printf("\n\r"); 192219089Spjd c = 0; 193219089Spjd if (format[0] != ' ' && depth > 0) { 194219089Spjd console_printf(" "); 195219089Spjd c++; 196219089Spjd } 197219089Spjd } 198219089Spjd 199219089Spjd va_start(ap, format); 200219089Spjd console_vprintf(format, ap); 201219089Spjd va_end(ap); 202219089Spjd 203219089Spjd return ((c + width) % cols); 204219089Spjd} 205219089Spjd 206219089Spjd/* 207219089Spjd * Recursively print a nvlist in the specified column width and return the 208219089Spjd * column we end up in. This function is called recursively by fm_nvprint(), 209219089Spjd * below. We generically format the entire nvpair using hexadecimal 210219089Spjd * integers and strings, and elide any integer arrays. Arrays are basically 211219089Spjd * used for cache dumps right now, so we suppress them so as not to overwhelm 212219089Spjd * the amount of console output we produce at panic time. This can be further 213219089Spjd * enhanced as FMA technology grows based upon the needs of consumers. All 214219089Spjd * FMA telemetry is logged using the dump device transport, so the console 215219089Spjd * output serves only as a fallback in case this procedure is unsuccessful. 216219089Spjd */ 217219089Spjdstatic int 218219089Spjdfm_nvprintr(nvlist_t *nvl, int d, int c, int cols) 219219089Spjd{ 220219089Spjd nvpair_t *nvp; 221219089Spjd 222219089Spjd for (nvp = nvlist_next_nvpair(nvl, NULL); 223219089Spjd nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) { 224219089Spjd 225219089Spjd data_type_t type = nvpair_type(nvp); 226219089Spjd const char *name = nvpair_name(nvp); 227219089Spjd 228219089Spjd boolean_t b; 229219089Spjd uint8_t i8; 230219089Spjd uint16_t i16; 231219089Spjd uint32_t i32; 232219089Spjd uint64_t i64; 233219089Spjd char *str; 234219089Spjd nvlist_t *cnv; 235219089Spjd 236219089Spjd if (strcmp(name, FM_CLASS) == 0) 237219089Spjd continue; /* already printed by caller */ 238219089Spjd 239219089Spjd c = fm_printf(d, c, cols, " %s=", name); 240219089Spjd 241219089Spjd switch (type) { 242219089Spjd case DATA_TYPE_BOOLEAN: 243219089Spjd c = fm_printf(d + 1, c, cols, " 1"); 244219089Spjd break; 245219089Spjd 246219089Spjd case DATA_TYPE_BOOLEAN_VALUE: 247219089Spjd (void) nvpair_value_boolean_value(nvp, &b); 248219089Spjd c = fm_printf(d + 1, c, cols, b ? "1" : "0"); 249219089Spjd break; 250219089Spjd 251219089Spjd case DATA_TYPE_BYTE: 252219089Spjd (void) nvpair_value_byte(nvp, &i8); 253219089Spjd c = fm_printf(d + 1, c, cols, "%x", i8); 254219089Spjd break; 255219089Spjd 256219089Spjd case DATA_TYPE_INT8: 257219089Spjd (void) nvpair_value_int8(nvp, (void *)&i8); 258219089Spjd c = fm_printf(d + 1, c, cols, "%x", i8); 259219089Spjd break; 260219089Spjd 261219089Spjd case DATA_TYPE_UINT8: 262219089Spjd (void) nvpair_value_uint8(nvp, &i8); 263219089Spjd c = fm_printf(d + 1, c, cols, "%x", i8); 264219089Spjd break; 265219089Spjd 266219089Spjd case DATA_TYPE_INT16: 267219089Spjd (void) nvpair_value_int16(nvp, (void *)&i16); 268219089Spjd c = fm_printf(d + 1, c, cols, "%x", i16); 269219089Spjd break; 270219089Spjd 271219089Spjd case DATA_TYPE_UINT16: 272219089Spjd (void) nvpair_value_uint16(nvp, &i16); 273219089Spjd c = fm_printf(d + 1, c, cols, "%x", i16); 274219089Spjd break; 275219089Spjd 276219089Spjd case DATA_TYPE_INT32: 277219089Spjd (void) nvpair_value_int32(nvp, (void *)&i32); 278219089Spjd c = fm_printf(d + 1, c, cols, "%x", i32); 279219089Spjd break; 280219089Spjd 281219089Spjd case DATA_TYPE_UINT32: 282219089Spjd (void) nvpair_value_uint32(nvp, &i32); 283219089Spjd c = fm_printf(d + 1, c, cols, "%x", i32); 284219089Spjd break; 285219089Spjd 286219089Spjd case DATA_TYPE_INT64: 287219089Spjd (void) nvpair_value_int64(nvp, (void *)&i64); 288219089Spjd c = fm_printf(d + 1, c, cols, "%llx", 289219089Spjd (u_longlong_t)i64); 290219089Spjd break; 291219089Spjd 292219089Spjd case DATA_TYPE_UINT64: 293219089Spjd (void) nvpair_value_uint64(nvp, &i64); 294219089Spjd c = fm_printf(d + 1, c, cols, "%llx", 295219089Spjd (u_longlong_t)i64); 296219089Spjd break; 297219089Spjd 298219089Spjd case DATA_TYPE_HRTIME: 299219089Spjd (void) nvpair_value_hrtime(nvp, (void *)&i64); 300219089Spjd c = fm_printf(d + 1, c, cols, "%llx", 301219089Spjd (u_longlong_t)i64); 302219089Spjd break; 303219089Spjd 304219089Spjd case DATA_TYPE_STRING: 305219089Spjd (void) nvpair_value_string(nvp, &str); 306219089Spjd c = fm_printf(d + 1, c, cols, "\"%s\"", 307219089Spjd str ? str : "<NULL>"); 308219089Spjd break; 309219089Spjd 310219089Spjd case DATA_TYPE_NVLIST: 311219089Spjd c = fm_printf(d + 1, c, cols, "["); 312219089Spjd (void) nvpair_value_nvlist(nvp, &cnv); 313219089Spjd c = fm_nvprintr(cnv, d + 1, c, cols); 314219089Spjd c = fm_printf(d + 1, c, cols, " ]"); 315219089Spjd break; 316219089Spjd 317219089Spjd case DATA_TYPE_NVLIST_ARRAY: { 318219089Spjd nvlist_t **val; 319219089Spjd uint_t i, nelem; 320219089Spjd 321219089Spjd c = fm_printf(d + 1, c, cols, "["); 322219089Spjd (void) nvpair_value_nvlist_array(nvp, &val, &nelem); 323219089Spjd for (i = 0; i < nelem; i++) { 324219089Spjd c = fm_nvprintr(val[i], d + 1, c, cols); 325219089Spjd } 326219089Spjd c = fm_printf(d + 1, c, cols, " ]"); 327219089Spjd } 328219089Spjd break; 329219089Spjd 330219089Spjd case DATA_TYPE_BOOLEAN_ARRAY: 331219089Spjd case DATA_TYPE_BYTE_ARRAY: 332219089Spjd case DATA_TYPE_INT8_ARRAY: 333219089Spjd case DATA_TYPE_UINT8_ARRAY: 334219089Spjd case DATA_TYPE_INT16_ARRAY: 335219089Spjd case DATA_TYPE_UINT16_ARRAY: 336219089Spjd case DATA_TYPE_INT32_ARRAY: 337219089Spjd case DATA_TYPE_UINT32_ARRAY: 338219089Spjd case DATA_TYPE_INT64_ARRAY: 339219089Spjd case DATA_TYPE_UINT64_ARRAY: 340219089Spjd case DATA_TYPE_STRING_ARRAY: 341219089Spjd c = fm_printf(d + 1, c, cols, "[...]"); 342219089Spjd break; 343219089Spjd case DATA_TYPE_UNKNOWN: 344219089Spjd c = fm_printf(d + 1, c, cols, "<unknown>"); 345219089Spjd break; 346219089Spjd } 347219089Spjd } 348219089Spjd 349219089Spjd return (c); 350219089Spjd} 351219089Spjd 352219089Spjdvoid 353219089Spjdfm_nvprint(nvlist_t *nvl) 354219089Spjd{ 355219089Spjd char *class; 356219089Spjd int c = 0; 357219089Spjd 358219089Spjd console_printf("\r"); 359219089Spjd 360219089Spjd if (nvlist_lookup_string(nvl, FM_CLASS, &class) == 0) 361219089Spjd c = fm_printf(0, c, ereport_cols, "%s", class); 362219089Spjd 363219089Spjd if (fm_nvprintr(nvl, 0, c, ereport_cols) != 0) 364219089Spjd console_printf("\n"); 365219089Spjd 366219089Spjd console_printf("\n"); 367219089Spjd} 368219089Spjd 369219089Spjd/* 370219089Spjd * Wrapper for panic() that first produces an FMA-style message for admins. 371219089Spjd * Normally such messages are generated by fmd(1M)'s syslog-msgs agent: this 372219089Spjd * is the one exception to that rule and the only error that gets messaged. 373219089Spjd * This function is intended for use by subsystems that have detected a fatal 374219089Spjd * error and enqueued appropriate ereports and wish to then force a panic. 375219089Spjd */ 376219089Spjd/*PRINTFLIKE1*/ 377219089Spjdvoid 378219089Spjdfm_panic(const char *format, ...) 379219089Spjd{ 380219089Spjd va_list ap; 381219089Spjd 382219089Spjd (void) casptr((void *)&fm_panicstr, NULL, (void *)format); 383219089Spjd#if defined(__i386) || defined(__amd64) 384219089Spjd fastreboot_disable_highpil(); 385219089Spjd#endif /* __i386 || __amd64 */ 386219089Spjd va_start(ap, format); 387219089Spjd vpanic(format, ap); 388219089Spjd va_end(ap); 389219089Spjd} 390219089Spjd 391219089Spjd/* 392219089Spjd * Simply tell the caller if fm_panicstr is set, ie. an fma event has 393219089Spjd * caused the panic. If so, something other than the default panic 394219089Spjd * diagnosis method will diagnose the cause of the panic. 395219089Spjd */ 396219089Spjdint 397219089Spjdis_fm_panic() 398219089Spjd{ 399219089Spjd if (fm_panicstr) 400219089Spjd return (1); 401219089Spjd else 402219089Spjd return (0); 403219089Spjd} 404219089Spjd 405219089Spjd/* 406219089Spjd * Print any appropriate FMA banner message before the panic message. This 407219089Spjd * function is called by panicsys() and prints the message for fm_panic(). 408219089Spjd * We print the message here so that it comes after the system is quiesced. 409219089Spjd * A one-line summary is recorded in the log only (cmn_err(9F) with "!" prefix). 410219089Spjd * The rest of the message is for the console only and not needed in the log, 411219089Spjd * so it is printed using console_printf(). We break it up into multiple 412219089Spjd * chunks so as to avoid overflowing any small legacy prom_printf() buffers. 413219089Spjd */ 414219089Spjdvoid 415219089Spjdfm_banner(void) 416219089Spjd{ 417219089Spjd timespec_t tod; 418219089Spjd hrtime_t now; 419219089Spjd 420219089Spjd if (!fm_panicstr) 421219089Spjd return; /* panic was not initiated by fm_panic(); do nothing */ 422219089Spjd 423219089Spjd if (panicstr) { 424219089Spjd tod = panic_hrestime; 425219089Spjd now = panic_hrtime; 426219089Spjd } else { 427219089Spjd gethrestime(&tod); 428219089Spjd now = gethrtime_waitfree(); 429219089Spjd } 430219089Spjd 431219089Spjd cmn_err(CE_NOTE, "!SUNW-MSG-ID: %s, " 432219089Spjd "TYPE: Error, VER: 1, SEVERITY: Major\n", fm_msgid); 433219089Spjd 434219089Spjd console_printf( 435219089Spjd"\n\rSUNW-MSG-ID: %s, TYPE: Error, VER: 1, SEVERITY: Major\n" 436219089Spjd"EVENT-TIME: 0x%lx.0x%lx (0x%llx)\n", 437219089Spjd fm_msgid, tod.tv_sec, tod.tv_nsec, (u_longlong_t)now); 438219089Spjd 439219089Spjd console_printf( 440219089Spjd"PLATFORM: %s, CSN: -, HOSTNAME: %s\n" 441219089Spjd"SOURCE: %s, REV: %s %s\n", 442219089Spjd platform, utsname.nodename, utsname.sysname, 443219089Spjd utsname.release, utsname.version); 444219089Spjd 445219089Spjd console_printf( 446219089Spjd"DESC: Errors have been detected that require a reboot to ensure system\n" 447219089Spjd"integrity. See %s/%s for more information.\n", 448219089Spjd fm_url, fm_msgid); 449219089Spjd 450219089Spjd console_printf( 451219089Spjd"AUTO-RESPONSE: Solaris will attempt to save and diagnose the error telemetry\n" 452219089Spjd"IMPACT: The system will sync files, save a crash dump if needed, and reboot\n" 453219089Spjd"REC-ACTION: Save the error summary below in case telemetry cannot be saved\n"); 454219089Spjd 455219089Spjd console_printf("\n"); 456219089Spjd} 457219089Spjd 458219089Spjd/* 459219089Spjd * Utility function to write all of the pending ereports to the dump device. 460219089Spjd * This function is called at either normal reboot or panic time, and simply 461219089Spjd * iterates over the in-transit messages in the ereport sysevent channel. 462219089Spjd */ 463219089Spjdvoid 464219089Spjdfm_ereport_dump(void) 465219089Spjd{ 466219089Spjd evchanq_t *chq; 467219089Spjd sysevent_t *sep; 468219089Spjd erpt_dump_t ed; 469219089Spjd 470219089Spjd timespec_t tod; 471219089Spjd hrtime_t now; 472219089Spjd char *buf; 473219089Spjd size_t len; 474219089Spjd 475219089Spjd if (panicstr) { 476219089Spjd tod = panic_hrestime; 477219089Spjd now = panic_hrtime; 478219089Spjd } else { 479219089Spjd if (ereport_errorq != NULL) 480219089Spjd errorq_drain(ereport_errorq); 481219089Spjd gethrestime(&tod); 482219089Spjd now = gethrtime_waitfree(); 483219089Spjd } 484219089Spjd 485219089Spjd /* 486219089Spjd * In the panic case, sysevent_evc_walk_init() will return NULL. 487219089Spjd */ 488219089Spjd if ((chq = sysevent_evc_walk_init(ereport_chan, NULL)) == NULL && 489219089Spjd !panicstr) 490219089Spjd return; /* event channel isn't initialized yet */ 491219089Spjd 492219089Spjd while ((sep = sysevent_evc_walk_step(chq)) != NULL) { 493219089Spjd if ((buf = sysevent_evc_event_attr(sep, &len)) == NULL) 494219089Spjd break; 495219089Spjd 496219089Spjd ed.ed_magic = ERPT_MAGIC; 497219089Spjd ed.ed_chksum = checksum32(buf, len); 498219089Spjd ed.ed_size = (uint32_t)len; 499219089Spjd ed.ed_pad = 0; 500219089Spjd ed.ed_hrt_nsec = SE_TIME(sep); 501219089Spjd ed.ed_hrt_base = now; 502219089Spjd ed.ed_tod_base.sec = tod.tv_sec; 503219089Spjd ed.ed_tod_base.nsec = tod.tv_nsec; 504219089Spjd 505219089Spjd dumpvp_write(&ed, sizeof (ed)); 506219089Spjd dumpvp_write(buf, len); 507219089Spjd } 508219089Spjd 509219089Spjd sysevent_evc_walk_fini(chq); 510219089Spjd} 511219089Spjd#endif 512219089Spjd 513219089Spjd/* 514219089Spjd * Post an error report (ereport) to the sysevent error channel. The error 515219089Spjd * channel must be established with a prior call to sysevent_evc_create() 516219089Spjd * before publication may occur. 517219089Spjd */ 518219089Spjdvoid 519219089Spjdfm_ereport_post(nvlist_t *ereport, int evc_flag) 520219089Spjd{ 521219089Spjd size_t nvl_size = 0; 522219089Spjd evchan_t *error_chan; 523219089Spjd sysevent_id_t eid; 524219089Spjd 525219089Spjd (void) nvlist_size(ereport, &nvl_size, NV_ENCODE_NATIVE); 526219089Spjd if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) { 527219089Spjd atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1); 528219089Spjd return; 529219089Spjd } 530219089Spjd 531219089Spjd#ifdef sun 532219089Spjd if (sysevent_evc_bind(FM_ERROR_CHAN, &error_chan, 533219089Spjd EVCH_CREAT|EVCH_HOLD_PEND) != 0) { 534219089Spjd atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1); 535219089Spjd return; 536219089Spjd } 537219089Spjd 538219089Spjd if (sysevent_evc_publish(error_chan, EC_FM, ESC_FM_ERROR, 539219089Spjd SUNW_VENDOR, FM_PUB, ereport, evc_flag) != 0) { 540219089Spjd atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1); 541219089Spjd (void) sysevent_evc_unbind(error_chan); 542219089Spjd return; 543219089Spjd } 544219089Spjd (void) sysevent_evc_unbind(error_chan); 545219089Spjd#else 546219089Spjd (void) ddi_log_sysevent(NULL, SUNW_VENDOR, EC_DEV_STATUS, 547219089Spjd ESC_DEV_DLE, ereport, &eid, DDI_SLEEP); 548219089Spjd#endif 549219089Spjd} 550219089Spjd 551219089Spjd/* 552219089Spjd * Wrapppers for FM nvlist allocators 553219089Spjd */ 554219089Spjd/* ARGSUSED */ 555219089Spjdstatic void * 556219089Spjdi_fm_alloc(nv_alloc_t *nva, size_t size) 557219089Spjd{ 558219089Spjd return (kmem_zalloc(size, KM_SLEEP)); 559219089Spjd} 560219089Spjd 561219089Spjd/* ARGSUSED */ 562219089Spjdstatic void 563219089Spjdi_fm_free(nv_alloc_t *nva, void *buf, size_t size) 564219089Spjd{ 565219089Spjd kmem_free(buf, size); 566219089Spjd} 567219089Spjd 568219089Spjdconst nv_alloc_ops_t fm_mem_alloc_ops = { 569219089Spjd NULL, 570219089Spjd NULL, 571219089Spjd i_fm_alloc, 572219089Spjd i_fm_free, 573219089Spjd NULL 574219089Spjd}; 575219089Spjd 576219089Spjd/* 577219089Spjd * Create and initialize a new nv_alloc_t for a fixed buffer, buf. A pointer 578219089Spjd * to the newly allocated nv_alloc_t structure is returned upon success or NULL 579219089Spjd * is returned to indicate that the nv_alloc structure could not be created. 580219089Spjd */ 581219089Spjdnv_alloc_t * 582219089Spjdfm_nva_xcreate(char *buf, size_t bufsz) 583219089Spjd{ 584219089Spjd nv_alloc_t *nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP); 585219089Spjd 586219089Spjd if (bufsz == 0 || nv_alloc_init(nvhdl, nv_fixed_ops, buf, bufsz) != 0) { 587219089Spjd kmem_free(nvhdl, sizeof (nv_alloc_t)); 588219089Spjd return (NULL); 589219089Spjd } 590219089Spjd 591219089Spjd return (nvhdl); 592219089Spjd} 593219089Spjd 594219089Spjd/* 595219089Spjd * Destroy a previously allocated nv_alloc structure. The fixed buffer 596219089Spjd * associated with nva must be freed by the caller. 597219089Spjd */ 598219089Spjdvoid 599219089Spjdfm_nva_xdestroy(nv_alloc_t *nva) 600219089Spjd{ 601219089Spjd nv_alloc_fini(nva); 602219089Spjd kmem_free(nva, sizeof (nv_alloc_t)); 603219089Spjd} 604219089Spjd 605219089Spjd/* 606219089Spjd * Create a new nv list. A pointer to a new nv list structure is returned 607219089Spjd * upon success or NULL is returned to indicate that the structure could 608219089Spjd * not be created. The newly created nv list is created and managed by the 609219089Spjd * operations installed in nva. If nva is NULL, the default FMA nva 610219089Spjd * operations are installed and used. 611219089Spjd * 612219089Spjd * When called from the kernel and nva == NULL, this function must be called 613219089Spjd * from passive kernel context with no locks held that can prevent a 614219089Spjd * sleeping memory allocation from occurring. Otherwise, this function may 615219089Spjd * be called from other kernel contexts as long a valid nva created via 616219089Spjd * fm_nva_create() is supplied. 617219089Spjd */ 618219089Spjdnvlist_t * 619219089Spjdfm_nvlist_create(nv_alloc_t *nva) 620219089Spjd{ 621219089Spjd int hdl_alloced = 0; 622219089Spjd nvlist_t *nvl; 623219089Spjd nv_alloc_t *nvhdl; 624219089Spjd 625219089Spjd if (nva == NULL) { 626219089Spjd nvhdl = kmem_zalloc(sizeof (nv_alloc_t), KM_SLEEP); 627219089Spjd 628219089Spjd if (nv_alloc_init(nvhdl, &fm_mem_alloc_ops, NULL, 0) != 0) { 629219089Spjd kmem_free(nvhdl, sizeof (nv_alloc_t)); 630219089Spjd return (NULL); 631219089Spjd } 632219089Spjd hdl_alloced = 1; 633219089Spjd } else { 634219089Spjd nvhdl = nva; 635219089Spjd } 636219089Spjd 637219089Spjd if (nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nvhdl) != 0) { 638219089Spjd if (hdl_alloced) { 639219089Spjd nv_alloc_fini(nvhdl); 640219089Spjd kmem_free(nvhdl, sizeof (nv_alloc_t)); 641219089Spjd } 642219089Spjd return (NULL); 643219089Spjd } 644219089Spjd 645219089Spjd return (nvl); 646219089Spjd} 647219089Spjd 648219089Spjd/* 649219089Spjd * Destroy a previously allocated nvlist structure. flag indicates whether 650219089Spjd * or not the associated nva structure should be freed (FM_NVA_FREE) or 651219089Spjd * retained (FM_NVA_RETAIN). Retaining the nv alloc structure allows 652219089Spjd * it to be re-used for future nvlist creation operations. 653219089Spjd */ 654219089Spjdvoid 655219089Spjdfm_nvlist_destroy(nvlist_t *nvl, int flag) 656219089Spjd{ 657219089Spjd nv_alloc_t *nva = nvlist_lookup_nv_alloc(nvl); 658219089Spjd 659219089Spjd nvlist_free(nvl); 660219089Spjd 661219089Spjd if (nva != NULL) { 662219089Spjd if (flag == FM_NVA_FREE) 663219089Spjd fm_nva_xdestroy(nva); 664219089Spjd } 665219089Spjd} 666219089Spjd 667219089Spjdint 668219089Spjdi_fm_payload_set(nvlist_t *payload, const char *name, va_list ap) 669219089Spjd{ 670219089Spjd int nelem, ret = 0; 671219089Spjd data_type_t type; 672219089Spjd 673219089Spjd while (ret == 0 && name != NULL) { 674219089Spjd type = va_arg(ap, data_type_t); 675219089Spjd switch (type) { 676219089Spjd case DATA_TYPE_BYTE: 677219089Spjd ret = nvlist_add_byte(payload, name, 678219089Spjd va_arg(ap, uint_t)); 679219089Spjd break; 680219089Spjd case DATA_TYPE_BYTE_ARRAY: 681219089Spjd nelem = va_arg(ap, int); 682219089Spjd ret = nvlist_add_byte_array(payload, name, 683219089Spjd va_arg(ap, uchar_t *), nelem); 684219089Spjd break; 685219089Spjd case DATA_TYPE_BOOLEAN_VALUE: 686219089Spjd ret = nvlist_add_boolean_value(payload, name, 687219089Spjd va_arg(ap, boolean_t)); 688219089Spjd break; 689219089Spjd case DATA_TYPE_BOOLEAN_ARRAY: 690219089Spjd nelem = va_arg(ap, int); 691219089Spjd ret = nvlist_add_boolean_array(payload, name, 692219089Spjd va_arg(ap, boolean_t *), nelem); 693219089Spjd break; 694219089Spjd case DATA_TYPE_INT8: 695219089Spjd ret = nvlist_add_int8(payload, name, 696219089Spjd va_arg(ap, int)); 697219089Spjd break; 698219089Spjd case DATA_TYPE_INT8_ARRAY: 699219089Spjd nelem = va_arg(ap, int); 700219089Spjd ret = nvlist_add_int8_array(payload, name, 701219089Spjd va_arg(ap, int8_t *), nelem); 702219089Spjd break; 703219089Spjd case DATA_TYPE_UINT8: 704219089Spjd ret = nvlist_add_uint8(payload, name, 705219089Spjd va_arg(ap, uint_t)); 706219089Spjd break; 707219089Spjd case DATA_TYPE_UINT8_ARRAY: 708219089Spjd nelem = va_arg(ap, int); 709219089Spjd ret = nvlist_add_uint8_array(payload, name, 710219089Spjd va_arg(ap, uint8_t *), nelem); 711219089Spjd break; 712219089Spjd case DATA_TYPE_INT16: 713219089Spjd ret = nvlist_add_int16(payload, name, 714219089Spjd va_arg(ap, int)); 715219089Spjd break; 716219089Spjd case DATA_TYPE_INT16_ARRAY: 717219089Spjd nelem = va_arg(ap, int); 718219089Spjd ret = nvlist_add_int16_array(payload, name, 719219089Spjd va_arg(ap, int16_t *), nelem); 720219089Spjd break; 721219089Spjd case DATA_TYPE_UINT16: 722219089Spjd ret = nvlist_add_uint16(payload, name, 723219089Spjd va_arg(ap, uint_t)); 724219089Spjd break; 725219089Spjd case DATA_TYPE_UINT16_ARRAY: 726219089Spjd nelem = va_arg(ap, int); 727219089Spjd ret = nvlist_add_uint16_array(payload, name, 728219089Spjd va_arg(ap, uint16_t *), nelem); 729219089Spjd break; 730219089Spjd case DATA_TYPE_INT32: 731219089Spjd ret = nvlist_add_int32(payload, name, 732219089Spjd va_arg(ap, int32_t)); 733219089Spjd break; 734219089Spjd case DATA_TYPE_INT32_ARRAY: 735219089Spjd nelem = va_arg(ap, int); 736219089Spjd ret = nvlist_add_int32_array(payload, name, 737219089Spjd va_arg(ap, int32_t *), nelem); 738219089Spjd break; 739219089Spjd case DATA_TYPE_UINT32: 740219089Spjd ret = nvlist_add_uint32(payload, name, 741219089Spjd va_arg(ap, uint32_t)); 742219089Spjd break; 743219089Spjd case DATA_TYPE_UINT32_ARRAY: 744219089Spjd nelem = va_arg(ap, int); 745219089Spjd ret = nvlist_add_uint32_array(payload, name, 746219089Spjd va_arg(ap, uint32_t *), nelem); 747219089Spjd break; 748219089Spjd case DATA_TYPE_INT64: 749219089Spjd ret = nvlist_add_int64(payload, name, 750219089Spjd va_arg(ap, int64_t)); 751219089Spjd break; 752219089Spjd case DATA_TYPE_INT64_ARRAY: 753219089Spjd nelem = va_arg(ap, int); 754219089Spjd ret = nvlist_add_int64_array(payload, name, 755219089Spjd va_arg(ap, int64_t *), nelem); 756219089Spjd break; 757219089Spjd case DATA_TYPE_UINT64: 758219089Spjd ret = nvlist_add_uint64(payload, name, 759219089Spjd va_arg(ap, uint64_t)); 760219089Spjd break; 761219089Spjd case DATA_TYPE_UINT64_ARRAY: 762219089Spjd nelem = va_arg(ap, int); 763219089Spjd ret = nvlist_add_uint64_array(payload, name, 764219089Spjd va_arg(ap, uint64_t *), nelem); 765219089Spjd break; 766219089Spjd case DATA_TYPE_STRING: 767219089Spjd ret = nvlist_add_string(payload, name, 768219089Spjd va_arg(ap, char *)); 769219089Spjd break; 770219089Spjd case DATA_TYPE_STRING_ARRAY: 771219089Spjd nelem = va_arg(ap, int); 772219089Spjd ret = nvlist_add_string_array(payload, name, 773219089Spjd va_arg(ap, char **), nelem); 774219089Spjd break; 775219089Spjd case DATA_TYPE_NVLIST: 776219089Spjd ret = nvlist_add_nvlist(payload, name, 777219089Spjd va_arg(ap, nvlist_t *)); 778219089Spjd break; 779219089Spjd case DATA_TYPE_NVLIST_ARRAY: 780219089Spjd nelem = va_arg(ap, int); 781219089Spjd ret = nvlist_add_nvlist_array(payload, name, 782219089Spjd va_arg(ap, nvlist_t **), nelem); 783219089Spjd break; 784219089Spjd default: 785219089Spjd ret = EINVAL; 786219089Spjd } 787219089Spjd 788219089Spjd name = va_arg(ap, char *); 789219089Spjd } 790219089Spjd return (ret); 791219089Spjd} 792219089Spjd 793219089Spjdvoid 794219089Spjdfm_payload_set(nvlist_t *payload, ...) 795219089Spjd{ 796219089Spjd int ret; 797219089Spjd const char *name; 798219089Spjd va_list ap; 799219089Spjd 800219089Spjd va_start(ap, payload); 801219089Spjd name = va_arg(ap, char *); 802219089Spjd ret = i_fm_payload_set(payload, name, ap); 803219089Spjd va_end(ap); 804219089Spjd 805219089Spjd if (ret) 806219089Spjd atomic_add_64( 807219089Spjd &erpt_kstat_data.payload_set_failed.value.ui64, 1); 808219089Spjd} 809219089Spjd 810219089Spjd/* 811219089Spjd * Set-up and validate the members of an ereport event according to: 812219089Spjd * 813219089Spjd * Member name Type Value 814219089Spjd * ==================================================== 815219089Spjd * class string ereport 816219089Spjd * version uint8_t 0 817219089Spjd * ena uint64_t <ena> 818219089Spjd * detector nvlist_t <detector> 819219089Spjd * ereport-payload nvlist_t <var args> 820219089Spjd * 821219089Spjd * We don't actually add a 'version' member to the payload. Really, 822219089Spjd * the version quoted to us by our caller is that of the category 1 823219089Spjd * "ereport" event class (and we require FM_EREPORT_VERS0) but 824219089Spjd * the payload version of the actual leaf class event under construction 825219089Spjd * may be something else. Callers should supply a version in the varargs, 826219089Spjd * or (better) we could take two version arguments - one for the 827219089Spjd * ereport category 1 classification (expect FM_EREPORT_VERS0) and one 828219089Spjd * for the leaf class. 829219089Spjd */ 830219089Spjdvoid 831219089Spjdfm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class, 832219089Spjd uint64_t ena, const nvlist_t *detector, ...) 833219089Spjd{ 834219089Spjd char ereport_class[FM_MAX_CLASS]; 835219089Spjd const char *name; 836219089Spjd va_list ap; 837219089Spjd int ret; 838219089Spjd 839219089Spjd if (version != FM_EREPORT_VERS0) { 840219089Spjd atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); 841219089Spjd return; 842219089Spjd } 843219089Spjd 844219089Spjd (void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s", 845219089Spjd FM_EREPORT_CLASS, erpt_class); 846219089Spjd if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) { 847219089Spjd atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); 848219089Spjd return; 849219089Spjd } 850219089Spjd 851219089Spjd if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) { 852219089Spjd atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); 853219089Spjd } 854219089Spjd 855219089Spjd if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR, 856219089Spjd (nvlist_t *)detector) != 0) { 857219089Spjd atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); 858219089Spjd } 859219089Spjd 860219089Spjd va_start(ap, detector); 861219089Spjd name = va_arg(ap, const char *); 862219089Spjd ret = i_fm_payload_set(ereport, name, ap); 863219089Spjd va_end(ap); 864219089Spjd 865219089Spjd if (ret) 866219089Spjd atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1); 867219089Spjd} 868219089Spjd 869219089Spjd/* 870219089Spjd * Set-up and validate the members of an hc fmri according to; 871219089Spjd * 872219089Spjd * Member name Type Value 873219089Spjd * =================================================== 874219089Spjd * version uint8_t 0 875219089Spjd * auth nvlist_t <auth> 876219089Spjd * hc-name string <name> 877219089Spjd * hc-id string <id> 878219089Spjd * 879219089Spjd * Note that auth and hc-id are optional members. 880219089Spjd */ 881219089Spjd 882219089Spjd#define HC_MAXPAIRS 20 883219089Spjd#define HC_MAXNAMELEN 50 884219089Spjd 885219089Spjdstatic int 886219089Spjdfm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth) 887219089Spjd{ 888219089Spjd if (version != FM_HC_SCHEME_VERSION) { 889219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 890219089Spjd return (0); 891219089Spjd } 892219089Spjd 893219089Spjd if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 || 894219089Spjd nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) { 895219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 896219089Spjd return (0); 897219089Spjd } 898219089Spjd 899219089Spjd if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 900219089Spjd (nvlist_t *)auth) != 0) { 901219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 902219089Spjd return (0); 903219089Spjd } 904219089Spjd 905219089Spjd return (1); 906219089Spjd} 907219089Spjd 908219089Spjdvoid 909219089Spjdfm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth, 910219089Spjd nvlist_t *snvl, int npairs, ...) 911219089Spjd{ 912219089Spjd nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); 913219089Spjd nvlist_t *pairs[HC_MAXPAIRS]; 914219089Spjd va_list ap; 915219089Spjd int i; 916219089Spjd 917219089Spjd if (!fm_fmri_hc_set_common(fmri, version, auth)) 918219089Spjd return; 919219089Spjd 920219089Spjd npairs = MIN(npairs, HC_MAXPAIRS); 921219089Spjd 922219089Spjd va_start(ap, npairs); 923219089Spjd for (i = 0; i < npairs; i++) { 924219089Spjd const char *name = va_arg(ap, const char *); 925219089Spjd uint32_t id = va_arg(ap, uint32_t); 926219089Spjd char idstr[11]; 927219089Spjd 928219089Spjd (void) snprintf(idstr, sizeof (idstr), "%u", id); 929219089Spjd 930219089Spjd pairs[i] = fm_nvlist_create(nva); 931219089Spjd if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || 932219089Spjd nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { 933219089Spjd atomic_add_64( 934219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 935219089Spjd } 936219089Spjd } 937219089Spjd va_end(ap); 938219089Spjd 939219089Spjd if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0) 940219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 941219089Spjd 942219089Spjd for (i = 0; i < npairs; i++) 943219089Spjd fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); 944219089Spjd 945219089Spjd if (snvl != NULL) { 946219089Spjd if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { 947219089Spjd atomic_add_64( 948219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 949219089Spjd } 950219089Spjd } 951219089Spjd} 952219089Spjd 953219089Spjd/* 954219089Spjd * Set-up and validate the members of an dev fmri according to: 955219089Spjd * 956219089Spjd * Member name Type Value 957219089Spjd * ==================================================== 958219089Spjd * version uint8_t 0 959219089Spjd * auth nvlist_t <auth> 960219089Spjd * devpath string <devpath> 961219089Spjd * [devid] string <devid> 962219089Spjd * [target-port-l0id] string <target-port-lun0-id> 963219089Spjd * 964219089Spjd * Note that auth and devid are optional members. 965219089Spjd */ 966219089Spjdvoid 967219089Spjdfm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth, 968219089Spjd const char *devpath, const char *devid, const char *tpl0) 969219089Spjd{ 970219089Spjd int err = 0; 971219089Spjd 972219089Spjd if (version != DEV_SCHEME_VERSION0) { 973219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 974219089Spjd return; 975219089Spjd } 976219089Spjd 977219089Spjd err |= nvlist_add_uint8(fmri_dev, FM_VERSION, version); 978219089Spjd err |= nvlist_add_string(fmri_dev, FM_FMRI_SCHEME, FM_FMRI_SCHEME_DEV); 979219089Spjd 980219089Spjd if (auth != NULL) { 981219089Spjd err |= nvlist_add_nvlist(fmri_dev, FM_FMRI_AUTHORITY, 982219089Spjd (nvlist_t *)auth); 983219089Spjd } 984219089Spjd 985219089Spjd err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_PATH, devpath); 986219089Spjd 987219089Spjd if (devid != NULL) 988219089Spjd err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_ID, devid); 989219089Spjd 990219089Spjd if (tpl0 != NULL) 991219089Spjd err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0); 992219089Spjd 993219089Spjd if (err) 994219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 995219089Spjd 996219089Spjd} 997219089Spjd 998219089Spjd/* 999219089Spjd * Set-up and validate the members of an cpu fmri according to: 1000219089Spjd * 1001219089Spjd * Member name Type Value 1002219089Spjd * ==================================================== 1003219089Spjd * version uint8_t 0 1004219089Spjd * auth nvlist_t <auth> 1005219089Spjd * cpuid uint32_t <cpu_id> 1006219089Spjd * cpumask uint8_t <cpu_mask> 1007219089Spjd * serial uint64_t <serial_id> 1008219089Spjd * 1009219089Spjd * Note that auth, cpumask, serial are optional members. 1010219089Spjd * 1011219089Spjd */ 1012219089Spjdvoid 1013219089Spjdfm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth, 1014219089Spjd uint32_t cpu_id, uint8_t *cpu_maskp, const char *serial_idp) 1015219089Spjd{ 1016219089Spjd uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64; 1017219089Spjd 1018219089Spjd if (version < CPU_SCHEME_VERSION1) { 1019219089Spjd atomic_add_64(failedp, 1); 1020219089Spjd return; 1021219089Spjd } 1022219089Spjd 1023219089Spjd if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) { 1024219089Spjd atomic_add_64(failedp, 1); 1025219089Spjd return; 1026219089Spjd } 1027219089Spjd 1028219089Spjd if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME, 1029219089Spjd FM_FMRI_SCHEME_CPU) != 0) { 1030219089Spjd atomic_add_64(failedp, 1); 1031219089Spjd return; 1032219089Spjd } 1033219089Spjd 1034219089Spjd if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY, 1035219089Spjd (nvlist_t *)auth) != 0) 1036219089Spjd atomic_add_64(failedp, 1); 1037219089Spjd 1038219089Spjd if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) 1039219089Spjd atomic_add_64(failedp, 1); 1040219089Spjd 1041219089Spjd if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK, 1042219089Spjd *cpu_maskp) != 0) 1043219089Spjd atomic_add_64(failedp, 1); 1044219089Spjd 1045219089Spjd if (serial_idp == NULL || nvlist_add_string(fmri_cpu, 1046219089Spjd FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0) 1047219089Spjd atomic_add_64(failedp, 1); 1048219089Spjd} 1049219089Spjd 1050219089Spjd/* 1051219089Spjd * Set-up and validate the members of a mem according to: 1052219089Spjd * 1053219089Spjd * Member name Type Value 1054219089Spjd * ==================================================== 1055219089Spjd * version uint8_t 0 1056219089Spjd * auth nvlist_t <auth> [optional] 1057219089Spjd * unum string <unum> 1058219089Spjd * serial string <serial> [optional*] 1059219089Spjd * offset uint64_t <offset> [optional] 1060219089Spjd * 1061219089Spjd * * serial is required if offset is present 1062219089Spjd */ 1063219089Spjdvoid 1064219089Spjdfm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth, 1065219089Spjd const char *unum, const char *serial, uint64_t offset) 1066219089Spjd{ 1067219089Spjd if (version != MEM_SCHEME_VERSION0) { 1068219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1069219089Spjd return; 1070219089Spjd } 1071219089Spjd 1072219089Spjd if (!serial && (offset != (uint64_t)-1)) { 1073219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1074219089Spjd return; 1075219089Spjd } 1076219089Spjd 1077219089Spjd if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) { 1078219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1079219089Spjd return; 1080219089Spjd } 1081219089Spjd 1082219089Spjd if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) { 1083219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1084219089Spjd return; 1085219089Spjd } 1086219089Spjd 1087219089Spjd if (auth != NULL) { 1088219089Spjd if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, 1089219089Spjd (nvlist_t *)auth) != 0) { 1090219089Spjd atomic_add_64( 1091219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1092219089Spjd } 1093219089Spjd } 1094219089Spjd 1095219089Spjd if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) { 1096219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1097219089Spjd } 1098219089Spjd 1099219089Spjd if (serial != NULL) { 1100219089Spjd if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID, 1101219089Spjd (char **)&serial, 1) != 0) { 1102219089Spjd atomic_add_64( 1103219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1104219089Spjd } 1105219089Spjd if (offset != (uint64_t)-1) { 1106219089Spjd if (nvlist_add_uint64(fmri, FM_FMRI_MEM_OFFSET, 1107219089Spjd offset) != 0) { 1108219089Spjd atomic_add_64(&erpt_kstat_data. 1109219089Spjd fmri_set_failed.value.ui64, 1); 1110219089Spjd } 1111219089Spjd } 1112219089Spjd } 1113219089Spjd} 1114219089Spjd 1115219089Spjdvoid 1116219089Spjdfm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid, 1117219089Spjd uint64_t vdev_guid) 1118219089Spjd{ 1119219089Spjd if (version != ZFS_SCHEME_VERSION0) { 1120219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1121219089Spjd return; 1122219089Spjd } 1123219089Spjd 1124219089Spjd if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) { 1125219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1126219089Spjd return; 1127219089Spjd } 1128219089Spjd 1129219089Spjd if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) { 1130219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1131219089Spjd return; 1132219089Spjd } 1133219089Spjd 1134219089Spjd if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) { 1135219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1136219089Spjd } 1137219089Spjd 1138219089Spjd if (vdev_guid != 0) { 1139219089Spjd if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) { 1140219089Spjd atomic_add_64( 1141219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1142219089Spjd } 1143219089Spjd } 1144219089Spjd} 1145219089Spjd 1146219089Spjduint64_t 1147219089Spjdfm_ena_increment(uint64_t ena) 1148219089Spjd{ 1149219089Spjd uint64_t new_ena; 1150219089Spjd 1151219089Spjd switch (ENA_FORMAT(ena)) { 1152219089Spjd case FM_ENA_FMT1: 1153219089Spjd new_ena = ena + (1 << ENA_FMT1_GEN_SHFT); 1154219089Spjd break; 1155219089Spjd case FM_ENA_FMT2: 1156219089Spjd new_ena = ena + (1 << ENA_FMT2_GEN_SHFT); 1157219089Spjd break; 1158219089Spjd default: 1159219089Spjd new_ena = 0; 1160219089Spjd } 1161219089Spjd 1162219089Spjd return (new_ena); 1163219089Spjd} 1164219089Spjd 1165219089Spjduint64_t 1166219089Spjdfm_ena_generate_cpu(uint64_t timestamp, processorid_t cpuid, uchar_t format) 1167219089Spjd{ 1168219089Spjd uint64_t ena = 0; 1169219089Spjd 1170219089Spjd switch (format) { 1171219089Spjd case FM_ENA_FMT1: 1172219089Spjd if (timestamp) { 1173219089Spjd ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1174219089Spjd ((cpuid << ENA_FMT1_CPUID_SHFT) & 1175219089Spjd ENA_FMT1_CPUID_MASK) | 1176219089Spjd ((timestamp << ENA_FMT1_TIME_SHFT) & 1177219089Spjd ENA_FMT1_TIME_MASK)); 1178219089Spjd } else { 1179219089Spjd ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1180219089Spjd ((cpuid << ENA_FMT1_CPUID_SHFT) & 1181219089Spjd ENA_FMT1_CPUID_MASK) | 1182219089Spjd ((gethrtime_waitfree() << ENA_FMT1_TIME_SHFT) & 1183219089Spjd ENA_FMT1_TIME_MASK)); 1184219089Spjd } 1185219089Spjd break; 1186219089Spjd case FM_ENA_FMT2: 1187219089Spjd ena = (uint64_t)((format & ENA_FORMAT_MASK) | 1188219089Spjd ((timestamp << ENA_FMT2_TIME_SHFT) & ENA_FMT2_TIME_MASK)); 1189219089Spjd break; 1190219089Spjd default: 1191219089Spjd break; 1192219089Spjd } 1193219089Spjd 1194219089Spjd return (ena); 1195219089Spjd} 1196219089Spjd 1197219089Spjduint64_t 1198219089Spjdfm_ena_generate(uint64_t timestamp, uchar_t format) 1199219089Spjd{ 1200219089Spjd return (fm_ena_generate_cpu(timestamp, PCPU_GET(cpuid), format)); 1201219089Spjd} 1202219089Spjd 1203219089Spjduint64_t 1204219089Spjdfm_ena_generation_get(uint64_t ena) 1205219089Spjd{ 1206219089Spjd uint64_t gen; 1207219089Spjd 1208219089Spjd switch (ENA_FORMAT(ena)) { 1209219089Spjd case FM_ENA_FMT1: 1210219089Spjd gen = (ena & ENA_FMT1_GEN_MASK) >> ENA_FMT1_GEN_SHFT; 1211219089Spjd break; 1212219089Spjd case FM_ENA_FMT2: 1213219089Spjd gen = (ena & ENA_FMT2_GEN_MASK) >> ENA_FMT2_GEN_SHFT; 1214219089Spjd break; 1215219089Spjd default: 1216219089Spjd gen = 0; 1217219089Spjd break; 1218219089Spjd } 1219219089Spjd 1220219089Spjd return (gen); 1221219089Spjd} 1222219089Spjd 1223219089Spjduchar_t 1224219089Spjdfm_ena_format_get(uint64_t ena) 1225219089Spjd{ 1226219089Spjd 1227219089Spjd return (ENA_FORMAT(ena)); 1228219089Spjd} 1229219089Spjd 1230219089Spjduint64_t 1231219089Spjdfm_ena_id_get(uint64_t ena) 1232219089Spjd{ 1233219089Spjd uint64_t id; 1234219089Spjd 1235219089Spjd switch (ENA_FORMAT(ena)) { 1236219089Spjd case FM_ENA_FMT1: 1237219089Spjd id = (ena & ENA_FMT1_ID_MASK) >> ENA_FMT1_ID_SHFT; 1238219089Spjd break; 1239219089Spjd case FM_ENA_FMT2: 1240219089Spjd id = (ena & ENA_FMT2_ID_MASK) >> ENA_FMT2_ID_SHFT; 1241219089Spjd break; 1242219089Spjd default: 1243219089Spjd id = 0; 1244219089Spjd } 1245219089Spjd 1246219089Spjd return (id); 1247219089Spjd} 1248219089Spjd 1249219089Spjduint64_t 1250219089Spjdfm_ena_time_get(uint64_t ena) 1251219089Spjd{ 1252219089Spjd uint64_t time; 1253219089Spjd 1254219089Spjd switch (ENA_FORMAT(ena)) { 1255219089Spjd case FM_ENA_FMT1: 1256219089Spjd time = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT; 1257219089Spjd break; 1258219089Spjd case FM_ENA_FMT2: 1259219089Spjd time = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT; 1260219089Spjd break; 1261219089Spjd default: 1262219089Spjd time = 0; 1263219089Spjd } 1264219089Spjd 1265219089Spjd return (time); 1266219089Spjd} 1267219089Spjd 1268219089Spjd#ifdef sun 1269219089Spjd/* 1270219089Spjd * Convert a getpcstack() trace to symbolic name+offset, and add the resulting 1271219089Spjd * string array to a Fault Management ereport as FM_EREPORT_PAYLOAD_NAME_STACK. 1272219089Spjd */ 1273219089Spjdvoid 1274219089Spjdfm_payload_stack_add(nvlist_t *payload, const pc_t *stack, int depth) 1275219089Spjd{ 1276219089Spjd int i; 1277219089Spjd char *sym; 1278219089Spjd ulong_t off; 1279219089Spjd char *stkpp[FM_STK_DEPTH]; 1280219089Spjd char buf[FM_STK_DEPTH * FM_SYM_SZ]; 1281219089Spjd char *stkp = buf; 1282219089Spjd 1283219089Spjd for (i = 0; i < depth && i != FM_STK_DEPTH; i++, stkp += FM_SYM_SZ) { 1284219089Spjd if ((sym = kobj_getsymname(stack[i], &off)) != NULL) 1285219089Spjd (void) snprintf(stkp, FM_SYM_SZ, "%s+%lx", sym, off); 1286219089Spjd else 1287219089Spjd (void) snprintf(stkp, FM_SYM_SZ, "%lx", (long)stack[i]); 1288219089Spjd stkpp[i] = stkp; 1289219089Spjd } 1290219089Spjd 1291219089Spjd fm_payload_set(payload, FM_EREPORT_PAYLOAD_NAME_STACK, 1292219089Spjd DATA_TYPE_STRING_ARRAY, depth, stkpp, NULL); 1293219089Spjd} 1294219089Spjd#endif 1295219089Spjd 1296219089Spjd#ifdef sun 1297219089Spjdvoid 1298219089Spjdprint_msg_hwerr(ctid_t ct_id, proc_t *p) 1299219089Spjd{ 1300219089Spjd uprintf("Killed process %d (%s) in contract id %d " 1301219089Spjd "due to hardware error\n", p->p_pid, p->p_user.u_comm, ct_id); 1302219089Spjd} 1303219089Spjd#endif 1304219089Spjd 1305219089Spjdvoid 1306219089Spjdfm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth, 1307219089Spjd nvlist_t *snvl, nvlist_t *bboard, int npairs, ...) 1308219089Spjd{ 1309219089Spjd nv_alloc_t *nva = nvlist_lookup_nv_alloc(fmri); 1310219089Spjd nvlist_t *pairs[HC_MAXPAIRS]; 1311219089Spjd nvlist_t **hcl; 1312219089Spjd uint_t n; 1313219089Spjd int i, j; 1314219089Spjd va_list ap; 1315219089Spjd char *hcname, *hcid; 1316219089Spjd 1317219089Spjd if (!fm_fmri_hc_set_common(fmri, version, auth)) 1318219089Spjd return; 1319219089Spjd 1320219089Spjd /* 1321219089Spjd * copy the bboard nvpairs to the pairs array 1322219089Spjd */ 1323219089Spjd if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n) 1324219089Spjd != 0) { 1325219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1326219089Spjd return; 1327219089Spjd } 1328219089Spjd 1329219089Spjd for (i = 0; i < n; i++) { 1330219089Spjd if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, 1331219089Spjd &hcname) != 0) { 1332219089Spjd atomic_add_64( 1333219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1334219089Spjd return; 1335219089Spjd } 1336219089Spjd if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) { 1337219089Spjd atomic_add_64( 1338219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1339219089Spjd return; 1340219089Spjd } 1341219089Spjd 1342219089Spjd pairs[i] = fm_nvlist_create(nva); 1343219089Spjd if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, hcname) != 0 || 1344219089Spjd nvlist_add_string(pairs[i], FM_FMRI_HC_ID, hcid) != 0) { 1345219089Spjd for (j = 0; j <= i; j++) { 1346219089Spjd if (pairs[j] != NULL) 1347219089Spjd fm_nvlist_destroy(pairs[j], 1348219089Spjd FM_NVA_RETAIN); 1349219089Spjd } 1350219089Spjd atomic_add_64( 1351219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1352219089Spjd return; 1353219089Spjd } 1354219089Spjd } 1355219089Spjd 1356219089Spjd /* 1357219089Spjd * create the pairs from passed in pairs 1358219089Spjd */ 1359219089Spjd npairs = MIN(npairs, HC_MAXPAIRS); 1360219089Spjd 1361219089Spjd va_start(ap, npairs); 1362219089Spjd for (i = n; i < npairs + n; i++) { 1363219089Spjd const char *name = va_arg(ap, const char *); 1364219089Spjd uint32_t id = va_arg(ap, uint32_t); 1365219089Spjd char idstr[11]; 1366219089Spjd (void) snprintf(idstr, sizeof (idstr), "%u", id); 1367219089Spjd pairs[i] = fm_nvlist_create(nva); 1368219089Spjd if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 || 1369219089Spjd nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) { 1370219089Spjd for (j = 0; j <= i; j++) { 1371219089Spjd if (pairs[j] != NULL) 1372219089Spjd fm_nvlist_destroy(pairs[j], 1373219089Spjd FM_NVA_RETAIN); 1374219089Spjd } 1375219089Spjd atomic_add_64( 1376219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1377219089Spjd return; 1378219089Spjd } 1379219089Spjd } 1380219089Spjd va_end(ap); 1381219089Spjd 1382219089Spjd /* 1383219089Spjd * Create the fmri hc list 1384219089Spjd */ 1385219089Spjd if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, 1386219089Spjd npairs + n) != 0) { 1387219089Spjd atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1388219089Spjd return; 1389219089Spjd } 1390219089Spjd 1391219089Spjd for (i = 0; i < npairs + n; i++) { 1392219089Spjd fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN); 1393219089Spjd } 1394219089Spjd 1395219089Spjd if (snvl != NULL) { 1396219089Spjd if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) { 1397219089Spjd atomic_add_64( 1398219089Spjd &erpt_kstat_data.fmri_set_failed.value.ui64, 1); 1399219089Spjd return; 1400219089Spjd } 1401219089Spjd } 1402219089Spjd} 1403