diskmon_t * dm_fmri_to_diskmon(fmd_hdl_t *hdl, nvlist_t *fmri) { topo_hdl_t *thdl; nvlist_t *dupfmri; diskmon_t *diskp; char *buf; int err; if (nvlist_dup(fmri, &dupfmri, 0) != 0) return (NULL); (void) nvlist_remove(dupfmri, FM_FMRI_HC_REVISION, DATA_TYPE_STRING); (void) nvlist_remove(dupfmri, FM_FMRI_HC_SERIAL_ID, DATA_TYPE_STRING); (void) nvlist_remove(dupfmri, FM_FMRI_HC_PART, DATA_TYPE_STRING); thdl = fmd_hdl_topo_hold(hdl, TOPO_VERSION); if (topo_fmri_nvl2str(thdl, dupfmri, &buf, &err) != 0) { fmd_hdl_topo_rele(hdl, thdl); nvlist_free(dupfmri); return (NULL); } fmd_hdl_topo_rele(hdl, thdl); diskp = dm_fmristring_to_diskmon(buf); nvlist_free(dupfmri); topo_hdl_strfree(thdl, buf); return (diskp); }
/* * The cmd_dimm_t structure created for a DIMM in a branch never has a * Jxxx in its unum; the cmd_dimm_t structure created for a DIMM containing * a page, or in a bank (i.e. for ECC errors)-always-has a Jxxx in its * unum. Therefore the set of cmd_dimm_t's created for a branch is always * disjoint from the set of cmd_dimm_t's created for pages and/or banks, so * the cmd_dimm_create will never link a 'branch' cmd_dimm_t into bank. * Faulting a DIMM for ECC will not prevent subsequent faulting of "same" * dimm for FBR/FBU and vice versa */ static int branch_dimmlist_create(fmd_hdl_t *hdl, cmd_branch_t *branch) { topo_hdl_t *thp; topo_walk_t *twp; int err, dimm_count; cmd_list_t *bp; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) return (0); if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_MEM, branch_dimm_cb, branch, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (0); } br_hdl = hdl; (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); for (dimm_count = 0, bp = cmd_list_next(&branch->branch_dimms); bp != NULL; bp = cmd_list_next(bp), dimm_count++) ; return (dimm_count); }
nvlist_t * cmd_find_dimm_by_sn(fmd_hdl_t *hdl, char *schemename, char *sn) { topo_hdl_t *thp; topo_walk_t *twp; int err; dimm_nvl = NULL; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) return (NULL); if (strcmp(schemename, FM_FMRI_SCHEME_MEM) == 0) { if ((twp = topo_walk_init(thp, schemename, find_dimm_sn_mem, sn, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (NULL); } } else { if ((twp = topo_walk_init(thp, schemename, find_dimm_sn_hc, sn, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (NULL); } } (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); return (dimm_nvl); }
/* * Convert a shorthand svc FMRI into a full svc FMRI nvlist */ static nvlist_t * shortfmri_to_fmri(fmd_hdl_t *hdl, const char *shortfmristr) { nvlist_t *ret, *fmri; topo_hdl_t *thp; char *fmristr; int err; if ((fmristr = shortfmri_to_fmristr(hdl, shortfmristr)) == NULL) return (NULL); thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION); if (topo_fmri_str2nvl(thp, fmristr, &fmri, &err) != 0) { fmd_hdl_error(hdl, "failed to convert '%s' to nvlist\n", fmristr); fmd_hdl_strfree(hdl, fmristr); fmd_hdl_topo_rele(hdl, thp); return (NULL); } fmd_hdl_strfree(hdl, fmristr); if ((ret = fmd_nvl_dup(hdl, fmri, FMD_SLEEP)) == NULL) { fmd_hdl_error(hdl, "failed to dup fmri\n"); nvlist_free(fmri); fmd_hdl_topo_rele(hdl, thp); return (NULL); } nvlist_free(fmri); fmd_hdl_topo_rele(hdl, thp); return (ret); }
/* * Walk all of the topology nodes looking for DISKs that match the structure * described in the overview. Once we find them, check their fault status * and update their fault indiciator accordingly. */ static void dl_examine_topo(disk_lights_t *dl) { int err; topo_hdl_t *thp = NULL; topo_walk_t *twp = NULL; thp = fmd_hdl_topo_hold(dl->dl_fmd, TOPO_VERSION); if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, dl_fault_walk_outer, dl, &err)) == NULL) { fmd_hdl_error(dl->dl_fmd, "failed to get topology: %s\n", topo_strerror(err)); goto out; } if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { fmd_hdl_error(dl->dl_fmd, "failed to walk topology: %s\n", topo_strerror(err)); goto out; } out: if (twp != NULL) topo_walk_fini(twp); if (thp != NULL) fmd_hdl_topo_rele(dl->dl_fmd, thp); }
nvlist_t * cmd_find_cpu_rsc_by_sn(fmd_hdl_t *hdl, cpuid_t *cpuid) { topo_hdl_t *thp; topo_walk_t *twp; int err; rsc_nvl = NULL; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) return (NULL); if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, find_cpu_rsc_by_sn, cpuid, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (NULL); } (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); return (rsc_nvl); }
nvlist_t * init_mb(fmd_hdl_t *hdl) { topo_hdl_t *thp; topo_walk_t *twp; int err; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) return (NULL); if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, find_mb, NULL, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (NULL); } (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); return (mb_nvl); }
static int branch_exist(fmd_hdl_t *hdl, cmd_branch_t *branch) { topo_hdl_t *thp; topo_walk_t *twp; int err; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) return (0); if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_MEM, branch_exist_cb, branch, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (0); } br_dimmcount = 0; (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); return (br_dimmcount); }
/*ARGSUSED*/ int update_configuration_from_topo(fmd_hdl_t *hdl, diskmon_t *diskp) { int err; topo_hdl_t *thp; topo_walk_t *twp; walk_diskmon_t wd; if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) { return (TOPO_OPEN_ERROR); } wd.target = diskp; wd.pfmri = NULL; if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, gather_topo_cfg, &wd, &err)) == NULL) { fmd_hdl_topo_rele(hdl, thp); return (err ? TOPO_WALK_INIT_ERROR : TOPO_SUCCESS); } if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) { topo_walk_fini(twp); if (wd.pfmri != NULL) dstrfree(wd.pfmri); fmd_hdl_topo_rele(hdl, thp); return (TOPO_WALK_ERROR); } topo_walk_fini(twp); fmd_hdl_topo_rele(hdl, thp); if (wd.pfmri != NULL) dstrfree(wd.pfmri); return (TOPO_SUCCESS); }
static nvlist_t * fru_by_label(fmd_hdl_t *hdl, const char *target) { topo_hdl_t *thp; topo_walk_t *twp; int err; br_memb_nvl = NULL; if (((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) != NULL) && ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, fru_by_label_cb, (void *)target, &err)) != NULL)) { br_hdl = hdl; (void) topo_walk_step(twp, TOPO_WALK_CHILD); topo_walk_fini(twp); } fmd_hdl_topo_rele(hdl, thp); return (br_memb_nvl); }
/* * 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); }