static int logpage_selftest_analyze(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length) { int i, plen = 0; int entries = 0; ushort_t param_code; scsi_selftest_log_param_t *stp; nvlist_t *nvl; assert(sip->si_dsp->ds_testfail == NULL); if (nvlist_alloc(&sip->si_dsp->ds_testfail, NV_UNIQUE_NAME, 0) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); nvl = sip->si_dsp->ds_testfail; for (i = 0; i < log_length; i += plen, entries++) { lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen); param_code = BE_16(lphp->lph_param); stp = (scsi_selftest_log_param_t *)lphp; if (param_code >= LOGPAGE_SELFTEST_MIN_PARAM_CODE && param_code <= LOGPAGE_SELFTEST_MAX_PARAM_CODE && lphp->lph_length >= LOGPAGE_SELFTEST_PARAM_LEN) { /* * We always log the last result, or the result of the * last completed test. */ if ((param_code == 1 || SELFTEST_COMPLETE(stp->st_results))) { if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_RESULTCODE, stp->st_results) != 0 || nvlist_add_uint16(nvl, FM_EREPORT_PAYLOAD_SCSI_TIMESTAMP, BE_16(stp->st_timestamp)) != 0 || nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_SEGMENT, stp->st_number) != 0 || nvlist_add_uint64(nvl, FM_EREPORT_PAYLOAD_SCSI_ADDRESS, BE_64(stp->st_lba)) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); if (SELFTEST_COMPLETE(stp->st_results)) { if (stp->st_results != SELFTEST_OK) sip->si_dsp->ds_faults |= DS_FAULT_TESTFAIL; return (0); } } } plen = lphp->lph_length + sizeof (scsi_log_parameter_header_t); } return (0); }
static int logpage_temp_analyze(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length) { int i, plen = 0; uint8_t reftemp, curtemp; ushort_t param_code; scsi_temp_log_param_t *temp; nvlist_t *nvl; assert(sip->si_dsp->ds_overtemp == NULL); if (nvlist_alloc(&sip->si_dsp->ds_overtemp, NV_UNIQUE_NAME, 0) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); nvl = sip->si_dsp->ds_overtemp; reftemp = curtemp = INVALID_TEMPERATURE; for (i = 0; i < log_length; i += plen) { lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen); param_code = BE_16(lphp->lph_param); temp = (scsi_temp_log_param_t *)lphp; switch (param_code) { case LOGPARAM_TEMP_CURTEMP: if (lphp->lph_length != LOGPARAM_TEMP_LEN) break; if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_CURTEMP, temp->t_temp) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); curtemp = temp->t_temp; break; case LOGPARAM_TEMP_REFTEMP: if (lphp->lph_length != LOGPARAM_TEMP_LEN) break; if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_THRESHTEMP, temp->t_temp) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); reftemp = temp->t_temp; break; } plen = lphp->lph_length + sizeof (scsi_log_parameter_header_t); } if (reftemp != INVALID_TEMPERATURE && curtemp != INVALID_TEMPERATURE && curtemp > reftemp) sip->si_dsp->ds_faults |= DS_FAULT_OVERTEMP; return (0); }
/* * Verify the contents of the temperature log page. The temperature log page * contains two log parameters: the current temperature, and (optionally) the * reference temperature. For the verification phase, we check that the two * parameters we care about are well-formed. If there is no reference * temperature, then we cannot use the page for monitoring purposes. */ static int logpage_temp_verify(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length, nvlist_t *nvl) { int i, plen = 0; boolean_t has_reftemp = B_FALSE; boolean_t bad_length = B_FALSE; ushort_t param_code; for (i = 0; i < log_length; i += plen) { lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen); param_code = BE_16(lphp->lph_param); switch (param_code) { case LOGPARAM_TEMP_CURTEMP: if (nvlist_add_boolean_value(nvl, "current-temperature", B_TRUE) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); if (lphp->lph_length != LOGPARAM_TEMP_LEN) { if (nvlist_add_uint8(nvl, "invalid-length", lphp->lph_length) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); bad_length = B_TRUE; } break; case LOGPARAM_TEMP_REFTEMP: if (nvlist_add_boolean_value(nvl, "reference-temperature", B_TRUE) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); if (lphp->lph_length != LOGPARAM_TEMP_LEN) { if (nvlist_add_uint8(nvl, "invalid-length", lphp->lph_length) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); bad_length = B_TRUE; } has_reftemp = B_TRUE; break; } plen = lphp->lph_length + sizeof (scsi_log_parameter_header_t); } if (bad_length || !has_reftemp) { sip->si_supp_log &= ~LOGPAGE_SUPP_TEMP; printf("temperature logpage validation failed\n"); } return (0); }
void inhm_create_nvl(int chip) { nvlist_t *nvl; (void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_VERSTR, MCINTEL_NVLIST_VERS); (void) nvlist_add_string(nvl, MCINTEL_NVLIST_MEM, inhm_mc_name()); (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_NMEM, 1); (void) nvlist_add_uint8(nvl, MCINTEL_NVLIST_NRANKS, 4); inhm_dimmlist(chip, nvl); if (inhm_mc_nvl[chip]) nvlist_free(inhm_mc_nvl[chip]); inhm_mc_nvl[chip] = nvl; }
/* * Load the current IE mode pages */ static int load_ie_modepage(ds_scsi_info_t *sip) { struct scsi_ms_hdrs junk_hdrs; int result; uint_t skey, asc, ascq; if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC)) return (0); bzero(&sip->si_iec_current, sizeof (sip->si_iec_current)); bzero(&sip->si_iec_changeable, sizeof (sip->si_iec_changeable)); if ((result = scsi_mode_sense(sip, MODEPAGE_INFO_EXCPT, PC_CURRENT, &sip->si_iec_current, MODEPAGE_INFO_EXCPT_LEN, &sip->si_hdrs, &skey, &asc, &ascq)) == 0) { result = scsi_mode_sense(sip, MODEPAGE_INFO_EXCPT, PC_CHANGEABLE, &sip->si_iec_changeable, MODEPAGE_INFO_EXCPT_LEN, &junk_hdrs, &skey, &asc, &ascq); } if (result != 0) { printf("failed to get IEC modepage (KEY=0x%x " "ASC=0x%x ASCQ=0x%x)", skey, asc, ascq); sip->si_supp_mode &= ~MODEPAGE_SUPP_IEC; } else { if (nvlist_add_boolean_value(sip->si_state_iec, "dexcpt", sip->si_iec_current.ie_dexcpt) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "logerr", sip->si_iec_current.ie_logerr) != 0 || nvlist_add_uint8(sip->si_state_iec, "mrie", sip->si_iec_current.ie_mrie) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "test", sip->si_iec_current.ie_test) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "ewasc", sip->si_iec_current.ie_ewasc) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "perf", sip->si_iec_current.ie_perf) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "ebf", sip->si_iec_current.ie_ebf) != 0 || nvlist_add_uint32(sip->si_state_iec, "interval-timer", BE_32(sip->si_iec_current.ie_interval_timer)) != 0 || nvlist_add_uint32(sip->si_state_iec, "report-count", BE_32(sip->si_iec_current.ie_report_count)) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); } return (0); }
/* * Analyze the IE logpage. If we find an IE log record with a non-zero 'asc', * then we have a fault. */ static int logpage_ie_analyze(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length) { int i, plen = 0; scsi_ie_log_param_t *iep = (scsi_ie_log_param_t *)lphp; nvlist_t *nvl; assert(sip->si_dsp->ds_predfail == NULL); if (nvlist_alloc(&sip->si_dsp->ds_predfail, NV_UNIQUE_NAME, 0) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); nvl = sip->si_dsp->ds_predfail; for (i = 0; i < log_length; i += plen) { iep = (scsi_ie_log_param_t *)((char *)iep + plen); /* * Even though we validated the length during the initial phase, * never trust the device. */ if (BE_16(iep->ie_hdr.lph_param) == LOGPARAM_IE && iep->ie_hdr.lph_length >= LOGPARAM_IE_MIN_LEN) { if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASC, iep->ie_asc) != 0 || nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASCQ, iep->ie_ascq) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); if (iep->ie_asc != 0) sip->si_dsp->ds_faults |= DS_FAULT_PREDFAIL; break; } plen = iep->ie_hdr.lph_length + sizeof (scsi_log_parameter_header_t); } return (0); }
/* * Analyze the IE mode sense page explicitly. This is only needed if the IE log * page is not supported. */ static int analyze_ie_sense(ds_scsi_info_t *sip) { uint_t skey, asc, ascq; nvlist_t *nvl; /* * Don't bother checking if we weren't able to set our MRIE correctly. */ if (sip->si_iec_current.ie_mrie != IE_REPORT_ON_REQUEST) return (0); if (scsi_request_sense(sip, &skey, &asc, &ascq) != 0) { printf("failed to request IE page (KEY=0x%x ASC=0x%x " "ASCQ=0x%x)\n", skey, asc, ascq); return (scsi_set_errno(sip, EDS_IO)); } else if (skey == KEY_NO_SENSE) { assert(sip->si_dsp->ds_predfail == NULL); if (nvlist_alloc(&sip->si_dsp->ds_predfail, NV_UNIQUE_NAME, 0) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); nvl = sip->si_dsp->ds_predfail; if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASC, asc) != 0 || nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASCQ, ascq) != 0) { nvlist_free(nvl); return (scsi_set_errno(sip, EDS_NOMEM)); } if (asc != 0) sip->si_dsp->ds_faults |= DS_FAULT_PREDFAIL; } return (0); }
/* * fps_fmri_cpu_set(nvlist_t *fmri_cpu, uint32_t cpu_id) * adds the resource data to fmri_cpu. */ static int fps_fmri_cpu_set(nvlist_t *fmri_cpu, uint32_t cpu_id) { if (fmri_cpu == NULL) return (1); if (nvlist_add_uint8(fmri_cpu, FM_VERSION, FM_CPU_SCHEME_VERSION) != 0) return (1); if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME, FM_FMRI_SCHEME_CPU) != 0) return (1); if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0) return (1); return (0); }
/* * Solve a given ZFS case. This first checks to make sure the diagnosis is * still valid, as well as cleaning up any pending timer associated with the * case. */ static void zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname, boolean_t checkunusable) { nvlist_t *detector, *fault; boolean_t serialize; nvlist_t *fru = NULL; fmd_hdl_debug(hdl, "solving fault '%s'", faultname); /* * Construct the detector from the case data. The detector is in the * ZFS scheme, and is either the pool or the vdev, depending on whether * this is a vdev or pool fault. */ detector = fmd_nvl_alloc(hdl, FMD_SLEEP); (void) nvlist_add_uint8(detector, FM_VERSION, ZFS_SCHEME_VERSION0); (void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS); (void) nvlist_add_uint64(detector, FM_FMRI_ZFS_POOL, zcp->zc_data.zc_pool_guid); if (zcp->zc_data.zc_vdev_guid != 0) { (void) nvlist_add_uint64(detector, FM_FMRI_ZFS_VDEV, zcp->zc_data.zc_vdev_guid); } fault = fmd_nvl_create_fault(hdl, faultname, 100, detector, fru, detector); fmd_case_add_suspect(hdl, zcp->zc_case, fault); nvlist_free(fru); fmd_case_solve(hdl, zcp->zc_case); serialize = B_FALSE; if (zcp->zc_data.zc_has_remove_timer) { fmd_timer_remove(hdl, zcp->zc_remove_timer); zcp->zc_data.zc_has_remove_timer = 0; serialize = B_TRUE; } if (serialize) zfs_case_serialize(hdl, zcp); nvlist_free(detector); }
/* * Verify the contents of the self test log page. The log supports a maximum of * 20 entries, where each entry's parameter code is its index in the log. We * check that the parameter codes fall within this range, and that the size of * each page is what we expect. It's perfectly acceptable for there to be no * entries in this log, so we must also be sure to validate the contents as part * of the analysis phase. */ static int logpage_selftest_verify(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length, nvlist_t *nvl) { int i, plen = 0; boolean_t bad = B_FALSE; int entries = 0; ushort_t param_code; for (i = 0; i < log_length; i += plen, entries++) { lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen); param_code = BE_16(lphp->lph_param); if (param_code < LOGPAGE_SELFTEST_MIN_PARAM_CODE || param_code > LOGPAGE_SELFTEST_MAX_PARAM_CODE) { if (nvlist_add_uint16(nvl, "invalid-param-code", param_code) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); bad = B_TRUE; break; } if (lphp->lph_length != LOGPAGE_SELFTEST_PARAM_LEN) { if (nvlist_add_uint8(nvl, "invalid-length", lphp->lph_length) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); bad = B_TRUE; break; } plen = lphp->lph_length + sizeof (scsi_log_parameter_header_t); } if (bad) { sip->si_supp_log &= ~LOGPAGE_SUPP_SELFTEST; printf("selftest logpage validation failed\n"); } return (0); }
/* * fps_fmri_svc_set(nvlist_t *fmri_svc, const char *svc_fmri) * adds the detector data to fmri_svc. */ static int fps_fmri_svc_set(nvlist_t *fmri_svc, const char *svc_fmri) { if (fmri_svc == NULL) return (1); if (svc_fmri == NULL) return (1); if (nvlist_add_uint8(fmri_svc, FM_VERSION, FM_SVC_SCHEME_VERSION) != 0) return (1); if (nvlist_add_string(fmri_svc, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SVC) != 0) return (1); if (nvlist_add_string(fmri_svc, FM_FMRI_SVC_NAME, svc_fmri) != 0) return (1); return (0); }
/* * Verify that the IE log page is sane. This log page is potentially chock-full * of vendor specific information that we do not know how to access. All we can * do is check for the generic predictive failure bit. If this log page is not * well-formed, then bail out. */ static int logpage_ie_verify(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp, int log_length, nvlist_t *nvl) { int i, plen = 0; boolean_t seen = B_FALSE; scsi_ie_log_param_t *iep = (scsi_ie_log_param_t *)lphp; for (i = 0; i < log_length; i += plen) { iep = (scsi_ie_log_param_t *)((char *)iep + plen); if (BE_16(iep->ie_hdr.lph_param) == LOGPARAM_IE) { if (nvlist_add_boolean_value(nvl, "general", B_TRUE) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); if (lphp->lph_length < LOGPARAM_IE_MIN_LEN) { if (nvlist_add_uint8(nvl, "invalid-length", lphp->lph_length) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); } else { seen = B_TRUE; } break; } plen = iep->ie_hdr.lph_length + sizeof (scsi_log_parameter_header_t); } if (!seen) { sip->si_supp_log &= ~LOGPAGE_SUPP_IE; printf("IE logpage validation failed\n"); } return (0); }
static nvlist_t * mem_fmri_create(topo_mod_t *mod, char *serial, char *label) { int err; nvlist_t *fmri; if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0) return (NULL); err = nvlist_add_uint8(fmri, FM_VERSION, FM_MEM_SCHEME_VERSION); err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM); if (serial != NULL) err |= nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID, &serial, 1); if (label != NULL) err |= nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, label); if (err != 0) { nvlist_free(fmri); (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); return (NULL); } return (fmri); }
void fnvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) { VERIFY0(nvlist_add_uint8(nvl, name, val)); }
/*ARGSUSED3*/ static nvlist_t * fmevt_detector(nvlist_t *attr, char *ruleset, int user, int priv, fmev_pri_t pri) { char buf[FMEV_MAX_RULESET_LEN + 1]; char *ns, *subsys; nvlist_t *obj, *dtcr, *site, *ctxt; char *execname = NULL; int32_t i32; int64_t i64; int err = 0; char *str; (void) strncpy(buf, ruleset, sizeof (buf)); if (!fmevt_rs_burst(NULL, buf, &ns, &subsys, B_FALSE)) return (NULL); obj = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); dtcr = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); site = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); ctxt = fmd_nvl_alloc(fmevt_hdl, FMD_SLEEP); if (obj == NULL || dtcr == NULL || site == NULL || ctxt == NULL) { err++; goto done; } /* * Build up 'object' nvlist. */ if (nvlist_lookup_string(attr, "__fmev_execname", &execname) == 0) err += nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, execname); /* * Build up 'site' nvlist. We should have source file and line * number and, if the producer was compiled with C99, function name. */ if (nvlist_lookup_string(attr, "__fmev_file", &str) == 0) { err += nvlist_add_string(site, FM_FMRI_SW_SITE_FILE, str); (void) nvlist_remove(attr, "__fmev_file", DATA_TYPE_STRING); } if (nvlist_lookup_string(attr, "__fmev_func", &str) == 0) { err += nvlist_add_string(site, FM_FMRI_SW_SITE_FUNC, str); (void) nvlist_remove(attr, "__fmev_func", DATA_TYPE_STRING); } if (nvlist_lookup_int64(attr, "__fmev_line", &i64) == 0) { err += nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, i64); (void) nvlist_remove(attr, "__fmev_line", DATA_TYPE_INT64); } /* * Build up 'context' nvlist. We do not include contract id at * this time. */ err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN, user ? "userland" : "kernel"); if (execname) { err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME, execname); (void) nvlist_remove(attr, "__fmev_execname", DATA_TYPE_STRING); } if (nvlist_lookup_int32(attr, "__fmev_pid", &i32) == 0) { err += nvlist_add_int32(ctxt, FM_FMRI_SW_CTXT_PID, i32); (void) nvlist_remove(attr, "__fmev_pid", DATA_TYPE_INT32); } if (!isglobalzone) err += nvlist_add_string(ctxt, FM_FMRI_SW_CTXT_ZONE, zonename); /* Put it all together */ err += nvlist_add_uint8(dtcr, FM_VERSION, SW_SCHEME_VERSION0); err += nvlist_add_string(dtcr, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW); err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_OBJ, obj); err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_SITE, site); err += nvlist_add_nvlist(dtcr, FM_FMRI_SW_CTXT, ctxt); done: nvlist_free(obj); nvlist_free(site); nvlist_free(ctxt); if (err == 0) { return (dtcr); } else { nvlist_free(dtcr); return (NULL); } }
/* * fps_generate_ereport_struct(struct fps_test_ereport *report) * takes report and constructs an nvlist that will be used * for the ereport. */ int fps_generate_ereport_struct(struct fps_test_ereport *report) { char class_name[FM_MAX_CLASS]; char *cpu_brand; char *string_data; int expect_size; int is_valid_cpu; int mask; int observe_size; int ret; nvlist_t *detector; nvlist_t *ereport; nvlist_t *resource; uint32_t cpu_id; uint32_t test; uint8_t fps_ver; uint64_t ena; uint64_t ereport_time; uint64_t *expect; uint64_t *observe; if (report == NULL) return (FPU_EREPORT_FAIL); ret = FPU_FOROFFLINE; cpu_id = report->cpu_id; test = report->test_id; mask = report->mask; is_valid_cpu = report->is_valid_cpu; expect_size = report->expected_size; expect = report->expected; observe_size = report->observed_size; observe = report->observed; string_data = report->info; /* allocate nvlists */ if ((ereport = fps_nvlist_create()) == NULL) _exit(FPU_EREPORT_FAIL); if ((detector = fps_nvlist_create()) == NULL) { _exit(FPU_EREPORT_FAIL); } /* setup class */ if ((cpu_brand = fps_get_cpu_brand(cpu_id)) == NULL) _exit(FPU_EREPORT_FAIL); if ((snprintf(class_name, FM_MAX_CLASS, "%s.%s.%s", CLASS_HEAD, cpu_brand, CLASS_TAIL)) < 0) _exit(FPU_EREPORT_FAIL); /* setup ena */ ereport_time = gethrtime(); ena = fps_ena_generate(ereport_time, cpu_id, FM_ENA_FMT1); /* setup detector */ if (fps_fmri_svc_set(detector, getenv("SMF_FMRI")) != 0) { _exit(FPU_EREPORT_FAIL); } /* setup fps-version */ fps_ver = FPS_VERSION; /* setup resource */ if (is_valid_cpu) { resource = fps_nvlist_create(); if (fps_fmri_cpu_set(resource, cpu_id)) { _exit(FPU_EREPORT_FAIL); } } else { resource = NULL; } /* put it together */ if (nvlist_add_string(ereport, NAME_FPS_CLASS, class_name) != 0) _exit(FPU_EREPORT_FAIL); if (ena != 0) { if (nvlist_add_uint64(ereport, NAME_FPS_ENA, ena) != 0) _exit(FPU_EREPORT_FAIL); } else _exit(FPU_EREPORT_FAIL); if (nvlist_add_nvlist(ereport, NAME_FPS_DETECTOR, (nvlist_t *)detector) != 0) _exit(FPU_EREPORT_FAIL); if (nvlist_add_uint8(ereport, NAME_FPS_VERSION, fps_ver) != 0) _exit(FPU_EREPORT_FAIL); if (nvlist_add_uint32(ereport, NAME_FPS_TEST_ID, test) != 0) ret = FPU_EREPORT_INCOM; if (nvlist_add_uint64_array(ereport, NAME_FPS_EXPECTED_VALUE, expect, expect_size) != 0) ret = FPU_EREPORT_INCOM; if (nvlist_add_uint64_array(ereport, NAME_FPS_OBSERVED_VALUE, observe, observe_size) != 0) ret = FPU_EREPORT_INCOM; if (mask & IS_EREPORT_INFO) { if (nvlist_add_string(ereport, NAME_FPS_STRING_DATA, string_data) != 0) ret = FPU_EREPORT_INCOM; } if (is_valid_cpu) { if (nvlist_add_nvlist(ereport, NAME_FPS_RESOURCE, (nvlist_t *)resource) != 0) _exit(FPU_EREPORT_FAIL); } /* publish */ if (fps_post_ereport(ereport)) { ret = FPU_EREPORT_FAIL; } /* free nvlists */ nvlist_free(ereport); if (resource != NULL) nvlist_free(resource); if (detector != NULL) nvlist_free(detector); return (ret); }
/* * Solve a given ZFS case. This first checks to make sure the diagnosis is * still valid, as well as cleaning up any pending timer associated with the * case. */ static void zfs_case_solve(fmd_hdl_t *hdl, zfs_case_t *zcp, const char *faultname, boolean_t checkunusable) { libzfs_handle_t *zhdl = fmd_hdl_getspecific(hdl); nvlist_t *detector, *fault; boolean_t serialize; nvlist_t *fmri, *fru; topo_hdl_t *thp; int err; /* * Construct the detector from the case data. The detector is in the * ZFS scheme, and is either the pool or the vdev, depending on whether * this is a vdev or pool fault. */ detector = fmd_nvl_alloc(hdl, FMD_SLEEP); (void) nvlist_add_uint8(detector, FM_VERSION, ZFS_SCHEME_VERSION0); (void) nvlist_add_string(detector, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS); (void) nvlist_add_uint64(detector, FM_FMRI_ZFS_POOL, zcp->zc_data.zc_pool_guid); if (zcp->zc_data.zc_vdev_guid != 0) { (void) nvlist_add_uint64(detector, FM_FMRI_ZFS_VDEV, zcp->zc_data.zc_vdev_guid); } /* * We also want to make sure that the detector (pool or vdev) properly * reflects the diagnosed state, when the fault corresponds to internal * ZFS state (i.e. not checksum or I/O error-induced). Otherwise, a * device which was unavailable early in boot (because the driver/file * wasn't available) and is now healthy will be mis-diagnosed. */ if (!fmd_nvl_fmri_present(hdl, detector) || (checkunusable && !fmd_nvl_fmri_unusable(hdl, detector))) { fmd_case_close(hdl, zcp->zc_case); nvlist_free(detector); return; } fru = NULL; if (zcp->zc_fru != NULL && (thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) != NULL) { /* * If the vdev had an associated FRU, then get the FRU nvlist * from the topo handle and use that in the suspect list. We * explicitly lookup the FRU because the fmri reported from the * kernel may not have up to date details about the disk itself * (serial, part, etc). */ if (topo_fmri_str2nvl(thp, zcp->zc_fru, &fmri, &err) == 0) { /* * If the disk is part of the system chassis, but the * FRU indicates a different chassis ID than our * current system, then ignore the error. This * indicates that the device was part of another * cluster head, and for obvious reasons cannot be * imported on this system. */ if (libzfs_fru_notself(zhdl, zcp->zc_fru)) { fmd_case_close(hdl, zcp->zc_case); nvlist_free(fmri); fmd_hdl_topo_rele(hdl, thp); nvlist_free(detector); return; } /* * If the device is no longer present on the system, or * topo_fmri_fru() fails for other reasons, then fall * back to the fmri specified in the vdev. */ if (topo_fmri_fru(thp, fmri, &fru, &err) != 0) fru = fmd_nvl_dup(hdl, fmri, FMD_SLEEP); nvlist_free(fmri); } fmd_hdl_topo_rele(hdl, thp); } fault = fmd_nvl_create_fault(hdl, faultname, 100, detector, fru, detector); fmd_case_add_suspect(hdl, zcp->zc_case, fault); nvlist_free(fru); fmd_case_solve(hdl, zcp->zc_case); serialize = B_FALSE; if (zcp->zc_data.zc_has_remove_timer) { fmd_timer_remove(hdl, zcp->zc_remove_timer); zcp->zc_data.zc_has_remove_timer = 0; serialize = B_TRUE; } if (serialize) zfs_case_serialize(hdl, zcp); nvlist_free(detector); }
/*ARGSUSED*/ static int sw_fmri_create(topo_mod_t *mod, tnode_t *node, topo_version_t version, nvlist_t *in, nvlist_t **out) { nvlist_t *args, *fmri = NULL, *obj = NULL, *site = NULL, *ctxt = NULL; topo_mod_errno_t moderr; int err = 0; char *obj_path, *obj_root; nvlist_t *obj_pkg; char *site_token, *site_module, *site_file, *site_func; int64_t site_line; char *ctxt_origin, *ctxt_execname, *ctxt_zone; int64_t ctxt_pid, ctxt_ctid; char **ctxt_stack; uint_t ctxt_stackdepth; if (version > TOPO_METH_FMRI_VERSION) return (topo_mod_seterrno(mod, EMOD_VER_NEW)); if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NVL, &args) != 0) return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL)); if (nvlist_lookup_string(args, "obj_path", &obj_path) != 0) return (topo_mod_seterrno(mod, EMOD_NVL_INVAL)); err |= sw_get_optl_string(args, "obj_root", &obj_root); err |= sw_get_optl_nvlist(args, "obj-pkg", &obj_pkg); err |= sw_get_optl_string(args, "site_token", &site_token); err |= sw_get_optl_string(args, "site_module", &site_module); err |= sw_get_optl_string(args, "site_file", &site_file); err |= sw_get_optl_string(args, "site_func", &site_func); err |= sw_get_optl_int64(args, "site_line", &site_line); err |= sw_get_optl_string(args, "ctxt_origin", &ctxt_origin); err |= sw_get_optl_string(args, "ctxt_execname", &ctxt_execname); err |= sw_get_optl_string(args, "ctxt_zone", &ctxt_zone); err |= sw_get_optl_int64(args, "ctxt_pid", &ctxt_pid); err |= sw_get_optl_int64(args, "ctxt_ctid", &ctxt_ctid); if (nvlist_lookup_string_array(args, "stack", &ctxt_stack, &ctxt_stackdepth) != 0) { if (errno == ENOENT) ctxt_stack = NULL; else err++; } if (err) (void) topo_mod_seterrno(mod, EMOD_FMRI_NVL); if (topo_mod_nvalloc(mod, &fmri, NV_UNIQUE_NAME) != 0 || topo_mod_nvalloc(mod, &obj, NV_UNIQUE_NAME) != 0) { moderr = EMOD_NOMEM; goto out; } /* * Add standard FMRI members 'version' and 'scheme'. */ err |= nvlist_add_uint8(fmri, FM_VERSION, FM_SW_SCHEME_VERSION); err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_SW); /* * Build up the 'object' nvlist. */ err |= nvlist_add_string(obj, FM_FMRI_SW_OBJ_PATH, obj_path); err |= sw_add_optl_string(obj, FM_FMRI_SW_OBJ_ROOT, obj_root); if (obj_pkg) err |= nvlist_add_nvlist(obj, FM_FMRI_SW_OBJ_PKG, obj_pkg); /* * Add 'object' to the fmri. */ if (err == 0) err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_OBJ, obj); if (err) { moderr = EMOD_NOMEM; goto out; } /* * Do we have anything for a 'site' nvlist? */ if (site_token == NULL && site_module == NULL && site_file == NULL && site_func == NULL && site_line == -1) goto context; /* * Allocate and build 'site' nvlist. */ if (topo_mod_nvalloc(mod, &site, NV_UNIQUE_NAME) != 0) { moderr = EMOD_NOMEM; goto out; } err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_TOKEN, site_token); err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_MODULE, site_module); err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FILE, site_file); err |= sw_add_optl_string(site, FM_FMRI_SW_SITE_FUNC, site_func); if ((site_token || site_module || site_file || site_func) && site_line != -1) err |= nvlist_add_int64(site, FM_FMRI_SW_SITE_LINE, site_line); /* * Add 'site' to the fmri. */ if (err == 0) err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_SITE, site); if (err) { moderr = EMOD_NOMEM; goto out; } context: /* * Do we have anything for a 'context' nvlist? */ if (ctxt_origin || ctxt_execname || ctxt_zone || ctxt_pid != -1 || ctxt_ctid != -1 || ctxt_stack != NULL) goto out; /* * Allocate and build 'context' nvlist. */ if (topo_mod_nvalloc(mod, &ctxt, NV_UNIQUE_NAME) != 0) { moderr = EMOD_NOMEM; goto out; } err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ORIGIN, ctxt_origin); err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_EXECNAME, ctxt_execname); err |= sw_add_optl_string(ctxt, FM_FMRI_SW_CTXT_ZONE, ctxt_zone); if (ctxt_pid != -1) err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_PID, ctxt_pid); if (ctxt_ctid != -1) err |= nvlist_add_int64(ctxt, FM_FMRI_SW_CTXT_CTID, ctxt_ctid); if (ctxt_stack != NULL) err |= nvlist_add_string_array(ctxt, FM_FMRI_SW_CTXT_STACK, ctxt_stack, ctxt_stackdepth); /* * Add 'context' to the fmri. */ if (err == 0) err |= nvlist_add_nvlist(fmri, FM_FMRI_SW_CTXT, ctxt); moderr = err ? EMOD_NOMEM : 0; out: if (moderr == 0) *out = fmri; if (moderr != 0 && fmri) nvlist_free(fmri); if (obj) nvlist_free(obj); if (site) nvlist_free(site); if (ctxt) nvlist_free(ctxt); return (moderr == 0 ? 0 : topo_mod_seterrno(mod, moderr)); }
int main(int argc, char *argv[]) { fmd_msg_hdl_t *h; pid_t pid; int i, err = 0; char *s; nvlist_t *auth, *fmri, *list, *test_arr[TEST_ARR_SZ]; const char *code = "TEST-8000-08"; int64_t tod[] = { 0x9400000, 0 }; if (argc > 1) { (void) fprintf(stderr, "Usage: %s\n", argv[0]); return (2); } /* * Build up a valid list.suspect event for a fictional diagnosis * using a diagnosis code from our test dictionary so we can format * messages. */ if (nvlist_alloc(&auth, NV_UNIQUE_NAME, 0) != 0 || nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0) != 0 || nvlist_alloc(&list, NV_UNIQUE_NAME, 0) != 0) { (void) fprintf(stderr, "%s: nvlist_alloc failed\n", argv[0]); return (1); } err |= nvlist_add_uint8(auth, FM_VERSION, FM_FMRI_AUTH_VERSION); err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, "product"); err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT_SN, "product_sn"); err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, "chassis"); err |= nvlist_add_string(auth, FM_FMRI_AUTH_DOMAIN, "domain"); err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, "server"); if (err != 0) { (void) fprintf(stderr, "%s: failed to build auth nvlist: %s\n", argv[0], strerror(err)); return (1); } err |= nvlist_add_uint8(fmri, FM_VERSION, FM_FMD_SCHEME_VERSION); err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_FMD); err |= nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, auth); err |= nvlist_add_string(fmri, FM_FMRI_FMD_NAME, "fmd_msg_test"); err |= nvlist_add_string(fmri, FM_FMRI_FMD_VERSION, "1.0"); if (err != 0) { (void) fprintf(stderr, "%s: failed to build fmri nvlist: %s\n", argv[0], strerror(err)); return (1); } err |= nvlist_add_uint8(list, FM_VERSION, FM_SUSPECT_VERSION); err |= nvlist_add_string(list, FM_CLASS, FM_LIST_SUSPECT_CLASS); err |= nvlist_add_string(list, FM_SUSPECT_UUID, "12345678"); err |= nvlist_add_string(list, FM_SUSPECT_DIAG_CODE, code); err |= nvlist_add_int64_array(list, FM_SUSPECT_DIAG_TIME, tod, 2); err |= nvlist_add_nvlist(list, FM_SUSPECT_DE, fmri); err |= nvlist_add_uint32(list, FM_SUSPECT_FAULT_SZ, 0); /* * Add a contrived nvlist array to our list.suspect so that we can * exercise the expansion syntax for dereferencing nvlist array members */ for (i = 0; i < TEST_ARR_SZ; i++) { if (nvlist_alloc(&test_arr[i], NV_UNIQUE_NAME, 0) != 0) { (void) fprintf(stderr, "%s: failed to alloc nvlist " "array: %s\n", argv[0], strerror(err)); return (1); } err |= nvlist_add_uint8(test_arr[i], "index", i); } err |= nvlist_add_nvlist_array(list, "test_arr", test_arr, TEST_ARR_SZ); if (err != 0) { (void) fprintf(stderr, "%s: failed to build list nvlist: %s\n", argv[0], strerror(err)); return (1); } /* * Now initialize the libfmd_msg library for testing, using the message * catalogs found in the proto area of the current workspace. */ if ((h = fmd_msg_init(getenv("ROOT"), FMD_MSG_VERSION)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_init failed: %s\n", argv[0], strerror(errno)); return (1); } /* * Test 0: Verify that both fmd_msg_getitem_id and fmd_msg_gettext_id * return NULL and EINVAL for an illegal message code, and NULL * and ENOENT for a valid but not defined message code. */ s = fmd_msg_getitem_id(h, NULL, "I_AM_NOT_VALID", 0); if (s != NULL || errno != EINVAL) { (void) fprintf(stderr, "%s: test0 FAIL: illegal code returned " "s = %p, errno = %d\n", argv[0], (void *)s, errno); return (1); } s = fmd_msg_gettext_id(h, NULL, "I_AM_NOT_VALID"); if (s != NULL || errno != EINVAL) { (void) fprintf(stderr, "%s: test0 FAIL: illegal code returned " "s = %p, errno = %d\n", argv[0], (void *)s, errno); return (1); } s = fmd_msg_getitem_id(h, NULL, "I_AM_NOT_HERE-0000-0000", 0); if (s != NULL || errno != ENOENT) { (void) fprintf(stderr, "%s: test0 FAIL: missing code returned " "s = %p, errno = %d\n", argv[0], (void *)s, errno); return (1); } s = fmd_msg_gettext_id(h, NULL, "I_AM_NOT_HERE-0000-0000"); if (s != NULL || errno != ENOENT) { (void) fprintf(stderr, "%s: test0 FAIL: missing code returned " "s = %p, errno = %d\n", argv[0], (void *)s, errno); return (1); } /* * Test 1: Use fmd_msg_getitem_id to retrieve the item strings for * a known message code without having any actual event handle. */ for (i = 0; i < FMD_MSG_ITEM_MAX; i++) { if ((s = fmd_msg_getitem_id(h, NULL, code, i)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_getitem_id failed " "for %s, item %d: %s\n", argv[0], code, i, strerror(errno)); } (void) printf("code %s item %d = <<%s>>\n", code, i, s); free(s); } /* * Test 2: Use fmd_msg_gettext_id to retrieve the complete message for * a known message code without having any actual event handle. */ if ((s = fmd_msg_gettext_id(h, NULL, code)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_gettext_id failed for %s: " "%s\n", argv[0], code, strerror(errno)); return (1); } (void) printf("%s\n", s); free(s); /* * Test 3: Use fmd_msg_getitem_nv to retrieve the item strings for * our list.suspect event handle. */ for (i = 0; i < FMD_MSG_ITEM_MAX; i++) { if ((s = fmd_msg_getitem_nv(h, NULL, list, i)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_getitem_nv failed " "for %s, item %d: %s\n", argv[0], code, i, strerror(errno)); } (void) printf("code %s item %d = <<%s>>\n", code, i, s); free(s); } /* * Test 4: Use fmd_msg_getitem_nv to retrieve the complete message for * a known message code using our list.suspect event handle. */ if ((s = fmd_msg_gettext_nv(h, NULL, list)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_gettext_nv failed for %s: " "%s\n", argv[0], code, strerror(errno)); return (1); } (void) printf("%s\n", s); free(s); /* * Test 5: Use fmd_msg_getitem_nv to retrieve the complete message for * a known message code using our list.suspect event handle, but this * time set the URL to our own customized URL. Our contrived message * has been designed to exercise the key aspects of the variable * expansion syntax. */ if (fmd_msg_url_set(h, "http://foo.bar.com/") != 0) { (void) fprintf(stderr, "%s: fmd_msg_url_set failed: %s\n", argv[0], strerror(errno)); } if ((s = fmd_msg_gettext_nv(h, NULL, list)) == NULL) { (void) fprintf(stderr, "%s: fmd_msg_gettext_nv failed for %s: " "%s\n", argv[0], code, strerror(errno)); return (1); } (void) printf("%s\n", s); free(s); for (i = 0; i < TEST_ARR_SZ; i++) nvlist_free(test_arr[i]); nvlist_free(fmri); nvlist_free(auth); nvlist_free(list); fmd_msg_fini(h); /* free library state before dumping core */ pid = fork(); /* fork into background to not bother make(1) */ switch (pid) { case -1: (void) fprintf(stderr, "FAIL (failed to fork)\n"); return (1); case 0: abort(); return (1); } if (waitpid(pid, &err, 0) == -1) { (void) fprintf(stderr, "FAIL (failed to wait for %d: %s)\n", (int)pid, strerror(errno)); return (1); } if (WIFSIGNALED(err) == 0 || WTERMSIG(err) != SIGABRT) { (void) fprintf(stderr, "FAIL (child did not SIGABRT)\n"); return (1); } if (!WCOREDUMP(err)) { (void) fprintf(stderr, "FAIL (no core generated)\n"); return (1); } (void) fprintf(stderr, "done\n"); return (0); }
nvlist_t * cmd_mkboard_fru(fmd_hdl_t *hdl, char *frustr, char *serialstr, char *partstr) { char *nac, *nac_name; int n, i, len; nvlist_t *fru, **hc_list; if (frustr == NULL) return (NULL); if ((nac_name = strstr(frustr, "MB")) == NULL) return (NULL); len = strlen(nac_name) + 1; nac = fmd_hdl_zalloc(hdl, len, FMD_SLEEP); (void) strcpy(nac, nac_name); n = cmd_count_components(nac, '/'); fmd_hdl_debug(hdl, "cmd_mkboard_fru: nac=%s components=%d\n", nac, n); hc_list = fmd_hdl_zalloc(hdl, sizeof (nvlist_t *)*n, FMD_SLEEP); for (i = 0; i < n; i++) { (void) nvlist_alloc(&hc_list[i], NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE, 0); } if (cmd_breakup_components(nac, "/", hc_list) < 0) { for (i = 0; i < n; i++) { if (hc_list[i] != NULL) nvlist_free(hc_list[i]); } fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); fmd_hdl_free(hdl, nac, len); return (NULL); } if (nvlist_alloc(&fru, NV_UNIQUE_NAME, 0) != 0) { for (i = 0; i < n; i++) { if (hc_list[i] != NULL) nvlist_free(hc_list[i]); } fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); fmd_hdl_free(hdl, nac, len); return (NULL); } if (nvlist_add_uint8(fru, FM_VERSION, FM_HC_SCHEME_VERSION) != 0 || nvlist_add_string(fru, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0 || nvlist_add_string(fru, FM_FMRI_HC_ROOT, "") != 0 || nvlist_add_uint32(fru, FM_FMRI_HC_LIST_SZ, n) != 0 || nvlist_add_nvlist_array(fru, FM_FMRI_HC_LIST, hc_list, n) != 0) { for (i = 0; i < n; i++) { if (hc_list[i] != NULL) nvlist_free(hc_list[i]); } fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); fmd_hdl_free(hdl, nac, len); nvlist_free(fru); return (NULL); } for (i = 0; i < n; i++) { if (hc_list[i] != NULL) nvlist_free(hc_list[i]); } fmd_hdl_free(hdl, hc_list, sizeof (nvlist_t *)*n); fmd_hdl_free(hdl, nac, len); if ((serialstr != NULL && nvlist_add_string(fru, FM_FMRI_HC_SERIAL_ID, serialstr) != 0) || (partstr != NULL && nvlist_add_string(fru, FM_FMRI_HC_PART, partstr) != 0)) { nvlist_free(fru); return (NULL); } return (fru); }